forked from OSchip/llvm-project
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. This reinstates r362358 (reverted in r362375) with a fix for an uninitialized variable use in UpdateMarkingForLValueToRValue. llvm-svn: 362531
This commit is contained in:
parent
f4302ad35e
commit
7bf8f6fa8a
|
@ -15,6 +15,7 @@
|
||||||
#define LLVM_CLANG_SEMA_SCOPEINFO_H
|
#define LLVM_CLANG_SEMA_SCOPEINFO_H
|
||||||
|
|
||||||
#include "clang/AST/Expr.h"
|
#include "clang/AST/Expr.h"
|
||||||
|
#include "clang/AST/ExprCXX.h"
|
||||||
#include "clang/AST/Type.h"
|
#include "clang/AST/Type.h"
|
||||||
#include "clang/Basic/CapturedStmt.h"
|
#include "clang/Basic/CapturedStmt.h"
|
||||||
#include "clang/Basic/LLVM.h"
|
#include "clang/Basic/LLVM.h"
|
||||||
|
@ -913,7 +914,8 @@ public:
|
||||||
/// };
|
/// };
|
||||||
/// }
|
/// }
|
||||||
void addPotentialCapture(Expr *VarExpr) {
|
void addPotentialCapture(Expr *VarExpr) {
|
||||||
assert(isa<DeclRefExpr>(VarExpr) || isa<MemberExpr>(VarExpr));
|
assert(isa<DeclRefExpr>(VarExpr) || isa<MemberExpr>(VarExpr) ||
|
||||||
|
isa<FunctionParmPackExpr>(VarExpr));
|
||||||
PotentiallyCapturingExprs.push_back(VarExpr);
|
PotentiallyCapturingExprs.push_back(VarExpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -965,13 +967,15 @@ public:
|
||||||
/// building such a node. So we need a rule that anyone can implement and get
|
/// building such a node. So we need a rule that anyone can implement and get
|
||||||
/// exactly the same result".
|
/// exactly the same result".
|
||||||
void markVariableExprAsNonODRUsed(Expr *CapturingVarExpr) {
|
void markVariableExprAsNonODRUsed(Expr *CapturingVarExpr) {
|
||||||
assert(isa<DeclRefExpr>(CapturingVarExpr)
|
assert(isa<DeclRefExpr>(CapturingVarExpr) ||
|
||||||
|| isa<MemberExpr>(CapturingVarExpr));
|
isa<MemberExpr>(CapturingVarExpr) ||
|
||||||
|
isa<FunctionParmPackExpr>(CapturingVarExpr));
|
||||||
NonODRUsedCapturingExprs.insert(CapturingVarExpr);
|
NonODRUsedCapturingExprs.insert(CapturingVarExpr);
|
||||||
}
|
}
|
||||||
bool isVariableExprMarkedAsNonODRUsed(Expr *CapturingVarExpr) const {
|
bool isVariableExprMarkedAsNonODRUsed(Expr *CapturingVarExpr) const {
|
||||||
assert(isa<DeclRefExpr>(CapturingVarExpr)
|
assert(isa<DeclRefExpr>(CapturingVarExpr) ||
|
||||||
|| isa<MemberExpr>(CapturingVarExpr));
|
isa<MemberExpr>(CapturingVarExpr) ||
|
||||||
|
isa<FunctionParmPackExpr>(CapturingVarExpr));
|
||||||
return NonODRUsedCapturingExprs.count(CapturingVarExpr);
|
return NonODRUsedCapturingExprs.count(CapturingVarExpr);
|
||||||
}
|
}
|
||||||
void removePotentialCapture(Expr *E) {
|
void removePotentialCapture(Expr *E) {
|
||||||
|
@ -993,9 +997,8 @@ public:
|
||||||
PotentialThisCaptureLocation.isValid();
|
PotentialThisCaptureLocation.isValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
// When passed the index, returns the VarDecl and Expr associated
|
void visitPotentialCaptures(
|
||||||
// with the index.
|
llvm::function_ref<void(VarDecl *, Expr *)> Callback) const;
|
||||||
void getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy()
|
FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy()
|
||||||
|
|
|
@ -4181,6 +4181,7 @@ public:
|
||||||
void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var);
|
void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var);
|
||||||
void MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base = nullptr);
|
void MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base = nullptr);
|
||||||
void MarkMemberReferenced(MemberExpr *E);
|
void MarkMemberReferenced(MemberExpr *E);
|
||||||
|
void MarkFunctionParmPackReferenced(FunctionParmPackExpr *E);
|
||||||
void MarkCaptureUsedInEnclosingContext(VarDecl *Capture, SourceLocation Loc,
|
void MarkCaptureUsedInEnclosingContext(VarDecl *Capture, SourceLocation Loc,
|
||||||
unsigned CapturingScopeIndex);
|
unsigned CapturingScopeIndex);
|
||||||
|
|
||||||
|
|
|
@ -229,20 +229,20 @@ bool CapturingScopeInfo::isVLATypeCaptured(const VariableArrayType *VAT) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LambdaScopeInfo::getPotentialVariableCapture(unsigned Idx, VarDecl *&VD,
|
void LambdaScopeInfo::visitPotentialCaptures(
|
||||||
Expr *&E) const {
|
llvm::function_ref<void(VarDecl *, Expr *)> Callback) const {
|
||||||
assert(Idx < getNumPotentialVariableCaptures() &&
|
for (Expr *E : PotentiallyCapturingExprs) {
|
||||||
"Index of potential capture must be within 0 to less than the "
|
if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
|
||||||
"number of captures!");
|
Callback(cast<VarDecl>(DRE->getFoundDecl()), E);
|
||||||
E = PotentiallyCapturingExprs[Idx];
|
} else if (auto *ME = dyn_cast<MemberExpr>(E)) {
|
||||||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
|
Callback(cast<VarDecl>(ME->getMemberDecl()), E);
|
||||||
VD = dyn_cast<VarDecl>(DRE->getFoundDecl());
|
} else if (auto *FP = dyn_cast<FunctionParmPackExpr>(E)) {
|
||||||
else if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
|
for (VarDecl *VD : *FP)
|
||||||
VD = dyn_cast<VarDecl>(ME->getMemberDecl());
|
Callback(VD, E);
|
||||||
else
|
} else {
|
||||||
llvm_unreachable("Only DeclRefExprs or MemberExprs should be added for "
|
llvm_unreachable("unexpected expression in potential captures list");
|
||||||
"potential captures");
|
}
|
||||||
assert(VD);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionScopeInfo::~FunctionScopeInfo() { }
|
FunctionScopeInfo::~FunctionScopeInfo() { }
|
||||||
|
|
|
@ -14610,7 +14610,9 @@ namespace {
|
||||||
// context so never needs to be transformed.
|
// context so never needs to be transformed.
|
||||||
// FIXME: Ideally we wouldn't transform the closure type either, and would
|
// FIXME: Ideally we wouldn't transform the closure type either, and would
|
||||||
// just recreate the capture expressions and lambda expression.
|
// 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.
|
/// *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack.
|
||||||
static void
|
static void
|
||||||
MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
|
MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
|
||||||
const unsigned *const FunctionScopeIndexToStopAt) {
|
const unsigned *const FunctionScopeIndexToStopAt = nullptr) {
|
||||||
// Keep track of used but undefined variables.
|
// Keep track of used but undefined variables.
|
||||||
// FIXME: We shouldn't suppress this warning for static data members.
|
// FIXME: We shouldn't suppress this warning for static data members.
|
||||||
if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&
|
if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&
|
||||||
|
@ -15735,15 +15737,22 @@ void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
|
||||||
// variable.
|
// variable.
|
||||||
if (LambdaScopeInfo *LSI = getCurLambda()) {
|
if (LambdaScopeInfo *LSI = getCurLambda()) {
|
||||||
Expr *SansParensExpr = E->IgnoreParens();
|
Expr *SansParensExpr = E->IgnoreParens();
|
||||||
VarDecl *Var = nullptr;
|
VarDecl *Var;
|
||||||
|
ArrayRef<VarDecl *> Vars(&Var, &Var + 1);
|
||||||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SansParensExpr))
|
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SansParensExpr))
|
||||||
Var = dyn_cast<VarDecl>(DRE->getFoundDecl());
|
Var = dyn_cast<VarDecl>(DRE->getFoundDecl());
|
||||||
else if (MemberExpr *ME = dyn_cast<MemberExpr>(SansParensExpr))
|
else if (MemberExpr *ME = dyn_cast<MemberExpr>(SansParensExpr))
|
||||||
Var = dyn_cast<VarDecl>(ME->getMemberDecl());
|
Var = dyn_cast<VarDecl>(ME->getMemberDecl());
|
||||||
|
else if (auto *FPPE = dyn_cast<FunctionParmPackExpr>(SansParensExpr))
|
||||||
|
Vars = llvm::makeArrayRef(FPPE->begin(), FPPE->end());
|
||||||
|
else
|
||||||
|
Vars = None;
|
||||||
|
|
||||||
if (Var && IsVariableNonDependentAndAConstantExpression(Var, Context))
|
for (VarDecl *VD : Vars) {
|
||||||
|
if (VD && IsVariableNonDependentAndAConstantExpression(VD, Context))
|
||||||
LSI->markVariableExprAsNonODRUsed(SansParensExpr);
|
LSI->markVariableExprAsNonODRUsed(SansParensExpr);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
|
ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
|
||||||
|
@ -15767,20 +15776,18 @@ void Sema::CleanupVarDeclMarking() {
|
||||||
std::swap(LocalMaybeODRUseExprs, MaybeODRUseExprs);
|
std::swap(LocalMaybeODRUseExprs, MaybeODRUseExprs);
|
||||||
|
|
||||||
for (Expr *E : LocalMaybeODRUseExprs) {
|
for (Expr *E : LocalMaybeODRUseExprs) {
|
||||||
VarDecl *Var;
|
if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
|
||||||
SourceLocation Loc;
|
MarkVarDeclODRUsed(cast<VarDecl>(DRE->getDecl()),
|
||||||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
|
DRE->getLocation(), *this);
|
||||||
Var = cast<VarDecl>(DRE->getDecl());
|
} else if (auto *ME = dyn_cast<MemberExpr>(E)) {
|
||||||
Loc = DRE->getLocation();
|
MarkVarDeclODRUsed(cast<VarDecl>(ME->getMemberDecl()), ME->getMemberLoc(),
|
||||||
} else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
|
*this);
|
||||||
Var = cast<VarDecl>(ME->getMemberDecl());
|
} else if (auto *FP = dyn_cast<FunctionParmPackExpr>(E)) {
|
||||||
Loc = ME->getMemberLoc();
|
for (VarDecl *VD : *FP)
|
||||||
|
MarkVarDeclODRUsed(VD, FP->getParameterPackLocation(), *this);
|
||||||
} else {
|
} else {
|
||||||
llvm_unreachable("Unexpected expression");
|
llvm_unreachable("Unexpected expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
MarkVarDeclODRUsed(Var, Loc, *this,
|
|
||||||
/*MaxFunctionScopeIndex Pointer*/ nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(MaybeODRUseExprs.empty() &&
|
assert(MaybeODRUseExprs.empty() &&
|
||||||
|
@ -15789,7 +15796,8 @@ void Sema::CleanupVarDeclMarking() {
|
||||||
|
|
||||||
static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
|
static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
|
||||||
VarDecl *Var, Expr *E) {
|
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");
|
"Invalid Expr argument to DoMarkVarDeclReferenced");
|
||||||
Var->setReferenced();
|
Var->setReferenced();
|
||||||
|
|
||||||
|
@ -16022,6 +16030,12 @@ void Sema::MarkMemberReferenced(MemberExpr *E) {
|
||||||
MarkExprReferenced(*this, Loc, E->getMemberDecl(), E, MightBeOdrUse);
|
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
|
/// Perform marking for a reference to an arbitrary declaration. It
|
||||||
/// marks the declaration referenced, and performs odr-use checking for
|
/// marks the declaration referenced, and performs odr-use checking for
|
||||||
/// functions and variables. This method should not be used when building a
|
/// functions and variables. This method should not be used when building a
|
||||||
|
|
|
@ -7427,12 +7427,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
|
||||||
// All the potentially captureable variables in the current nested
|
// All the potentially captureable variables in the current nested
|
||||||
// lambda (within a generic outer lambda), must be captured by an
|
// lambda (within a generic outer lambda), must be captured by an
|
||||||
// outer lambda that is enclosed within a non-dependent context.
|
// outer lambda that is enclosed within a non-dependent context.
|
||||||
const unsigned NumPotentialCaptures =
|
CurrentLSI->visitPotentialCaptures([&] (VarDecl *Var, Expr *VarExpr) {
|
||||||
CurrentLSI->getNumPotentialVariableCaptures();
|
|
||||||
for (unsigned I = 0; I != NumPotentialCaptures; ++I) {
|
|
||||||
Expr *VarExpr = nullptr;
|
|
||||||
VarDecl *Var = nullptr;
|
|
||||||
CurrentLSI->getPotentialVariableCapture(I, Var, VarExpr);
|
|
||||||
// If the variable is clearly identified as non-odr-used and the full
|
// If the variable is clearly identified as non-odr-used and the full
|
||||||
// expression is not instantiation dependent, only then do we not
|
// expression is not instantiation dependent, only then do we not
|
||||||
// need to check enclosing lambda's for speculative captures.
|
// need to check enclosing lambda's for speculative captures.
|
||||||
|
@ -7446,7 +7441,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
|
||||||
// }
|
// }
|
||||||
if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) &&
|
if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) &&
|
||||||
!IsFullExprInstantiationDependent)
|
!IsFullExprInstantiationDependent)
|
||||||
continue;
|
return;
|
||||||
|
|
||||||
// If we have a capture-capable lambda for the variable, go ahead and
|
// If we have a capture-capable lambda for the variable, go ahead and
|
||||||
// capture the variable in that lambda (and all its enclosing lambdas).
|
// capture the variable in that lambda (and all its enclosing lambdas).
|
||||||
|
@ -7478,7 +7473,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
|
||||||
DeclRefType, nullptr);
|
DeclRefType, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
// Check if 'this' needs to be captured.
|
// Check if 'this' needs to be captured.
|
||||||
if (CurrentLSI->hasPotentialThisCapture()) {
|
if (CurrentLSI->hasPotentialThisCapture()) {
|
||||||
|
|
|
@ -1368,9 +1368,11 @@ TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
|
||||||
Vars.push_back(D);
|
Vars.push_back(D);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FunctionParmPackExpr::Create(getSema().Context, T,
|
auto *PackExpr =
|
||||||
E->getParameterPack(),
|
FunctionParmPackExpr::Create(getSema().Context, T, E->getParameterPack(),
|
||||||
E->getParameterPackLocation(), Vars);
|
E->getParameterPackLocation(), Vars);
|
||||||
|
getSema().MarkFunctionParmPackReferenced(PackExpr);
|
||||||
|
return PackExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprResult
|
ExprResult
|
||||||
|
@ -1389,8 +1391,10 @@ TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E,
|
||||||
QualType T = TransformType(E->getType());
|
QualType T = TransformType(E->getType());
|
||||||
if (T.isNull())
|
if (T.isNull())
|
||||||
return ExprError();
|
return ExprError();
|
||||||
return FunctionParmPackExpr::Create(getSema().Context, T, PD,
|
auto *PackExpr = FunctionParmPackExpr::Create(getSema().Context, T, PD,
|
||||||
E->getExprLoc(), *Pack);
|
E->getExprLoc(), *Pack);
|
||||||
|
getSema().MarkFunctionParmPackReferenced(PackExpr);
|
||||||
|
return PackExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransformedDecl = (*Pack)[getSema().ArgumentPackSubstitutionIndex];
|
TransformedDecl = (*Pack)[getSema().ArgumentPackSubstitutionIndex];
|
||||||
|
|
|
@ -660,7 +660,10 @@ public:
|
||||||
bool ExpectParameterPack);
|
bool ExpectParameterPack);
|
||||||
|
|
||||||
/// Transform the body of a lambda-expression.
|
/// 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);
|
QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
|
||||||
|
|
||||||
|
@ -11370,16 +11373,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
||||||
bool Invalid = false;
|
bool Invalid = false;
|
||||||
|
|
||||||
// Transform captures.
|
// Transform captures.
|
||||||
bool FinishedExplicitCaptures = false;
|
|
||||||
for (LambdaExpr::capture_iterator C = E->capture_begin(),
|
for (LambdaExpr::capture_iterator C = E->capture_begin(),
|
||||||
CEnd = E->capture_end();
|
CEnd = E->capture_end();
|
||||||
C != CEnd; ++C) {
|
C != CEnd; ++C) {
|
||||||
// When we hit the first implicit capture, tell Sema that we've finished
|
// When we hit the first implicit capture, tell Sema that we've finished
|
||||||
// the list of explicit captures.
|
// the list of explicit captures.
|
||||||
if (!FinishedExplicitCaptures && C->isImplicit()) {
|
if (C->isImplicit())
|
||||||
getSema().finishLambdaExplicitCaptures(LSI);
|
break;
|
||||||
FinishedExplicitCaptures = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Capturing 'this' is trivial.
|
// Capturing 'this' is trivial.
|
||||||
if (C->capturesThis()) {
|
if (C->capturesThis()) {
|
||||||
|
@ -11488,17 +11488,16 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
||||||
getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind,
|
getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind,
|
||||||
EllipsisLoc);
|
EllipsisLoc);
|
||||||
}
|
}
|
||||||
if (!FinishedExplicitCaptures)
|
|
||||||
getSema().finishLambdaExplicitCaptures(LSI);
|
getSema().finishLambdaExplicitCaptures(LSI);
|
||||||
|
|
||||||
// Enter a new evaluation context to insulate the lambda from any
|
// FIXME: Sema's lambda-building mechanism expects us to push an expression
|
||||||
// cleanups from the enclosing full-expression.
|
// evaluation context even if we're not transforming the function body.
|
||||||
getSema().PushExpressionEvaluationContext(
|
getSema().PushExpressionEvaluationContext(
|
||||||
Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
|
Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
|
||||||
|
|
||||||
// Instantiate the body of the lambda expression.
|
// Instantiate the body of the lambda expression.
|
||||||
StmtResult Body =
|
StmtResult Body =
|
||||||
Invalid ? StmtError() : getDerived().TransformLambdaBody(E->getBody());
|
Invalid ? StmtError() : getDerived().TransformLambdaBody(E, E->getBody());
|
||||||
|
|
||||||
// ActOnLambda* will pop the function scope for us.
|
// ActOnLambda* will pop the function scope for us.
|
||||||
FuncScopeCleanup.disable();
|
FuncScopeCleanup.disable();
|
||||||
|
@ -11524,10 +11523,50 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
StmtResult
|
StmtResult
|
||||||
TreeTransform<Derived>::TransformLambdaBody(Stmt *S) {
|
TreeTransform<Derived>::TransformLambdaBody(LambdaExpr *E, Stmt *S) {
|
||||||
return TransformStmt(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>
|
template<typename Derived>
|
||||||
ExprResult
|
ExprResult
|
||||||
TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
|
TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm-only %s
|
// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm-only %s
|
||||||
|
// RUN: %clang_cc1 -std=c++2a -verify -fsyntax-only -fblocks -emit-llvm-only %s
|
||||||
// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
|
// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
|
||||||
// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
|
// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
|
||||||
// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
|
// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
|
||||||
|
@ -176,7 +177,13 @@ void doit() {
|
||||||
sample::X cx{5};
|
sample::X cx{5};
|
||||||
auto L = [=](auto a) {
|
auto L = [=](auto a) {
|
||||||
const int z = 3;
|
const int z = 3;
|
||||||
|
// FIXME: The warning below is correct but for some reason doesn't show
|
||||||
|
// up in C++17 mode.
|
||||||
return [&,a](auto b) {
|
return [&,a](auto b) {
|
||||||
|
#if __cplusplus > 201702L
|
||||||
|
// expected-warning@-2 {{address of stack memory associated with local variable 'z' returned}}
|
||||||
|
// expected-note@#call {{in instantiation of}}
|
||||||
|
#endif
|
||||||
const int y = 5;
|
const int y = 5;
|
||||||
return [=](auto c) {
|
return [=](auto c) {
|
||||||
int d[sizeof(a) == sizeof(c) || sizeof(c) == sizeof(b) ? 2 : 1];
|
int d[sizeof(a) == sizeof(c) || sizeof(c) == sizeof(b) ? 2 : 1];
|
||||||
|
@ -189,7 +196,7 @@ void doit() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
auto M = L(3)(3.5);
|
auto M = L(3)(3.5); // #call
|
||||||
M(3.14);
|
M(3.14);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1519,6 +1526,20 @@ void test() {
|
||||||
|
|
||||||
} // end ns5
|
} // end ns5
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // end PR34266
|
} // end PR34266
|
||||||
|
|
||||||
|
namespace capture_pack {
|
||||||
|
#if __cplusplus >= 201702L
|
||||||
|
constexpr
|
||||||
|
#endif
|
||||||
|
auto v =
|
||||||
|
[](auto ...a) {
|
||||||
|
[&](auto ...b) {
|
||||||
|
((a = b), ...); // expected-warning 0-1{{extension}}
|
||||||
|
}(100, 20, 3);
|
||||||
|
return (a + ...); // expected-warning 0-1{{extension}}
|
||||||
|
}(400, 50, 6);
|
||||||
|
#if __cplusplus >= 201702L
|
||||||
|
static_assert(v == 123);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
// RUN: %clang_cc1 -std=c++2a -verify %s
|
||||||
|
// expected-no-diagnostics
|
||||||
|
|
||||||
|
template<typename ...T, typename ...Lambda> void check_sizes(Lambda ...L) {
|
||||||
|
static_assert(((sizeof(T) == sizeof(Lambda)) && ...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ...T> void f(T ...v) {
|
||||||
|
// Pack expansion of lambdas: each lambda captures only one pack element.
|
||||||
|
check_sizes<T...>([=] { (void)&v; } ...);
|
||||||
|
|
||||||
|
// Pack expansion inside lambda: captures all pack elements.
|
||||||
|
auto l = [=] { ((void)&v, ...); };
|
||||||
|
static_assert(sizeof(l) >= (sizeof(T) + ...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template void f(int, char, double);
|
Loading…
Reference in New Issue