diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 45b5f77545361..1b12061dad85b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -304,6 +304,8 @@ C23 Feature Support which clarified how Clang is handling underspecified object declarations. - Clang now accepts single variadic parameter in type-name. It's a part of `WG14 N2975 `_ +- Fixed a bug with handling the type operand form of ``typeof`` when it is used + to specify a fixed underlying type for an enumeration. #GH146351 C11 Feature Support ^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index a47e23ffbd357..683934321a449 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -101,8 +101,13 @@ enum class ObjCTypeQual { NumQuals }; -/// TypeCastState - State whether an expression is or may be a type cast. -enum class TypeCastState { NotTypeCast = 0, MaybeTypeCast, IsTypeCast }; +/// If a typo should be encountered, should typo correction suggest type names, +/// non type names, or both? +enum class TypoCorrectionTypeBehavior { + AllowNonTypes, + AllowTypes, + AllowBoth, +}; /// Control what ParseCastExpression will parse. enum class CastParseKind { AnyCastExpr = 0, UnaryExprOnly, PrimaryExprOnly }; @@ -116,6 +121,15 @@ enum class ParenParseOption { CastExpr // Also allow '(' type-name ')' }; +/// In a call to ParseParenExpression, are the initial parentheses part of an +/// operator that requires the parens be there (like typeof(int)) or could they +/// be something else, such as part of a compound literal or a sizeof +/// expression, etc. +enum class ParenExprKind { + PartOfOperator, // typeof(int) + Unknown, // sizeof(int) or sizeof (int)1.0f, or compound literal, etc +}; + /// Describes the behavior that should be taken for an __if_exists /// block. enum class IfExistsBehavior { @@ -3709,11 +3723,12 @@ class Parser : public CodeCompletionHandler { /// assignment-expression ...[opt] /// expression ',' assignment-expression ...[opt] /// \endverbatim - ExprResult - ParseExpression(TypeCastState isTypeCast = TypeCastState::NotTypeCast); + ExprResult ParseExpression(TypoCorrectionTypeBehavior CorrectionBehavior = + TypoCorrectionTypeBehavior::AllowNonTypes); ExprResult ParseConstantExpressionInExprEvalContext( - TypeCastState isTypeCast = TypeCastState::NotTypeCast); + TypoCorrectionTypeBehavior CorrectionBehavior = + TypoCorrectionTypeBehavior::AllowNonTypes); ExprResult ParseConstantExpression(); ExprResult ParseArrayBoundExpression(); ExprResult ParseCaseExpression(SourceLocation CaseLoc); @@ -3750,8 +3765,9 @@ class Parser : public CodeCompletionHandler { ExprResult ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause); /// Parse an expr that doesn't include (top-level) commas. - ExprResult ParseAssignmentExpression( - TypeCastState isTypeCast = TypeCastState::NotTypeCast); + ExprResult + ParseAssignmentExpression(TypoCorrectionTypeBehavior CorrectionBehavior = + TypoCorrectionTypeBehavior::AllowNonTypes); ExprResult ParseConditionalExpression(); @@ -4017,14 +4033,15 @@ class Parser : public CodeCompletionHandler { /// ExprResult ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, bool &NotCastExpr, - TypeCastState isTypeCast, + TypoCorrectionTypeBehavior CorrectionBehavior, + bool isVectorLiteral = false, + bool *NotPrimaryExpression = nullptr); + ExprResult ParseCastExpression(CastParseKind ParseKind, + bool isAddressOfOperand = false, + TypoCorrectionTypeBehavior CorrectionBehavior = + TypoCorrectionTypeBehavior::AllowNonTypes, bool isVectorLiteral = false, bool *NotPrimaryExpression = nullptr); - ExprResult - ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand = false, - TypeCastState isTypeCast = TypeCastState::NotTypeCast, - bool isVectorLiteral = false, - bool *NotPrimaryExpression = nullptr); /// Returns true if the next token cannot start an expression. bool isNotExpressionStart(); @@ -4181,10 +4198,15 @@ class Parser : public CodeCompletionHandler { /// \endverbatim bool ParseSimpleExpressionList(SmallVectorImpl &Exprs); - /// ParseParenExpression - This parses the unit that starts with a '(' token, - /// based on what is allowed by ExprType. The actual thing parsed is returned - /// in ExprType. If stopIfCastExpr is true, it will only return the parsed - /// type, not the parsed cast-expression. + /// This parses the unit that starts with a '(' token, based on what is + /// allowed by ExprType. The actual thing parsed is returned in ExprType. If + /// StopIfCastExpr is true, it will only return the parsed type, not the + /// parsed cast-expression. If ParenBehavior is ParenExprKind::PartOfOperator, + /// the initial open paren and its matching close paren are known to be part + /// of another grammar production and not part of the operand. e.g., the + /// typeof and typeof_unqual operators in C. Otherwise, the function has to + /// parse the parens to determine whether they're part of a cast or compound + /// literal expression rather than a parenthesized type. /// /// \verbatim /// primary-expression: [C99 6.5.1] @@ -4209,7 +4231,9 @@ class Parser : public CodeCompletionHandler { /// '(' '[' expression ']' { '[' expression ']' } cast-expression /// \endverbatim ExprResult ParseParenExpression(ParenParseOption &ExprType, - bool stopIfCastExpr, bool isTypeCast, + bool StopIfCastExpr, + ParenExprKind ParenBehavior, + TypoCorrectionTypeBehavior CorrectionBehavior, ParsedType &CastTy, SourceLocation &RParenLoc); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 3cf3d4ea7d705..bc238a9517a37 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -43,8 +43,9 @@ #include using namespace clang; -ExprResult Parser::ParseExpression(TypeCastState isTypeCast) { - ExprResult LHS(ParseAssignmentExpression(isTypeCast)); +ExprResult +Parser::ParseExpression(TypoCorrectionTypeBehavior CorrectionBehavior) { + ExprResult LHS(ParseAssignmentExpression(CorrectionBehavior)); return ParseRHSOfBinaryExpression(LHS, prec::Comma); } @@ -71,7 +72,8 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { return ParseRHSOfBinaryExpression(LHS, prec::Comma); } -ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { +ExprResult Parser::ParseAssignmentExpression( + TypoCorrectionTypeBehavior CorrectionBehavior) { if (Tok.is(tok::code_completion)) { cutOffParsing(); Actions.CodeCompletion().CodeCompleteExpression( @@ -86,7 +88,7 @@ ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { ExprResult LHS = ParseCastExpression(CastParseKind::AnyCastExpr, - /*isAddressOfOperand=*/false, isTypeCast); + /*isAddressOfOperand=*/false, CorrectionBehavior); return ParseRHSOfBinaryExpression(LHS, prec::Assignment); } @@ -98,9 +100,9 @@ ExprResult Parser::ParseConditionalExpression() { return ExprError(); } - ExprResult LHS = ParseCastExpression(CastParseKind::AnyCastExpr, - /*isAddressOfOperand=*/false, - TypeCastState::NotTypeCast); + ExprResult LHS = ParseCastExpression( + CastParseKind::AnyCastExpr, + /*isAddressOfOperand=*/false, TypoCorrectionTypeBehavior::AllowNonTypes); return ParseRHSOfBinaryExpression(LHS, prec::Conditional); } @@ -116,14 +118,14 @@ Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc, return ParseRHSOfBinaryExpression(R, prec::Assignment); } -ExprResult -Parser::ParseConstantExpressionInExprEvalContext(TypeCastState isTypeCast) { +ExprResult Parser::ParseConstantExpressionInExprEvalContext( + TypoCorrectionTypeBehavior CorrectionBehavior) { assert(Actions.ExprEvalContexts.back().Context == Sema::ExpressionEvaluationContext::ConstantEvaluated && "Call this function only if your ExpressionEvaluationContext is " "already ConstantEvaluated"); - ExprResult LHS( - ParseCastExpression(CastParseKind::AnyCastExpr, false, isTypeCast)); + ExprResult LHS(ParseCastExpression(CastParseKind::AnyCastExpr, false, + CorrectionBehavior)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); return Actions.ActOnConstantExpression(Res); } @@ -135,7 +137,8 @@ ExprResult Parser::ParseConstantExpression() { // C++98 and C++11 have no such rule, but this is only a defect in C++98. EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); - return ParseConstantExpressionInExprEvalContext(TypeCastState::NotTypeCast); + return ParseConstantExpressionInExprEvalContext( + TypoCorrectionTypeBehavior::AllowNonTypes); } ExprResult Parser::ParseArrayBoundExpression() { @@ -163,7 +166,8 @@ ExprResult Parser::ParseArrayBoundExpression() { break; Iter->InConditionallyConstantEvaluateContext = true; } - return ParseConstantExpressionInExprEvalContext(TypeCastState::NotTypeCast); + return ParseConstantExpressionInExprEvalContext( + TypoCorrectionTypeBehavior::AllowNonTypes); } ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) { @@ -171,8 +175,9 @@ ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) { Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); Actions.currentEvaluationContext().IsCaseExpr = true; - ExprResult LHS(ParseCastExpression(CastParseKind::AnyCastExpr, false, - TypeCastState::NotTypeCast)); + ExprResult LHS( + ParseCastExpression(CastParseKind::AnyCastExpr, false, + TypoCorrectionTypeBehavior::AllowNonTypes)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); return Actions.ActOnCaseExpr(CaseLoc, Res); } @@ -194,11 +199,10 @@ Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) { Actions, Sema::ExpressionEvaluationContext::Unevaluated); bool NotPrimaryExpression = false; auto ParsePrimary = [&]() { - ExprResult E = - ParseCastExpression(CastParseKind::PrimaryExprOnly, - /*isAddressOfOperand=*/false, - /*isTypeCast=*/TypeCastState::NotTypeCast, - /*isVectorLiteral=*/false, &NotPrimaryExpression); + ExprResult E = ParseCastExpression( + CastParseKind::PrimaryExprOnly, + /*isAddressOfOperand=*/false, TypoCorrectionTypeBehavior::AllowNonTypes, + /*isVectorLiteral=*/false, &NotPrimaryExpression); if (E.isInvalid()) return ExprError(); auto RecoverFromNonPrimary = [&] (ExprResult E, bool Note) { @@ -555,18 +559,14 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { } } -ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, - bool isAddressOfOperand, - TypeCastState isTypeCast, - bool isVectorLiteral, - bool *NotPrimaryExpression) { +ExprResult +Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, + TypoCorrectionTypeBehavior CorrectionBehavior, + bool isVectorLiteral, bool *NotPrimaryExpression) { bool NotCastExpr; - ExprResult Res = ParseCastExpression(ParseKind, - isAddressOfOperand, - NotCastExpr, - isTypeCast, - isVectorLiteral, - NotPrimaryExpression); + ExprResult Res = ParseCastExpression(ParseKind, isAddressOfOperand, + NotCastExpr, CorrectionBehavior, + isVectorLiteral, NotPrimaryExpression); if (NotCastExpr) Diag(Tok, diag::err_expected_expression); return Res; @@ -574,10 +574,14 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, namespace { class CastExpressionIdValidator final : public CorrectionCandidateCallback { - public: - CastExpressionIdValidator(Token Next, bool AllowTypes, bool AllowNonTypes) - : NextToken(Next), AllowNonTypes(AllowNonTypes) { - WantTypeSpecifiers = WantFunctionLikeCasts = AllowTypes; +public: + CastExpressionIdValidator(Token Next, + TypoCorrectionTypeBehavior CorrectionBehavior) + : NextToken(Next) { + WantTypeSpecifiers = WantFunctionLikeCasts = + (CorrectionBehavior != TypoCorrectionTypeBehavior::AllowNonTypes); + AllowNonTypes = + (CorrectionBehavior != TypoCorrectionTypeBehavior::AllowTypes); } bool ValidateCandidate(const TypoCorrection &candidate) override { @@ -713,12 +717,11 @@ ExprResult Parser::ParseBuiltinPtrauthTypeDiscriminator() { /*isType=*/true, Ty.get().getAsOpaquePtr(), SourceRange(Loc, EndLoc)); } -ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, - bool isAddressOfOperand, - bool &NotCastExpr, - TypeCastState isTypeCast, - bool isVectorLiteral, - bool *NotPrimaryExpression) { +ExprResult +Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, + bool &NotCastExpr, + TypoCorrectionTypeBehavior CorrectionBehavior, + bool isVectorLiteral, bool *NotPrimaryExpression) { ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); auto SavedType = PreferredType; @@ -757,9 +760,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, } ParsedType CastTy; SourceLocation RParenLoc; - Res = ParseParenExpression(ParenExprType, false /*stopIfCastExr*/, - isTypeCast == TypeCastState::IsTypeCast, CastTy, - RParenLoc); + Res = ParseParenExpression(ParenExprType, /*StopIfCastExr=*/false, + ParenExprKind::Unknown, CorrectionBehavior, + CastTy, RParenLoc); // FIXME: What should we do if a vector literal is followed by a // postfix-expression suffix? Usually postfix operators are permitted on @@ -842,8 +845,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, case tok::annot_embed: { injectEmbedTokens(); - return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast, - isVectorLiteral, NotPrimaryExpression); + return ParseCastExpression(ParseKind, isAddressOfOperand, + CorrectionBehavior, isVectorLiteral, + NotPrimaryExpression); } case tok::kw___super: @@ -852,8 +856,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, if (TryAnnotateTypeOrScopeToken()) return ExprError(); assert(Tok.isNot(tok::kw_decltype) && Tok.isNot(tok::kw___super)); - return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast, - isVectorLiteral, NotPrimaryExpression); + return ParseCastExpression(ParseKind, isAddressOfOperand, + CorrectionBehavior, isVectorLiteral, + NotPrimaryExpression); case tok::identifier: ParseIdentifier: { // primary-expression: identifier @@ -873,8 +878,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, // indexing if (!TryAnnotateTypeOrScopeToken() && Tok.isOneOf(tok::annot_pack_indexing_type, tok::annot_cxxscope)) - return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast, - isVectorLiteral, NotPrimaryExpression); + return ParseCastExpression(ParseKind, isAddressOfOperand, + CorrectionBehavior, isVectorLiteral, + NotPrimaryExpression); } // If this identifier was reverted from a token ID, and the next token @@ -886,9 +892,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, tok::TokenKind Kind; if (isRevertibleTypeTrait(II, &Kind)) { Tok.setKind(Kind); - return ParseCastExpression(ParseKind, isAddressOfOperand, - NotCastExpr, isTypeCast, - isVectorLiteral, NotPrimaryExpression); + return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, + CorrectionBehavior, isVectorLiteral, + NotPrimaryExpression); } } @@ -899,9 +905,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::identifier)) - return ParseCastExpression(ParseKind, isAddressOfOperand, - NotCastExpr, isTypeCast, - isVectorLiteral, + return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, + CorrectionBehavior, isVectorLiteral, NotPrimaryExpression); } } @@ -998,10 +1003,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, CXXScopeSpec ScopeSpec; SourceLocation TemplateKWLoc; Token Replacement; - CastExpressionIdValidator Validator( - /*Next=*/Tok, - /*AllowTypes=*/isTypeCast != TypeCastState::NotTypeCast, - /*AllowNonTypes=*/isTypeCast != TypeCastState::IsTypeCast); + CastExpressionIdValidator Validator(Tok, CorrectionBehavior); Validator.IsAddressOfOperand = isAddressOfOperand; if (Tok.isOneOf(tok::periodstar, tok::arrowstar)) { Validator.WantExpressionKeywords = false; @@ -1017,10 +1019,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, Tok.is(tok::r_paren) ? nullptr : &Replacement); if (!Res.isInvalid() && Res.isUnset()) { UnconsumeToken(Replacement); - return ParseCastExpression(ParseKind, isAddressOfOperand, - NotCastExpr, isTypeCast, - /*isVectorLiteral=*/false, - NotPrimaryExpression); + return ParseCastExpression( + ParseKind, isAddressOfOperand, NotCastExpr, CorrectionBehavior, + /*isVectorLiteral=*/false, NotPrimaryExpression); } Res = tryParseCXXPackIndexingExpression(Res); if (!Res.isInvalid() && Tok.is(tok::less)) @@ -1102,10 +1103,11 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, // One special case is implicitly handled here: if the preceding tokens are // an ambiguous cast expression, such as "(T())++", then we recurse to // determine whether the '++' is prefix or postfix. - Res = ParseCastExpression( - getLangOpts().CPlusPlus ? CastParseKind::UnaryExprOnly - : CastParseKind::AnyCastExpr, - /*isAddressOfOperand*/ false, NotCastExpr, TypeCastState::NotTypeCast); + Res = ParseCastExpression(getLangOpts().CPlusPlus + ? CastParseKind::UnaryExprOnly + : CastParseKind::AnyCastExpr, + /*isAddressOfOperand*/ false, NotCastExpr, + TypoCorrectionTypeBehavior::AllowNonTypes); if (NotCastExpr) { // If we return with NotCastExpr = true, we must not consume any tokens, // so put the token back where we found it. @@ -1366,7 +1368,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, return ExprError(); if (!Tok.is(tok::annot_cxxscope)) return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, - isTypeCast, isVectorLiteral, + CorrectionBehavior, isVectorLiteral, NotPrimaryExpression); Token Next = NextToken(); @@ -1382,7 +1384,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, /*EnteringContext=*/false); AnnotateTemplateIdTokenAsType(SS, ImplicitTypenameContext::Yes); return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, - isTypeCast, isVectorLiteral, + CorrectionBehavior, isVectorLiteral, NotPrimaryExpression); } } @@ -1400,8 +1402,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, // expression. CXXScopeSpec SS; AnnotateTemplateIdTokenAsType(SS, ImplicitTypenameContext::Yes); - return ParseCastExpression(ParseKind, isAddressOfOperand, - NotCastExpr, isTypeCast, isVectorLiteral, + return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, + CorrectionBehavior, isVectorLiteral, NotPrimaryExpression); } @@ -1419,8 +1421,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::coloncolon)) - return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast, - isVectorLiteral, NotPrimaryExpression); + return ParseCastExpression(ParseKind, isAddressOfOperand, + CorrectionBehavior, isVectorLiteral, + NotPrimaryExpression); // ::new -> [C++] new-expression // ::delete -> [C++] delete-expression @@ -2110,12 +2113,27 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, // If it starts with a '(', we know that it is either a parenthesized // type-name, or it is a unary-expression that starts with a compound // literal, or starts with a primary-expression that is a parenthesized - // expression. + // expression. Most unary operators have an expression form without parens + // as part of the grammar for the operator, and a type form with the parens + // as part of the grammar for the operator. However, typeof and + // typeof_unqual require parens for both forms. This means that we *know* + // that the open and close parens cannot be part of a cast expression, + // which means we definitely are not parsing a compound literal expression. + // This disambiguates a case like enum E : typeof(int) { }; where we've + // parsed typeof and need to handle the (int){} tokens properly despite + // them looking like a compound literal, as in sizeof (int){}; where the + // parens could be part of a parenthesized type name or for a cast + // expression of some kind. + bool ParenKnownToBeNonCast = + OpTok.isOneOf(tok::kw_typeof, tok::kw_typeof_unqual); ParenParseOption ExprType = ParenParseOption::CastExpr; SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; - Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, - false, CastTy, RParenLoc); + Operand = ParseParenExpression( + ExprType, /*StopIfCastExr=*/true, + ParenKnownToBeNonCast ? ParenExprKind::PartOfOperator + : ParenExprKind::Unknown, + TypoCorrectionTypeBehavior::AllowBoth, CastTy, RParenLoc); CastRange = SourceRange(LParenLoc, RParenLoc); // If ParseParenExpression parsed a '(typename)' sequence only, then this is @@ -2590,9 +2608,10 @@ bool Parser::tryParseOpenMPArrayShapingCastPart() { } ExprResult -Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, - bool isTypeCast, ParsedType &CastTy, - SourceLocation &RParenLoc) { +Parser::ParseParenExpression(ParenParseOption &ExprType, bool StopIfCastExpr, + ParenExprKind ParenBehavior, + TypoCorrectionTypeBehavior CorrectionBehavior, + ParsedType &CastTy, SourceLocation &RParenLoc) { assert(Tok.is(tok::l_paren) && "Not a paren expr!"); ColonProtectionRAIIObject ColonProtection(*this, false); BalancedDelimiterTracker T(*this, tok::l_paren); @@ -2714,7 +2733,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // in which case we should treat it as type-id. // if stopIfCastExpr is false, we need to determine the context past the // parens, so we defer to ParseCXXAmbiguousParenExpression for that. - if (isAmbiguousTypeId && !stopIfCastExpr) { + if (isAmbiguousTypeId && !StopIfCastExpr) { ExprResult res = ParseCXXAmbiguousParenExpression(ExprType, CastTy, T, ColonProtection); RParenLoc = T.getCloseLocation(); @@ -2747,7 +2766,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, T.consumeClose(); ColonProtection.restore(); RParenLoc = T.getCloseLocation(); - if (Tok.is(tok::l_brace)) { + if (ParenBehavior == ParenExprKind::Unknown && Tok.is(tok::l_brace)) { ExprType = ParenParseOption::CompoundLiteral; TypeResult Ty; { @@ -2757,7 +2776,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc); } - if (Tok.is(tok::l_paren)) { + if (ParenBehavior == ParenExprKind::Unknown && Tok.is(tok::l_paren)) { // This could be OpenCL vector Literals if (getLangOpts().OpenCL) { @@ -2781,7 +2800,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Result = ParseCastExpression( /*isUnaryExpression=*/CastParseKind::AnyCastExpr, /*isAddressOfOperand=*/false, - /*isTypeCast=*/TypeCastState::IsTypeCast, + TypoCorrectionTypeBehavior::AllowTypes, /*isVectorLiteral=*/true); if (!Result.isInvalid()) { @@ -2808,7 +2827,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // Note that this doesn't parse the subsequent cast-expression, it just // returns the parsed type to the callee. - if (stopIfCastExpr) { + if (StopIfCastExpr) { TypeResult Ty; { InMessageExpressionRAIIObject InMessage(*this, false); @@ -2834,7 +2853,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Result = ParseCastExpression( /*isUnaryExpression=*/CastParseKind::AnyCastExpr, /*isAddressOfOperand=*/false, - /*isTypeCast=*/TypeCastState::IsTypeCast); + TypoCorrectionTypeBehavior::AllowTypes); if (!Result.isInvalid()) { Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, DeclaratorInfo, CastTy, @@ -2850,7 +2869,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, isFoldOperator(NextToken().getKind())) { ExprType = ParenParseOption::FoldExpr; return ParseFoldExpression(ExprResult(), T); - } else if (isTypeCast) { + } else if (CorrectionBehavior == TypoCorrectionTypeBehavior::AllowTypes) { + // FIXME: This should not be predicated on typo correction behavior. // Parse the expression-list. InMessageExpressionRAIIObject InMessage(*this, false); ExprVector ArgExprs; @@ -2902,7 +2922,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, } else { InMessageExpressionRAIIObject InMessage(*this, false); - Result = ParseExpression(TypeCastState::MaybeTypeCast); + Result = ParseExpression(TypoCorrectionTypeBehavior::AllowBoth); if (ExprType >= ParenParseOption::FoldExpr && isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) { ExprType = ParenParseOption::FoldExpr; diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 1ea0cf52933f6..7686ff73f827b 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -3607,7 +3607,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, Result = ParseCastExpression(CastParseKind::AnyCastExpr, false /*isAddressofOperand*/, NotCastExpr, // type-id has priority. - TypeCastState::IsTypeCast); + TypoCorrectionTypeBehavior::AllowTypes); } // If we parsed a cast-expression, it's really a type-id, otherwise it's diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index f694ae1d0d112..2c18f3e9306b6 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -3503,9 +3503,9 @@ ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName, return ExprError(); SourceLocation ELoc = Tok.getLocation(); - ExprResult LHS(ParseCastExpression(CastParseKind::AnyCastExpr, - IsAddressOfOperand, - TypeCastState::NotTypeCast)); + ExprResult LHS( + ParseCastExpression(CastParseKind::AnyCastExpr, IsAddressOfOperand, + TypoCorrectionTypeBehavior::AllowNonTypes)); ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false); @@ -4036,8 +4036,9 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, Kind == OMPC_num_threads; if (NeedAnExpression) { SourceLocation ELoc = Tok.getLocation(); - ExprResult LHS(ParseCastExpression(CastParseKind::AnyCastExpr, false, - TypeCastState::NotTypeCast)); + ExprResult LHS( + ParseCastExpression(CastParseKind::AnyCastExpr, false, + TypoCorrectionTypeBehavior::AllowNonTypes)); Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional); Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false); diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index a16dbe95b788d..9a04bf298c0ac 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -1318,8 +1318,8 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) ExprArg = ParseBraceInitializer(); else - ExprArg = - ParseConstantExpressionInExprEvalContext(TypeCastState::MaybeTypeCast); + ExprArg = ParseConstantExpressionInExprEvalContext( + TypoCorrectionTypeBehavior::AllowBoth); if (ExprArg.isInvalid() || !ExprArg.get()) { return ParsedTemplateArgument(); } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 18f399aca59e8..8834bf80c4016 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1606,8 +1606,9 @@ ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) { EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); - AsmString = ParseParenExpression(ExprType, true /*stopIfCastExpr*/, false, - CastTy, RParenLoc); + AsmString = ParseParenExpression( + ExprType, /*StopIfCastExr=*/true, ParenExprKind::Unknown, + TypoCorrectionTypeBehavior::AllowBoth, CastTy, RParenLoc); if (!AsmString.isInvalid()) AsmString = Actions.ActOnConstantExpression(AsmString); diff --git a/clang/test/Parser/c23-typeof.m b/clang/test/Parser/c23-typeof.m new file mode 100644 index 0000000000000..e6a8dc918dbb1 --- /dev/null +++ b/clang/test/Parser/c23-typeof.m @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -verify -std=c23 -fblocks -Wno-unused %s +// expected-no-diagnostics + +void f() { + ^ typeof((void)0) {}; // Ok + ^ typeof(void) {}; // Ok +} diff --git a/clang/test/Parser/c2x-typeof.c b/clang/test/Parser/c2x-typeof.c index 9c836dfa6d823..245c127d71e03 100644 --- a/clang/test/Parser/c2x-typeof.c +++ b/clang/test/Parser/c2x-typeof.c @@ -42,3 +42,13 @@ _Static_assert(__builtin_offsetof(typeof(s), i) == 0); _Static_assert(__builtin_offsetof(typeof_unqual(struct S), i) == 0); _Static_assert(__builtin_offsetof(typeof_unqual(s), i) == 0); +// Show that typeof and typeof_unqual can be used in the underlying type of an +// enumeration even when given the type form. Note, this can look like a +// compound literal expression, which caused GH146351. +enum E3 : typeof(int) { ThirdZero }; // (int) {}; is not a compound literal! +enum E4 : typeof_unqual(int) { FourthZero }; // Same here + +// Ensure that this invalid construct is diagnosed instead of being treated +// as typeof((int){ 0 }). +typeof(int) { 0 } x; // expected-error {{a type specifier is required for all declarations}} \ + expected-error {{expected identifier or '('}}