Keep track of the set of array index variables we use when we
synthesize a by-copy captured array in a lambda. This information will
be needed by IR generation.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150396 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 2b56871..5487c77 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -561,7 +561,8 @@
     typedef LambdaExpr::Capture Capture;
     
     LambdaDefinitionData(CXXRecordDecl *D) 
-      : DefinitionData(D), NumCaptures(0), NumExplicitCaptures(0), Extra(0) { 
+      : DefinitionData(D), NumCaptures(0), NumExplicitCaptures(0), 
+        HasArrayIndexVars(false), Extra(0) { 
       IsLambda = true;
     }
 
@@ -569,15 +570,22 @@
     unsigned NumCaptures : 16;
 
     /// \brief The number of explicit captures in this lambda.
-    unsigned NumExplicitCaptures : 16;
+    unsigned NumExplicitCaptures : 15;
 
+    /// \brief Whether This lambda has any by-copy array captures, and therefore
+    /// has array index variables.
+    unsigned HasArrayIndexVars : 1;
+    
     /// \brief The "extra" data associated with the lambda, including
-    /// captures, capture initializers, and the body of the lambda.
+    /// captures, capture initializers, the body of the lambda, and the
+    /// array-index variables for array captures.
     void *Extra;
     
     /// \brief Allocate the "extra" data associated with a lambda definition.
     void allocateExtra(ArrayRef<Capture> Captures,
                        ArrayRef<Expr *> CaptureInits,
+                       ArrayRef<VarDecl *> ArrayIndexVars,
+                       ArrayRef<unsigned> ArrayIndexStarts,
                        Stmt *Body);
     
     /// \brief Retrieve the set of captures.
@@ -588,6 +596,18 @@
     Stmt **getStoredStmts() const {
       return reinterpret_cast<Stmt **>(getCaptures() + NumCaptures);
     }
+
+    /// \brief Retrieve the mapping from captures to the first array index
+    /// variable.
+    unsigned *getArrayIndexStarts() const {
+      return reinterpret_cast<unsigned *>(getStoredStmts() + NumCaptures + 1);
+    }
+
+    /// \brief Retrieve the complete set of array-index variables.
+    VarDecl **getArrayIndexVars() const {
+      return reinterpret_cast<VarDecl **>(
+               getArrayIndexStarts() + NumCaptures + 1);
+    }
   };
 
   struct DefinitionData &data() {
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 5037347..55ad486 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -1066,22 +1066,16 @@
   /// module file just to determine the source range.
   SourceLocation ClosingBrace;
 
-  // Note: The Create method allocates storage after the LambdaExpr
-  // object, which contains the captures, followed by the capture
-  // initializers, and finally the body of the lambda. The capture
-  // initializers and lambda body are placed next to each other so
-  // that the children() function can visit all of them easily.
-
 public:
   /// \brief Describes the capture of either a variable or 'this'.
   class Capture {
     llvm::PointerIntPair<VarDecl *, 2> VarAndBits;
     SourceLocation Loc;
     SourceLocation EllipsisLoc;
-
+    
     friend class ASTStmtReader;
     friend class ASTStmtWriter;
-
+    
   public:
     /// \brief Create a new capture.
     ///
@@ -1155,6 +1149,8 @@
              ArrayRef<Capture> Captures,
              bool ExplicitParams,
              ArrayRef<Expr *> CaptureInits,
+             ArrayRef<VarDecl *> ArrayIndexVars,
+             ArrayRef<unsigned> ArrayIndexStarts,
              SourceLocation ClosingBrace);
 
 public:
@@ -1166,6 +1162,8 @@
                             ArrayRef<Capture> Captures,
                             bool ExplicitParams,
                             ArrayRef<Expr *> CaptureInits,
+                            ArrayRef<VarDecl *> ArrayIndexVars,
+                            ArrayRef<unsigned> ArrayIndexStarts,
                             SourceLocation ClosingBrace);
 
   /// \brief Determine the default capture kind for this lambda.
