[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(),