Move the storage of lambda captures and capture initializers from
LambdaExpr over to the CXXRecordDecl. This allows us to eliminate the
back-link from the closure type to the LambdaExpr, which will simplify
and lazify AST deserialization.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150393 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index f9d95b1..257a507 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -35,6 +35,35 @@
   return new (Mem) AccessSpecDecl(EmptyShell());
 }
 
+void CXXRecordDecl::LambdaDefinitionData::allocateExtra(
+       ArrayRef<LambdaExpr::Capture> Captures,
+       ArrayRef<Expr *> CaptureInits,
+       Stmt *Body) {
+  NumCaptures = Captures.size();
+  NumExplicitCaptures = 0;
+  
+  ASTContext &Context = Definition->getASTContext();
+  this->Extra = Context.Allocate(sizeof(Capture) * Captures.size() +
+                                 sizeof(Stmt*) * (Captures.size() + 1));
+  
+  // Copy captures.
+  Capture *ToCapture = getCaptures();
+  for (unsigned I = 0, N = Captures.size(); I != N; ++I) {
+    if (Captures[I].isExplicit())
+      ++NumExplicitCaptures;
+    
+    *ToCapture++ = Captures[I];
+  }
+  
+  // Copy initialization expressions for the non-static data members.
+  Stmt **Stored = getStoredStmts();
+  for (unsigned I = 0, N = CaptureInits.size(); I != N; ++I)
+    *Stored++ = CaptureInits[I];
+  
+  // Copy the body of the lambda.
+  *Stored++ = Body;
+}
+
 
 CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
   : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
@@ -83,6 +112,16 @@
   return R;
 }
 
+CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
+                                           SourceLocation Loc) {
+  CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc,
+                                           0, 0);
+  R->IsBeingDefined = true;
+  R->DefinitionData = new (C) struct LambdaDefinitionData(R);
+  C.getTypeDeclType(R, /*PrevDecl=*/0);
+  return R;
+}
+
 CXXRecordDecl *
 CXXRecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
   void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXRecordDecl));
@@ -969,24 +1008,16 @@
   return isPOD() && data().HasOnlyCMembers;
 }
 
-void CXXRecordDecl::setLambda(LambdaExpr *Lambda) {
-  if (!Lambda)
-    return;
-
-  data().IsLambda = true;
-  getASTContext().Lambdas[this] = Lambda;
-}
-
 void CXXRecordDecl::getCaptureFields(
        llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
        FieldDecl *&ThisCapture) const {
   Captures.clear();
   ThisCapture = 0;
 
-  LambdaExpr *Lambda = getASTContext().Lambdas[this];
+  LambdaDefinitionData &Lambda = getLambdaData();
   RecordDecl::field_iterator Field = field_begin();
-  for (LambdaExpr::capture_iterator C = Lambda->capture_begin(), 
-                                 CEnd = Lambda->capture_end();
+  for (LambdaExpr::Capture *C = Lambda.getCaptures(), 
+                        *CEnd = C + Lambda.NumCaptures;
        C != CEnd; ++C, ++Field) {
     if (C->capturesThis()) {
       ThisCapture = *Field;
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index a38488b..29ff69d 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -758,30 +758,16 @@
          T->isDependentType(), T->isDependentType(), T->isDependentType(),
          /*ContainsUnexpandedParameterPack=*/false),
     IntroducerRange(IntroducerRange),
-    NumCaptures(Captures.size()),
-    NumExplicitCaptures(0),
     CaptureDefault(CaptureDefault),
     ExplicitParams(ExplicitParams),
     ClosingBrace(ClosingBrace)
 {
   assert(CaptureInits.size() == Captures.size() && "Wrong number of arguments");
-
-  // Copy captures.
-  // FIXME: Do we need to update "contains unexpanded parameter pack" here?
-  Capture *ToCapture = reinterpret_cast<Capture *>(this + 1);
-  for (unsigned I = 0, N = Captures.size(); I != N; ++I) {
-    if (Captures[I].isExplicit())
-      ++NumExplicitCaptures;
-    *ToCapture++ = Captures[I];
-  }
-
-  // Copy initialization expressions for the non-static data members.
-  Stmt **Stored = getStoredStmts();
-  for (unsigned I = 0, N = CaptureInits.size(); I != N; ++I)
-    *Stored++ = CaptureInits[I];
-
-  // Copy the body of the lambda.
-  *Stored++ = getCallOperator()->getBody();
+  CXXRecordDecl *Class = getLambdaClass();
+  CXXRecordDecl::LambdaDefinitionData &Data = Class->getLambdaData();
+  Data.allocateExtra(Captures, CaptureInits, getCallOperator()->getBody());
+  
+  // FIXME: Propagate "has unexpanded parameter pack" bit.
 }
 
 LambdaExpr *LambdaExpr::Create(ASTContext &Context, 
@@ -804,6 +790,45 @@
                               ClosingBrace);
 }
 
+LambdaExpr::capture_iterator LambdaExpr::capture_begin() const {
+  return getLambdaClass()->getLambdaData().getCaptures();
+}
+
+LambdaExpr::capture_iterator LambdaExpr::capture_end() const {
+  struct CXXRecordDecl::LambdaDefinitionData &Data
+    = getLambdaClass()->getLambdaData();
+  return Data.getCaptures() + Data.NumCaptures;
+}
+
+LambdaExpr::capture_iterator LambdaExpr::explicit_capture_begin() const {
+  return capture_begin();
+}
+
+LambdaExpr::capture_iterator LambdaExpr::explicit_capture_end() const {
+  struct CXXRecordDecl::LambdaDefinitionData &Data
+    = getLambdaClass()->getLambdaData();
+  return Data.getCaptures() + Data.NumExplicitCaptures;
+}
+
+LambdaExpr::capture_iterator LambdaExpr::implicit_capture_begin() const {
+  return explicit_capture_end();
+}
+
+LambdaExpr::capture_iterator LambdaExpr::implicit_capture_end() const {
+  return capture_end();
+}
+
+LambdaExpr::capture_init_iterator LambdaExpr::capture_init_begin() const {
+  return reinterpret_cast<Expr **>(
+           getLambdaClass()->getLambdaData().getStoredStmts());
+}
+
+LambdaExpr::capture_init_iterator LambdaExpr::capture_init_end() const {
+  struct CXXRecordDecl::LambdaDefinitionData &Data
+    = getLambdaClass()->getLambdaData();
+  return reinterpret_cast<Expr **>(Data.getStoredStmts() + Data.NumCaptures);
+}
+
 CXXRecordDecl *LambdaExpr::getLambdaClass() const {
   return getType()->getAsCXXRecordDecl();
 }
@@ -819,10 +844,22 @@
   return Result;
 }
 
+/// \brief Retrieve the body of the lambda.
+CompoundStmt *LambdaExpr::getBody() const {
+  return cast<CompoundStmt>(*capture_init_end());
+}
+
 bool LambdaExpr::isMutable() const {
   return (getCallOperator()->getTypeQualifiers() & Qualifiers::Const) == 0;
 }
 
+Stmt::child_range LambdaExpr::children() {
+  struct CXXRecordDecl::LambdaDefinitionData &Data
+    = getLambdaClass()->getLambdaData();
+  return child_range(Data.getStoredStmts(), 
+                     Data.getStoredStmts() + Data.NumCaptures + 1);
+}
+
 ExprWithCleanups::ExprWithCleanups(Expr *subexpr,
                                    ArrayRef<CleanupObject> objects)
   : Expr(ExprWithCleanupsClass, subexpr->getType(),