@@ -1212,6 +1210,13 @@
   /// initialization argument for this lambda expression.
   capture_init_iterator capture_init_end() const;
 
+  /// \brief Retrieve the set of index variables used in the capture 
+  /// initializer of an array captured by copy.
+  ///
+  /// \param Iter The iterator that points at the capture initializer for 
+  /// which we are extracting the corresponding index variables.
+  ArrayRef<VarDecl *> getCaptureInitIndexVars(capture_init_iterator Iter) const;
+  
   /// \brief Retrieve the source range covering the lambda introducer,
   /// which contains the explicit capture list surrounded by square
   /// brackets ([...]).
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index 1861e95..57a49e6 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -301,6 +301,13 @@
   /// \brief Whether any of the capture expressions requires cleanups.
   bool ExprNeedsCleanups;
 
+  /// \brief Variables used to index into by-copy array captures.
+  llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
+
+  /// \brief Offsets into the ArrayIndexVars array at which each capture starts
+  /// its list of array index variables.
+  llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
+  
   LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda,
                   CXXMethodDecl *CallOperator)
     : CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda),
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 257a507..fcd4508 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -38,13 +38,23 @@
 void CXXRecordDecl::LambdaDefinitionData::allocateExtra(
        ArrayRef<LambdaExpr::Capture> Captures,
        ArrayRef<Expr *> CaptureInits,
+       ArrayRef<VarDecl *> ArrayIndexVars,
+       ArrayRef<unsigned> ArrayIndexStarts,
        Stmt *Body) {
   NumCaptures = Captures.size();
   NumExplicitCaptures = 0;
   
   ASTContext &Context = Definition->getASTContext();
+  unsigned ArrayIndexSize = 0;
+  if (ArrayIndexVars.size() > 0) {
+    HasArrayIndexVars = true;
+    ArrayIndexSize = sizeof(unsigned) * (Captures.size() + 1)
+                   + sizeof(VarDecl *) * ArrayIndexVars.size();
+  }
+  
   this->Extra = Context.Allocate(sizeof(Capture) * Captures.size() +
-                                 sizeof(Stmt*) * (Captures.size() + 1));
+                                 sizeof(Stmt*) * (Captures.size() + 1) +
+                                 ArrayIndexSize);
   
   // Copy captures.
   Capture *ToCapture = getCaptures();
@@ -62,6 +72,15 @@
   
   // Copy the body of the lambda.
   *Stored++ = Body;
+  
+  if (ArrayIndexVars.size() > 0) {
+    assert(ArrayIndexStarts.size() == Captures.size());
+    memcpy(getArrayIndexVars(), ArrayIndexVars.data(),
+           sizeof(VarDecl *) * ArrayIndexVars.size());
+    memcpy(getArrayIndexStarts(), ArrayIndexStarts.data(), 
+           sizeof(unsigned) * Captures.size());
+    getArrayIndexStarts()[Captures.size()] = ArrayIndexVars.size();
+  }
 }
 
 
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 1f8a57a..1e766ad 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -753,6 +753,8 @@
                        ArrayRef<Capture> Captures, 
                        bool ExplicitParams,
                        ArrayRef<Expr *> CaptureInits,
+                       ArrayRef<VarDecl *> ArrayElementVars,
+                       ArrayRef<unsigned> ArrayElementStarts,
                        SourceLocation ClosingBrace)
   : Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary,
          T->isDependentType(), T->isDependentType(), T->isDependentType(),
@@ -765,7 +767,8 @@
   assert(CaptureInits.size() == Captures.size() && "Wrong number of arguments");
   CXXRecordDecl *Class = getLambdaClass();
   CXXRecordDecl::LambdaDefinitionData &Data = Class->getLambdaData();
-  Data.allocateExtra(Captures, CaptureInits, getCallOperator()->getBody());
+  Data.allocateExtra(Captures, CaptureInits, ArrayElementVars, 
+                     ArrayElementStarts, getCallOperator()->getBody());
   
   // FIXME: Propagate "has unexpanded parameter pack" bit.
 }
@@ -777,6 +780,8 @@
                                ArrayRef<Capture> Captures, 
                                bool ExplicitParams,
                                ArrayRef<Expr *> CaptureInits,
+                               ArrayRef<VarDecl *> ArrayElementVars,
+                               ArrayRef<unsigned> ArrayElementStarts,
                                SourceLocation ClosingBrace) {
   // Determine the type of the expression (i.e., the type of the
   // function object we're creating).
@@ -784,6 +789,7 @@
 
   return new (Context) LambdaExpr(T, IntroducerRange, CaptureDefault, 
                                   Captures, ExplicitParams, CaptureInits,
+                                  ArrayElementVars, ArrayElementStarts,
                                   ClosingBrace);
 }
 
@@ -826,6 +832,19 @@
   return reinterpret_cast<Expr **>(Data.getStoredStmts() + Data.NumCaptures);
 }
 
+ArrayRef<VarDecl *> 
+LambdaExpr::getCaptureInitIndexVars(capture_init_iterator Iter) const {
+  CXXRecordDecl::LambdaDefinitionData &Data = getLambdaClass()->getLambdaData();
+  assert(Data.HasArrayIndexVars && "No array index-var data?");
+  
+  unsigned Index = Iter - capture_init_begin();
+  assert(Index < Data.NumCaptures && "Capture index out-of-range");
+  VarDecl **IndexVars = Data.getArrayIndexVars();
+  unsigned *IndexStarts = Data.getArrayIndexStarts();
+  return ArrayRef<VarDecl *>(IndexVars + IndexStarts[Index],
+                             IndexVars + IndexStarts[Index + 1]);
+}
+
 CXXRecordDecl *LambdaExpr::getLambdaClass() const {
   return getType()->getAsCXXRecordDecl();
 }
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 9bd1074..0d43afc 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -9642,6 +9642,7 @@
   bool InitializingArray = false;
   QualType BaseType = FieldType;
   QualType SizeType = S.Context.getSizeType();
+  LSI->ArrayIndexStarts.push_back(LSI->ArrayIndexVars.size());
   while (const ConstantArrayType *Array
                         = S.Context.getAsConstantArrayType(BaseType)) {
     InitializingArray = true;
@@ -9660,7 +9661,8 @@
                         S.Context.getTrivialTypeSourceInfo(SizeType, Loc),
                         SC_None, SC_None);
     IndexVariables.push_back(IterationVar);
-
+    LSI->ArrayIndexVars.push_back(IterationVar);
+    
     // Create a reference to the iteration variable.
     ExprResult IterationVarRef
       = S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc);
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 44b3883..f91b93f 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -306,6 +306,8 @@
   SourceRange IntroducerRange;
   bool ExplicitParams;
   bool LambdaExprNeedsCleanups;
+  llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
+  llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
   {
     LambdaScopeInfo *LSI = getCurLambda();
     CallOperator = LSI->CallOperator;
@@ -313,7 +315,9 @@
     IntroducerRange = LSI->IntroducerRange;
     ExplicitParams = LSI->ExplicitParams;
     LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups;
-
+    ArrayIndexVars.swap(LSI->ArrayIndexVars);
+    ArrayIndexStarts.swap(LSI->ArrayIndexStarts);
+    
     // Translate captures.
     for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) {
       LambdaScopeInfo::Capture From = LSI->Captures[I];
@@ -467,6 +471,7 @@
   LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, 
                                           CaptureDefault, Captures, 
                                           ExplicitParams, CaptureInits, 
+                                          ArrayIndexVars, ArrayIndexStarts,
                                           Body->getLocEnd());
 
   // C++11 [expr.prim.lambda]p2: