Unify our computation of the type of a captured reference to a
variable; it was previously duplicated, and one of the copies failed
to account for outer non-mutable lambda captures.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150872 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index c15102c..38783eb 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -2094,42 +2094,6 @@
   return S.getCurBlock() != 0;
 }
 
-/// \brief Determine whether the given lambda would capture the given
-/// variable by copy.
-static bool willCaptureByCopy(LambdaScopeInfo *LSI, VarDecl *Var) {
-  if (LSI->isCaptured(Var))
-    return LSI->getCapture(Var).isCopyCapture();
-
-  return LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval;
-}
-
-static bool shouldAddConstQualToVarRef(ValueDecl *D, Sema &S) {
-  VarDecl *var = dyn_cast<VarDecl>(D);
-  if (!var)
-    return false;
-  if (var->getDeclContext() == S.CurContext)
-    return false;
-  if (!var->hasLocalStorage())
-    return false;
-
-  LambdaScopeInfo *LSI = S.getCurLambda();
-  if (!LSI)
-    return false;
-
-  // We don't actually allow capturing a __block variable in a lambda, but
-  // this way gives better diagnostics.
-  if (var->hasAttr<BlocksAttr>())
-    return false;
-
-  // FIXME: Does the addition of const really only apply in
-  // potentially-evaluated contexts?  The text in the lambda spec
-  // about decltype hints that it might apply in unevaluated contexts
-  // as well... and there's precent in our blocks implementation.
-  return !LSI->Mutable &&
-         S.ExprEvalContexts.back().Context != Sema::Unevaluated &&
-         willCaptureByCopy(LSI, var);
-}
-
 static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *VD,
                                         const DeclarationNameInfo &NameInfo) {
   VarDecl *var = cast<VarDecl>(VD);
@@ -2269,7 +2233,7 @@
       // fallthrough
 
     case Decl::ImplicitParam:
-    case Decl::ParmVar:
+    case Decl::ParmVar: {
       // These are always l-values.
       valueKind = VK_LValue;
       type = type.getNonReferenceType();
@@ -2277,11 +2241,18 @@
       if (shouldBuildBlockDeclRef(VD, *this))
         return BuildBlockDeclRefExpr(*this, VD, NameInfo);
 
-      if (shouldAddConstQualToVarRef(VD, *this))
-        type.addConst();
-
+      // FIXME: Does the addition of const really only apply in
+      // potentially-evaluated contexts? Since the variable isn't actually
+      // captured in an unevaluated context, it seems that the answer is no.
+      if (ExprEvalContexts.back().Context != Sema::Unevaluated) {
+        QualType CapturedType = getCapturedDeclRefType(cast<VarDecl>(VD), Loc);
+        if (!CapturedType.isNull())
+          type = CapturedType;
+      }
+      
       break;
-
+    }
+        
     case Decl::Function: {
       const FunctionType *fty = type->castAs<FunctionType>();
 
@@ -9850,6 +9821,34 @@
   return !Type->isVariablyModifiedType();
 }
 
+QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
+  QualType T = Var->getType().getNonReferenceType();
+  unsigned FunctionScopesIndex;
+  bool Nested;
+  // Determine whether we can capture this variable.
+  if (!canCaptureVariable(Var, Loc, /*Explicit=*/false, /*Diagnose=*/false, 
+                          T, FunctionScopesIndex, Nested))
+    return QualType();
+    
+  // Outer lambda scopes may have an effect on the type of a
+  // capture. Walk the captures outside-in to determine
+  // whether they can add 'const' to a capture by copy.
+  T = Var->getType().getNonReferenceType();
+  if (FunctionScopesIndex == FunctionScopes.size())
+    --FunctionScopesIndex;
+  for (unsigned I = FunctionScopesIndex, E = FunctionScopes.size();
+       I != E; ++I) {
+    CapturingScopeInfo *CSI = dyn_cast<LambdaScopeInfo>(FunctionScopes[I]);
+    if (!CSI)
+      break;
+    
+    if (shouldAddConstForScope(CSI, Var))
+      T.addConst();
+  }
+  
+  return T;
+}
+
 // Check if the variable needs to be captured; if so, try to perform
 // the capture.
 void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc,
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index a4b3d86..9c8a68b 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -4382,42 +4382,9 @@
     if (isa<ParenExpr>(E)) {
       if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
         if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
-          QualType T = Var->getType();
-          unsigned FunctionScopesIndex;
-          bool Nested;
-          // Determine whether we can capture this variable.
-          if (S.canCaptureVariable(Var, DRE->getLocation(), 
-                                   /*Explicit=*/false, /*Diagnose=*/false, 
-                                   T, FunctionScopesIndex, Nested)) {
-            // Outer lambda scopes may have an effect on the type of a
-            // capture. Walk the captures outside-in to determine
-            // whether they can add 'const' to a capture by copy.
-            if (FunctionScopesIndex == S.FunctionScopes.size())
-              --FunctionScopesIndex;
-            for (unsigned I = FunctionScopesIndex, 
-                          E = S.FunctionScopes.size();
-                 I != E; ++I) {
-              LambdaScopeInfo *LSI
-                = dyn_cast<LambdaScopeInfo>(S.FunctionScopes[I]);
-              if (!LSI)
-                continue;
-
-              bool ByRef = false;
-              if (LSI->isCaptured(Var))
-                ByRef = LSI->getCapture(Var).isReferenceCapture();
-              else
-                ByRef = (LSI->ImpCaptureStyle
-                           == CapturingScopeInfo::ImpCap_LambdaByref);
-
-              T = S.getLambdaCaptureFieldType(T, ByRef);
-              if (!ByRef && !LSI->Mutable)
-                T.addConst();
-            }
-
-            if (!T->isReferenceType())
-              T = S.Context.getLValueReferenceType(T);
-            return T;
-          }
+          QualType T = S.getCapturedDeclRefType(Var, DRE->getLocation());
+          if (!T.isNull())
+            return S.Context.getLValueReferenceType(T);
         }
       }
     }