diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp | 619 |
1 files changed, 429 insertions, 190 deletions
diff --git a/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp b/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp index ebfe048513b1..d0ff33bd1379 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp @@ -14,13 +14,17 @@ #include "clang/AST/PrettyDeclStackTrace.h" #include "clang/Basic/Attributes.h" #include "clang/Basic/PrettyStackTrace.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Parse/LoopHint.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Scope.h" #include "clang/Sema/TypoCorrection.h" #include "llvm/ADT/STLExtras.h" +#include <optional> using namespace clang; @@ -36,8 +40,8 @@ StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc, // We may get back a null statement if we found a #pragma. Keep going until // we get an actual statement. + StmtVector Stmts; do { - StmtVector Stmts; Res = ParseStatementOrDeclaration(Stmts, StmtCtx, TrailingElseLoc); } while (!Res.isInvalid() && !Res.get()); @@ -105,15 +109,21 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, // statement are different from [[]] attributes that follow an __attribute__ // at the start of the statement. Thus, we're not using MaybeParseAttributes // here because we don't want to allow arbitrary orderings. - ParsedAttributesWithRange Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true); + ParsedAttributes CXX11Attrs(AttrFactory); + MaybeParseCXX11Attributes(CXX11Attrs, /*MightBeObjCMessageSend*/ true); + ParsedAttributes GNUAttrs(AttrFactory); if (getLangOpts().OpenCL) - MaybeParseGNUAttributes(Attrs); + MaybeParseGNUAttributes(GNUAttrs); StmtResult Res = ParseStatementOrDeclarationAfterAttributes( - Stmts, StmtCtx, TrailingElseLoc, Attrs); + Stmts, StmtCtx, TrailingElseLoc, CXX11Attrs, GNUAttrs); MaybeDestroyTemplateIds(); + // Attributes that are left should all go on the statement, so concatenate the + // two lists. + ParsedAttributes Attrs(AttrFactory); + takeAndConcatenateAttrs(CXX11Attrs, GNUAttrs, Attrs); + assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) && "attributes on empty statement"); @@ -158,7 +168,8 @@ private: StmtResult Parser::ParseStatementOrDeclarationAfterAttributes( StmtVector &Stmts, ParsedStmtContext StmtCtx, - SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs) { + SourceLocation *TrailingElseLoc, ParsedAttributes &CXX11Attrs, + ParsedAttributes &GNUAttrs) { const char *SemiError = nullptr; StmtResult Res; SourceLocation GNUAttributeLoc; @@ -181,9 +192,16 @@ Retry: Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement); return StmtError(); - case tok::identifier: { + case tok::identifier: + ParseIdentifier: { Token Next = NextToken(); if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement + // Both C++11 and GNU attributes preceding the label appertain to the + // label, so put them in a single list to pass on to + // ParseLabeledStatement(). + ParsedAttributes Attrs(AttrFactory); + takeAndConcatenateAttrs(CXX11Attrs, GNUAttrs, Attrs); + // identifier ':' statement return ParseLabeledStatement(Attrs, StmtCtx); } @@ -209,29 +227,34 @@ Retry: } // Fall through - LLVM_FALLTHROUGH; + [[fallthrough]]; } default: { - if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || - (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != - ParsedStmtContext()) && - ((GNUAttributeLoc.isValid() && - !(!Attrs.empty() && - llvm::all_of( - Attrs, [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }))) || + bool HaveAttrs = !CXX11Attrs.empty() || !GNUAttrs.empty(); + auto IsStmtAttr = [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }; + bool AllAttrsAreStmtAttrs = llvm::all_of(CXX11Attrs, IsStmtAttr) && + llvm::all_of(GNUAttrs, IsStmtAttr); + if (((GNUAttributeLoc.isValid() && !(HaveAttrs && AllAttrsAreStmtAttrs)) || isDeclarationStatement())) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl; if (GNUAttributeLoc.isValid()) { DeclStart = GNUAttributeLoc; - Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, Attrs, - &GNUAttributeLoc); + Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, CXX11Attrs, + GNUAttrs, &GNUAttributeLoc); } else { - Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, Attrs); + Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, CXX11Attrs, + GNUAttrs); } - if (Attrs.Range.getBegin().isValid()) - DeclStart = Attrs.Range.getBegin(); + if (CXX11Attrs.Range.getBegin().isValid()) { + // The caller must guarantee that the CXX11Attrs appear before the + // GNUAttrs, and we rely on that here. + assert(GNUAttrs.Range.getBegin().isInvalid() || + GNUAttrs.Range.getBegin() > CXX11Attrs.Range.getBegin()); + DeclStart = CXX11Attrs.Range.getBegin(); + } else if (GNUAttrs.Range.getBegin().isValid()) + DeclStart = GNUAttrs.Range.getBegin(); return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd); } @@ -240,12 +263,24 @@ Retry: return StmtError(); } - return ParseExprStatement(StmtCtx); + switch (Tok.getKind()) { +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" + if (NextToken().is(tok::less)) { + Tok.setKind(tok::identifier); + Diag(Tok, diag::ext_keyword_as_ident) + << Tok.getIdentifierInfo()->getName() << 0; + goto ParseIdentifier; + } + [[fallthrough]]; + default: + return ParseExprStatement(StmtCtx); + } } case tok::kw___attribute: { GNUAttributeLoc = Tok.getLocation(); - ParseGNUAttributes(Attrs); + ParseGNUAttributes(GNUAttrs); goto Retry; } @@ -297,10 +332,18 @@ Retry: break; case tok::kw_asm: { - ProhibitAttributes(Attrs); + for (const ParsedAttr &AL : CXX11Attrs) + // Could be relaxed if asm-related regular keyword attributes are + // added later. + (AL.isRegularKeywordAttribute() + ? Diag(AL.getRange().getBegin(), diag::err_keyword_not_allowed) + : Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored)) + << AL; + // Prevent these from being interpreted as statement attributes later on. + CXX11Attrs.clear(); + ProhibitAttributes(GNUAttrs); bool msAsm = false; Res = ParseAsmStatement(msAsm); - Res = Actions.ActOnFinishFullStmt(Res.get()); if (msAsm) return Res; SemiError = "asm"; break; @@ -308,7 +351,8 @@ Retry: case tok::kw___if_exists: case tok::kw___if_not_exists: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); ParseMicrosoftIfExistsStatement(Stmts); // An __if_exists block is like a compound statement, but it doesn't create // a new scope. @@ -318,7 +362,8 @@ Retry: return ParseCXXTryBlock(); case tok::kw___try: - ProhibitAttributes(Attrs); // TODO: is it correct? + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); return ParseSEHTryBlock(); case tok::kw___leave: @@ -327,106 +372,139 @@ Retry: break; case tok::annot_pragma_vis: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaVisibility(); return StmtEmpty(); case tok::annot_pragma_pack: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaPack(); return StmtEmpty(); case tok::annot_pragma_msstruct: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaMSStruct(); return StmtEmpty(); case tok::annot_pragma_align: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaAlign(); return StmtEmpty(); case tok::annot_pragma_weak: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaWeak(); return StmtEmpty(); case tok::annot_pragma_weakalias: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaWeakAlias(); return StmtEmpty(); case tok::annot_pragma_redefine_extname: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaRedefineExtname(); return StmtEmpty(); case tok::annot_pragma_fp_contract: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "fp_contract"; ConsumeAnnotationToken(); return StmtError(); case tok::annot_pragma_fp: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "clang fp"; ConsumeAnnotationToken(); return StmtError(); case tok::annot_pragma_fenv_access: - ProhibitAttributes(Attrs); - Diag(Tok, diag::err_pragma_stdc_fenv_access_scope); + case tok::annot_pragma_fenv_access_ms: + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); + Diag(Tok, diag::err_pragma_file_or_compound_scope) + << (Kind == tok::annot_pragma_fenv_access ? "STDC FENV_ACCESS" + : "fenv_access"); ConsumeAnnotationToken(); return StmtEmpty(); case tok::annot_pragma_fenv_round: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "STDC FENV_ROUND"; ConsumeAnnotationToken(); return StmtError(); + case tok::annot_pragma_cx_limited_range: + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); + Diag(Tok, diag::err_pragma_file_or_compound_scope) + << "STDC CX_LIMITED_RANGE"; + ConsumeAnnotationToken(); + return StmtError(); + case tok::annot_pragma_float_control: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "float_control"; ConsumeAnnotationToken(); return StmtError(); case tok::annot_pragma_opencl_extension: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaOpenCLExtension(); return StmtEmpty(); case tok::annot_pragma_captured: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); return HandlePragmaCaptured(); case tok::annot_pragma_openmp: // Prohibit attributes that are not OpenMP attributes, but only before // processing a #pragma omp clause. - ProhibitAttributes(Attrs); - LLVM_FALLTHROUGH; + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); + [[fallthrough]]; case tok::annot_attr_openmp: // Do not prohibit attributes if they were OpenMP attributes. return ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx); + case tok::annot_pragma_openacc: + return ParseOpenACCDirectiveStmt(); + case tok::annot_pragma_ms_pointers_to_members: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaMSPointersToMembers(); return StmtEmpty(); case tok::annot_pragma_ms_pragma: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaMSPragma(); return StmtEmpty(); case tok::annot_pragma_ms_vtordisp: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaMSVtorDisp(); return StmtEmpty(); case tok::annot_pragma_loop_hint: - ProhibitAttributes(Attrs); - return ParsePragmaLoopHint(Stmts, StmtCtx, TrailingElseLoc, Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); + return ParsePragmaLoopHint(Stmts, StmtCtx, TrailingElseLoc, CXX11Attrs); case tok::annot_pragma_dump: HandlePragmaDump(); @@ -480,9 +558,22 @@ StmtResult Parser::ParseExprStatement(ParsedStmtContext StmtCtx) { return ParseCaseStatement(StmtCtx, /*MissingCase=*/true, Expr); } - // Otherwise, eat the semicolon. - ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); - return handleExprStmt(Expr, StmtCtx); + Token *CurTok = nullptr; + // If the semicolon is missing at the end of REPL input, consider if + // we want to do value printing. Note this is only enabled in C++ mode + // since part of the implementation requires C++ language features. + // Note we shouldn't eat the token since the callback needs it. + if (Tok.is(tok::annot_repl_input_end) && Actions.getLangOpts().CPlusPlus) + CurTok = &Tok; + else + // Otherwise, eat the semicolon. + ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); + + StmtResult R = handleExprStmt(Expr, StmtCtx); + if (CurTok && !R.isInvalid()) + CurTok->setAnnotationValue(R.get()); + + return R; } /// ParseSEHTryBlockCommon @@ -615,20 +706,36 @@ StmtResult Parser::ParseSEHLeaveStatement() { return Actions.ActOnSEHLeaveStmt(LeaveLoc, getCurScope()); } +static void DiagnoseLabelFollowedByDecl(Parser &P, const Stmt *SubStmt) { + // When in C mode (but not Microsoft extensions mode), diagnose use of a + // label that is followed by a declaration rather than a statement. + if (!P.getLangOpts().CPlusPlus && !P.getLangOpts().MicrosoftExt && + isa<DeclStmt>(SubStmt)) { + P.Diag(SubStmt->getBeginLoc(), + P.getLangOpts().C23 + ? diag::warn_c23_compat_label_followed_by_declaration + : diag::ext_c_label_followed_by_declaration); + } +} + /// ParseLabeledStatement - We have an identifier and a ':' after it. /// +/// label: +/// identifier ':' +/// [GNU] identifier ':' attributes[opt] +/// /// labeled-statement: -/// identifier ':' statement -/// [GNU] identifier ':' attributes[opt] statement +/// label statement /// -StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs, +StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs, ParsedStmtContext StmtCtx) { assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && "Not an identifier!"); - // The substatement is always a 'statement', not a 'declaration', but is - // otherwise in the same context as the labeled-statement. - StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC; + // [OpenMP 5.1] 2.1.3: A stand-alone directive may not be used in place of a + // substatement in a selection statement, in place of the loop body in an + // iteration statement, or in place of the statement that follows a label. + StmtCtx &= ~ParsedStmtContext::AllowStandaloneOpenMPDirectives; Token IdentTok = Tok; // Save the whole token. ConsumeToken(); // eat the identifier. @@ -641,7 +748,7 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs, // Read label attributes, if present. StmtResult SubStmt; if (Tok.is(tok::kw___attribute)) { - ParsedAttributesWithRange TempAttrs(AttrFactory); + ParsedAttributes TempAttrs(AttrFactory); ParseGNUAttributes(TempAttrs); // In C++, GNU attributes only apply to the label if they are followed by a @@ -652,16 +759,23 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs, // and followed by a semicolon, GCC will reject (it appears to parse the // attributes as part of a statement in that case). That looks like a bug. if (!getLangOpts().CPlusPlus || Tok.is(tok::semi)) - attrs.takeAllFrom(TempAttrs); + Attrs.takeAllFrom(TempAttrs); else { StmtVector Stmts; - SubStmt = ParseStatementOrDeclarationAfterAttributes(Stmts, StmtCtx, - nullptr, TempAttrs); + ParsedAttributes EmptyCXX11Attrs(AttrFactory); + SubStmt = ParseStatementOrDeclarationAfterAttributes( + Stmts, StmtCtx, nullptr, EmptyCXX11Attrs, TempAttrs); if (!TempAttrs.empty() && !SubStmt.isInvalid()) SubStmt = Actions.ActOnAttributedStmt(TempAttrs, SubStmt.get()); } } + // The label may have no statement following it + if (SubStmt.isUnset() && Tok.is(tok::r_brace)) { + DiagnoseLabelAtEndOfCompoundStatement(); + SubStmt = Actions.ActOnNullStmt(ColonLoc); + } + // If we've not parsed a statement yet, parse one now. if (!SubStmt.isInvalid() && !SubStmt.isUsable()) SubStmt = ParseStatement(nullptr, StmtCtx); @@ -670,10 +784,12 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs, if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(ColonLoc); + DiagnoseLabelFollowedByDecl(*this, SubStmt.get()); + LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(), IdentTok.getLocation()); - Actions.ProcessDeclAttributeList(Actions.CurScope, LD, attrs); - attrs.clear(); + Actions.ProcessDeclAttributeList(Actions.CurScope, LD, Attrs); + Attrs.clear(); return Actions.ActOnLabelStmt(IdentTok.getLocation(), LD, ColonLoc, SubStmt.get()); @@ -688,11 +804,12 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx, bool MissingCase, ExprResult Expr) { assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!"); - // The substatement is always a 'statement', not a 'declaration', but is - // otherwise in the same context as the labeled-statement. - StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC; + // [OpenMP 5.1] 2.1.3: A stand-alone directive may not be used in place of a + // substatement in a selection statement, in place of the loop body in an + // iteration statement, or in place of the statement that follows a label. + StmtCtx &= ~ParsedStmtContext::AllowStandaloneOpenMPDirectives; - // It is very very common for code to contain many case statements recursively + // It is very common for code to contain many case statements recursively // nested, as in (but usually without indentation): // case 1: // case 2: @@ -802,18 +919,13 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx, // If we found a non-case statement, start by parsing it. StmtResult SubStmt; - if (Tok.isNot(tok::r_brace)) { - SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx); + if (Tok.is(tok::r_brace)) { + // "switch (X) { case 4: }", is valid and is treated as if label was + // followed by a null statement. + DiagnoseLabelAtEndOfCompoundStatement(); + SubStmt = Actions.ActOnNullStmt(ColonLoc); } else { - // Nicely diagnose the common error "switch (X) { case 4: }", which is - // not valid. If ColonLoc doesn't point to a valid text location, there was - // another parsing error, so avoid producing extra diagnostics. - if (ColonLoc.isValid()) { - SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc); - Diag(AfterColonLoc, diag::err_label_end_of_compound_statement) - << FixItHint::CreateInsertion(AfterColonLoc, " ;"); - } - SubStmt = StmtError(); + SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx); } // Install the body into the most deeply-nested case. @@ -821,6 +933,7 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx, // Broken sub-stmt shouldn't prevent forming the case statement properly. if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(SourceLocation()); + DiagnoseLabelFollowedByDecl(*this, SubStmt.get()); Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get()); } @@ -836,9 +949,10 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx, StmtResult Parser::ParseDefaultStatement(ParsedStmtContext StmtCtx) { assert(Tok.is(tok::kw_default) && "Not a default stmt!"); - // The substatement is always a 'statement', not a 'declaration', but is - // otherwise in the same context as the labeled-statement. - StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC; + // [OpenMP 5.1] 2.1.3: A stand-alone directive may not be used in place of a + // substatement in a selection statement, in place of the loop body in an + // iteration statement, or in place of the statement that follows a label. + StmtCtx &= ~ParsedStmtContext::AllowStandaloneOpenMPDirectives; SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'. @@ -859,21 +973,20 @@ StmtResult Parser::ParseDefaultStatement(ParsedStmtContext StmtCtx) { StmtResult SubStmt; - if (Tok.isNot(tok::r_brace)) { - SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx); + if (Tok.is(tok::r_brace)) { + // "switch (X) {... default: }", is valid and is treated as if label was + // followed by a null statement. + DiagnoseLabelAtEndOfCompoundStatement(); + SubStmt = Actions.ActOnNullStmt(ColonLoc); } else { - // Diagnose the common error "switch (X) {... default: }", which is - // not valid. - SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc); - Diag(AfterColonLoc, diag::err_label_end_of_compound_statement) - << FixItHint::CreateInsertion(AfterColonLoc, " ;"); - SubStmt = true; + SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx); } // Broken sub-stmt shouldn't prevent forming the case statement properly. if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(ColonLoc); + DiagnoseLabelFollowedByDecl(*this, SubStmt.get()); return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc, SubStmt.get(), getCurScope()); } @@ -907,7 +1020,7 @@ StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) { /// StmtResult Parser::ParseCompoundStatement(bool isStmtExpr, unsigned ScopeFlags) { - assert(Tok.is(tok::l_brace) && "Not a compount stmt!"); + assert(Tok.is(tok::l_brace) && "Not a compound stmt!"); // Enter a scope to hold everything within the compound stmt. Compound // statements can always hold declarations. @@ -955,11 +1068,15 @@ void Parser::ParseCompoundStatementLeadingPragmas() { HandlePragmaFP(); break; case tok::annot_pragma_fenv_access: + case tok::annot_pragma_fenv_access_ms: HandlePragmaFEnvAccess(); break; case tok::annot_pragma_fenv_round: HandlePragmaFEnvRound(); break; + case tok::annot_pragma_cx_limited_range: + HandlePragmaCXLimitedRange(); + break; case tok::annot_pragma_float_control: HandlePragmaFloatControl(); break; @@ -983,6 +1100,18 @@ void Parser::ParseCompoundStatementLeadingPragmas() { } +void Parser::DiagnoseLabelAtEndOfCompoundStatement() { + if (getLangOpts().CPlusPlus) { + Diag(Tok, getLangOpts().CPlusPlus23 + ? diag::warn_cxx20_compat_label_end_of_compound_statement + : diag::ext_cxx_label_end_of_compound_statement); + } else { + Diag(Tok, getLangOpts().C23 + ? diag::warn_c23_compat_label_end_of_compound_statement + : diag::ext_c_label_end_of_compound_statement); + } +} + /// Consume any extra semi-colons resulting in null statements, /// returning true if any tok::semi were consumed. bool Parser::ConsumeNullStmt(StmtVector &Stmts) { @@ -1021,7 +1150,7 @@ StmtResult Parser::handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx) { ++LookAhead; } // Then look to see if the next two tokens close the statement expression; - // if so, this expression statement is the last statement in a statment + // if so, this expression statement is the last statement in a statement // expression. IsStmtExprResult = GetLookAheadToken(LookAhead).is(tok::r_brace) && GetLookAheadToken(LookAhead + 1).is(tok::r_paren); @@ -1032,10 +1161,10 @@ StmtResult Parser::handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx) { return Actions.ActOnExprStmt(E, /*DiscardedValue=*/!IsStmtExprResult); } -/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the -/// ActOnCompoundStmt action. This expects the '{' to be the current token, and -/// consume the '}' at the end of the block. It does not manipulate the scope -/// stack. +/// ParseCompoundStatementBody - Parse a sequence of statements optionally +/// followed by a label and invoke the ActOnCompoundStmt action. This expects +/// the '{' to be the current token, and consume the '}' at the end of the +/// block. It does not manipulate the scope stack. StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), Tok.getLocation(), @@ -1064,7 +1193,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { SourceLocation LabelLoc = ConsumeToken(); SmallVector<Decl *, 8> DeclsInGroup; - while (1) { + while (true) { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; break; @@ -1114,9 +1243,8 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { while (Tok.is(tok::kw___extension__)) ConsumeToken(); - ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs, nullptr, - /*MightBeObjCMessageSend*/ true); + ParsedAttributes attrs(AttrFactory); + MaybeParseCXX11Attributes(attrs, /*MightBeObjCMessageSend*/ true); // If this is the start of a declaration, parse it as such. if (isDeclarationStatement()) { @@ -1125,8 +1253,9 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { ExtensionRAIIObject O(Diags); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy Res = - ParseDeclaration(DeclaratorContext::Block, DeclEnd, attrs); + ParsedAttributes DeclSpecAttrs(AttrFactory); + DeclGroupPtrTy Res = ParseDeclaration(DeclaratorContext::Block, DeclEnd, + attrs, DeclSpecAttrs); R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd); } else { // Otherwise this was a unary __extension__ marker. @@ -1149,6 +1278,16 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { if (R.isUsable()) Stmts.push_back(R.get()); } + // Warn the user that using option `-ffp-eval-method=source` on a + // 32-bit target and feature `sse` disabled, or using + // `pragma clang fp eval_method=source` and feature `sse` disabled, is not + // supported. + if (!PP.getTargetInfo().supportSourceEvalMethod() && + (PP.getLastFPEvalPragmaLocation().isValid() || + PP.getCurrentFPEvalMethod() == + LangOptions::FPEvalMethodKind::FEM_Source)) + Diag(Tok.getLocation(), + diag::warn_no_support_for_eval_method_source_on_m32); SourceLocation CloseLoc = Tok.getLocation(); @@ -1182,27 +1321,29 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { /// should try to recover harder. It returns false if the condition is /// successfully parsed. Note that a successful parse can still have semantic /// errors in the condition. -/// Additionally, if LParenLoc and RParenLoc are non-null, it will assign -/// the location of the outer-most '(' and ')', respectively, to them. +/// Additionally, it will assign the location of the outer-most '(' and ')', +/// to LParenLoc and RParenLoc, respectively. bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, Sema::ConditionResult &Cond, SourceLocation Loc, Sema::ConditionKind CK, - SourceLocation *LParenLoc, - SourceLocation *RParenLoc) { + SourceLocation &LParenLoc, + SourceLocation &RParenLoc) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); + SourceLocation Start = Tok.getLocation(); - if (getLangOpts().CPlusPlus) - Cond = ParseCXXCondition(InitStmt, Loc, CK); - else { + if (getLangOpts().CPlusPlus) { + Cond = ParseCXXCondition(InitStmt, Loc, CK, false); + } else { ExprResult CondExpr = ParseExpression(); // If required, convert to a boolean value. if (CondExpr.isInvalid()) Cond = Sema::ConditionError(); else - Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK); + Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK, + /*MissingOK=*/false); } // If the parser was confused by the condition and we don't have a ')', try to @@ -1216,16 +1357,20 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, return true; } - // Otherwise the condition is valid or the rparen is present. - T.consumeClose(); - - if (LParenLoc != nullptr) { - *LParenLoc = T.getOpenLocation(); - } - if (RParenLoc != nullptr) { - *RParenLoc = T.getCloseLocation(); + if (Cond.isInvalid()) { + ExprResult CondExpr = Actions.CreateRecoveryExpr( + Start, Tok.getLocation() == Start ? Start : PrevTokLocation, {}, + Actions.PreferredConditionType(CK)); + if (!CondExpr.isInvalid()) + Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK, + /*MissingOK=*/false); } + // Either the condition is valid or the rparen is present. + T.consumeClose(); + LParenLoc = T.getOpenLocation(); + RParenLoc = T.getCloseLocation(); + // Check for extraneous ')'s to catch things like "if (foo())) {". We know // that all callers are looking for a statement after the condition, so ")" // isn't valid. @@ -1338,20 +1483,36 @@ struct MisleadingIndentationChecker { /// 'if' '(' expression ')' statement 'else' statement /// [C++] 'if' '(' condition ')' statement /// [C++] 'if' '(' condition ')' statement 'else' statement +/// [C++23] 'if' '!' [opt] consteval compound-statement +/// [C++23] 'if' '!' [opt] consteval compound-statement 'else' statement /// StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_if) && "Not an if stmt!"); SourceLocation IfLoc = ConsumeToken(); // eat the 'if'. bool IsConstexpr = false; + bool IsConsteval = false; + SourceLocation NotLocation; + SourceLocation ConstevalLoc; + if (Tok.is(tok::kw_constexpr)) { Diag(Tok, getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_constexpr_if : diag::ext_constexpr_if); IsConstexpr = true; ConsumeToken(); - } + } else { + if (Tok.is(tok::exclaim)) { + NotLocation = ConsumeToken(); + } - if (Tok.isNot(tok::l_paren)) { + if (Tok.is(tok::kw_consteval)) { + Diag(Tok, getLangOpts().CPlusPlus23 ? diag::warn_cxx20_compat_consteval_if + : diag::ext_consteval_if); + IsConsteval = true; + ConstevalLoc = ConsumeToken(); + } + } + if (!IsConsteval && (NotLocation.isValid() || Tok.isNot(tok::l_paren))) { Diag(Tok, diag::err_expected_lparen_after) << "if"; SkipUntil(tok::semi); return StmtError(); @@ -1378,15 +1539,18 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { Sema::ConditionResult Cond; SourceLocation LParen; SourceLocation RParen; - if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc, - IsConstexpr ? Sema::ConditionKind::ConstexprIf - : Sema::ConditionKind::Boolean, - &LParen, &RParen)) - return StmtError(); + std::optional<bool> ConstexprCondition; + if (!IsConsteval) { - llvm::Optional<bool> ConstexprCondition; - if (IsConstexpr) - ConstexprCondition = Cond.getKnownValue(); + if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc, + IsConstexpr ? Sema::ConditionKind::ConstexprIf + : Sema::ConditionKind::Boolean, + LParen, RParen)) + return StmtError(); + + if (IsConstexpr) + ConstexprCondition = Cond.getKnownValue(); + } bool IsBracedThen = Tok.is(tok::l_brace); @@ -1418,10 +1582,17 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { SourceLocation InnerStatementTrailingElseLoc; StmtResult ThenStmt; { + bool ShouldEnter = ConstexprCondition && !*ConstexprCondition; + Sema::ExpressionEvaluationContext Context = + Sema::ExpressionEvaluationContext::DiscardedStatement; + if (NotLocation.isInvalid() && IsConsteval) { + Context = Sema::ExpressionEvaluationContext::ImmediateFunctionContext; + ShouldEnter = true; + } + EnterExpressionEvaluationContext PotentiallyDiscarded( - Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr, - Sema::ExpressionEvaluationContextRecord::EK_Other, - /*ShouldEnter=*/ConstexprCondition && !*ConstexprCondition); + Actions, Context, nullptr, + Sema::ExpressionEvaluationContextRecord::EK_Other, ShouldEnter); ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc); } @@ -1456,11 +1627,17 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { Tok.is(tok::l_brace)); MisleadingIndentationChecker MIChecker(*this, MSK_else, ElseLoc); + bool ShouldEnter = ConstexprCondition && *ConstexprCondition; + Sema::ExpressionEvaluationContext Context = + Sema::ExpressionEvaluationContext::DiscardedStatement; + if (NotLocation.isValid() && IsConsteval) { + Context = Sema::ExpressionEvaluationContext::ImmediateFunctionContext; + ShouldEnter = true; + } EnterExpressionEvaluationContext PotentiallyDiscarded( - Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr, - Sema::ExpressionEvaluationContextRecord::EK_Other, - /*ShouldEnter=*/ConstexprCondition && *ConstexprCondition); + Actions, Context, nullptr, + Sema::ExpressionEvaluationContextRecord::EK_Other, ShouldEnter); ElseStmt = ParseStatement(); if (ElseStmt.isUsable()) @@ -1479,7 +1656,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { IfScope.Exit(); // If the then or else stmt is invalid and the other is valid (and present), - // make turn the invalid one into a null stmt to avoid dropping the other + // turn the invalid one into a null stmt to avoid dropping the other // part. If both are invalid, return error. if ((ThenStmt.isInvalid() && ElseStmt.isInvalid()) || (ThenStmt.isInvalid() && ElseStmt.get() == nullptr) || @@ -1488,14 +1665,40 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { return StmtError(); } + if (IsConsteval) { + auto IsCompoundStatement = [](const Stmt *S) { + if (const auto *Outer = dyn_cast_if_present<AttributedStmt>(S)) + S = Outer->getSubStmt(); + return isa_and_nonnull<clang::CompoundStmt>(S); + }; + + if (!IsCompoundStatement(ThenStmt.get())) { + Diag(ConstevalLoc, diag::err_expected_after) << "consteval" + << "{"; + return StmtError(); + } + if (!ElseStmt.isUnset() && !IsCompoundStatement(ElseStmt.get())) { + Diag(ElseLoc, diag::err_expected_after) << "else" + << "{"; + return StmtError(); + } + } + // Now if either are invalid, replace with a ';'. if (ThenStmt.isInvalid()) ThenStmt = Actions.ActOnNullStmt(ThenStmtLoc); if (ElseStmt.isInvalid()) ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); - return Actions.ActOnIfStmt(IfLoc, IsConstexpr, LParen, InitStmt.get(), Cond, - RParen, ThenStmt.get(), ElseLoc, ElseStmt.get()); + IfStatementKind Kind = IfStatementKind::Ordinary; + if (IsConstexpr) + Kind = IfStatementKind::Constexpr; + else if (IsConsteval) + Kind = NotLocation.isValid() ? IfStatementKind::ConstevalNegated + : IfStatementKind::ConstevalNonNegated; + + return Actions.ActOnIfStmt(IfLoc, Kind, LParen, InitStmt.get(), Cond, RParen, + ThenStmt.get(), ElseLoc, ElseStmt.get()); } /// ParseSwitchStatement @@ -1537,7 +1740,7 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) { SourceLocation LParen; SourceLocation RParen; if (ParseParenExprOrCondition(&InitStmt, Cond, SwitchLoc, - Sema::ConditionKind::Switch, &LParen, &RParen)) + Sema::ConditionKind::Switch, LParen, RParen)) return StmtError(); StmtResult Switch = Actions.ActOnStartOfSwitchStmt( @@ -1627,7 +1830,7 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) { SourceLocation LParen; SourceLocation RParen; if (ParseParenExprOrCondition(nullptr, Cond, WhileLoc, - Sema::ConditionKind::Boolean, &LParen, &RParen)) + Sema::ConditionKind::Boolean, LParen, RParen)) return StmtError(); // C99 6.8.5p5 - In C99, the body of the while statement is a scope, even if @@ -1718,10 +1921,19 @@ StmtResult Parser::ParseDoStatement() { // A do-while expression is not a condition, so can't have attributes. DiagnoseAndSkipCXX11Attributes(); + SourceLocation Start = Tok.getLocation(); ExprResult Cond = ParseExpression(); // Correct the typos in condition before closing the scope. if (Cond.isUsable()) - Cond = Actions.CorrectDelayedTyposInExpr(Cond); + Cond = Actions.CorrectDelayedTyposInExpr(Cond, /*InitDecl=*/nullptr, + /*RecoverUncorrectedTypos=*/true); + else { + if (!Tok.isOneOf(tok::r_paren, tok::r_square, tok::r_brace)) + SkipUntil(tok::semi); + Cond = Actions.CreateRecoveryExpr( + Start, Start == Tok.getLocation() ? Start : PrevTokLocation, {}, + Actions.getASTContext().BoolTy); + } T.consumeClose(); DoScope.Exit(); @@ -1767,6 +1979,7 @@ bool Parser::isForRangeIdentifier() { /// [C++] for-init-statement: /// [C++] expression-statement /// [C++] simple-declaration +/// [C++23] alias-declaration /// /// [C++0x] for-range-declaration: /// [C++0x] attribute-specifier-seq[opt] type-specifier-seq declarator @@ -1831,7 +2044,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { return StmtError(); } - ParsedAttributesWithRange attrs(AttrFactory); + ParsedAttributes attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); SourceLocation EmptyInitStmtSemiLoc; @@ -1862,8 +2075,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { ? FixItHint::CreateInsertion(Loc, "auto &&") : FixItHint()); - ForRangeInfo.LoopVar = Actions.ActOnCXXForRangeIdentifier( - getCurScope(), Loc, Name, attrs, attrs.Range.getEnd()); + ForRangeInfo.LoopVar = + Actions.ActOnCXXForRangeIdentifier(getCurScope(), Loc, Name, attrs); } else if (isForInitDeclaration()) { // for (int X = 4; ParenBraceBracketBalancer BalancerRAIIObj(*this); @@ -1872,36 +2085,43 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); Diag(Tok, diag::warn_gcc_variable_decl_in_for_loop); } - - // In C++0x, "for (T NS:a" might not be a typo for :: - bool MightBeForRangeStmt = getLangOpts().CPlusPlus; - ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); - + DeclGroupPtrTy DG; SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy DG = ParseSimpleDeclaration( - DeclaratorContext::ForInit, DeclEnd, attrs, false, - MightBeForRangeStmt ? &ForRangeInfo : nullptr); - FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); - if (ForRangeInfo.ParsedForRangeDecl()) { - Diag(ForRangeInfo.ColonLoc, getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_for_range : diag::ext_for_range); - ForRangeInfo.LoopVar = FirstPart; - FirstPart = StmtResult(); - } else if (Tok.is(tok::semi)) { // for (int x = 4; - ConsumeToken(); - } else if ((ForEach = isTokIdentifier_in())) { - Actions.ActOnForEachDeclStmt(DG); - // ObjC: for (id x in expr) - ConsumeToken(); // consume 'in' - - if (Tok.is(tok::code_completion)) { - cutOffParsing(); - Actions.CodeCompleteObjCForCollection(getCurScope(), DG); - return StmtError(); - } - Collection = ParseExpression(); + if (Tok.is(tok::kw_using)) { + DG = ParseAliasDeclarationInInitStatement(DeclaratorContext::ForInit, + attrs); + FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); } else { - Diag(Tok, diag::err_expected_semi_for); + // In C++0x, "for (T NS:a" might not be a typo for :: + bool MightBeForRangeStmt = getLangOpts().CPlusPlus; + ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); + ParsedAttributes DeclSpecAttrs(AttrFactory); + DG = ParseSimpleDeclaration( + DeclaratorContext::ForInit, DeclEnd, attrs, DeclSpecAttrs, false, + MightBeForRangeStmt ? &ForRangeInfo : nullptr); + FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); + if (ForRangeInfo.ParsedForRangeDecl()) { + Diag(ForRangeInfo.ColonLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_for_range + : diag::ext_for_range); + ForRangeInfo.LoopVar = FirstPart; + FirstPart = StmtResult(); + } else if (Tok.is(tok::semi)) { // for (int x = 4; + ConsumeToken(); + } else if ((ForEach = isTokIdentifier_in())) { + Actions.ActOnForEachDeclStmt(DG); + // ObjC: for (id x in expr) + ConsumeToken(); // consume 'in' + + if (Tok.is(tok::code_completion)) { + cutOffParsing(); + Actions.CodeCompleteObjCForCollection(getCurScope(), DG); + return StmtError(); + } + Collection = ParseExpression(); + } else { + Diag(Tok, diag::err_expected_semi_for); + } } } else { ProhibitAttributes(attrs); @@ -1969,10 +2189,13 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { // for-range-declaration next. bool MightBeForRangeStmt = !ForRangeInfo.ParsedForRangeDecl(); ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); - SecondPart = - ParseCXXCondition(nullptr, ForLoc, Sema::ConditionKind::Boolean, - MightBeForRangeStmt ? &ForRangeInfo : nullptr, - /*EnterForConditionScope*/ true); + SourceLocation SecondPartStart = Tok.getLocation(); + Sema::ConditionKind CK = Sema::ConditionKind::Boolean; + SecondPart = ParseCXXCondition( + /*InitStmt=*/nullptr, ForLoc, CK, + // FIXME: recovery if we don't see another semi! + /*MissingOK=*/true, MightBeForRangeStmt ? &ForRangeInfo : nullptr, + /*EnterForConditionScope=*/true); if (ForRangeInfo.ParsedForRangeDecl()) { Diag(FirstPart.get() ? FirstPart.get()->getBeginLoc() @@ -1988,6 +2211,19 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { << FixItHint::CreateRemoval(EmptyInitStmtSemiLoc); } } + + if (SecondPart.isInvalid()) { + ExprResult CondExpr = Actions.CreateRecoveryExpr( + SecondPartStart, + Tok.getLocation() == SecondPartStart ? SecondPartStart + : PrevTokLocation, + {}, Actions.PreferredConditionType(CK)); + if (!CondExpr.isInvalid()) + SecondPart = Actions.ActOnCondition(getCurScope(), ForLoc, + CondExpr.get(), CK, + /*MissingOK=*/false); + } + } else { // We permit 'continue' and 'break' in the condition of a for loop. getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope); @@ -1996,16 +2232,16 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { if (SecondExpr.isInvalid()) SecondPart = Sema::ConditionError(); else - SecondPart = - Actions.ActOnCondition(getCurScope(), ForLoc, SecondExpr.get(), - Sema::ConditionKind::Boolean); + SecondPart = Actions.ActOnCondition( + getCurScope(), ForLoc, SecondExpr.get(), + Sema::ConditionKind::Boolean, /*MissingOK=*/true); } } } // Enter a break / continue scope, if we didn't already enter one while // parsing the second part. - if (!(getCurScope()->getFlags() & Scope::ContinueScope)) + if (!getCurScope()->isContinueScope()) getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope); // Parse the third part of the for statement. @@ -2013,9 +2249,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { if (Tok.isNot(tok::semi)) { if (!SecondPart.isInvalid()) Diag(Tok, diag::err_expected_semi_for); - else - // Skip until semicolon or rparen, don't consume it. - SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); + SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); } if (Tok.is(tok::semi)) { @@ -2039,6 +2273,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { CoawaitLoc = SourceLocation(); } + if (CoawaitLoc.isValid() && getLangOpts().CPlusPlus20) + Diag(CoawaitLoc, diag::warn_deprecated_for_co_await); + // We need to perform most of the semantic analysis for a C++0x for-range // statememt before parsing the body, in order to be able to deduce the type // of an auto-typed loop variable. @@ -2222,9 +2459,9 @@ StmtResult Parser::ParseReturnStatement() { StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, ParsedStmtContext StmtCtx, SourceLocation *TrailingElseLoc, - ParsedAttributesWithRange &Attrs) { + ParsedAttributes &Attrs) { // Create temporary attribute list. - ParsedAttributesWithRange TempAttrs(AttrFactory); + ParsedAttributes TempAttrs(AttrFactory); SourceLocation StartLoc = Tok.getLocation(); @@ -2238,14 +2475,15 @@ StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, ArgsUnion(Hint.ValueExpr)}; TempAttrs.addNew(Hint.PragmaNameLoc->Ident, Hint.Range, nullptr, Hint.PragmaNameLoc->Loc, ArgHints, 4, - ParsedAttr::AS_Pragma); + ParsedAttr::Form::Pragma()); } // Get the next statement. MaybeParseCXX11Attributes(Attrs); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); StmtResult S = ParseStatementOrDeclarationAfterAttributes( - Stmts, StmtCtx, TrailingElseLoc, Attrs); + Stmts, StmtCtx, TrailingElseLoc, Attrs, EmptyDeclSpecAttrs); Attrs.takeAllFrom(TempAttrs); @@ -2278,7 +2516,8 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { // If the function body could not be parsed, make a bogus compoundstmt. if (FnBody.isInvalid()) { Sema::CompoundScopeRAII CompoundScope(Actions); - FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false); + FnBody = + Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, std::nullopt, false); } BodyScope.Exit(); @@ -2315,7 +2554,8 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { // compound statement as the body. if (FnBody.isInvalid()) { Sema::CompoundScopeRAII CompoundScope(Actions); - FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false); + FnBody = + Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, std::nullopt, false); } BodyScope.Exit(); @@ -2477,16 +2717,15 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) { // without default arguments. Decl *ExceptionDecl = nullptr; if (Tok.isNot(tok::ellipsis)) { - ParsedAttributesWithRange Attributes(AttrFactory); + ParsedAttributes Attributes(AttrFactory); MaybeParseCXX11Attributes(Attributes); DeclSpec DS(AttrFactory); - DS.takeAttributesFrom(Attributes); if (ParseCXXTypeSpecifierSeq(DS)) return StmtError(); - Declarator ExDecl(DS, DeclaratorContext::CXXCatch); + Declarator ExDecl(DS, Attributes, DeclaratorContext::CXXCatch); ParseDeclarator(ExDecl); ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl); } else |