r362375 - Revert rL362358 : PR42104: Support instantiations of lambdas that implicitly capture packs.
Simon Pilgrim via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 3 02:56:09 PDT 2019
Author: rksimon
Date: Mon Jun 3 02:56:09 2019
New Revision: 362375
URL: http://llvm.org/viewvc/llvm-project?rev=362375&view=rev
Log:
Revert rL362358 : 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.
........
Fixes http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensive-checks-win buildbot failures
Removed:
cfe/trunk/test/SemaTemplate/lambda-capture-pack.cpp
Modified:
cfe/trunk/include/clang/Sema/ScopeInfo.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/ScopeInfo.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/lib/Sema/TreeTransform.h
cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=362375&r1=362374&r2=362375&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Mon Jun 3 02:56:09 2019
@@ -15,7 +15,6 @@
#define LLVM_CLANG_SEMA_SCOPEINFO_H
#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/Type.h"
#include "clang/Basic/CapturedStmt.h"
#include "clang/Basic/LLVM.h"
@@ -914,8 +913,7 @@ public:
/// };
/// }
void addPotentialCapture(Expr *VarExpr) {
- assert(isa<DeclRefExpr>(VarExpr) || isa<MemberExpr>(VarExpr) ||
- isa<FunctionParmPackExpr>(VarExpr));
+ assert(isa<DeclRefExpr>(VarExpr) || isa<MemberExpr>(VarExpr));
PotentiallyCapturingExprs.push_back(VarExpr);
}
@@ -967,15 +965,13 @@ public:
/// building such a node. So we need a rule that anyone can implement and get
/// exactly the same result".
void markVariableExprAsNonODRUsed(Expr *CapturingVarExpr) {
- assert(isa<DeclRefExpr>(CapturingVarExpr) ||
- isa<MemberExpr>(CapturingVarExpr) ||
- isa<FunctionParmPackExpr>(CapturingVarExpr));
+ assert(isa<DeclRefExpr>(CapturingVarExpr)
+ || isa<MemberExpr>(CapturingVarExpr));
NonODRUsedCapturingExprs.insert(CapturingVarExpr);
}
bool isVariableExprMarkedAsNonODRUsed(Expr *CapturingVarExpr) const {
- assert(isa<DeclRefExpr>(CapturingVarExpr) ||
- isa<MemberExpr>(CapturingVarExpr) ||
- isa<FunctionParmPackExpr>(CapturingVarExpr));
+ assert(isa<DeclRefExpr>(CapturingVarExpr)
+ || isa<MemberExpr>(CapturingVarExpr));
return NonODRUsedCapturingExprs.count(CapturingVarExpr);
}
void removePotentialCapture(Expr *E) {
@@ -997,8 +993,9 @@ public:
PotentialThisCaptureLocation.isValid();
}
- void visitPotentialCaptures(
- llvm::function_ref<void(VarDecl *, Expr *)> Callback) const;
+ // When passed the index, returns the VarDecl and Expr associated
+ // with the index.
+ void getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E) const;
};
FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy()
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=362375&r1=362374&r2=362375&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Jun 3 02:56:09 2019
@@ -4179,7 +4179,6 @@ public:
void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var);
void MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base = nullptr);
void MarkMemberReferenced(MemberExpr *E);
- void MarkFunctionParmPackReferenced(FunctionParmPackExpr *E);
void MarkCaptureUsedInEnclosingContext(VarDecl *Capture, SourceLocation Loc,
unsigned CapturingScopeIndex);
Modified: cfe/trunk/lib/Sema/ScopeInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ScopeInfo.cpp?rev=362375&r1=362374&r2=362375&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/ScopeInfo.cpp (original)
+++ cfe/trunk/lib/Sema/ScopeInfo.cpp Mon Jun 3 02:56:09 2019
@@ -229,20 +229,20 @@ bool CapturingScopeInfo::isVLATypeCaptur
return false;
}
-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");
- }
- }
+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);
}
FunctionScopeInfo::~FunctionScopeInfo() { }
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=362375&r1=362374&r2=362375&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Jun 3 02:56:09 2019
@@ -14610,9 +14610,7 @@ 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(LambdaExpr *E, Stmt *Body) {
- return SkipLambdaBody(E, Body);
- }
+ StmtResult TransformLambdaBody(Stmt *Body) { return Body; }
};
}
@@ -15056,7 +15054,7 @@ void Sema::MarkFunctionReferenced(Source
/// *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack.
static void
MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
- const unsigned *const FunctionScopeIndexToStopAt = nullptr) {
+ const unsigned *const FunctionScopeIndexToStopAt) {
// 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 &&
@@ -15737,19 +15735,14 @@ void Sema::UpdateMarkingForLValueToRValu
// variable.
if (LambdaScopeInfo *LSI = getCurLambda()) {
Expr *SansParensExpr = E->IgnoreParens();
- VarDecl *Var;
- ArrayRef<VarDecl *> Vars = None;
+ VarDecl *Var = nullptr;
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SansParensExpr))
- Vars = Var = dyn_cast<VarDecl>(DRE->getFoundDecl());
+ Var = dyn_cast<VarDecl>(DRE->getFoundDecl());
else if (MemberExpr *ME = dyn_cast<MemberExpr>(SansParensExpr))
- Vars = Var = dyn_cast<VarDecl>(ME->getMemberDecl());
- else if (auto *FPPE = dyn_cast<FunctionParmPackExpr>(SansParensExpr))
- Vars = llvm::makeArrayRef(FPPE->begin(), FPPE->end());
-
- for (VarDecl *VD : Vars) {
- if (Var && IsVariableNonDependentAndAConstantExpression(VD, Context))
- LSI->markVariableExprAsNonODRUsed(SansParensExpr);
- }
+ Var = dyn_cast<VarDecl>(ME->getMemberDecl());
+
+ if (Var && IsVariableNonDependentAndAConstantExpression(Var, Context))
+ LSI->markVariableExprAsNonODRUsed(SansParensExpr);
}
}
@@ -15774,18 +15767,20 @@ void Sema::CleanupVarDeclMarking() {
std::swap(LocalMaybeODRUseExprs, MaybeODRUseExprs);
for (Expr *E : LocalMaybeODRUseExprs) {
- 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);
+ 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();
} else {
llvm_unreachable("Unexpected expression");
}
+
+ MarkVarDeclODRUsed(Var, Loc, *this,
+ /*MaxFunctionScopeIndex Pointer*/ nullptr);
}
assert(MaybeODRUseExprs.empty() &&
@@ -15794,8 +15789,7 @@ void Sema::CleanupVarDeclMarking() {
static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
VarDecl *Var, Expr *E) {
- assert((!E || isa<DeclRefExpr>(E) || isa<MemberExpr>(E) ||
- isa<FunctionParmPackExpr>(E)) &&
+ assert((!E || isa<DeclRefExpr>(E) || isa<MemberExpr>(E)) &&
"Invalid Expr argument to DoMarkVarDeclReferenced");
Var->setReferenced();
@@ -16028,12 +16022,6 @@ void Sema::MarkMemberReferenced(MemberEx
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
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=362375&r1=362374&r2=362375&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon Jun 3 02:56:09 2019
@@ -7427,7 +7427,12 @@ static void CheckIfAnyEnclosingLambdasMu
// 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.
- CurrentLSI->visitPotentialCaptures([&] (VarDecl *Var, Expr *VarExpr) {
+ const unsigned NumPotentialCaptures =
+ 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
// expression is not instantiation dependent, only then do we not
// need to check enclosing lambda's for speculative captures.
@@ -7441,7 +7446,7 @@ static void CheckIfAnyEnclosingLambdasMu
// }
if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) &&
!IsFullExprInstantiationDependent)
- return;
+ continue;
// If we have a capture-capable lambda for the variable, go ahead and
// capture the variable in that lambda (and all its enclosing lambdas).
@@ -7473,7 +7478,7 @@ static void CheckIfAnyEnclosingLambdasMu
DeclRefType, nullptr);
}
}
- });
+ }
// Check if 'this' needs to be captured.
if (CurrentLSI->hasPotentialThisCapture()) {
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=362375&r1=362374&r2=362375&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Jun 3 02:56:09 2019
@@ -1368,11 +1368,9 @@ TemplateInstantiator::TransformFunctionP
Vars.push_back(D);
}
- auto *PackExpr =
- FunctionParmPackExpr::Create(getSema().Context, T, E->getParameterPack(),
- E->getParameterPackLocation(), Vars);
- getSema().MarkFunctionParmPackReferenced(PackExpr);
- return PackExpr;
+ return FunctionParmPackExpr::Create(getSema().Context, T,
+ E->getParameterPack(),
+ E->getParameterPackLocation(), Vars);
}
ExprResult
@@ -1391,10 +1389,8 @@ TemplateInstantiator::TransformFunctionP
QualType T = TransformType(E->getType());
if (T.isNull())
return ExprError();
- auto *PackExpr = FunctionParmPackExpr::Create(getSema().Context, T, PD,
- E->getExprLoc(), *Pack);
- getSema().MarkFunctionParmPackReferenced(PackExpr);
- return PackExpr;
+ return FunctionParmPackExpr::Create(getSema().Context, T, PD,
+ E->getExprLoc(), *Pack);
}
TransformedDecl = (*Pack)[getSema().ArgumentPackSubstitutionIndex];
Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=362375&r1=362374&r2=362375&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Mon Jun 3 02:56:09 2019
@@ -660,10 +660,7 @@ public:
bool ExpectParameterPack);
/// Transform the body of a lambda-expression.
- StmtResult TransformLambdaBody(LambdaExpr *E, Stmt *Body);
- /// Alternative implementation of TransformLambdaBody that skips transforming
- /// the body.
- StmtResult SkipLambdaBody(LambdaExpr *E, Stmt *Body);
+ StmtResult TransformLambdaBody(Stmt *Body);
QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
@@ -11361,13 +11358,16 @@ TreeTransform<Derived>::TransformLambdaE
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 (C->isImplicit())
- break;
+ if (!FinishedExplicitCaptures && C->isImplicit()) {
+ getSema().finishLambdaExplicitCaptures(LSI);
+ FinishedExplicitCaptures = true;
+ }
// Capturing 'this' is trivial.
if (C->capturesThis()) {
@@ -11476,16 +11476,17 @@ TreeTransform<Derived>::TransformLambdaE
getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind,
EllipsisLoc);
}
- getSema().finishLambdaExplicitCaptures(LSI);
+ if (!FinishedExplicitCaptures)
+ getSema().finishLambdaExplicitCaptures(LSI);
- // FIXME: Sema's lambda-building mechanism expects us to push an expression
- // evaluation context even if we're not transforming the function body.
+ // Enter a new evaluation context to insulate the lambda from any
+ // cleanups from the enclosing full-expression.
getSema().PushExpressionEvaluationContext(
Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
// Instantiate the body of the lambda expression.
StmtResult Body =
- Invalid ? StmtError() : getDerived().TransformLambdaBody(E, E->getBody());
+ Invalid ? StmtError() : getDerived().TransformLambdaBody(E->getBody());
// ActOnLambda* will pop the function scope for us.
FuncScopeCleanup.disable();
@@ -11511,51 +11512,11 @@ TreeTransform<Derived>::TransformLambdaE
template<typename Derived>
StmtResult
-TreeTransform<Derived>::TransformLambdaBody(LambdaExpr *E, Stmt *S) {
+TreeTransform<Derived>::TransformLambdaBody(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) {
Modified: cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp?rev=362375&r1=362374&r2=362375&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp Mon Jun 3 02:56:09 2019
@@ -1,5 +1,4 @@
// 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 -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
@@ -177,13 +176,7 @@ void doit() {
sample::X cx{5};
auto L = [=](auto a) {
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) {
-#if __cplusplus > 201702L
- // expected-warning at -2 {{address of stack memory associated with local variable 'z' returned}}
- // expected-note@#call {{in instantiation of}}
-#endif
const int y = 5;
return [=](auto c) {
int d[sizeof(a) == sizeof(c) || sizeof(c) == sizeof(b) ? 2 : 1];
@@ -196,7 +189,7 @@ void doit() {
};
};
};
- auto M = L(3)(3.5); // #call
+ auto M = L(3)(3.5);
M(3.14);
}
}
@@ -1526,20 +1519,6 @@ void test() {
} // end ns5
-} // 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
-}
+
+} // end PR34266
Removed: cfe/trunk/test/SemaTemplate/lambda-capture-pack.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/lambda-capture-pack.cpp?rev=362374&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/lambda-capture-pack.cpp (original)
+++ cfe/trunk/test/SemaTemplate/lambda-capture-pack.cpp (removed)
@@ -1,17 +0,0 @@
-// 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);
More information about the cfe-commits
mailing list