Start refactoring code for capturing variables and 'this' so that it is shared between lambda expressions and block literals.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147917 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index f9fb3bc..ceb836b 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1248,20 +1248,16 @@
 /// There is a well-formed capture at a particular scope level;
 /// propagate it through all the nested blocks.
 static CaptureResult propagateCapture(Sema &S, unsigned ValidScopeIndex,
-                                      const BlockDecl::Capture &Capture) {
-  VarDecl *var = Capture.getVariable();
-
+                                      const CapturingScopeInfo::Capture &Cap) {
   // Update all the inner blocks with the capture information.
   for (unsigned i = ValidScopeIndex + 1, e = S.FunctionScopes.size();
          i != e; ++i) {
     BlockScopeInfo *innerBlock = cast<BlockScopeInfo>(S.FunctionScopes[i]);
-    innerBlock->Captures.push_back(
-      BlockDecl::Capture(Capture.getVariable(), Capture.isByRef(),
-                         /*nested*/ true, Capture.getCopyExpr()));
-    innerBlock->CaptureMap[var] = innerBlock->Captures.size(); // +1
+    innerBlock->AddCapture(Cap.getVariable(), Cap.isReferenceCapture(),
+                           /*nested*/ true, Cap.getCopyExpr());
   }
 
-  return Capture.isByRef() ? CR_CaptureByRef : CR_Capture;
+  return Cap.isReferenceCapture() ? CR_CaptureByRef : CR_Capture;
 }
 
 /// shouldCaptureValueReference - Determine if a reference to the
@@ -1372,9 +1368,7 @@
     cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]);
 
   // Build a valid capture in this scope.
-  blockScope->Captures.push_back(
-                 BlockDecl::Capture(var, byRef, /*nested*/ false, copyExpr));
-  blockScope->CaptureMap[var] = blockScope->Captures.size(); // +1
+  blockScope->AddCapture(var, byRef, /*nested*/ false, copyExpr);
 
   // Propagate that to inner captures if necessary.
   return propagateCapture(S, functionScopesIndex,
@@ -8861,8 +8855,18 @@
   QualType BlockTy;
 
   // Set the captured variables on the block.
-  BSI->TheDecl->setCaptures(Context, BSI->Captures.begin(), BSI->Captures.end(),
-                            BSI->CapturesCXXThis);
+  // FIXME: Share capture structure between BlockDecl and CapturingScopeInfo!
+  SmallVector<BlockDecl::Capture, 4> Captures;
+  for (unsigned i = 0, e = BSI->Captures.size(); i != e; i++) {
+    CapturingScopeInfo::Capture &Cap = BSI->Captures[i];
+    if (Cap.isThisCapture())
+      continue;
+    BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isReferenceCapture(),
+                              Cap.isNested(), Cap.getCopyExpr());
+    Captures.push_back(NewCap);
+  }
+  BSI->TheDecl->setCaptures(Context, Captures.begin(), Captures.end(),
+                            BSI->CXXThisCaptureIndex != 0);
 
   // If the user wrote a function type in some form, try to use that.
   if (!BSI->FunctionType.isNull()) {
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index d4efa78..da7ba1a 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -680,19 +680,21 @@
   // Otherwise, check that we can capture 'this'.
   unsigned NumClosures = 0;
   for (unsigned idx = FunctionScopes.size() - 1; idx != 0; idx--) {
-    if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(FunctionScopes[idx])) {
-      if (LSI->CapturesCXXThis) {
-        // This lambda already captures 'this'; there isn't anything more to do.
+    if (CapturingScopeInfo *CSI =
+            dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) {
+      if (CSI->CXXThisCaptureIndex != 0) {
+        // 'this' is already being captured; there isn't anything more to do.
         break;
       }
-      if (LSI->Default == LCD_ByRef) {
-        // This lambda can implicitly capture 'this'; continue looking upwards.
+      if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref ||
+          CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block) {
+        // This closure can implicitly capture 'this'; continue looking upwards.
         // FIXME: Is this check correct?  The rules in the standard are a bit
         // unclear.
         NumClosures++;
         continue;
       }
-      // This lambda can't implicitly capture 'this'; fail out.
+      // This context can't implicitly capture 'this'; fail out.
       // (We need to delay the diagnostic in the
       // PotentiallyPotentiallyEvaluated case because it doesn't apply to
       // unevaluated contexts.)
@@ -703,10 +705,6 @@
         Diag(Loc, diag::err_implicit_this_capture);
       return;
     }
-    if (isa<BlockScopeInfo>(FunctionScopes[idx])) {
-      NumClosures++;
-      continue;
-    }
     break;
   }
 
@@ -715,14 +713,9 @@
   // contexts.
   for (unsigned idx = FunctionScopes.size() - 1;
        NumClosures; --idx, --NumClosures) {
-    if (BlockScopeInfo *BSI = dyn_cast<BlockScopeInfo>(FunctionScopes[idx])) {
-      BSI->CapturesCXXThis = true;
-    } else {
-      LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(FunctionScopes[idx]);
-      assert(LSI && "Unexpected closure");
-      LSI->CapturesCXXThis = true;
-      LSI->Captures.push_back(LambdaScopeInfo::Capture::ThisCapture);
-    }
+    CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]);
+    bool isNested = NumClosures > 1;
+    CSI->AddThisCapture(isNested);
   }
 }
 
