[cxx2a] P0614R1: Support init-statements in range-based for loops.
We don't yet support this for the case where a range-based for loop is
implicitly rewritten to an ObjC for..in statement.
llvm-svn: 343350
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 574293f..ba7c808 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -1570,11 +1570,11 @@
ExprResult Value;
- bool ForEach = false, ForRange = false;
+ bool ForEach = false;
StmtResult FirstPart;
Sema::ConditionResult SecondPart;
ExprResult Collection;
- ForRangeInit ForRangeInit;
+ ForRangeInfo ForRangeInfo;
FullExprArg ThirdPart(Actions);
if (Tok.is(tok::code_completion)) {
@@ -1600,20 +1600,19 @@
SourceLocation Loc = ConsumeToken();
MaybeParseCXX11Attributes(attrs);
- ForRangeInit.ColonLoc = ConsumeToken();
+ ForRangeInfo.ColonLoc = ConsumeToken();
if (Tok.is(tok::l_brace))
- ForRangeInit.RangeExpr = ParseBraceInitializer();
+ ForRangeInfo.RangeExpr = ParseBraceInitializer();
else
- ForRangeInit.RangeExpr = ParseExpression();
+ ForRangeInfo.RangeExpr = ParseExpression();
Diag(Loc, diag::err_for_range_identifier)
<< ((getLangOpts().CPlusPlus11 && !getLangOpts().CPlusPlus17)
? FixItHint::CreateInsertion(Loc, "auto &&")
: FixItHint());
- FirstPart = Actions.ActOnCXXForRangeIdentifier(getCurScope(), Loc, Name,
- attrs, attrs.Range.getEnd());
- ForRange = true;
+ ForRangeInfo.LoopVar = Actions.ActOnCXXForRangeIdentifier(
+ getCurScope(), Loc, Name, attrs, attrs.Range.getEnd());
} else if (isForInitDeclaration()) { // for (int X = 4;
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@@ -1630,13 +1629,13 @@
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy DG = ParseSimpleDeclaration(
DeclaratorContext::ForContext, DeclEnd, attrs, false,
- MightBeForRangeStmt ? &ForRangeInit : nullptr);
+ MightBeForRangeStmt ? &ForRangeInfo : nullptr);
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
- if (ForRangeInit.ParsedForRangeDecl()) {
- Diag(ForRangeInit.ColonLoc, getLangOpts().CPlusPlus11 ?
+ if (ForRangeInfo.ParsedForRangeDecl()) {
+ Diag(ForRangeInfo.ColonLoc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_for_range : diag::ext_for_range);
-
- ForRange = true;
+ ForRangeInfo.LoopVar = FirstPart;
+ FirstPart = StmtResult();
} else if (Tok.is(tok::semi)) { // for (int x = 4;
ConsumeToken();
} else if ((ForEach = isTokIdentifier_in())) {
@@ -1699,17 +1698,33 @@
// Parse the second part of the for specifier.
getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
- if (!ForEach && !ForRange && !SecondPart.isInvalid()) {
+ if (!ForEach && !ForRangeInfo.ParsedForRangeDecl() &&
+ !SecondPart.isInvalid()) {
// Parse the second part of the for specifier.
if (Tok.is(tok::semi)) { // for (...;;
// no second part.
} else if (Tok.is(tok::r_paren)) {
// missing both semicolons.
} else {
- if (getLangOpts().CPlusPlus)
+ if (getLangOpts().CPlusPlus) {
+ // C++2a: We've parsed an init-statement; we might have a
+ // for-range-declaration next.
+ bool MightBeForRangeStmt = !ForRangeInfo.ParsedForRangeDecl();
+ ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
SecondPart =
- ParseCXXCondition(nullptr, ForLoc, Sema::ConditionKind::Boolean);
- else {
+ ParseCXXCondition(nullptr, ForLoc, Sema::ConditionKind::Boolean,
+ MightBeForRangeStmt ? &ForRangeInfo : nullptr);
+
+ if (ForRangeInfo.ParsedForRangeDecl()) {
+ Diag(FirstPart.get() ? FirstPart.get()->getBeginLoc()
+ : ForRangeInfo.ColonLoc,
+ getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_for_range_init_stmt
+ : diag::ext_for_range_init_stmt)
+ << (FirstPart.get() ? FirstPart.get()->getSourceRange()
+ : SourceRange());
+ }
+ } else {
ExprResult SecondExpr = ParseExpression();
if (SecondExpr.isInvalid())
SecondPart = Sema::ConditionError();
@@ -1719,7 +1734,10 @@
Sema::ConditionKind::Boolean);
}
}
+ }
+ // 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);
@@ -1732,7 +1750,6 @@
ConsumeToken();
}
- // Parse the third part of the for specifier.
if (Tok.isNot(tok::r_paren)) { // for (...;...;)
ExprResult Third = ParseExpression();
// FIXME: The C++11 standard doesn't actually say that this is a
@@ -1745,7 +1762,7 @@
// C++ Coroutines [stmt.iter]:
// 'co_await' can only be used for a range-based for statement.
- if (CoawaitLoc.isValid() && !ForRange) {
+ if (CoawaitLoc.isValid() && !ForRangeInfo.ParsedForRangeDecl()) {
Diag(CoawaitLoc, diag::err_for_co_await_not_range_for);
CoawaitLoc = SourceLocation();
}
@@ -1756,12 +1773,12 @@
StmtResult ForRangeStmt;
StmtResult ForEachStmt;
- if (ForRange) {
+ if (ForRangeInfo.ParsedForRangeDecl()) {
ExprResult CorrectedRange =
- Actions.CorrectDelayedTyposInExpr(ForRangeInit.RangeExpr.get());
+ Actions.CorrectDelayedTyposInExpr(ForRangeInfo.RangeExpr.get());
ForRangeStmt = Actions.ActOnCXXForRangeStmt(
getCurScope(), ForLoc, CoawaitLoc, FirstPart.get(),
- ForRangeInit.ColonLoc, CorrectedRange.get(),
+ ForRangeInfo.LoopVar.get(), ForRangeInfo.ColonLoc, CorrectedRange.get(),
T.getCloseLocation(), Sema::BFRK_Build);
// Similarly, we need to do the semantic analysis for a for-range
@@ -1816,7 +1833,7 @@
return Actions.FinishObjCForCollectionStmt(ForEachStmt.get(),
Body.get());
- if (ForRange)
+ if (ForRangeInfo.ParsedForRangeDecl())
return Actions.FinishCXXForRangeStmt(ForRangeStmt.get(), Body.get());
return Actions.ActOnForStmt(ForLoc, T.getOpenLocation(), FirstPart.get(),