Index: include/clang/Sema/ScopeInfo.h =================================================================== --- include/clang/Sema/ScopeInfo.h +++ include/clang/Sema/ScopeInfo.h @@ -410,14 +410,17 @@ /// non-static data member that would hold the capture. QualType CaptureType; + /// \brief Does this represent an init capture: [x = move(x)]{ ... } + bool IsInitCapture; public: Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested, SourceLocation Loc, SourceLocation EllipsisLoc, - QualType CaptureType, Expr *Cpy) + QualType CaptureType, Expr *Cpy, bool IsInitCapture) : VarAndNested(Var, IsNested), InitExprAndCaptureKind(Cpy, Block ? Cap_Block : ByRef ? Cap_ByRef : Cap_ByCopy), - Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType) {} + Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType), + IsInitCapture(IsInitCapture) {} enum IsThisCapture { ThisCapture }; Capture(IsThisCapture, bool IsNested, SourceLocation Loc, @@ -424,8 +427,11 @@ QualType CaptureType, Expr *Cpy) : VarAndNested(nullptr, IsNested), InitExprAndCaptureKind(Cpy, Cap_This), - Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {} + Loc(Loc), EllipsisLoc(), CaptureType(CaptureType), + IsInitCapture(false) {} + bool isInitCapture() const { return IsInitCapture; } + bool isThisCapture() const { return InitExprAndCaptureKind.getInt() == Cap_This; } @@ -495,9 +501,9 @@ void addCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested, SourceLocation Loc, SourceLocation EllipsisLoc, - QualType CaptureType, Expr *Cpy) { + QualType CaptureType, Expr *Cpy, bool IsInitCapture) { Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc, - EllipsisLoc, CaptureType, Cpy)); + EllipsisLoc, CaptureType, Cpy, IsInitCapture)); CaptureMap[Var] = Captures.size(); } @@ -505,7 +511,7 @@ Captures.push_back(Capture(/*Var*/ nullptr, /*isBlock*/ false, /*isByref*/ false, /*isNested*/ false, Loc, /*EllipsisLoc*/ SourceLocation(), CaptureType, - /*Cpy*/ nullptr)); + /*Cpy*/ nullptr, /*IsInitCapture*/false)); } void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType, @@ -648,13 +654,6 @@ /// \brief Whether the lambda contains an unexpanded parameter pack. bool ContainsUnexpandedParameterPack; - /// \brief Variables used to index into by-copy array captures. - SmallVector ArrayIndexVars; - - /// \brief Offsets into the ArrayIndexVars array at which each capture starts - /// its list of array index variables. - SmallVector ArrayIndexStarts; - /// \brief If this is a generic lambda, use this as the depth of /// each 'auto' parameter, during initial AST construction. unsigned AutoTemplateParameterDepth; @@ -842,9 +841,6 @@ Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, CaptureType, Cpy)); CXXThisCaptureIndex = Captures.size(); - - if (LambdaScopeInfo *LSI = dyn_cast(this)) - LSI->ArrayIndexStarts.push_back(LSI->ArrayIndexVars.size()); } } // end namespace sema Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10251,7 +10251,7 @@ /*RefersToEnclosingVariableOrCapture*/true, C.getLocation(), /*EllipsisLoc*/C.isPackExpansion() ? C.getEllipsisLoc() : SourceLocation(), - CaptureType, /*Expr*/ nullptr); + CaptureType, /*Expr*/ nullptr, C.isInitCapture()); } else if (C.capturesThis()) { LSI->addThisCapture(/*Nested*/ false, C.getLocation(), Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -12137,7 +12137,8 @@ // Actually capture the variable. if (BuildAndDiagnose) BSI->addCapture(Var, HasBlocksAttr, ByRef, Nested, Loc, - SourceLocation(), CaptureType, CopyExpr); + SourceLocation(), CaptureType, CopyExpr, + /*IsInitCapture*/false); return true; @@ -12182,7 +12183,8 @@ // Actually capture the variable. if (BuildAndDiagnose) RSI->addCapture(Var, /*isBlock*/false, ByRef, RefersToCapturedVariable, Loc, - SourceLocation(), CaptureType, CopyExpr); + SourceLocation(), CaptureType, CopyExpr, + /*IsInitCapture*/false); return true; @@ -12190,7 +12192,7 @@ /// \brief Create a field within the lambda class for the variable /// being captured. Handle Array captures. -static ExprResult addAsFieldToClosureType(Sema &S, +static Expr *addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI, VarDecl *Var, QualType FieldType, QualType DeclRefType, @@ -12206,107 +12208,10 @@ Field->setImplicit(true); Field->setAccess(AS_private); Lambda->addDecl(Field); - - // C++11 [expr.prim.lambda]p21: - // When the lambda-expression is evaluated, the entities that - // are captured by copy are used to direct-initialize each - // corresponding non-static data member of the resulting closure - // object. (For array members, the array elements are - // direct-initialized in increasing subscript order.) These - // initializations are performed in the (unspecified) order in - // which the non-static data members are declared. - - // Introduce a new evaluation context for the initialization, so - // that temporaries introduced as part of the capture are retained - // to be re-"exported" from the lambda expression itself. - EnterExpressionEvaluationContext scope(S, Sema::PotentiallyEvaluated); - - // C++ [expr.prim.labda]p12: - // An entity captured by a lambda-expression is odr-used (3.2) in - // the scope containing the lambda-expression. - Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable, - DeclRefType, VK_LValue, Loc); Var->setReferenced(true); - Var->markUsed(S.Context); - - // When the field has array type, create index variables for each - // dimension of the array. We use these index variables to subscript - // the source array, and other clients (e.g., CodeGen) will perform - // the necessary iteration with these index variables. - SmallVector IndexVariables; - QualType BaseType = FieldType; - QualType SizeType = S.Context.getSizeType(); - LSI->ArrayIndexStarts.push_back(LSI->ArrayIndexVars.size()); - while (const ConstantArrayType *Array - = S.Context.getAsConstantArrayType(BaseType)) { - // Create the iteration variable for this array index. - IdentifierInfo *IterationVarName = nullptr; - { - SmallString<8> Str; - llvm::raw_svector_ostream OS(Str); - OS << "__i" << IndexVariables.size(); - IterationVarName = &S.Context.Idents.get(OS.str()); - } - VarDecl *IterationVar - = VarDecl::Create(S.Context, S.CurContext, Loc, Loc, - IterationVarName, SizeType, - S.Context.getTrivialTypeSourceInfo(SizeType, Loc), - SC_None); - IndexVariables.push_back(IterationVar); - LSI->ArrayIndexVars.push_back(IterationVar); - - // Create a reference to the iteration variable. - ExprResult IterationVarRef - = S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc); - assert(!IterationVarRef.isInvalid() && - "Reference to invented variable cannot fail!"); - IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.get()); - assert(!IterationVarRef.isInvalid() && - "Conversion of invented variable cannot fail!"); - - // Subscript the array with this iteration variable. - ExprResult Subscript = S.CreateBuiltinArraySubscriptExpr( - Ref, Loc, IterationVarRef.get(), Loc); - if (Subscript.isInvalid()) { - S.CleanupVarDeclMarking(); - S.DiscardCleanupsInEvaluationContext(); - return ExprError(); - } - - Ref = Subscript.get(); - BaseType = Array->getElementType(); - } - - // Construct the entity that we will be initializing. For an array, this - // will be first element in the array, which may require several levels - // of array-subscript entities. - SmallVector Entities; - Entities.reserve(1 + IndexVariables.size()); - Entities.push_back( - 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, - Entities.back())); - - InitializationKind InitKind - = InitializationKind::CreateDirect(Loc, Loc, Loc); - InitializationSequence Init(S, Entities.back(), InitKind, Ref); - ExprResult Result(true); - if (!Init.Diagnose(S, Entities.back(), InitKind, Ref)) - Result = Init.Perform(S, Entities.back(), InitKind, Ref); - - // If this initialization requires any cleanups (e.g., due to a - // default argument to a copy constructor), note that for the - // lambda. - if (S.ExprNeedsCleanups) - LSI->ExprNeedsCleanups = true; - - // Exit the expression evaluation context used for the capture. - S.CleanupVarDeclMarking(); - S.DiscardCleanupsInEvaluationContext(); - return Result; + return new (S.Context) + DeclRefExpr(Var, RefersToCapturedVariable, DeclRefType, VK_LValue, Loc); + } @@ -12390,11 +12295,9 @@ // Capture this variable in the lambda. Expr *CopyExpr = nullptr; if (BuildAndDiagnose) { - ExprResult Result = addAsFieldToClosureType(S, LSI, Var, + CopyExpr = addAsFieldToClosureType(S, LSI, Var, CaptureType, DeclRefType, Loc, RefersToCapturedVariable); - if (!Result.isInvalid()) - CopyExpr = Result.get(); } // Compute the type of a reference to this captured variable. @@ -12414,7 +12317,8 @@ // Add the capture. if (BuildAndDiagnose) LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToCapturedVariable, - Loc, EllipsisLoc, CaptureType, CopyExpr); + Loc, EllipsisLoc, CaptureType, CopyExpr, + /*IsInitCapture*/false); return true; } Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -832,7 +832,7 @@ LSI->addCapture(Var, /*isBlock*/false, Var->getType()->isReferenceType(), /*isNested*/false, Var->getLocation(), SourceLocation(), - Var->getType(), Var->getInit()); + Var->getType(), Var->getInit(), /*IsInitCapture*/true); return Field; } @@ -1374,7 +1374,83 @@ Conversion->setImplicit(true); Class->addDecl(Conversion); } - + +static ExprResult performLambdaNonInitCaptureInitialization( + Sema &S, DeclRefExpr *const DRExpr, QualType FieldType, + const SourceLocation Loc, SmallVectorImpl &ArrayIndexVars, + SmallVectorImpl &ArrayIndexStarts) { + + VarDecl *const Var = dyn_cast(DRExpr->getDecl()); + assert(Var && "Each DeclREfExpr must refer to a variable!"); + if (!S.CurContext->isDependentContext()) + Var->markUsed(S.Context); + Expr *ExprRet = DRExpr; + // When the field has array type, create index variables for each dimension of + // the array. We use these index variables to subscript the source array, and + // other clients (e.g., CodeGen) will perform the necessary iteration with + // these index variables. + SmallVector IndexVariables; + QualType BaseType = FieldType; + QualType SizeType = S.Context.getSizeType(); + ArrayIndexStarts.push_back(ArrayIndexVars.size()); + while (const ConstantArrayType *Array = + S.Context.getAsConstantArrayType(BaseType)) { + // Create the iteration variable for this array index. + IdentifierInfo *IterationVarName = nullptr; + { + SmallString<8> Str; + llvm::raw_svector_ostream OS(Str); + OS << "__i" << IndexVariables.size(); + IterationVarName = &S.Context.Idents.get(OS.str()); + } + VarDecl *IterationVar = VarDecl::Create( + S.Context, S.CurContext, Loc, Loc, IterationVarName, SizeType, + S.Context.getTrivialTypeSourceInfo(SizeType, Loc), SC_None); + IndexVariables.push_back(IterationVar); + ArrayIndexVars.push_back(IterationVar); + + // Create a reference to the iteration variable. + ExprResult IterationVarRef = + S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc); + assert(!IterationVarRef.isInvalid() && + "Reference to invented variable cannot fail!"); + IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.get()); + assert(!IterationVarRef.isInvalid() && + "Conversion of invented variable cannot fail!"); + + // Subscript the array with this iteration variable. + ExprResult Subscript = + S.CreateBuiltinArraySubscriptExpr(DRExpr, Loc, IterationVarRef.get(), Loc); + if (Subscript.isInvalid()) { + S.CleanupVarDeclMarking(); + S.DiscardCleanupsInEvaluationContext(); + return ExprError(); + } + + ExprRet = Subscript.get(); + BaseType = Array->getElementType(); + } + // Construct the entity that we will be initializing. For an array, this will + // be first element in the array, which may require several levels of + // array-subscript entities. + SmallVector Entities; + Entities.reserve(1 + IndexVariables.size()); + Entities.push_back(InitializedEntity::InitializeLambdaCapture( + Var->getIdentifier(), FieldType, Loc)); + for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I) + Entities.push_back( + InitializedEntity::InitializeElement(S.Context, 0, Entities.back())); + + InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc); + InitializationSequence Init(S, Entities.back(), InitKind, ExprRet); + ExprResult Result(true); + + if (!Init.Diagnose(S, Entities.back(), InitKind, ExprRet)) + Result = Init.Perform(S, Entities.back(), InitKind, ExprRet); + + return Result; +} + ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Scope *CurScope, bool IsInstantiation) { @@ -1390,8 +1466,8 @@ bool ExplicitResultType; bool LambdaExprNeedsCleanups; bool ContainsUnexpandedParameterPack; - SmallVector ArrayIndexVars; - SmallVector ArrayIndexStarts; + SmallVector LSICaptures; + unsigned NumExplicitCaptures; { LambdaScopeInfo *LSI = getCurLambda(); CallOperator = LSI->CallOperator; @@ -1401,38 +1477,13 @@ ExplicitResultType = !LSI->HasImplicitReturnType; LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups; ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack; - ArrayIndexVars.swap(LSI->ArrayIndexVars); - ArrayIndexStarts.swap(LSI->ArrayIndexStarts); - - // Translate captures. - for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) { - LambdaScopeInfo::Capture From = LSI->Captures[I]; - assert(!From.isBlockCapture() && "Cannot capture __block variables"); - bool IsImplicit = I >= LSI->NumExplicitCaptures; + LSICaptures.swap(LSI->Captures); + NumExplicitCaptures = LSI->NumExplicitCaptures; - // Handle 'this' capture. - if (From.isThisCapture()) { - Captures.push_back( - LambdaCapture(From.getLocation(), IsImplicit, LCK_This)); - CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(), - getCurrentThisType(), - /*isImplicit=*/true)); - continue; - } - if (From.isVLATypeCapture()) { - Captures.push_back( - LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType)); - CaptureInits.push_back(nullptr); - continue; - } + assert((LSICaptures.size() == + SmallVector(Class->fields()).size()) && + "There should be a field for each capture (reference or value)"); - VarDecl *Var = From.getVariable(); - LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef; - Captures.push_back(LambdaCapture(From.getLocation(), IsImplicit, Kind, - Var, From.getEllipsisLoc())); - CaptureInits.push_back(From.getInitExpr()); - } - switch (LSI->ImpCaptureStyle) { case CapturingScopeInfo::ImpCap_None: CaptureDefault = LCD_None; @@ -1484,6 +1535,8 @@ // The lambda-expression's compound-statement yields the // function-body (8.4) of the function call operator [...]. ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation); + assert((!getCurLambda() || getCurLambda()->CallOperator != CallOperator) && + "ActOnFinishFunctionBody should pop the current LambdaScopeInfo"); CallOperator->setLexicalDeclContext(Class); Decl *TemplateOrNonTemplateCallOperatorDecl = CallOperator->getDescribedFunctionTemplate() @@ -1500,7 +1553,7 @@ // has a public non-virtual non-explicit const conversion function // to pointer to function having the same parameter and return // types as the closure type's function call operator. - if (Captures.empty() && CaptureDefault == LCD_None) + if (LSICaptures.empty() && CaptureDefault == LCD_None) addFunctionPointerConversion(*this, IntroducerRange, Class, CallOperator); @@ -1520,7 +1573,66 @@ SourceLocation(), nullptr); CheckCompletedCXXClass(Class); } + // Now that the Lambda's call operator's context has been popped off, process + // any analysis or conversion's required for initializing captures by copy or + // by reference within the enclosing context. This ensures that any functions + // required during the initialization (such as copy contructors of base + // classes...) are marked as used depending on the enclosing context of the + // lambda and not the context of the lambda's call operator (which for a + // generic lambda is a dependent context, and thus would fail to trigger use). + // Variables used to index into by-copy array captures. + SmallVector ArrayIndexVars; + + // ArrayIndexStarts contains offsets into the ArrayIndexVars array at which + // each capture starts its list of array index variables. For each capture, + // ArrayIndexStarts, stores the number of index variables created prior to it. + // Thus, for each capture that is an array, by computing the difference + // between its corresponding entry into ArrayIndexStarts and the entry + // following it, we can determine the number of indexed variables required for + // the array capture initialization. + SmallVector ArrayIndexStarts; + + // C++ [expr.prim.labda]p12: An entity captured by a lambda-expression is + // odr-used (3.2) in the scope containing the lambda-expression. + for (unsigned I = 0, N = LSICaptures.size(); I != N; ++I) { + LambdaScopeInfo::Capture From = LSICaptures[I]; + assert(!From.isBlockCapture() && "Cannot capture __block variables"); + bool IsImplicit = I >= NumExplicitCaptures; + + // Handle 'this' capture. + if (From.isThisCapture()) { + Captures.push_back( + LambdaCapture(From.getLocation(), IsImplicit, LCK_This)); + CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(), + getCurrentThisType(), + /*isImplicit=*/true)); + ArrayIndexStarts.push_back(ArrayIndexVars.size()); + continue; + } + if (From.isVLATypeCapture()) { + Captures.push_back( + LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType)); + CaptureInits.push_back(nullptr); + ArrayIndexStarts.push_back(ArrayIndexVars.size()); + continue; + } + + VarDecl *Var = From.getVariable(); + LambdaCaptureKind Kind = From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef; + Captures.push_back(LambdaCapture(From.getLocation(), IsImplicit, Kind, Var, + From.getEllipsisLoc())); + Expr *InitE = From.getInitExpr(); + if (!From.isInitCapture() && dyn_cast_or_null(InitE)) { + DeclRefExpr *InitDRE = cast(InitE); + ExprResult ER = performLambdaNonInitCaptureInitialization( + *this, InitDRE, From.getCaptureType(), From.getLocation(), + ArrayIndexVars, ArrayIndexStarts); + InitE = ER.isInvalid() ? nullptr : ER.get(); + } + CaptureInits.push_back(InitE); + } + if (LambdaExprNeedsCleanups) ExprNeedsCleanups = true; Index: test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp =================================================================== --- test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp +++ test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp @@ -24,7 +24,6 @@ struct Boom { Boom(const Boom&) { T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} \ - // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}} \ // expected-error{{cannot initialize a variable of type 'double *' with an rvalue of type 'int'}} } void tickle() const; @@ -35,8 +34,7 @@ const std::type_info &ti1 = typeid([=,&p]() -> P& { boom_int.tickle(); return p; }()); // expected-note{{in instantiation of member function 'Boom::Boom' requested here}} const std::type_info &ti2 - = typeid([=]() -> int { boom_float.tickle(); return 0; }()); // expected-error{{lambda expression in an unevaluated operand}} \ - // expected-note{{in instantiation of member function 'Boom::Boom' requested here}} + = typeid([=]() -> int { boom_float.tickle(); return 0; }()); // expected-error{{lambda expression in an unevaluated operand}} auto foo = [=]() -> int { boom_double.tickle(); return 0; }; // expected-note{{in instantiation of member function 'Boom::Boom' requested here}} } Index: test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp =================================================================== --- test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp +++ test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp @@ -69,8 +69,7 @@ template struct Boom { Boom(const Boom&) { - T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} \ - // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}} + T* x = 1; // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}} } void tickle() const; }; @@ -79,7 +78,7 @@ void odr_used(R &r, Boom boom) { const std::type_info &ti = typeid([=,&r] () -> R& { // expected-error{{lambda expression in an unevaluated operand}} - boom.tickle(); // expected-note{{in instantiation of member function}} + boom.tickle(); return r; }()); } Index: test/SemaCXX/cxx1y-generic-lambdas-pr20619.cpp =================================================================== --- test/SemaCXX/cxx1y-generic-lambdas-pr20619.cpp +++ test/SemaCXX/cxx1y-generic-lambdas-pr20619.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks -emit-llvm-only %s +// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS +// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING + +//expected-no-diagnostics + +namespace PR20619_capturing_class_variables_within_generic_lambdas { +// http://llvm.org/bugs/show_bug.cgi?id=20619 +namespace ns1 { +int g; +struct A { }; +struct B : virtual A { int get() const { return g; } }; +void foo0() { + B x; + auto L = [x=x](auto) { }; +} + +void foo() { + B x; + B arrX[100]; + auto L = [x, arrX](auto) { }; + (void) [=](auto) { return arrX[0].get() + x.get(); }; +} + +} // end ns1 + +namespace ns2 { + +struct A { A(A &); }; +struct B : A { B(int); }; + +void foo2() { + B x{0}; + (void)[x](auto) { }; +} +} //end ns2 + + +void bar() { + struct S { + int m = 0; + auto foo(int i) { + int x[10] = { 1, 2, 3, 4 }; + int v[i]; + v[i-1] = i; + return [=,&v](auto n) { return v[n] + x[n] + m; }; + } + }; + S s; + int x1 = s.foo(1)(1); + int x2 = s.foo(2)(2); +} + +} // end PR20619_capturing_class_variables_within_generic_lambdas