aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp679
1 files changed, 459 insertions, 220 deletions
diff --git a/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp b/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp
index 26a02575010c..d0ff33bd1379 100644
--- a/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp
+++ b/contrib/llvm-project/clang/lib/Parse/ParseStmt.cpp
@@ -14,12 +14,18 @@
#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;
//===----------------------------------------------------------------------===//
@@ -34,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());
@@ -98,22 +104,33 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
ParenBraceBracketBalancer BalancerRAIIObj(*this);
- ParsedAttributesWithRange Attrs(AttrFactory);
- MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true);
- if (!MaybeParseOpenCLUnrollHintAttribute(Attrs))
- return StmtError();
+ // Because we're parsing either a statement or a declaration, the order of
+ // attribute parsing is important. [[]] attributes at the start of a
+ // 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.
+ ParsedAttributes CXX11Attrs(AttrFactory);
+ MaybeParseCXX11Attributes(CXX11Attrs, /*MightBeObjCMessageSend*/ true);
+ ParsedAttributes GNUAttrs(AttrFactory);
+ if (getLangOpts().OpenCL)
+ 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");
if (Attrs.empty() || Res.isInvalid())
return Res;
- return Actions.ProcessStmtAttributes(Res.get(), Attrs, Attrs.Range);
+ return Actions.ActOnAttributedStmt(Attrs, Res.get());
}
namespace {
@@ -151,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;
@@ -165,19 +183,25 @@ Retry:
switch (Kind) {
case tok::at: // May be a @try or @throw statement
{
- ProhibitAttributes(Attrs); // TODO: is it correct?
AtLoc = ConsumeToken(); // consume @
return ParseObjCAtStatement(AtLoc, StmtCtx);
}
case tok::code_completion:
- Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
cutOffParsing();
+ 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);
}
@@ -203,25 +227,34 @@ Retry:
}
// Fall through
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
default: {
- if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt ||
- (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) !=
- ParsedStmtContext()) &&
- (GNUAttributeLoc.isValid() || isDeclarationStatement())) {
+ 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);
}
@@ -230,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;
}
@@ -287,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;
@@ -298,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.
@@ -308,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:
@@ -317,101 +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:
- ProhibitAttributes(Attrs);
+ // Prohibit attributes that are not OpenMP attributes, but only before
+ // processing a #pragma omp clause.
+ 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();
@@ -465,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
@@ -600,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.
@@ -626,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
@@ -637,23 +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);
- else if (isDeclarationStatement()) {
+ Attrs.takeAllFrom(TempAttrs);
+ else {
StmtVector Stmts;
- // FIXME: We should do this whether or not we have a declaration
- // statement, but that doesn't work correctly (because ProhibitAttributes
- // can't handle GNU attributes), so only call it in the one case where
- // GNU attributes are allowed.
- SubStmt = ParseStatementOrDeclarationAfterAttributes(Stmts, StmtCtx,
- nullptr, TempAttrs);
+ ParsedAttributes EmptyCXX11Attrs(AttrFactory);
+ SubStmt = ParseStatementOrDeclarationAfterAttributes(
+ Stmts, StmtCtx, nullptr, EmptyCXX11Attrs, TempAttrs);
if (!TempAttrs.empty() && !SubStmt.isInvalid())
- SubStmt = Actions.ProcessStmtAttributes(SubStmt.get(), TempAttrs,
- TempAttrs.Range);
- } else {
- Diag(Tok, diag::err_expected_after) << "__attribute__" << tok::semi;
+ 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);
@@ -662,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());
@@ -680,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:
@@ -715,8 +840,8 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx,
ColonLoc = SourceLocation();
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteCase(getCurScope());
cutOffParsing();
+ Actions.CodeCompleteCase(getCurScope());
return StmtError();
}
@@ -794,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.
@@ -813,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());
}
@@ -828,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'.
@@ -851,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());
}
@@ -899,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.
@@ -947,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;
@@ -975,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) {
@@ -1013,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);
@@ -1024,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(),
@@ -1056,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;
@@ -1106,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()) {
@@ -1117,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.
@@ -1134,13 +1271,23 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
R = handleExprStmt(Res, SubStmtCtx);
if (R.isUsable())
- R = Actions.ProcessStmtAttributes(R.get(), attrs, attrs.Range);
+ R = Actions.ActOnAttributedStmt(attrs, R.get());
}
}
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();
@@ -1174,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
@@ -1208,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.
@@ -1330,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();
@@ -1370,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);
@@ -1410,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);
}
@@ -1448,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())
@@ -1461,8 +1646,8 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// Pop the 'else' scope if needed.
InnerScope.Exit();
} else if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteAfterIf(getCurScope(), IsBracedThen);
cutOffParsing();
+ Actions.CodeCompleteAfterIf(getCurScope(), IsBracedThen);
return StmtError();
} else if (InnerStatementTrailingElseLoc.isValid()) {
Diag(InnerStatementTrailingElseLoc, diag::warn_dangling_else);
@@ -1471,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) ||
@@ -1480,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
@@ -1529,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(
@@ -1619,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
@@ -1710,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();
@@ -1759,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
@@ -1816,14 +2037,14 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
FullExprArg ThirdPart(Actions);
if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(),
C99orCXXorObjC? Sema::PCC_ForInit
: Sema::PCC_Expression);
- cutOffParsing();
return StmtError();
}
- ParsedAttributesWithRange attrs(AttrFactory);
+ ParsedAttributes attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
SourceLocation EmptyInitStmtSemiLoc;
@@ -1854,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);
@@ -1864,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)) {
- Actions.CodeCompleteObjCForCollection(getCurScope(), DG);
- cutOffParsing();
- 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);
@@ -1923,8 +2151,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ConsumeToken(); // consume 'in'
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCForCollection(getCurScope(), nullptr);
cutOffParsing();
+ Actions.CodeCompleteObjCForCollection(getCurScope(), nullptr);
return StmtError();
}
Collection = ParseExpression();
@@ -1948,7 +2176,6 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
}
// Parse the second part of the for specifier.
- getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
if (!ForEach && !ForRangeInfo.ParsedForRangeDecl() &&
!SecondPart.isInvalid()) {
// Parse the second part of the for specifier.
@@ -1962,9 +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);
+ 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()
@@ -1980,26 +2211,45 @@ 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);
+
ExprResult SecondExpr = ParseExpression();
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()->isContinueScope())
+ getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
+
// Parse the third part of the for statement.
if (!ForEach && !ForRangeInfo.ParsedForRangeDecl()) {
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)) {
@@ -2023,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.
@@ -2177,9 +2430,9 @@ StmtResult Parser::ParseReturnStatement() {
PreferredType.enterReturn(Actions, Tok.getLocation());
// FIXME: Code completion for co_return.
if (Tok.is(tok::code_completion) && !IsCoreturn) {
+ cutOffParsing();
Actions.CodeCompleteExpression(getCurScope(),
PreferredType.get(Tok.getLocation()));
- cutOffParsing();
return StmtError();
}
@@ -2206,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();
@@ -2222,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);
@@ -2262,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();
@@ -2299,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();
@@ -2461,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
@@ -2548,19 +2803,3 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
}
Braces.consumeClose();
}
-
-bool Parser::ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) {
- MaybeParseGNUAttributes(Attrs);
-
- if (Attrs.empty())
- return true;
-
- if (Attrs.begin()->getKind() != ParsedAttr::AT_OpenCLUnrollHint)
- return true;
-
- if (!(Tok.is(tok::kw_for) || Tok.is(tok::kw_while) || Tok.is(tok::kw_do))) {
- Diag(Tok, diag::err_opencl_unroll_hint_on_non_loop);
- return false;
- }
- return true;
-}