As per Richard's request:
- separated the initialization of the init-capture from the creation of the
variable
- dropped the CurLambdaInitCapture kludge to avoid diagnosing an unexpanded
pack prematurely
With this patch - init-captures should play nice with generic lambdas.
Thanks!
Hi rsmith, doug.gregor,
http://llvm-reviews.chandlerc.com/D2092
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D2092?vs=5327&id=5433#toc
Files:
include/clang/Sema/DeclSpec.h
include/clang/Sema/Initialization.h
include/clang/Sema/Sema.h
lib/Parse/ParseExprCXX.cpp
lib/Sema/SemaAccess.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaLambda.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/TreeTransform.h
test/SemaCXX/cxx1y-init-captures.cpp
Index: include/clang/Sema/DeclSpec.h
===================================================================
--- include/clang/Sema/DeclSpec.h
+++ include/clang/Sema/DeclSpec.h
@@ -2143,7 +2143,7 @@
IdentifierInfo *Id;
SourceLocation EllipsisLoc;
ExprResult Init;
-
+ ParsedType InitCaptureType;
LambdaCapture(LambdaCaptureKind Kind, SourceLocation Loc,
IdentifierInfo* Id = 0,
SourceLocation EllipsisLoc = SourceLocation(),
Index: include/clang/Sema/Initialization.h
===================================================================
--- include/clang/Sema/Initialization.h
+++ include/clang/Sema/Initialization.h
@@ -116,8 +116,8 @@
};
struct C {
- /// \brief The variable being captured by an EK_LambdaCapture.
- VarDecl *Var;
+ /// \brief The name of the variable being captured by an EK_LambdaCapture.
+ IdentifierInfo *VarID;
/// \brief The source location at which the capture occurs.
unsigned Location;
@@ -183,10 +183,10 @@
const InitializedEntity &Parent);
/// \brief Create the initialization entity for a lambda capture.
- InitializedEntity(VarDecl *Var, FieldDecl *Field, SourceLocation Loc)
- : Kind(EK_LambdaCapture), Parent(0), Type(Field->getType())
+ InitializedEntity(IdentifierInfo *VarID, QualType FieldType, SourceLocation Loc)
+ : Kind(EK_LambdaCapture), Parent(0), Type(FieldType)
{
- Capture.Var = Var;
+ Capture.VarID = VarID;
Capture.Location = Loc.getRawEncoding();
}
@@ -309,10 +309,10 @@
}
/// \brief Create the initialization entity for a lambda capture.
- static InitializedEntity InitializeLambdaCapture(VarDecl *Var,
- FieldDecl *Field,
+ static InitializedEntity InitializeLambdaCapture(IdentifierInfo *VarID,
+ QualType FieldType,
SourceLocation Loc) {
- return InitializedEntity(Var, Field, Loc);
+ return InitializedEntity(VarID, FieldType, Loc);
}
/// \brief Create the entity for a compound literal initializer.
@@ -402,13 +402,11 @@
getKind() == EK_ComplexElement);
this->Index = Index;
}
-
- /// \brief Retrieve the variable for a captured variable in a lambda.
- VarDecl *getCapturedVar() const {
+ /// \brief For a lambda capture, return the capture's name.
+ StringRef getCapturedVarName() const {
assert(getKind() == EK_LambdaCapture && "Not a lambda capture!");
- return Capture.Var;
+ return Capture.VarID->getName();
}
-
/// \brief Determine the location of the capture when initializing
/// field from a captured variable in a lambda.
SourceLocation getCaptureLoc() const {
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -281,6 +281,12 @@
/// element type here is ExprWithCleanups::Object.
SmallVector<BlockDecl*, 8> ExprCleanupObjects;
+ /// \brief Store a list of either DeclRefExprs or MemberExprs
+ /// that contain a reference to a variable (constant) that may or may not
+ /// be odr-used in this Expr, and we won't know until all lvalue-to-rvalue
+ /// and discarded value conversions have been applied to all subexpressions
+ /// of the enclosing full expression. This is cleared at the end of each
+ /// full expression.
llvm::SmallPtrSet<Expr*, 2> MaybeODRUseExprs;
/// \brief Stack containing information about each of the nested
@@ -4307,7 +4313,8 @@
}
ExprResult ActOnFinishFullExpr(Expr *Expr, SourceLocation CC,
bool DiscardedValue = false,
- bool IsConstexpr = false);
+ bool IsConstexpr = false,
+ bool IsLambdaInitCaptureInitializer = false);
StmtResult ActOnFinishFullStmt(Stmt *Stmt);
// Marks SS invalid if it represents an incomplete type.
@@ -4502,10 +4509,18 @@
bool ExplicitResultType,
bool Mutable);
- /// \brief Check an init-capture and build the implied variable declaration
- /// with the specified name and initializer.
- VarDecl *checkInitCapture(SourceLocation Loc, bool ByRef,
- IdentifierInfo *Id, Expr *Init);
+ /// \brief Perform initialization analysis of the init-capture and perform
+ /// any implicit conversions such as an lvalue-to-rvalue conversion if
+ /// not being used to initialize a reference.
+ QualType performLambdaInitCaptureInitialization(SourceLocation Loc,
+ bool ByRef, IdentifierInfo *Id, Expr *&Init);
+ /// \brief Create a dummy variable within the declcontext of the lambda's
+ /// call operator, for name lookup purposes for a lambda init capture.
+ ///
+ /// CodeGen handles emission of lambda captures, ignoring these dummy
+ /// variables appropriately.
+ VarDecl *createLambdaInitCaptureDummyVariable(SourceLocation Loc,
+ QualType InitCaptureType, IdentifierInfo *Id, Expr *Init);
/// \brief Build the implicit field for an init-capture.
FieldDecl *buildInitCaptureField(sema::LambdaScopeInfo *LSI, VarDecl *Var);
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -591,6 +591,58 @@
Tok.is(tok::l_paren), isAddressOfOperand);
}
+// For lambda init-captures such as the following:
+// const int x = 10;
+// auto L = [i = x+1](int a) {
+// return [j = x+2,
+// &k = x](char b) { };
+// };
+// keep in mind that each lambda init-capture has to have:
+// - its initialization expression executed in the context
+// of the enclosing/parent decl-context.
+// - but the variable itself has to be 'injected' into the
+// decl-context of its lambda's call-operator (which has
+// not yet been created).
+// Each init-expression is a full-expression that has to get
+// Sema-analyzed (for capturing etc.) before its lambda's
+// call-operator's decl-context, scope & scopeinfo are pushed on their
+// respective stacks. Thus if any variable is odr-used in the init-capture
+// it will correctly get captured in the enclosing lambda, if one exists.
+// The init-variables above are created later once the lambdascope and
+// call-operators decl-context is pushed onto its respective stack.
+
+static inline void performLambdaInitCaptureInitializations(
+ LambdaIntroducer &Intro, Sema &Actions) {
+ // The lambda init-capture's initializer expression occurs in the context of
+ // the enclosing function or lambda. Therefore we can not wait till a lambda
+ // scope has been pushed on before deciding whether the variable needs to be
+ // captured. We also need to process all lvalue-to-rvalue conversions and
+ // discarded-value conversions, so that we can avoid capturing certain
+ // constant variables.
+ // For e.g.,
+ // void test() {
+ // const int x = 10;
+ // auto L = [&z = x](char a) { <-- don't capture by the current lambda
+ // return [y = x](int i) { <-- don't capture by enclosing lambda
+ // return y;
+ // }
+ // };
+ // If x was not const, the second use would require 'L' to capture, and
+ // that would be an error.
+ for (SmallVectorImpl<LambdaCapture>::iterator C = Intro.Captures.begin(),
+ E = Intro.Captures.end(); C != E; ++C) {
+ if (!C->Init.isUsable())
+ continue;
+ // Get the pointer and store it in an lvalue, so we can use it as an
+ // out argument.
+ Expr *Init = C->Init.get();
+ // This performs any lvalue-to-rvalue conversions if necessary, which
+ // can affect what gets captured in the containing decl-context.
+ C->InitCaptureType.set(Actions.performLambdaInitCaptureInitialization(
+ C->Loc, C->Kind == LCK_ByRef, C->Id, Init));
+ C->Init = Init;
+ }
+}
/// ParseLambdaExpression - Parse a C++11 lambda expression.
///
/// lambda-expression:
@@ -633,8 +685,15 @@
ExprResult Parser::ParseLambdaExpression() {
// Parse lambda-introducer.
LambdaIntroducer Intro;
-
- Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
+ Optional<unsigned> DiagID;
+ {
+ // Each lambda init-capture forms its own full expression, which clears
+ // MaybeODRUseExprs. So create an expression evaluation context to save
+ // the necessary state, and restore it later.
+ EnterExpressionEvaluationContext EC(Actions, Sema::PotentiallyEvaluated);
+ DiagID = ParseLambdaIntroducer(Intro);
+ performLambdaInitCaptureInitializations(Intro, Actions);
+ }
if (DiagID) {
Diag(Tok, DiagID.getValue());
SkipUntil(tok::r_square);
@@ -674,7 +733,7 @@
if (Next.is(tok::identifier) && After.is(tok::identifier)) {
return ExprEmpty();
}
-
+
// Here, we're stuck: lambda introducers and Objective-C message sends are
// unambiguous, but it requires arbitrary lookhead. [a,b,c,d,e,f,g] is a
// lambda, and [a,b,c,d,e,f,g h] is a Objective-C message send. Instead of
@@ -682,8 +741,14 @@
// a lambda introducer first, and fall back if that fails.
// (TryParseLambdaIntroducer never produces any diagnostic output.)
LambdaIntroducer Intro;
- if (TryParseLambdaIntroducer(Intro))
- return ExprEmpty();
+ {
+ EnterExpressionEvaluationContext EC(Actions, Sema::PotentiallyEvaluated);
+ if (TryParseLambdaIntroducer(Intro)) {
+ performLambdaInitCaptureInitializations(Intro, Actions);
+ return ExprEmpty();
+ }
+ performLambdaInitCaptureInitializations(Intro, Actions);
+ }
return ParseLambdaExpressionAfterIntroducer(Intro);
}
Index: lib/Sema/SemaAccess.cpp
===================================================================
--- lib/Sema/SemaAccess.cpp
+++ lib/Sema/SemaAccess.cpp
@@ -1650,9 +1650,9 @@
}
case InitializedEntity::EK_LambdaCapture: {
- const VarDecl *Var = Entity.getCapturedVar();
+ StringRef VarName = Entity.getCapturedVarName();
PD = PDiag(diag::err_access_lambda_capture);
- PD << Var->getName() << Entity.getType() << getSpecialMember(Constructor);
+ PD << VarName << Entity.getType() << getSpecialMember(Constructor);
break;
}
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -11681,7 +11681,8 @@
SmallVector<InitializedEntity, 4> Entities;
Entities.reserve(1 + IndexVariables.size());
Entities.push_back(
- InitializedEntity::InitializeLambdaCapture(Var, Field, Loc));
+ InitializedEntity::InitializeLambdaCapture(Var->getIdentifier(),
+ Field->getType(), Loc));
for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
Entities.push_back(InitializedEntity::InitializeElement(S.Context,
0,
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5929,13 +5929,23 @@
ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
bool DiscardedValue,
- bool IsConstexpr) {
+ bool IsConstexpr,
+ bool IsLambdaInitCaptureInitializer) {
ExprResult FullExpr = Owned(FE);
if (!FullExpr.get())
return ExprError();
-
- if (DiagnoseUnexpandedParameterPack(FullExpr.get()))
+
+ // If we are an init-expression in a lambdas init-capture, we should not
+ // diagnose an unexpanded pack now (will be diagnosed once lambda-expr
+ // containing full-expression is done).
+ // template<class ... Ts> void test(Ts ... t) {
+ // test([&a(t)]() { <-- (t) is an init-expr that shouldn't be diagnosed now.
+ // return a;
+ // }() ...);
+ // }
+ if (!IsLambdaInitCaptureInitializer &&
+ DiagnoseUnexpandedParameterPack(FullExpr.get()))
return ExprError();
// Top-level expressions default to 'id' when we're in a debugger.
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -2506,7 +2506,7 @@
return VariableOrMember->getDeclName();
case EK_LambdaCapture:
- return Capture.Var->getDeclName();
+ return DeclarationName(Capture.VarID);
case EK_Result:
case EK_Exception:
@@ -2608,7 +2608,7 @@
case EK_BlockElement: OS << "Block"; break;
case EK_LambdaCapture:
OS << "LambdaCapture ";
- getCapturedVar()->printName(OS);
+ OS << DeclarationName(Capture.VarID);
break;
}
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -609,12 +609,15 @@
}
}
-VarDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef,
- IdentifierInfo *Id, Expr *Init) {
- // C++1y [expr.prim.lambda]p11:
- // An init-capture behaves as if it declares and explicitly captures
- // a variable of the form
- // "auto init-capture;"
+
+QualType Sema::performLambdaInitCaptureInitialization(SourceLocation Loc,
+ bool ByRef, IdentifierInfo *Id, Expr *&Init) {
+
+ const bool IsDirectInit = isa<ParenListExpr>(Init) ||
+ isa<InitListExpr>(Init);
+
+ // Create an 'auto' or 'auto&' TypeSourceInfo that we can use to
+ // deduce against.
QualType DeductType = Context.getAutoDeductType();
TypeLocBuilder TLB;
TLB.pushTypeSpec(DeductType).setNameLoc(Loc);
@@ -624,25 +627,106 @@
TLB.push<ReferenceTypeLoc>(DeductType).setSigilLoc(Loc);
}
TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, DeductType);
+
+ // Are we a non-list direct initialization?
+ ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
+ Expr *DeduceInit = Init;
+ // Initializer could be a C++ direct-initializer. Deduction only works if it
+ // contains exactly one expression.
+ if (CXXDirectInit) {
+ if (CXXDirectInit->getNumExprs() == 0) {
+ // It isn't possible to write this directly, but it is possible to
+ // end up in this situation with "x(some_pack...);"
+ Diag(CXXDirectInit->getLocStart(),
+ diag::err_init_capture_no_expression)
+ << DeclarationName(Id) << TSI->getType()
+ << Loc;
+ return QualType();
+ } else if (CXXDirectInit->getNumExprs() > 1) {
+ Diag(CXXDirectInit->getExpr(1)->getLocStart(),
+ diag::err_init_capture_multiple_expressions)
+ << DeclarationName(Id) << TSI->getType()
+ << Loc;
+ return QualType();
+ } else {
+ DeduceInit = CXXDirectInit->getExpr(0);
+ }
+ }
+
+ // Now deduce against the initialization expression and store the deduced
+ // type below.
+ QualType DeducedType;
+ if (DeduceAutoType(TSI, DeduceInit, DeducedType) ==
+ DAR_Failed) {
+ if (isa<InitListExpr>(Init))
+ Diag(Loc, diag::err_init_capture_deduction_failure_from_init_list)
+ << DeclarationName(Id) << (DeduceInit->getType().isNull()
+ ? TSI->getType() : DeduceInit->getType())
+ << DeduceInit->getSourceRange();
+ else
+ Diag(Loc, diag::err_init_capture_deduction_failure)
+ << DeclarationName(Id) << TSI->getType() <<
+ (DeduceInit->getType().isNull()
+ ? TSI->getType() : DeduceInit->getType())
+ << DeduceInit->getSourceRange();
+ }
+ if (DeducedType.isNull())
+ return QualType();
+
+ // Perform initialization analysis and ensure any implicit conversions
+ // (such as lvalue-to-rvalue) are enforced.
+ InitializedEntity Entity = InitializedEntity::InitializeLambdaCapture(Id,
+ DeducedType, Loc);
+ InitializationKind Kind =
+ IsDirectInit
+ ? (CXXDirectInit
+ ? InitializationKind::CreateDirect(Loc, Init->getLocStart(),
+ Init->getLocEnd())
+ : InitializationKind::CreateDirectList(Loc))
+ : InitializationKind::CreateCopy(Loc, Init->getLocStart());
+
+ MultiExprArg Args = Init;
+ if (CXXDirectInit)
+ Args = MultiExprArg(CXXDirectInit->getExprs(),
+ CXXDirectInit->getNumExprs());
+ QualType DclT;
+ InitializationSequence InitSeq(*this, Entity, Kind, Args);
+ ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT);
+
+ if (Result.isInvalid())
+ return QualType();
+ Init = Result.takeAs<Expr>();
+
+ // The init-capture initialization is a full-expression that must be
+ // processed as one before we enter the declcontext of the lambda's
+ // call-operator.
+ Result = ActOnFinishFullExpr(Init, Loc, /*DiscardedValue*/false,
+ /*IsConstexpr*/false, /*IsLambdaInitCaptureInitalizer*/true);
+ if (Result.isInvalid())
+ return QualType();
+
+ Init = Result.takeAs<Expr>();
+ return DeducedType;
+}
+
+VarDecl *Sema::createLambdaInitCaptureDummyVariable(SourceLocation Loc,
+ QualType InitCaptureType, IdentifierInfo *Id, Expr *Init) {
+
+ TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType,
+ Loc);
// Create a dummy variable representing the init-capture. This is not actually
// used as a variable, and only exists as a way to name and refer to the
// init-capture.
// FIXME: Pass in separate source locations for '&' and identifier.
VarDecl *NewVD = VarDecl::Create(Context, CurContext, Loc,
- Loc, Id, TSI->getType(), TSI, SC_Auto);
+ Loc, Id, InitCaptureType, TSI, SC_Auto);
NewVD->setInitCapture(true);
NewVD->setReferenced(true);
NewVD->markUsed(Context);
+ NewVD->setInit(Init);
+ return NewVD;
- // We do not need to distinguish between direct-list-initialization
- // and copy-list-initialization here, because we will always deduce
- // std::initializer_list<T>, and direct- and copy-list-initialization
- // always behave the same for such a type.
- // FIXME: We should model whether an '=' was present.
- bool DirectInit = isa<ParenListExpr>(Init) || isa<InitListExpr>(Init);
- AddInitializerToDecl(NewVD, Init, DirectInit, /*ContainsAuto*/true);
- return NewVD;
}
FieldDecl *Sema::buildInitCaptureField(LambdaScopeInfo *LSI, VarDecl *Var) {
@@ -816,7 +900,7 @@
if (C->Init.isInvalid())
continue;
- VarDecl *Var;
+ VarDecl *Var = 0;
if (C->Init.isUsable()) {
Diag(C->Loc, getLangOpts().CPlusPlus1y
? diag::warn_cxx11_compat_init_capture
@@ -824,9 +908,13 @@
if (C->Init.get()->containsUnexpandedParameterPack())
ContainsUnexpandedParameterPack = true;
-
- Var = checkInitCapture(C->Loc, C->Kind == LCK_ByRef,
- C->Id, C->Init.take());
+ // If the initializer expression is usable, but the InitCaptureType
+ // is not then an error has occured - so ignore the capture for now.
+ // for e.g., [n{0}] { }; <-- if no <initializer_list> is included.
+ if (C->InitCaptureType.get().isNull())
+ continue;
+ Var = createLambdaInitCaptureDummyVariable(C->Loc, C->InitCaptureType.get(),
+ C->Id, C->Init.take());
// C++1y [expr.prim.lambda]p11:
// An init-capture behaves as if it declares and explicitly
// captures a variable [...] whose declarative region is the
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -917,7 +917,8 @@
}
ExprResult TransformLambdaScope(LambdaExpr *E,
- CXXMethodDecl *NewCallOperator) {
+ CXXMethodDecl *NewCallOperator,
+ ArrayRef<ExprAndQualTypePairTy> InitCaptureExprsAndTypes) {
CXXMethodDecl *const OldCallOperator = E->getCallOperator();
// In the generic lambda case, we set the NewTemplate to be considered
// an "instantiation" of the OldTemplate.
@@ -936,7 +937,8 @@
NewCallOperator->setInstantiationOfMemberFunction(OldCallOperator,
TSK_ImplicitInstantiation);
- return inherited::TransformLambdaScope(E, NewCallOperator);
+ return inherited::TransformLambdaScope(E, NewCallOperator,
+ InitCaptureExprsAndTypes);
}
TemplateParameterList *TransformTemplateParameterList(
TemplateParameterList *OrigTPL) {
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -593,9 +593,10 @@
StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
ExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E);
-
+ typedef std::pair<ExprResult, QualType> ExprAndQualTypePairTy;
/// \brief Transform the captures and body of a lambda expression.
- ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);
+ ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator,
+ ArrayRef<ExprAndQualTypePairTy> InitCaptureExprsAndTypes);
TemplateParameterList *TransformTemplateParameterList(
TemplateParameterList *TPL) {
@@ -8276,6 +8277,39 @@
ExprResult
TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
+ // Transform any init-capture expressions before entering the scope of the
+ // lambda to avoid confusing tryCaptureVar during the transformation.
+ SmallVector<ExprAndQualTypePairTy, 8> InitCaptureExprsAndTypes;
+ InitCaptureExprsAndTypes.resize(E->explicit_capture_end() -
+ E->explicit_capture_begin());
+
+ for (LambdaExpr::capture_iterator C = E->capture_begin(),
+ CEnd = E->capture_end();
+ C != CEnd; ++C) {
+ if (!C->isInitCapture())
+ continue;
+ EnterExpressionEvaluationContext EEEC(getSema(),
+ Sema::PotentiallyEvaluated);
+ ExprResult NewExprInitResult = getDerived().TransformInitializer(
+ C->getCapturedVar()->getInit(),
+ C->getCapturedVar()->getInitStyle() == VarDecl::CallInit);
+
+ if (NewExprInitResult.isInvalid())
+ return ExprError();
+ Expr *NewExprInit = NewExprInitResult.get();
+
+ VarDecl *OldVD = C->getCapturedVar();
+ QualType NewInitCaptureType =
+ getSema().performLambdaInitCaptureInitialization(C->getLocation(),
+ OldVD->getType()->isReferenceType(), OldVD->getIdentifier(),
+ NewExprInit);
+ NewExprInitResult = NewExprInit;
+ VarDecl *NewVD = 0;
+ InitCaptureExprsAndTypes[C - E->capture_begin()] =
+ std::make_pair(NewExprInitResult, NewInitCaptureType);
+
+ }
+
getSema().PushLambdaScope();
LambdaScopeInfo *LSI = getSema().getCurLambda();
// Transform the template parameters, and add them to the current
@@ -8371,31 +8405,17 @@
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
- return getDerived().TransformLambdaScope(E, NewCallOperator);
+ return getDerived().TransformLambdaScope(E, NewCallOperator,
+ InitCaptureExprsAndTypes);
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
- CXXMethodDecl *CallOperator) {
+ CXXMethodDecl *CallOperator,
+ ArrayRef<ExprAndQualTypePairTy> InitCaptureExprsAndTypes) {
bool Invalid = false;
- // Transform any init-capture expressions before entering the scope of the
- // lambda.
- SmallVector<ExprResult, 8> InitCaptureExprs;
- InitCaptureExprs.resize(E->explicit_capture_end() -
- E->explicit_capture_begin());
- for (LambdaExpr::capture_iterator C = E->capture_begin(),
- CEnd = E->capture_end();
- C != CEnd; ++C) {
- if (!C->isInitCapture())
- continue;
- InitCaptureExprs[C - E->capture_begin()] =
- getDerived().TransformInitializer(
- C->getCapturedVar()->getInit(),
- C->getCapturedVar()->getInitStyle() == VarDecl::CallInit);
- }
-
// Introduce the context of the call operator.
Sema::ContextRAII SavedContext(getSema(), CallOperator);
@@ -8428,19 +8448,24 @@
// Rebuild init-captures, including the implied field declaration.
if (C->isInitCapture()) {
- ExprResult Init = InitCaptureExprs[C - E->capture_begin()];
- if (Init.isInvalid()) {
+
+ ExprAndQualTypePairTy InitExprTypePair =
+ InitCaptureExprsAndTypes[C - E->capture_begin()];
+ ExprResult Init = InitExprTypePair.first;
+ QualType InitQualType = InitExprTypePair.second;
+ if (Init.isInvalid() || InitQualType.isNull()) {
Invalid = true;
continue;
}
VarDecl *OldVD = C->getCapturedVar();
- VarDecl *NewVD = getSema().checkInitCapture(
- C->getLocation(), OldVD->getType()->isReferenceType(),
- OldVD->getIdentifier(), Init.take());
+ VarDecl *NewVD = getSema().createLambdaInitCaptureDummyVariable(
+ OldVD->getLocation(), InitExprTypePair.second,
+ OldVD->getIdentifier(), Init.get());
if (!NewVD)
Invalid = true;
- else
+ else {
getDerived().transformedLocalDecl(OldVD, NewVD);
+ }
getSema().buildInitCaptureField(LSI, NewVD);
continue;
}
Index: test/SemaCXX/cxx1y-init-captures.cpp
===================================================================
--- test/SemaCXX/cxx1y-init-captures.cpp
+++ test/SemaCXX/cxx1y-init-captures.cpp
@@ -1,14 +1,169 @@
-// RUN: %clang_cc1 -std=c++1y %s -verify
+// RUN: %clang_cc1 -std=c++1y %s -verify -emit-llvm-only
-// expected-no-diagnostics
namespace variadic_expansion {
- void f(int &, char &);
-
- template <typename ... T> void g(T &... t) {
+ int f(int &, char &) { return 0; }
+ template<class ... Ts> char fv(Ts ... ts) { return 0; }
+ // FIXME: why do we get 2 error messages
+ template <typename ... T> void g(T &... t) { //expected-note3{{declared here}}
f([&a(t)]()->decltype(auto) {
return a;
}() ...);
+
+ auto L = [x = f([&a(t)]()->decltype(auto) { return a; }()...)]() { return x; };
+ const int y = 10;
+ auto M = [x = y,
+ &z = y](T& ... t) { };
+ auto N = [x = y,
+ &z = y, n = f(t...),
+ o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...), t...](T& ... s) {
+ fv([&a(t)]()->decltype(auto) {
+ return a;
+ }() ...);
+ };
+ auto N2 = [x = y, //expected-note3{{begins here}}
+ &z = y, n = f(t...),
+ o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...)](T& ... s) {
+ fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}}
+ return a;
+ }() ...);
+ };
+
}
- void h(int i, char c) { g(i, c); }
+ void h(int i, char c) { g(i, c); } //expected-note{{in instantiation}}
}
+
+namespace odr_use_within_init_capture {
+
+int test() {
+
+ { // no captures
+ const int x = 10;
+ auto L = [z = x + 2](int a) {
+ auto M = [y = x - 2](char b) {
+ return y;
+ };
+ return M;
+ };
+
+ }
+ { // should not capture
+ const int x = 10;
+ auto L = [&z = x](int a) {
+ return a;;
+ };
+
+ }
+ {
+ const int x = 10;
+ auto L = [k = x](char a) { //expected-note {{declared}}
+ return [](int b) { //expected-note {{begins}}
+ return [j = k](int c) { //expected-error {{cannot be implicitly captured}}
+ return c;
+ };
+ };
+ };
+ }
+ {
+ const int x = 10;
+ auto L = [k = x](char a) {
+ return [=](int b) {
+ return [j = k](int c) {
+ return c;
+ };
+ };
+ };
+ }
+ {
+ const int x = 10;
+ auto L = [k = x](char a) {
+ return [k](int b) {
+ return [j = k](int c) {
+ return c;
+ };
+ };
+ };
+ }
+
+ return 0;
+}
+
+int run = test();
+
+}
+
+namespace odr_use_within_init_capture_template {
+
+template<class T = int>
+int test(T t = T{}) {
+
+ { // no captures
+ const T x = 10;
+ auto L = [z = x](char a) {
+ auto M = [y = x](T b) {
+ return y;
+ };
+ return M;
+ };
+
+ }
+ { // should not capture
+ const T x = 10;
+ auto L = [&z = x](T a) {
+ return a;;
+ };
+
+ }
+ { // will need to capture x in outer lambda
+ const T x = 10; //expected-note {{declared}}
+ auto L = [z = x](char a) { //expected-note {{begins}}
+ auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}}
+ return y;
+ };
+ return M;
+ };
+
+ }
+ { // will need to capture x in outer lambda
+ const T x = 10;
+ auto L = [=,z = x](char a) {
+ auto M = [&y = x](T b) {
+ return y;
+ };
+ return M;
+ };
+
+ }
+ { // will need to capture x in outer lambda
+ const T x = 10;
+ auto L = [x, z = x](char a) {
+ auto M = [&y = x](T b) {
+ return y;
+ };
+ return M;
+ };
+ }
+ { // will need to capture x in outer lambda
+ const int x = 10; //expected-note 2{{declared}}
+ auto L = [z = x](char a) { //expected-note 2{{begins}}
+ auto M = [&y = x](T b) { //expected-error 2{{cannot be implicitly captured}}
+ return y;
+ };
+ return M;
+ };
+ }
+ {
+ // no captures
+ const T x = 10;
+ auto L = [z =
+ [z = x, &y = x](char a) { return z + y; }('a')](char a)
+ { return z; };
+
+ }
+
+ return 0;
+}
+
+int run = test(); //expected-note {{instantiation}}
+
+}
\ No newline at end of file
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits