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);
}
}
}