r343350 - [cxx2a] P0614R1: Support init-statements in range-based for loops.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 28 11:44:10 PDT 2018


Author: rsmith
Date: Fri Sep 28 11:44:09 2018
New Revision: 343350

URL: http://llvm.org/viewvc/llvm-project?rev=343350&view=rev
Log:
[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.

Added:
    cfe/trunk/test/CodeGenCXX/cxx2a-init-statement.cpp
    cfe/trunk/test/PCH/cxx2a-for-init-statement.cpp
    cfe/trunk/test/Parser/cxx2a-init-statement.cpp
Modified:
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/include/clang/AST/StmtCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/AST/StmtCXX.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/lib/CodeGen/CodeGenPGO.cpp
    cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Parse/ParseStmt.cpp
    cfe/trunk/lib/Parse/ParseTentative.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
    cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
    cfe/trunk/test/Analysis/Inputs/expected-plists/cxx-for-range.cpp.plist
    cfe/trunk/test/Analysis/cxx-for-range.cpp
    cfe/trunk/test/Analysis/scopes-cfg-output.cpp
    cfe/trunk/test/Import/cxx-for-range/Inputs/F.cpp
    cfe/trunk/test/Import/cxx-for-range/test.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp
    cfe/trunk/test/SemaCXX/cxx17-compat.cpp
    cfe/trunk/test/SemaObjCXX/foreach.mm
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Fri Sep 28 11:44:09 2018
@@ -2180,6 +2180,8 @@ DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStm
 
 DEF_TRAVERSE_STMT(CXXForRangeStmt, {
   if (!getDerived().shouldVisitImplicitCode()) {
+    if (S->getInit())
+      TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getInit());
     TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getLoopVarStmt());
     TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getRangeInit());
     TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody());

Modified: cfe/trunk/include/clang/AST/StmtCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtCXX.h?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/StmtCXX.h (original)
+++ cfe/trunk/include/clang/AST/StmtCXX.h Fri Sep 28 11:44:09 2018
@@ -118,14 +118,15 @@ public:
 };
 
 /// CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for
-/// statement, represented as 'for (range-declarator : range-expression)'.
+/// statement, represented as 'for (range-declarator : range-expression)'
+/// or 'for (init-statement range-declarator : range-expression)'.
 ///
 /// This is stored in a partially-desugared form to allow full semantic
 /// analysis of the constituent components. The original syntactic components
 /// can be extracted using getLoopVariable and getRangeInit.
 class CXXForRangeStmt : public Stmt {
   SourceLocation ForLoc;
-  enum { RANGE, BEGINSTMT, ENDSTMT, COND, INC, LOOPVAR, BODY, END };
+  enum { INIT, RANGE, BEGINSTMT, ENDSTMT, COND, INC, LOOPVAR, BODY, END };
   // SubExprs[RANGE] is an expression or declstmt.
   // SubExprs[COND] and SubExprs[INC] are expressions.
   Stmt *SubExprs[END];
@@ -135,16 +136,17 @@ class CXXForRangeStmt : public Stmt {
 
   friend class ASTStmtReader;
 public:
-  CXXForRangeStmt(DeclStmt *Range, DeclStmt *Begin, DeclStmt *End,
-                  Expr *Cond, Expr *Inc, DeclStmt *LoopVar, Stmt *Body,
-                  SourceLocation FL, SourceLocation CAL, SourceLocation CL,
-                  SourceLocation RPL);
+  CXXForRangeStmt(Stmt *InitStmt, DeclStmt *Range, DeclStmt *Begin,
+                  DeclStmt *End, Expr *Cond, Expr *Inc, DeclStmt *LoopVar,
+                  Stmt *Body, SourceLocation FL, SourceLocation CAL,
+                  SourceLocation CL, SourceLocation RPL);
   CXXForRangeStmt(EmptyShell Empty) : Stmt(CXXForRangeStmtClass, Empty) { }
 
-
+  Stmt *getInit() { return SubExprs[INIT]; }
   VarDecl *getLoopVariable();
   Expr *getRangeInit();
 
+  const Stmt *getInit() const { return SubExprs[INIT]; }
   const VarDecl *getLoopVariable() const;
   const Expr *getRangeInit() const;
 
@@ -179,6 +181,7 @@ public:
   }
   const Stmt *getBody() const { return SubExprs[BODY]; }
 
+  void setInit(Stmt *S) { SubExprs[INIT] = S; }
   void setRangeInit(Expr *E) { SubExprs[RANGE] = reinterpret_cast<Stmt*>(E); }
   void setRangeStmt(Stmt *S) { SubExprs[RANGE] = S; }
   void setBeginStmt(Stmt *S) { SubExprs[BEGINSTMT] = S; }

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Fri Sep 28 11:44:09 2018
@@ -540,6 +540,12 @@ def ext_init_statement : ExtWarn<
 def warn_cxx14_compat_init_statement : Warning<
   "%select{if|switch}0 initialization statements are incompatible with "
   "C++ standards before C++17">, DefaultIgnore, InGroup<CXXPre17Compat>;
+def ext_for_range_init_stmt : ExtWarn<
+  "range-based for loop initialization statements are a C++2a extension">,
+  InGroup<CXX2a>;
+def warn_cxx17_compat_for_range_init_stmt : Warning<
+  "range-based for loop initialization statements are incompatible with "
+  "C++ standards before C++2a">, DefaultIgnore, InGroup<CXXPre2aCompat>;
 
 // C++ derived classes
 def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Sep 28 11:44:09 2018
@@ -2299,6 +2299,9 @@ def warn_for_range_copy : Warning<
   "loop variable %0 of type %1 creates a copy from type %2">,
   InGroup<RangeLoopAnalysis>, DefaultIgnore;
 def note_use_reference_type : Note<"use reference type %0 to prevent copying">;
+def err_objc_for_range_init_stmt : Error<
+  "initialization statement is not supported when iterating over Objective-C "
+  "collection">;
 
 // C++11 constexpr
 def warn_cxx98_compat_constexpr : Warning<

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Fri Sep 28 11:44:09 2018
@@ -1793,10 +1793,12 @@ private:
                                             SourceLocation Start);
 
   //===--------------------------------------------------------------------===//
-  // C++ if/switch/while condition expression.
+  // C++ if/switch/while/for condition expression.
+  struct ForRangeInfo;
   Sema::ConditionResult ParseCXXCondition(StmtResult *InitStmt,
                                           SourceLocation Loc,
-                                          Sema::ConditionKind CK);
+                                          Sema::ConditionKind CK,
+                                          ForRangeInfo *FRI = nullptr);
 
   //===--------------------------------------------------------------------===//
   // C++ Coroutines
@@ -2045,6 +2047,9 @@ private:
 
     bool ParsedForRangeDecl() { return !ColonLoc.isInvalid(); }
   };
+  struct ForRangeInfo : ForRangeInit {
+    StmtResult LoopVar;
+  };
 
   DeclGroupPtrTy ParseDeclaration(DeclaratorContext Context,
                                   SourceLocation &DeclEnd,
@@ -2215,13 +2220,15 @@ private:
     Expression,    ///< Disambiguated as an expression (either kind).
     ConditionDecl, ///< Disambiguated as the declaration form of condition.
     InitStmtDecl,  ///< Disambiguated as a simple-declaration init-statement.
+    ForRangeDecl,  ///< Disambiguated as a for-range declaration.
     Error          ///< Can't be any of the above!
   };
   /// Disambiguates between the different kinds of things that can happen
   /// after 'if (' or 'switch ('. This could be one of two different kinds of
   /// declaration (depending on whether there is a ';' later) or an expression.
   ConditionOrInitStatement
-  isCXXConditionDeclarationOrInitStatement(bool CanBeInitStmt);
+  isCXXConditionDeclarationOrInitStatement(bool CanBeInitStmt,
+                                           bool CanBeForRangeDecl);
 
   bool isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous);
   bool isCXXTypeId(TentativeCXXTypeIdContext Context) {

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Sep 28 11:44:09 2018
@@ -3777,12 +3777,14 @@ public:
 
   StmtResult ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
                                   SourceLocation CoawaitLoc,
+                                  Stmt *InitStmt,
                                   Stmt *LoopVar,
                                   SourceLocation ColonLoc, Expr *Collection,
                                   SourceLocation RParenLoc,
                                   BuildForRangeKind Kind);
   StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc,
                                   SourceLocation CoawaitLoc,
+                                  Stmt *InitStmt,
                                   SourceLocation ColonLoc,
                                   Stmt *RangeDecl, Stmt *Begin, Stmt *End,
                                   Expr *Cond, Expr *Inc,

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Fri Sep 28 11:44:09 2018
@@ -5394,6 +5394,9 @@ Stmt *ASTNodeImporter::VisitCXXTryStmt(C
 }
 
 Stmt *ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
+  auto *ToInit = dyn_cast_or_null<Stmt>(Importer.Import(S->getInit()));
+  if (!ToInit && S->getInit())
+    return nullptr;
   auto *ToRange =
     dyn_cast_or_null<DeclStmt>(Importer.Import(S->getRangeStmt()));
   if (!ToRange && S->getRangeStmt())
@@ -5423,11 +5426,9 @@ Stmt *ASTNodeImporter::VisitCXXForRangeS
   SourceLocation ToCoawaitLoc = Importer.Import(S->getCoawaitLoc());
   SourceLocation ToColonLoc = Importer.Import(S->getColonLoc());
   SourceLocation ToRParenLoc = Importer.Import(S->getRParenLoc());
-  return new (Importer.getToContext()) CXXForRangeStmt(ToRange, ToBegin, ToEnd,
-                                                       ToCond, ToInc,
-                                                       ToLoopVar, ToBody,
-                                                       ToForLoc, ToCoawaitLoc,
-                                                       ToColonLoc, ToRParenLoc);
+  return new (Importer.getToContext())
+      CXXForRangeStmt(ToInit, ToRange, ToBegin, ToEnd, ToCond, ToInc, ToLoopVar,
+                      ToBody, ToForLoc, ToCoawaitLoc, ToColonLoc, ToRParenLoc);
 }
 
 Stmt *ASTNodeImporter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Sep 28 11:44:09 2018
@@ -4217,6 +4217,13 @@ static EvalStmtResult EvaluateStmt(StmtR
     const CXXForRangeStmt *FS = cast<CXXForRangeStmt>(S);
     BlockScopeRAII Scope(Info);
 
+    // Evaluate the init-statement if present.
+    if (FS->getInit()) {
+      EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getInit());
+      if (ESR != ESR_Succeeded)
+        return ESR;
+    }
+
     // Initialize the __range variable.
     EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getRangeStmt());
     if (ESR != ESR_Succeeded)

Modified: cfe/trunk/lib/AST/StmtCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtCXX.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtCXX.cpp (original)
+++ cfe/trunk/lib/AST/StmtCXX.cpp Fri Sep 28 11:44:09 2018
@@ -45,7 +45,7 @@ CXXTryStmt::CXXTryStmt(SourceLocation tr
   std::copy(handlers.begin(), handlers.end(), Stmts + 1);
 }
 
-CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range,
+CXXForRangeStmt::CXXForRangeStmt(Stmt *Init, DeclStmt *Range,
                                  DeclStmt *BeginStmt, DeclStmt *EndStmt,
                                  Expr *Cond, Expr *Inc, DeclStmt *LoopVar,
                                  Stmt *Body, SourceLocation FL,
@@ -53,6 +53,7 @@ CXXForRangeStmt::CXXForRangeStmt(DeclStm
                                  SourceLocation RPL)
     : Stmt(CXXForRangeStmtClass), ForLoc(FL), CoawaitLoc(CAL), ColonLoc(CL),
       RParenLoc(RPL) {
+  SubExprs[INIT] = Init;
   SubExprs[RANGE] = Range;
   SubExprs[BEGINSTMT] = BeginStmt;
   SubExprs[ENDSTMT] = EndStmt;

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Fri Sep 28 11:44:09 2018
@@ -99,6 +99,28 @@ namespace {
       IndentLevel -= SubIndent;
     }
 
+    void PrintInitStmt(Stmt *S, unsigned PrefixWidth) {
+      // FIXME: Cope better with odd prefix widths.
+      IndentLevel += (PrefixWidth + 1) / 2;
+      if (auto *DS = dyn_cast<DeclStmt>(S))
+        PrintRawDeclStmt(DS);
+      else
+        PrintExpr(cast<Expr>(S));
+      OS << "; ";
+      IndentLevel -= (PrefixWidth + 1) / 2;
+    }
+
+    void PrintControlledStmt(Stmt *S) {
+      if (auto *CS = dyn_cast<CompoundStmt>(S)) {
+        OS << " ";
+        PrintRawCompoundStmt(CS);
+        OS << NL;
+      } else {
+        OS << NL;
+        PrintStmt(S);
+      }
+    }
+
     void PrintRawCompoundStmt(CompoundStmt *S);
     void PrintRawDecl(Decl *D);
     void PrintRawDeclStmt(const DeclStmt *S);
@@ -218,6 +240,8 @@ void StmtPrinter::VisitAttributedStmt(At
 
 void StmtPrinter::PrintRawIfStmt(IfStmt *If) {
   OS << "if (";
+  if (If->getInit())
+    PrintInitStmt(If->getInit(), 4);
   if (const DeclStmt *DS = If->getConditionVariableDeclStmt())
     PrintRawDeclStmt(DS);
   else
@@ -258,21 +282,14 @@ void StmtPrinter::VisitIfStmt(IfStmt *If
 
 void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) {
   Indent() << "switch (";
+  if (Node->getInit())
+    PrintInitStmt(Node->getInit(), 8);
   if (const DeclStmt *DS = Node->getConditionVariableDeclStmt())
     PrintRawDeclStmt(DS);
   else
     PrintExpr(Node->getCond());
   OS << ")";
-
-  // Pretty print compoundstmt bodies (very common).
-  if (auto *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
-    OS << " ";
-    PrintRawCompoundStmt(CS);
-    OS << NL;
-  } else {
-    OS << NL;
-    PrintStmt(Node->getBody());
-  }
+  PrintControlledStmt(Node->getBody());
 }
 
 void StmtPrinter::VisitWhileStmt(WhileStmt *Node) {
@@ -303,31 +320,19 @@ void StmtPrinter::VisitDoStmt(DoStmt *No
 
 void StmtPrinter::VisitForStmt(ForStmt *Node) {
   Indent() << "for (";
-  if (Node->getInit()) {
-    if (auto *DS = dyn_cast<DeclStmt>(Node->getInit()))
-      PrintRawDeclStmt(DS);
-    else
-      PrintExpr(cast<Expr>(Node->getInit()));
-  }
-  OS << ";";
-  if (Node->getCond()) {
-    OS << " ";
+  if (Node->getInit())
+    PrintInitStmt(Node->getInit(), 5);
+  else
+    OS << (Node->getCond() ? "; " : ";");
+  if (Node->getCond())
     PrintExpr(Node->getCond());
-  }
   OS << ";";
   if (Node->getInc()) {
     OS << " ";
     PrintExpr(Node->getInc());
   }
-  OS << ") ";
-
-  if (auto *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
-    PrintRawCompoundStmt(CS);
-    OS << NL;
-  } else {
-    OS << NL;
-    PrintStmt(Node->getBody());
-  }
+  OS << ")";
+  PrintControlledStmt(Node->getBody());
 }
 
 void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) {
@@ -338,28 +343,21 @@ void StmtPrinter::VisitObjCForCollection
     PrintExpr(cast<Expr>(Node->getElement()));
   OS << " in ";
   PrintExpr(Node->getCollection());
-  OS << ") ";
-
-  if (auto *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
-    PrintRawCompoundStmt(CS);
-    OS << NL;
-  } else {
-    OS << NL;
-    PrintStmt(Node->getBody());
-  }
+  OS << ")";
+  PrintControlledStmt(Node->getBody());
 }
 
 void StmtPrinter::VisitCXXForRangeStmt(CXXForRangeStmt *Node) {
   Indent() << "for (";
+  if (Node->getInit())
+    PrintInitStmt(Node->getInit(), 5);
   PrintingPolicy SubPolicy(Policy);
   SubPolicy.SuppressInitializers = true;
   Node->getLoopVariable()->print(OS, SubPolicy, IndentLevel);
   OS << " : ";
   PrintExpr(Node->getRangeInit());
-  OS << ") {" << NL;
-  PrintStmt(Node->getBody());
-  Indent() << "}";
-  if (Policy.IncludeNewlines) OS << NL;
+  OS << ")";
+  PrintControlledStmt(Node->getBody());
 }
 
 void StmtPrinter::VisitMSDependentExistsStmt(MSDependentExistsStmt *Node) {

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Fri Sep 28 11:44:09 2018
@@ -4255,7 +4255,10 @@ CFGBlock *CFGBuilder::VisitCXXForRangeSt
   Block = createBlock();
   addStmt(S->getBeginStmt());
   addStmt(S->getEndStmt());
-  return addStmt(S->getRangeStmt());
+  CFGBlock *Head = addStmt(S->getRangeStmt());
+  if (S->getInit())
+    Head = addStmt(S->getInit());
+  return Head;
 }
 
 CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Fri Sep 28 11:44:09 2018
@@ -932,6 +932,8 @@ CodeGenFunction::EmitCXXForRangeStmt(con
   LexicalScope ForScope(*this, S.getSourceRange());
 
   // Evaluate the first pieces before the loop.
+  if (S.getInit())
+    EmitStmt(S.getInit());
   EmitStmt(S.getRangeStmt());
   EmitStmt(S.getBeginStmt());
   EmitStmt(S.getEndStmt());

Modified: cfe/trunk/lib/CodeGen/CodeGenPGO.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenPGO.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenPGO.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenPGO.cpp Fri Sep 28 11:44:09 2018
@@ -544,6 +544,8 @@ struct ComputeRegionCounts : public Cons
 
   void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
     RecordStmtCount(S);
+    if (S->getInit())
+      Visit(S->getInit());
     Visit(S->getLoopVarStmt());
     Visit(S->getRangeStmt());
     Visit(S->getBeginStmt());

Modified: cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp (original)
+++ cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp Fri Sep 28 11:44:09 2018
@@ -1004,6 +1004,8 @@ struct CounterCoverageMappingBuilder
 
   void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
     extendRegion(S);
+    if (S->getInit())
+      Visit(S->getInit());
     Visit(S->getLoopVarStmt());
     Visit(S->getRangeStmt());
 

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Fri Sep 28 11:44:09 2018
@@ -1738,10 +1738,14 @@ Parser::ParseCXXTypeConstructExpression(
 /// \param Loc The location of the start of the statement that requires this
 /// condition, e.g., the "for" in a for loop.
 ///
+/// \param FRI If non-null, a for range declaration is permitted, and if
+/// present will be parsed and stored here, and a null result will be returned.
+///
 /// \returns The parsed condition.
 Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
                                                 SourceLocation Loc,
-                                                Sema::ConditionKind CK) {
+                                                Sema::ConditionKind CK,
+                                                ForRangeInfo *FRI) {
   ParenBraceBracketBalancer BalancerRAIIObj(*this);
 
   if (Tok.is(tok::code_completion)) {
@@ -1761,7 +1765,7 @@ Sema::ConditionResult Parser::ParseCXXCo
   };
 
   // Determine what kind of thing we have.
-  switch (isCXXConditionDeclarationOrInitStatement(InitStmt)) {
+  switch (isCXXConditionDeclarationOrInitStatement(InitStmt, FRI)) {
   case ConditionOrInitStatement::Expression: {
     ProhibitAttributes(attrs);
 
@@ -1799,6 +1803,15 @@ Sema::ConditionResult Parser::ParseCXXCo
     return ParseCXXCondition(nullptr, Loc, CK);
   }
 
+  case ConditionOrInitStatement::ForRangeDecl: {
+    assert(FRI && "should not parse a for range declaration here");
+    SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
+    DeclGroupPtrTy DG = ParseSimpleDeclaration(
+        DeclaratorContext::ForContext, DeclEnd, attrs, false, FRI);
+    FRI->LoopVar = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
+    return Sema::ConditionResult();
+  }
+
   case ConditionOrInitStatement::ConditionDecl:
   case ConditionOrInitStatement::Error:
     break;

Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Fri Sep 28 11:44:09 2018
@@ -1570,11 +1570,11 @@ StmtResult Parser::ParseForStatement(Sou
 
   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 @@ StmtResult Parser::ParseForStatement(Sou
     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 @@ StmtResult Parser::ParseForStatement(Sou
     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 @@ StmtResult Parser::ParseForStatement(Sou
 
   // 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 @@ StmtResult Parser::ParseForStatement(Sou
                                      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 @@ StmtResult Parser::ParseForStatement(Sou
       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 @@ StmtResult Parser::ParseForStatement(Sou
 
   // 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 Parser::ParseForStatement(Sou
   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 @@ StmtResult Parser::ParseForStatement(Sou
    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(),

Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Fri Sep 28 11:44:09 2018
@@ -345,22 +345,55 @@ struct Parser::ConditionDeclarationOrIni
   bool CanBeExpression = true;
   bool CanBeCondition = true;
   bool CanBeInitStatement;
+  bool CanBeForRangeDecl;
 
-  ConditionDeclarationOrInitStatementState(Parser &P, bool CanBeInitStatement)
-      : P(P), CanBeInitStatement(CanBeInitStatement) {}
+  ConditionDeclarationOrInitStatementState(Parser &P, bool CanBeInitStatement,
+                                           bool CanBeForRangeDecl)
+      : P(P), CanBeInitStatement(CanBeInitStatement),
+        CanBeForRangeDecl(CanBeForRangeDecl) {}
+
+  bool resolved() {
+    return CanBeExpression + CanBeCondition + CanBeInitStatement +
+               CanBeForRangeDecl < 2;
+  }
 
   void markNotExpression() {
     CanBeExpression = false;
 
-    if (CanBeCondition && CanBeInitStatement) {
+    if (!resolved()) {
       // FIXME: Unify the parsing codepaths for condition variables and
       // simple-declarations so that we don't need to eagerly figure out which
       // kind we have here. (Just parse init-declarators until we reach a
       // semicolon or right paren.)
       RevertingTentativeParsingAction PA(P);
-      P.SkipUntil(tok::r_paren, tok::semi, StopBeforeMatch);
+      if (CanBeForRangeDecl) {
+        // Skip until we hit a ')', ';', or a ':' with no matching '?'.
+        // The final case is a for range declaration, the rest are not.
+        while (true) {
+          unsigned QuestionColonDepth = 0;
+          P.SkipUntil({tok::r_paren, tok::semi, tok::question, tok::colon},
+                      StopBeforeMatch);
+          if (P.Tok.is(tok::question))
+            ++QuestionColonDepth;
+          else if (P.Tok.is(tok::colon)) {
+            if (QuestionColonDepth)
+              --QuestionColonDepth;
+            else {
+              CanBeCondition = CanBeInitStatement = false;
+              return;
+            }
+          } else {
+            CanBeForRangeDecl = false;
+            break;
+          }
+          P.ConsumeToken();
+        }
+      } else {
+        // Just skip until we hit a ')' or ';'.
+        P.SkipUntil(tok::r_paren, tok::semi, StopBeforeMatch);
+      }
       if (P.Tok.isNot(tok::r_paren))
-        CanBeCondition = false;
+        CanBeCondition = CanBeForRangeDecl = false;
       if (P.Tok.isNot(tok::semi))
         CanBeInitStatement = false;
     }
@@ -368,28 +401,36 @@ struct Parser::ConditionDeclarationOrIni
 
   bool markNotCondition() {
     CanBeCondition = false;
-    return !CanBeInitStatement || !CanBeExpression;
+    return resolved();
+  }
+
+  bool markNotForRangeDecl() {
+    CanBeForRangeDecl = false;
+    return resolved();
   }
 
   bool update(TPResult IsDecl) {
     switch (IsDecl) {
     case TPResult::True:
       markNotExpression();
-      return true;
+      assert(resolved() && "can't continue after tentative parsing bails out");
+      break;
     case TPResult::False:
-      CanBeCondition = CanBeInitStatement = false;
-      return true;
+      CanBeCondition = CanBeInitStatement = CanBeForRangeDecl = false;
+      break;
     case TPResult::Ambiguous:
-      return false;
+      break;
     case TPResult::Error:
-      CanBeExpression = CanBeCondition = CanBeInitStatement = false;
-      return true;
+      CanBeExpression = CanBeCondition = CanBeInitStatement =
+          CanBeForRangeDecl = false;
+      break;
     }
-    llvm_unreachable("unknown tentative parse result");
+    return resolved();
   }
 
   ConditionOrInitStatement result() const {
-    assert(CanBeExpression + CanBeCondition + CanBeInitStatement < 2 &&
+    assert(CanBeExpression + CanBeCondition + CanBeInitStatement +
+                   CanBeForRangeDecl < 2 &&
            "result called but not yet resolved");
     if (CanBeExpression)
       return ConditionOrInitStatement::Expression;
@@ -397,6 +438,8 @@ struct Parser::ConditionDeclarationOrIni
       return ConditionOrInitStatement::ConditionDecl;
     if (CanBeInitStatement)
       return ConditionOrInitStatement::InitStmtDecl;
+    if (CanBeForRangeDecl)
+      return ConditionOrInitStatement::ForRangeDecl;
     return ConditionOrInitStatement::Error;
   }
 };
@@ -419,8 +462,10 @@ struct Parser::ConditionDeclarationOrIni
 /// to the ';' to disambiguate cases like 'int(x))' (an expression) from
 /// 'int(x);' (a simple-declaration in an init-statement).
 Parser::ConditionOrInitStatement
-Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement) {
-  ConditionDeclarationOrInitStatementState State(*this, CanBeInitStatement);
+Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement,
+                                                 bool CanBeForRangeDecl) {
+  ConditionDeclarationOrInitStatementState State(*this, CanBeInitStatement,
+                                                 CanBeForRangeDecl);
 
   if (State.update(isCXXDeclarationSpecifier()))
     return State.result();
@@ -447,11 +492,19 @@ Parser::isCXXConditionDeclarationOrInitS
       return State.result();
     }
 
+    // A colon here identifies a for-range declaration.
+    if (State.CanBeForRangeDecl && Tok.is(tok::colon))
+      return ConditionOrInitStatement::ForRangeDecl;
+
     // At this point, it can't be a condition any more, because a condition
     // must have a brace-or-equal-initializer.
     if (State.markNotCondition())
       return State.result();
 
+    // Likewise, it can't be a for-range declaration any more.
+    if (State.markNotForRangeDecl())
+      return State.result();
+
     // A parenthesized initializer could be part of an expression or a
     // simple-declaration.
     if (Tok.is(tok::l_paren)) {

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Fri Sep 28 11:44:09 2018
@@ -1647,6 +1647,8 @@ namespace {
     void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
       // Only visit the initialization of a for loop; the body
       // has a different break/continue scope.
+      if (const Stmt *Init = S->getInit())
+        Visit(Init);
       if (const Stmt *Range = S->getRangeStmt())
         Visit(Range);
       if (const Stmt *Begin = S->getBeginStmt())
@@ -2065,15 +2067,20 @@ static bool ObjCEnumerationCollection(Ex
 /// The body of the loop is not available yet, since it cannot be analysed until
 /// we have determined the type of the for-range-declaration.
 StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
-                                      SourceLocation CoawaitLoc, Stmt *First,
-                                      SourceLocation ColonLoc, Expr *Range,
-                                      SourceLocation RParenLoc,
+                                      SourceLocation CoawaitLoc, Stmt *InitStmt,
+                                      Stmt *First, SourceLocation ColonLoc,
+                                      Expr *Range, SourceLocation RParenLoc,
                                       BuildForRangeKind Kind) {
   if (!First)
     return StmtError();
 
-  if (Range && ObjCEnumerationCollection(Range))
+  if (Range && ObjCEnumerationCollection(Range)) {
+    // FIXME: Support init-statements in Objective-C++20 ranged for statement.
+    if (InitStmt)
+      return Diag(InitStmt->getBeginLoc(), diag::err_objc_for_range_init_stmt)
+                 << InitStmt->getSourceRange();
     return ActOnObjCForCollectionStmt(ForLoc, First, Range, RParenLoc);
+  }
 
   DeclStmt *DS = dyn_cast<DeclStmt>(First);
   assert(DS && "first part of for range not a decl stmt");
@@ -2119,10 +2126,10 @@ StmtResult Sema::ActOnCXXForRangeStmt(Sc
     return StmtError();
   }
 
-  return BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, RangeDecl.get(),
-                              /*BeginStmt=*/nullptr, /*EndStmt=*/nullptr,
-                              /*Cond=*/nullptr, /*Inc=*/nullptr,
-                              DS, RParenLoc, Kind);
+  return BuildCXXForRangeStmt(
+      ForLoc, CoawaitLoc, InitStmt, ColonLoc, RangeDecl.get(),
+      /*BeginStmt=*/nullptr, /*EndStmt=*/nullptr,
+      /*Cond=*/nullptr, /*Inc=*/nullptr, DS, RParenLoc, Kind);
 }
 
 /// Create the initialization, compare, and increment steps for
@@ -2270,6 +2277,7 @@ BuildNonArrayForRange(Sema &SemaRef, Exp
 static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S,
                                                  SourceLocation ForLoc,
                                                  SourceLocation CoawaitLoc,
+                                                 Stmt *InitStmt,
                                                  Stmt *LoopVarDecl,
                                                  SourceLocation ColonLoc,
                                                  Expr *Range,
@@ -2286,8 +2294,8 @@ static StmtResult RebuildForRangeWithDer
       return StmtResult();
 
     StmtResult SR = SemaRef.ActOnCXXForRangeStmt(
-        S, ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc, AdjustedRange.get(),
-        RParenLoc, Sema::BFRK_Check);
+        S, ForLoc, CoawaitLoc, InitStmt, LoopVarDecl, ColonLoc,
+        AdjustedRange.get(), RParenLoc, Sema::BFRK_Check);
     if (SR.isInvalid())
       return StmtResult();
   }
@@ -2297,9 +2305,9 @@ static StmtResult RebuildForRangeWithDer
   // case there are any other (non-fatal) problems with it.
   SemaRef.Diag(RangeLoc, diag::err_for_range_dereference)
     << Range->getType() << FixItHint::CreateInsertion(RangeLoc, "*");
-  return SemaRef.ActOnCXXForRangeStmt(S, ForLoc, CoawaitLoc, LoopVarDecl,
-                                      ColonLoc, AdjustedRange.get(), RParenLoc,
-                                      Sema::BFRK_Rebuild);
+  return SemaRef.ActOnCXXForRangeStmt(
+      S, ForLoc, CoawaitLoc, InitStmt, LoopVarDecl, ColonLoc,
+      AdjustedRange.get(), RParenLoc, Sema::BFRK_Rebuild);
 }
 
 namespace {
@@ -2319,12 +2327,13 @@ struct InvalidateOnErrorScope {
 }
 
 /// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement.
-StmtResult
-Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
-                           SourceLocation ColonLoc, Stmt *RangeDecl,
-                           Stmt *Begin, Stmt *End, Expr *Cond,
-                           Expr *Inc, Stmt *LoopVarDecl,
-                           SourceLocation RParenLoc, BuildForRangeKind Kind) {
+StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc,
+                                      SourceLocation CoawaitLoc, Stmt *InitStmt,
+                                      SourceLocation ColonLoc, Stmt *RangeDecl,
+                                      Stmt *Begin, Stmt *End, Expr *Cond,
+                                      Expr *Inc, Stmt *LoopVarDecl,
+                                      SourceLocation RParenLoc,
+                                      BuildForRangeKind Kind) {
   // FIXME: This should not be used during template instantiation. We should
   // pick up the set of unqualified lookup results for the != and + operators
   // in the initial parse.
@@ -2519,7 +2528,7 @@ Sema::BuildCXXForRangeStmt(SourceLocatio
         // If building the range failed, try dereferencing the range expression
         // unless a diagnostic was issued or the end function is problematic.
         StmtResult SR = RebuildForRangeWithDereference(*this, S, ForLoc,
-                                                       CoawaitLoc,
+                                                       CoawaitLoc, InitStmt,
                                                        LoopVarDecl, ColonLoc,
                                                        Range, RangeLoc,
                                                        RParenLoc);
@@ -2636,7 +2645,7 @@ Sema::BuildCXXForRangeStmt(SourceLocatio
     return StmtResult();
 
   return new (Context) CXXForRangeStmt(
-      RangeDS, cast_or_null<DeclStmt>(BeginDeclStmt.get()),
+      InitStmt, RangeDS, cast_or_null<DeclStmt>(BeginDeclStmt.get()),
       cast_or_null<DeclStmt>(EndDeclStmt.get()), NotEqExpr.get(),
       IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, CoawaitLoc,
       ColonLoc, RParenLoc);

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Fri Sep 28 11:44:09 2018
@@ -2021,11 +2021,10 @@ public:
   /// By default, performs semantic analysis to build the new statement.
   /// Subclasses may override this routine to provide different behavior.
   StmtResult RebuildCXXForRangeStmt(SourceLocation ForLoc,
-                                    SourceLocation CoawaitLoc,
-                                    SourceLocation ColonLoc,
-                                    Stmt *Range, Stmt *Begin, Stmt *End,
-                                    Expr *Cond, Expr *Inc,
-                                    Stmt *LoopVar,
+                                    SourceLocation CoawaitLoc, Stmt *Init,
+                                    SourceLocation ColonLoc, Stmt *Range,
+                                    Stmt *Begin, Stmt *End, Expr *Cond,
+                                    Expr *Inc, Stmt *LoopVar,
                                     SourceLocation RParenLoc) {
     // If we've just learned that the range is actually an Objective-C
     // collection, treat this as an Objective-C fast enumeration loop.
@@ -2037,17 +2036,24 @@ public:
 
           Expr *RangeExpr = RangeVar->getInit();
           if (!RangeExpr->isTypeDependent() &&
-              RangeExpr->getType()->isObjCObjectPointerType())
-            return getSema().ActOnObjCForCollectionStmt(ForLoc, LoopVar, RangeExpr,
-                                                        RParenLoc);
+              RangeExpr->getType()->isObjCObjectPointerType()) {
+            // FIXME: Support init-statements in Objective-C++20 ranged for
+            // statement.
+            if (Init) {
+              return SemaRef.Diag(Init->getBeginLoc(),
+                                  diag::err_objc_for_range_init_stmt)
+                         << Init->getSourceRange();
+            }
+            return getSema().ActOnObjCForCollectionStmt(ForLoc, LoopVar,
+                                                        RangeExpr, RParenLoc);
+          }
         }
       }
     }
 
-    return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc,
-                                          Range, Begin, End,
-                                          Cond, Inc, LoopVar, RParenLoc,
-                                          Sema::BFRK_Rebuild);
+    return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, Init, ColonLoc,
+                                          Range, Begin, End, Cond, Inc, LoopVar,
+                                          RParenLoc, Sema::BFRK_Rebuild);
   }
 
   /// Build a new C++0x range-based for statement.
@@ -7412,6 +7418,11 @@ StmtResult TreeTransform<Derived>::Trans
 template<typename Derived>
 StmtResult
 TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
+  StmtResult Init =
+      S->getInit() ? getDerived().TransformStmt(S->getInit()) : StmtResult();
+  if (Init.isInvalid())
+    return StmtError();
+
   StmtResult Range = getDerived().TransformStmt(S->getRangeStmt());
   if (Range.isInvalid())
     return StmtError();
@@ -7445,6 +7456,7 @@ TreeTransform<Derived>::TransformCXXForR
 
   StmtResult NewStmt = S;
   if (getDerived().AlwaysRebuild() ||
+      Init.get() != S->getInit() ||
       Range.get() != S->getRangeStmt() ||
       Begin.get() != S->getBeginStmt() ||
       End.get() != S->getEndStmt() ||
@@ -7452,7 +7464,7 @@ TreeTransform<Derived>::TransformCXXForR
       Inc.get() != S->getInc() ||
       LoopVar.get() != S->getLoopVarStmt()) {
     NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
-                                                  S->getCoawaitLoc(),
+                                                  S->getCoawaitLoc(), Init.get(),
                                                   S->getColonLoc(), Range.get(),
                                                   Begin.get(), End.get(),
                                                   Cond.get(),
@@ -7470,7 +7482,7 @@ TreeTransform<Derived>::TransformCXXForR
   // it now so we have a new statement to attach the body to.
   if (Body.get() != S->getBody() && NewStmt.get() == S) {
     NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
-                                                  S->getCoawaitLoc(),
+                                                  S->getCoawaitLoc(), Init.get(),
                                                   S->getColonLoc(), Range.get(),
                                                   Begin.get(), End.get(),
                                                   Cond.get(),

Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Fri Sep 28 11:44:09 2018
@@ -1270,6 +1270,7 @@ void ASTStmtReader::VisitCXXForRangeStmt
   S->CoawaitLoc = ReadSourceLocation();
   S->ColonLoc = ReadSourceLocation();
   S->RParenLoc = ReadSourceLocation();
+  S->setInit(Record.readSubStmt());
   S->setRangeStmt(Record.readSubStmt());
   S->setBeginStmt(Record.readSubStmt());
   S->setEndStmt(Record.readSubStmt());

Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Fri Sep 28 11:44:09 2018
@@ -1222,6 +1222,7 @@ void ASTStmtWriter::VisitCXXForRangeStmt
   Record.AddSourceLocation(S->getCoawaitLoc());
   Record.AddSourceLocation(S->getColonLoc());
   Record.AddSourceLocation(S->getRParenLoc());
+  Record.AddStmt(S->getInit());
   Record.AddStmt(S->getRangeStmt());
   Record.AddStmt(S->getBeginStmt());
   Record.AddStmt(S->getEndStmt());

Modified: cfe/trunk/test/Analysis/Inputs/expected-plists/cxx-for-range.cpp.plist
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Inputs/expected-plists/cxx-for-range.cpp.plist?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/Inputs/expected-plists/cxx-for-range.cpp.plist (original)
+++ cfe/trunk/test/Analysis/Inputs/expected-plists/cxx-for-range.cpp.plist Fri Sep 28 11:44:09 2018
@@ -1670,6 +1670,287 @@
    </array>
   </dict>
   </dict>
+  <dict>
+   <key>path</key>
+   <array>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>5</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>8</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>10</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>102</integer>
+      <key>col</key><integer>8</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>102</integer>
+         <key>col</key><integer>8</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>102</integer>
+         <key>col</key><integer>15</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Initializing to a null pointer value</string>
+     <key>message</key>
+     <string>Initializing to a null pointer value</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>8</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>10</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>58</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>58</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>102</integer>
+      <key>col</key><integer>58</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>102</integer>
+         <key>col</key><integer>58</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>102</integer>
+         <key>col</key><integer>58</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Entering loop body</string>
+     <key>message</key>
+     <string>Entering loop body</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>58</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>58</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>51</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>53</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>102</integer>
+      <key>col</key><integer>51</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>102</integer>
+         <key>col</key><integer>51</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>102</integer>
+         <key>col</key><integer>56</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>'p' initialized to a null pointer value</string>
+     <key>message</key>
+     <string>'p' initialized to a null pointer value</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>51</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>53</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>103</integer>
+           <key>col</key><integer>8</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>103</integer>
+           <key>col</key><integer>8</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>103</integer>
+      <key>col</key><integer>8</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>103</integer>
+         <key>col</key><integer>6</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>103</integer>
+         <key>col</key><integer>6</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Dereference of null pointer (loaded from variable 'p')</string>
+     <key>message</key>
+     <string>Dereference of null pointer (loaded from variable 'p')</string>
+    </dict>
+   </array>
+   <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string>
+   <key>category</key><string>Logic error</string>
+   <key>type</key><string>Dereference of null pointer</string>
+   <key>check_name</key><string>core.NullDereference</string>
+   <!-- This hash is experimental and going to change! -->
+   <key>issue_hash_content_of_line_in_context</key><string>ad377f8d4510dfd77d6485c402d57a2d</string>
+  <key>issue_context_kind</key><string>function</string>
+  <key>issue_context</key><string>testForRangeInit</string>
+  <key>issue_hash_function_offset</key><string>2</string>
+  <key>location</key>
+  <dict>
+   <key>line</key><integer>103</integer>
+   <key>col</key><integer>8</integer>
+   <key>file</key><integer>0</integer>
+  </dict>
+  <key>ExecutedLines</key>
+  <dict>
+   <key>0</key>
+   <array>
+    <integer>101</integer>
+    <integer>102</integer>
+    <integer>103</integer>
+   </array>
+  </dict>
+  </dict>
  </array>
  <key>files</key>
  <array>

Modified: cfe/trunk/test/Analysis/cxx-for-range.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cxx-for-range.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/cxx-for-range.cpp (original)
+++ cfe/trunk/test/Analysis/cxx-for-range.cpp Fri Sep 28 11:44:09 2018
@@ -97,3 +97,8 @@ void testLoopErrorInRange() {
 
   *(volatile int *)0 = 1; // no-warning
 }
+
+void testForRangeInit() {
+  for (int *arr[3] = {nullptr, nullptr, nullptr}; int *p : arr) // expected-warning {{extension}}
+    *p = 1; // expected-warning {{Dereference of null pointer}}
+}

Modified: cfe/trunk/test/Analysis/scopes-cfg-output.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/scopes-cfg-output.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/scopes-cfg-output.cpp (original)
+++ cfe/trunk/test/Analysis/scopes-cfg-output.cpp Fri Sep 28 11:44:09 2018
@@ -820,10 +820,9 @@ void test_for_compound_and_break() {
 // CHECK-NEXT:   3: __end1
 // CHECK-NEXT:   4: [B2.3] (ImplicitCastExpr, LValueToRValue, class A *)
 // CHECK-NEXT:   5: [B2.2] != [B2.4]
-// CHECK-NEXT:   T: for (auto &i : [B5.4]) {
+// CHECK-NEXT:   T: for (auto &i : [B5.4])
 // CHECK:         [B4.11];
-// CHECK-NEXT:}
-// CHECK-NEXT:   Preds (2): B3 B5
+// CHECK:        Preds (2): B3 B5
 // CHECK-NEXT:   Succs (2): B4 B1
 // CHECK:      [B3]
 // CHECK-NEXT:   1: __begin1

Added: cfe/trunk/test/CodeGenCXX/cxx2a-init-statement.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx2a-init-statement.cpp?rev=343350&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx2a-init-statement.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/cxx2a-init-statement.cpp Fri Sep 28 11:44:09 2018
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++2a -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s -w | FileCheck %s
+
+// CHECK: @_ZZ1fvE3arr = private unnamed_addr constant [3 x i32] [i32 1, i32 2, i32 3], align 4
+
+void f() {
+  // CHECK: %[[ARR:.*]] = alloca [3 x i32], align 4
+  // CHECK: call void @llvm.memcpy{{.*}}({{.*}} @_ZZ1fvE3arr
+  for (int arr[3] = {1, 2, 3}; int a : arr)
+    ;
+}

Modified: cfe/trunk/test/Import/cxx-for-range/Inputs/F.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/cxx-for-range/Inputs/F.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/test/Import/cxx-for-range/Inputs/F.cpp (original)
+++ cfe/trunk/test/Import/cxx-for-range/Inputs/F.cpp Fri Sep 28 11:44:09 2018
@@ -4,8 +4,7 @@ struct Container {
 };
 
 void f() {
-  Container c;
-  for (int varname : c) {
+  for (Container c; int varname : c) {
     return;
   }
 }

Modified: cfe/trunk/test/Import/cxx-for-range/test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/cxx-for-range/test.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/test/Import/cxx-for-range/test.cpp (original)
+++ cfe/trunk/test/Import/cxx-for-range/test.cpp Fri Sep 28 11:44:09 2018
@@ -4,6 +4,11 @@
 
 // CHECK-NEXT: DeclStmt
 // CHECK-NEXT: VarDecl
+// CHECK-SAME: c 'Container'
+// CHECK-NEXT: CXXConstructExpr
+
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl
 // CHECK-NEXT: DeclRefExpr
 // CHECK-SAME: 'c'
 // CHECK-SAME: Container

Added: cfe/trunk/test/PCH/cxx2a-for-init-statement.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx2a-for-init-statement.cpp?rev=343350&view=auto
==============================================================================
--- cfe/trunk/test/PCH/cxx2a-for-init-statement.cpp (added)
+++ cfe/trunk/test/PCH/cxx2a-for-init-statement.cpp Fri Sep 28 11:44:09 2018
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-pch -std=c++2a -o %t %s
+// RUN: %clang_cc1 -std=c++2a -x ast -ast-print %t | FileCheck %s
+
+void f() {
+  // CHECK:      for (int arr[3]; int n : arr) {
+  // CHECK-NEXT: }
+  for (int arr[3]; int n : arr) {}
+}

Added: cfe/trunk/test/Parser/cxx2a-init-statement.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx2a-init-statement.cpp?rev=343350&view=auto
==============================================================================
--- cfe/trunk/test/Parser/cxx2a-init-statement.cpp (added)
+++ cfe/trunk/test/Parser/cxx2a-init-statement.cpp Fri Sep 28 11:44:09 2018
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
+template<int N> struct A {};
+
+using F = bool(*)(int);
+extern F *p;
+extern int m;
+
+struct Convertible { template<typename T> operator T(); };
+
+void f() {
+  int arr1[3];
+  for (int n = 5; int x : arr1) {}
+
+  int A<0>::*arr2[3];
+  for (int n = 5; int A<true ? 0 : 1>::*x : arr2) {}
+
+  F (*arr3[3])(int);
+  for (int n = 5; F (*p)(int n) : arr3) {}
+  for (int n = 5; F (*p)(int (n)) : arr3) {}
+
+  // Here, we have a declaration rather than an expression.
+  for (int n = 5; F (*p)(int (n)); ++n) {}
+
+  // We detect whether we have a for-range-declaration before parsing so that
+  // we can give different diagnostics for for-range-declarations versus
+  // conditions (even though the rules are currently identical).
+  Convertible arr4[3];
+  for (int n = 0; struct { operator bool(); } x = {}; ++n) {} // expected-error {{cannot be defined in a condition}}
+  for (int n = 0; struct { operator bool(); } x : arr4) {} // expected-error {{may not be defined in a for range declaration}}
+
+  for (int n = 0; static int m = 0; ++n) {} // expected-error {{type name does not allow storage class}}
+  for (int n = 0; static int m : arr1) {} // expected-error {{loop variable 'm' may not be declared 'static'}}
+}

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp Fri Sep 28 11:44:09 2018
@@ -204,3 +204,10 @@ static_assert(complex_test(makeComplex<_
                            std::strong_equality::nonequal));
 // TODO: defaulted operator <=>
 } // namespace ThreeWayComparison
+
+constexpr bool for_range_init() {
+  int k = 0;
+  for (int arr[3] = {1, 2, 3}; int n : arr) k += n;
+  return k == 6;
+}
+static_assert(for_range_init());

Modified: cfe/trunk/test/SemaCXX/cxx17-compat.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx17-compat.cpp?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx17-compat.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx17-compat.cpp Fri Sep 28 11:44:09 2018
@@ -54,3 +54,12 @@ struct DefaultDeleteWrongType : DefaultD
     // expected-warning at -4 {{explicitly defaulting this copy constructor with a type different from the implicit type is incompatible with C++ standards before C++2a}}
 #endif
 };
+
+void ForRangeInit() {
+  for (int arr[3] = {1, 2, 3}; int n : arr) {}
+#if __cplusplus <= 201703L
+    // expected-warning at -2 {{range-based for loop initialization statements are a C++2a extension}}
+#else
+    // expected-warning at -4 {{range-based for loop initialization statements are incompatible with C++ standards before C++2a}}
+#endif
+}

Modified: cfe/trunk/test/SemaObjCXX/foreach.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/foreach.mm?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/foreach.mm (original)
+++ cfe/trunk/test/SemaObjCXX/foreach.mm Fri Sep 28 11:44:09 2018
@@ -14,6 +14,14 @@ void f(NSArray *a) {
   for (auto thisKey : keys) { } // expected-warning{{'auto' deduced as 'id' in declaration of 'thisKey'}}
 }
 
+void for_init_stmt() {
+  for (id keys; id key : keys) {} // expected-warning{{extension}} expected-error{{not supported}}
+}
+template<typename T> void for_init_stmt_tmpl() {
+  for (T keys; id key : keys) {} // expected-warning{{extension}} expected-error{{not supported}}
+}
+template void for_init_stmt_tmpl<id>(); // expected-note {{in instantiation of}}
+
 template<typename Collection>
 void ft(Collection col) {
   for (id x : col) { }

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=343350&r1=343349&r2=343350&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Fri Sep 28 11:44:09 2018
@@ -874,7 +874,7 @@ as the draft C++2a standard evolves.
     <tr>
       <td>Range-based for statements with initializer</td>
       <td><a href="http://wg21.link/p0614r1">P0614R1</a></td>
-      <td class="none" align="center">No</td>
+      <td class="svn" align="center">SVN</td>
     </tr>
     <tr>
       <td>ADL and function templates that are not visible</td>




More information about the cfe-commits mailing list