@@ -4831,8 +4824,9 @@
   CurContext->addDecl(Class);
 
   QualType ThisCaptureType;
+  llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
+  unsigned CXXThisCaptureIndex = 0;
   llvm::SmallVector<LambdaScopeInfo::Capture, 4> Captures;
-  llvm::DenseMap<const IdentifierInfo*, SourceLocation> CapturesSoFar;
   for (llvm::SmallVector<LambdaCapture, 4>::const_iterator
        C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; ++C) {
     if (C->Kind == LCK_This) {
@@ -4853,7 +4847,12 @@
       }
       CheckCXXThisCapture(C->Loc);
 
-      Captures.push_back(LambdaScopeInfo::Capture::ThisCapture);
+      // FIXME: Need getCurCapture().
+      bool isNested = getCurBlock() || getCurLambda();
+      CapturingScopeInfo::Capture Cap(CapturingScopeInfo::Capture::ThisCapture,
+                                      isNested);
+      Captures.push_back(Cap);
+      CXXThisCaptureIndex = Captures.size();
       continue;
     }
 
@@ -4867,16 +4866,6 @@
       continue;
     }
 
-    llvm::DenseMap<const IdentifierInfo*, SourceLocation>::iterator Appearance;
-    bool IsFirstAppearance;
-    llvm::tie(Appearance, IsFirstAppearance)
-      = CapturesSoFar.insert(std::make_pair(C->Id, C->Loc));
-
-    if (!IsFirstAppearance) {
-      Diag(C->Loc, diag::err_capture_more_than_once) << C->Id;
-      continue;
-    }
-
     DeclarationNameInfo Name(C->Id, C->Loc);
     LookupResult R(*this, Name, LookupOrdinaryName);
     CXXScopeSpec ScopeSpec;
@@ -4893,16 +4882,22 @@
       continue;
     }
 
+    if (CaptureMap.count(Var)) {
+      Diag(C->Loc, diag::err_capture_more_than_once) << C->Id;
+      continue;
+    }
+
     if (!Var->hasLocalStorage()) {
       Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
       continue;
     }
 
-    // FIXME: Actually capturing a variable is much more complicated than this
-    // in the general case; see shouldCaptureValueReference.
-    // FIXME: Should we be building a DeclRefExpr here?  We don't really need
-    // it until the point where we're actually building the LambdaExpr.
-    Captures.push_back(LambdaScopeInfo::Capture(Var, C->Kind));
+    // FIXME: This is completely wrong for nested captures and variables
+    // with a non-trivial constructor.
+    // FIXME: We should refuse to capture __block variables.
+    Captures.push_back(LambdaScopeInfo::Capture(Var, C->Kind == LCK_ByRef,
+                                                /*isNested*/false, 0));
+    CaptureMap[Var] = Captures.size();
   }
 
   // Build the call operator; we don't really have all the relevant information
@@ -4982,15 +4977,20 @@
   PushLambdaScope(Class);
 
   LambdaScopeInfo *LSI = getCurLambda();
-  LSI->Default = Intro.Default;
-  if (!ThisCaptureType.isNull())
-    LSI->CapturesCXXThis = true;
+  LSI->CXXThisCaptureIndex = CXXThisCaptureIndex;
+  std::swap(LSI->CaptureMap, CaptureMap);
   std::swap(LSI->Captures, Captures);
+  LSI->NumExplicitCaptures = Captures.size();
+  if (Intro.Default == LCD_ByCopy)
+    LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval;
+  else if (Intro.Default == LCD_ByRef)
+    LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref;
 
   const FunctionType *Fn = MethodTy->getAs<FunctionType>();
   QualType RetTy = Fn->getResultType();
   if (RetTy != Context.DependentTy) {
     LSI->ReturnType = RetTy;
+  } else {
     LSI->HasImplicitReturnType = true;
   }
 
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 20c3b75..d229c18 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -265,8 +265,7 @@
     if (captureIndex) break;
 
     bool nested = isa<BlockScopeInfo>(FunctionScopes[idx-1]);
-    blockScope->Captures.push_back(
-              BlockDecl::Capture(self, /*byref*/ false, nested, /*copy*/ 0));
+    blockScope->AddCapture(self, /*byref*/ false, nested, /*copy*/ 0);
     captureIndex = blockScope->Captures.size(); // +1
   }
 
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 7995b0b..4908e88 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1890,6 +1890,7 @@
   ExprResult RebuildCXXThisExpr(SourceLocation ThisLoc,
                                 QualType ThisType,
                                 bool isImplicit) {
+    getSema().CheckCXXThisCapture(ThisLoc);
     return getSema().Owned(
                       new (getSema().Context) CXXThisExpr(ThisLoc, ThisType,
                                                           isImplicit));
@@ -8114,10 +8115,6 @@
   BlockScopeInfo *blockScope = SemaRef.getCurBlock();
 
   blockScope->TheDecl->setIsVariadic(oldBlock->isVariadic());
-  // We built a new blockScopeInfo in call to ActOnBlockStart
-  // in above, CapturesCXXThis need be set here from the block
-  // expression.
-  blockScope->CapturesCXXThis = oldBlock->capturesCXXThis();
   blockScope->TheDecl->setBlockMissingReturnType(
                          oldBlock->blockMissingReturnType());