Skip to content

Commit 8a5458c

Browse files
authored
[C23] Fix typeof handling in enum declarations (#146394)
We have a parsing helper function which parses either a parenthesized expression or a parenthesized type name. This is used when parsing a unary operator such as sizeof, for example. The problem this solves is when that construct is ambiguous. Consider: enum E : typeof(int) { F }; After we've parsed the 'typeof', what ParseParenExpression() is responsible for is '(int) { F }' which looks like a compound literal expression when it's actually the parens and operand for 'typeof' followed by the enumerator list for the enumeration declaration. Then consider: sizeof (int){ 0 }; After we've parsed 'sizeof', ParseParenExpression is responsible for parsing something grammatically similar to the problematic case. The solution is to recognize that the expression form of 'typeof' is required to have parentheses. So we know the open and close parens that ParseParenExpression handles must be part of the grammar production for the operator, not part of the operand expression itself. Fixes #146351
1 parent 40fb90e commit 8a5458c

File tree

9 files changed

+181
-116
lines changed

9 files changed

+181
-116
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ C23 Feature Support
306306
which clarified how Clang is handling underspecified object declarations.
307307
- Clang now accepts single variadic parameter in type-name. It's a part of
308308
`WG14 N2975 <https://open-std.org/JTC1/SC22/WG14/www/docs/n2975.pdf>`_
309+
- Fixed a bug with handling the type operand form of ``typeof`` when it is used
310+
to specify a fixed underlying type for an enumeration. #GH146351
309311

310312
C11 Feature Support
311313
^^^^^^^^^^^^^^^^^^^

clang/include/clang/Parse/Parser.h

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,13 @@ enum class ObjCTypeQual {
101101
NumQuals
102102
};
103103

104-
/// TypeCastState - State whether an expression is or may be a type cast.
105-
enum class TypeCastState { NotTypeCast = 0, MaybeTypeCast, IsTypeCast };
104+
/// If a typo should be encountered, should typo correction suggest type names,
105+
/// non type names, or both?
106+
enum class TypoCorrectionTypeBehavior {
107+
AllowNonTypes,
108+
AllowTypes,
109+
AllowBoth,
110+
};
106111

107112
/// Control what ParseCastExpression will parse.
108113
enum class CastParseKind { AnyCastExpr = 0, UnaryExprOnly, PrimaryExprOnly };
@@ -116,6 +121,15 @@ enum class ParenParseOption {
116121
CastExpr // Also allow '(' type-name ')' <anything>
117122
};
118123

124+
/// In a call to ParseParenExpression, are the initial parentheses part of an
125+
/// operator that requires the parens be there (like typeof(int)) or could they
126+
/// be something else, such as part of a compound literal or a sizeof
127+
/// expression, etc.
128+
enum class ParenExprKind {
129+
PartOfOperator, // typeof(int)
130+
Unknown, // sizeof(int) or sizeof (int)1.0f, or compound literal, etc
131+
};
132+
119133
/// Describes the behavior that should be taken for an __if_exists
120134
/// block.
121135
enum class IfExistsBehavior {
@@ -3709,11 +3723,12 @@ class Parser : public CodeCompletionHandler {
37093723
/// assignment-expression ...[opt]
37103724
/// expression ',' assignment-expression ...[opt]
37113725
/// \endverbatim
3712-
ExprResult
3713-
ParseExpression(TypeCastState isTypeCast = TypeCastState::NotTypeCast);
3726+
ExprResult ParseExpression(TypoCorrectionTypeBehavior CorrectionBehavior =
3727+
TypoCorrectionTypeBehavior::AllowNonTypes);
37143728

37153729
ExprResult ParseConstantExpressionInExprEvalContext(
3716-
TypeCastState isTypeCast = TypeCastState::NotTypeCast);
3730+
TypoCorrectionTypeBehavior CorrectionBehavior =
3731+
TypoCorrectionTypeBehavior::AllowNonTypes);
37173732
ExprResult ParseConstantExpression();
37183733
ExprResult ParseArrayBoundExpression();
37193734
ExprResult ParseCaseExpression(SourceLocation CaseLoc);
@@ -3750,8 +3765,9 @@ class Parser : public CodeCompletionHandler {
37503765
ExprResult ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause);
37513766

37523767
/// Parse an expr that doesn't include (top-level) commas.
3753-
ExprResult ParseAssignmentExpression(
3754-
TypeCastState isTypeCast = TypeCastState::NotTypeCast);
3768+
ExprResult
3769+
ParseAssignmentExpression(TypoCorrectionTypeBehavior CorrectionBehavior =
3770+
TypoCorrectionTypeBehavior::AllowNonTypes);
37553771

37563772
ExprResult ParseConditionalExpression();
37573773

@@ -4017,14 +4033,15 @@ class Parser : public CodeCompletionHandler {
40174033
///
40184034
ExprResult ParseCastExpression(CastParseKind ParseKind,
40194035
bool isAddressOfOperand, bool &NotCastExpr,
4020-
TypeCastState isTypeCast,
4036+
TypoCorrectionTypeBehavior CorrectionBehavior,
4037+
bool isVectorLiteral = false,
4038+
bool *NotPrimaryExpression = nullptr);
4039+
ExprResult ParseCastExpression(CastParseKind ParseKind,
4040+
bool isAddressOfOperand = false,
4041+
TypoCorrectionTypeBehavior CorrectionBehavior =
4042+
TypoCorrectionTypeBehavior::AllowNonTypes,
40214043
bool isVectorLiteral = false,
40224044
bool *NotPrimaryExpression = nullptr);
4023-
ExprResult
4024-
ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand = false,
4025-
TypeCastState isTypeCast = TypeCastState::NotTypeCast,
4026-
bool isVectorLiteral = false,
4027-
bool *NotPrimaryExpression = nullptr);
40284045

40294046
/// Returns true if the next token cannot start an expression.
40304047
bool isNotExpressionStart();
@@ -4181,10 +4198,15 @@ class Parser : public CodeCompletionHandler {
41814198
/// \endverbatim
41824199
bool ParseSimpleExpressionList(SmallVectorImpl<Expr *> &Exprs);
41834200

4184-
/// ParseParenExpression - This parses the unit that starts with a '(' token,
4185-
/// based on what is allowed by ExprType. The actual thing parsed is returned
4186-
/// in ExprType. If stopIfCastExpr is true, it will only return the parsed
4187-
/// type, not the parsed cast-expression.
4201+
/// This parses the unit that starts with a '(' token, based on what is
4202+
/// allowed by ExprType. The actual thing parsed is returned in ExprType. If
4203+
/// StopIfCastExpr is true, it will only return the parsed type, not the
4204+
/// parsed cast-expression. If ParenBehavior is ParenExprKind::PartOfOperator,
4205+
/// the initial open paren and its matching close paren are known to be part
4206+
/// of another grammar production and not part of the operand. e.g., the
4207+
/// typeof and typeof_unqual operators in C. Otherwise, the function has to
4208+
/// parse the parens to determine whether they're part of a cast or compound
4209+
/// literal expression rather than a parenthesized type.
41884210
///
41894211
/// \verbatim
41904212
/// primary-expression: [C99 6.5.1]
@@ -4209,7 +4231,9 @@ class Parser : public CodeCompletionHandler {
42094231
/// '(' '[' expression ']' { '[' expression ']' } cast-expression
42104232
/// \endverbatim
42114233
ExprResult ParseParenExpression(ParenParseOption &ExprType,
4212-
bool stopIfCastExpr, bool isTypeCast,
4234+
bool StopIfCastExpr,
4235+
ParenExprKind ParenBehavior,
4236+
TypoCorrectionTypeBehavior CorrectionBehavior,
42134237
ParsedType &CastTy,
42144238
SourceLocation &RParenLoc);
42154239

0 commit comments

Comments
 (0)