summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-06-03 06:02:10 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-06-03 06:02:10 +0000
commitea0c66be55114087d2151401756612b49f3589eb (patch)
tree9f189fa687f63dac6fc77d52fcaa25bb494891d6 /clang/lib
parentce1534b4055d52e007aff99dee521f6b7a7dba44 (diff)
downloadbcm5719-llvm-ea0c66be55114087d2151401756612b49f3589eb.tar.gz
bcm5719-llvm-ea0c66be55114087d2151401756612b49f3589eb.zip
PR42104: Support instantiations of lambdas that implicitly capture
packs. Two changes: * Track odr-use via FunctionParmPackExprs to properly handle dependent odr-uses of packs in generic lambdas. * Do not instantiate implicit captures; instead, regenerate them by instantiating the body of the lambda. This is necessary to distinguish between cases where only one element of a pack is captured and cases where the entire pack is captured. llvm-svn: 362358
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/ScopeInfo.cpp28
-rw-r--r--clang/lib/Sema/SemaExpr.cpp50
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp11
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp14
-rw-r--r--clang/lib/Sema/TreeTransform.h63
5 files changed, 108 insertions, 58 deletions
diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp
index e84e592a482..b2a26af9b4a 100644
--- a/clang/lib/Sema/ScopeInfo.cpp
+++ b/clang/lib/Sema/ScopeInfo.cpp
@@ -229,20 +229,20 @@ bool CapturingScopeInfo::isVLATypeCaptured(const VariableArrayType *VAT) const {
return false;
}
-void LambdaScopeInfo::getPotentialVariableCapture(unsigned Idx, VarDecl *&VD,
- Expr *&E) const {
- assert(Idx < getNumPotentialVariableCaptures() &&
- "Index of potential capture must be within 0 to less than the "
- "number of captures!");
- E = PotentiallyCapturingExprs[Idx];
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- VD = dyn_cast<VarDecl>(DRE->getFoundDecl());
- else if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
- VD = dyn_cast<VarDecl>(ME->getMemberDecl());
- else
- llvm_unreachable("Only DeclRefExprs or MemberExprs should be added for "
- "potential captures");
- assert(VD);
+void LambdaScopeInfo::visitPotentialCaptures(
+ llvm::function_ref<void(VarDecl *, Expr *)> Callback) const {
+ for (Expr *E : PotentiallyCapturingExprs) {
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+ Callback(cast<VarDecl>(DRE->getFoundDecl()), E);
+ } else if (auto *ME = dyn_cast<MemberExpr>(E)) {
+ Callback(cast<VarDecl>(ME->getMemberDecl()), E);
+ } else if (auto *FP = dyn_cast<FunctionParmPackExpr>(E)) {
+ for (VarDecl *VD : *FP)
+ Callback(VD, E);
+ } else {
+ llvm_unreachable("unexpected expression in potential captures list");
+ }
+ }
}
FunctionScopeInfo::~FunctionScopeInfo() { }
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 72b61b8e584..d0b27602846 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -14610,7 +14610,9 @@ namespace {
// context so never needs to be transformed.
// FIXME: Ideally we wouldn't transform the closure type either, and would
// just recreate the capture expressions and lambda expression.
- StmtResult TransformLambdaBody(Stmt *Body) { return Body; }
+ StmtResult TransformLambdaBody(LambdaExpr *E, Stmt *Body) {
+ return SkipLambdaBody(E, Body);
+ }
};
}
@@ -15054,7 +15056,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
/// *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack.
static void
MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
- const unsigned *const FunctionScopeIndexToStopAt) {
+ const unsigned *const FunctionScopeIndexToStopAt = nullptr) {
// Keep track of used but undefined variables.
// FIXME: We shouldn't suppress this warning for static data members.
if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&
@@ -15735,14 +15737,19 @@ void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
// variable.
if (LambdaScopeInfo *LSI = getCurLambda()) {
Expr *SansParensExpr = E->IgnoreParens();
- VarDecl *Var = nullptr;
+ VarDecl *Var;
+ ArrayRef<VarDecl *> Vars = None;
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SansParensExpr))
- Var = dyn_cast<VarDecl>(DRE->getFoundDecl());
+ Vars = Var = dyn_cast<VarDecl>(DRE->getFoundDecl());
else if (MemberExpr *ME = dyn_cast<MemberExpr>(SansParensExpr))
- Var = dyn_cast<VarDecl>(ME->getMemberDecl());
+ Vars = Var = dyn_cast<VarDecl>(ME->getMemberDecl());
+ else if (auto *FPPE = dyn_cast<FunctionParmPackExpr>(SansParensExpr))
+ Vars = llvm::makeArrayRef(FPPE->begin(), FPPE->end());
- if (Var && IsVariableNonDependentAndAConstantExpression(Var, Context))
- LSI->markVariableExprAsNonODRUsed(SansParensExpr);
+ for (VarDecl *VD : Vars) {
+ if (Var && IsVariableNonDependentAndAConstantExpression(VD, Context))
+ LSI->markVariableExprAsNonODRUsed(SansParensExpr);
+ }
}
}
@@ -15767,20 +15774,18 @@ void Sema::CleanupVarDeclMarking() {
std::swap(LocalMaybeODRUseExprs, MaybeODRUseExprs);
for (Expr *E : LocalMaybeODRUseExprs) {
- VarDecl *Var;
- SourceLocation Loc;
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
- Var = cast<VarDecl>(DRE->getDecl());
- Loc = DRE->getLocation();
- } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- Var = cast<VarDecl>(ME->getMemberDecl());
- Loc = ME->getMemberLoc();
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+ MarkVarDeclODRUsed(cast<VarDecl>(DRE->getDecl()),
+ DRE->getLocation(), *this);
+ } else if (auto *ME = dyn_cast<MemberExpr>(E)) {
+ MarkVarDeclODRUsed(cast<VarDecl>(ME->getMemberDecl()), ME->getMemberLoc(),
+ *this);
+ } else if (auto *FP = dyn_cast<FunctionParmPackExpr>(E)) {
+ for (VarDecl *VD : *FP)
+ MarkVarDeclODRUsed(VD, FP->getParameterPackLocation(), *this);
} else {
llvm_unreachable("Unexpected expression");
}
-
- MarkVarDeclODRUsed(Var, Loc, *this,
- /*MaxFunctionScopeIndex Pointer*/ nullptr);
}
assert(MaybeODRUseExprs.empty() &&
@@ -15789,7 +15794,8 @@ void Sema::CleanupVarDeclMarking() {
static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
VarDecl *Var, Expr *E) {
- assert((!E || isa<DeclRefExpr>(E) || isa<MemberExpr>(E)) &&
+ assert((!E || isa<DeclRefExpr>(E) || isa<MemberExpr>(E) ||
+ isa<FunctionParmPackExpr>(E)) &&
"Invalid Expr argument to DoMarkVarDeclReferenced");
Var->setReferenced();
@@ -16022,6 +16028,12 @@ void Sema::MarkMemberReferenced(MemberExpr *E) {
MarkExprReferenced(*this, Loc, E->getMemberDecl(), E, MightBeOdrUse);
}
+/// Perform reference-marking and odr-use handling for a FunctionParmPackExpr.
+void Sema::MarkFunctionParmPackReferenced(FunctionParmPackExpr *E) {
+ for (VarDecl *VD : *E)
+ MarkExprReferenced(*this, E->getParameterPackLocation(), VD, E, true);
+}
+
/// Perform marking for a reference to an arbitrary declaration. It
/// marks the declaration referenced, and performs odr-use checking for
/// functions and variables. This method should not be used when building a
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index ac050fa1ef5..5884cf906fd 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -7427,12 +7427,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
// All the potentially captureable variables in the current nested
// lambda (within a generic outer lambda), must be captured by an
// outer lambda that is enclosed within a non-dependent context.
- const unsigned NumPotentialCaptures =
- CurrentLSI->getNumPotentialVariableCaptures();
- for (unsigned I = 0; I != NumPotentialCaptures; ++I) {
- Expr *VarExpr = nullptr;
- VarDecl *Var = nullptr;
- CurrentLSI->getPotentialVariableCapture(I, Var, VarExpr);
+ CurrentLSI->visitPotentialCaptures([&] (VarDecl *Var, Expr *VarExpr) {
// If the variable is clearly identified as non-odr-used and the full
// expression is not instantiation dependent, only then do we not
// need to check enclosing lambda's for speculative captures.
@@ -7446,7 +7441,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
// }
if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) &&
!IsFullExprInstantiationDependent)
- continue;
+ return;
// If we have a capture-capable lambda for the variable, go ahead and
// capture the variable in that lambda (and all its enclosing lambdas).
@@ -7478,7 +7473,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
DeclRefType, nullptr);
}
}
- }
+ });
// Check if 'this' needs to be captured.
if (CurrentLSI->hasPotentialThisCapture()) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index ba54d5010ba..973f564d305 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1368,9 +1368,11 @@ TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
Vars.push_back(D);
}
- return FunctionParmPackExpr::Create(getSema().Context, T,
- E->getParameterPack(),
- E->getParameterPackLocation(), Vars);
+ auto *PackExpr =
+ FunctionParmPackExpr::Create(getSema().Context, T, E->getParameterPack(),
+ E->getParameterPackLocation(), Vars);
+ getSema().MarkFunctionParmPackReferenced(PackExpr);
+ return PackExpr;
}
ExprResult
@@ -1389,8 +1391,10 @@ TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E,
QualType T = TransformType(E->getType());
if (T.isNull())
return ExprError();
- return FunctionParmPackExpr::Create(getSema().Context, T, PD,
- E->getExprLoc(), *Pack);
+ auto *PackExpr = FunctionParmPackExpr::Create(getSema().Context, T, PD,
+ E->getExprLoc(), *Pack);
+ getSema().MarkFunctionParmPackReferenced(PackExpr);
+ return PackExpr;
}
TransformedDecl = (*Pack)[getSema().ArgumentPackSubstitutionIndex];
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 592787a5870..a1a9aaedee4 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -660,7 +660,10 @@ public:
bool ExpectParameterPack);
/// Transform the body of a lambda-expression.
- StmtResult TransformLambdaBody(Stmt *Body);
+ StmtResult TransformLambdaBody(LambdaExpr *E, Stmt *Body);
+ /// Alternative implementation of TransformLambdaBody that skips transforming
+ /// the body.
+ StmtResult SkipLambdaBody(LambdaExpr *E, Stmt *Body);
QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
@@ -11358,16 +11361,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
bool Invalid = false;
// Transform captures.
- bool FinishedExplicitCaptures = false;
for (LambdaExpr::capture_iterator C = E->capture_begin(),
CEnd = E->capture_end();
C != CEnd; ++C) {
// When we hit the first implicit capture, tell Sema that we've finished
// the list of explicit captures.
- if (!FinishedExplicitCaptures && C->isImplicit()) {
- getSema().finishLambdaExplicitCaptures(LSI);
- FinishedExplicitCaptures = true;
- }
+ if (C->isImplicit())
+ break;
// Capturing 'this' is trivial.
if (C->capturesThis()) {
@@ -11476,17 +11476,16 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind,
EllipsisLoc);
}
- if (!FinishedExplicitCaptures)
- getSema().finishLambdaExplicitCaptures(LSI);
+ getSema().finishLambdaExplicitCaptures(LSI);
- // Enter a new evaluation context to insulate the lambda from any
- // cleanups from the enclosing full-expression.
+ // FIXME: Sema's lambda-building mechanism expects us to push an expression
+ // evaluation context even if we're not transforming the function body.
getSema().PushExpressionEvaluationContext(
Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
// Instantiate the body of the lambda expression.
StmtResult Body =
- Invalid ? StmtError() : getDerived().TransformLambdaBody(E->getBody());
+ Invalid ? StmtError() : getDerived().TransformLambdaBody(E, E->getBody());
// ActOnLambda* will pop the function scope for us.
FuncScopeCleanup.disable();
@@ -11512,11 +11511,51 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
template<typename Derived>
StmtResult
-TreeTransform<Derived>::TransformLambdaBody(Stmt *S) {
+TreeTransform<Derived>::TransformLambdaBody(LambdaExpr *E, Stmt *S) {
return TransformStmt(S);
}
template<typename Derived>
+StmtResult
+TreeTransform<Derived>::SkipLambdaBody(LambdaExpr *E, Stmt *S) {
+ // Transform captures.
+ for (LambdaExpr::capture_iterator C = E->capture_begin(),
+ CEnd = E->capture_end();
+ C != CEnd; ++C) {
+ // When we hit the first implicit capture, tell Sema that we've finished
+ // the list of explicit captures.
+ if (!C->isImplicit())
+ continue;
+
+ // Capturing 'this' is trivial.
+ if (C->capturesThis()) {
+ getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit(),
+ /*BuildAndDiagnose*/ true, nullptr,
+ C->getCaptureKind() == LCK_StarThis);
+ continue;
+ }
+ // Captured expression will be recaptured during captured variables
+ // rebuilding.
+ if (C->capturesVLAType())
+ continue;
+
+ assert(C->capturesVariable() && "unexpected kind of lambda capture");
+ assert(!E->isInitCapture(C) && "implicit init-capture?");
+
+ // Transform the captured variable.
+ VarDecl *CapturedVar = cast_or_null<VarDecl>(
+ getDerived().TransformDecl(C->getLocation(), C->getCapturedVar()));
+ if (!CapturedVar || CapturedVar->isInvalidDecl())
+ return StmtError();
+
+ // Capture the transformed variable.
+ getSema().tryCaptureVariable(CapturedVar, C->getLocation());
+ }
+
+ return S;
+}
+
+template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
CXXUnresolvedConstructExpr *E) {
OpenPOWER on IntegriCloud