Index: include/clang/Sema/ScopeInfo.h =================================================================== --- include/clang/Sema/ScopeInfo.h +++ include/clang/Sema/ScopeInfo.h @@ -675,11 +675,14 @@ SourceLocation PotentialThisCaptureLocation; + bool IsInitializingExplicitOrImplicitCapture; + LambdaScopeInfo(DiagnosticsEngine &Diag) : CapturingScopeInfo(Diag, ImpCap_None), Lambda(nullptr), CallOperator(nullptr), NumExplicitCaptures(0), Mutable(false), ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false), - AutoTemplateParameterDepth(0), GLTemplateParameterList(nullptr) + AutoTemplateParameterDepth(0), GLTemplateParameterList(nullptr), + IsInitializingExplicitOrImplicitCapture(false) { Kind = SK_Lambda; } Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -11394,20 +11394,42 @@ Func->setReferenced(); - // C++11 [basic.def.odr]p3: - // A function whose name appears as a potentially-evaluated expression is - // odr-used if it is the unique lookup result or the selected member of a - // set of overloaded functions [...]. + // We need to identify copy initializations of explicit or implicit captures + // of generic lambdas since even if the current context is dependent (i.e. the + // generic lambda's member function template call operator has been pushed on + // the declcontext stack) we still need to mark these copy constructors + // as used if the context surrounding the generic lambda is non-dependent + // since the initialization of the data members of the closure type (which is + // a non-dependent context, if the surrounding context is non-dependent) must + // occur. + const bool IsInitializingExplicitOrImplicitByValCaptureOfGenericLambda = + ([](FunctionDecl *Func, Sema &S) { + if (auto *GenericLSI = S.getCurGenericLambda()) { + auto *GenericCallOp = GenericLSI->CallOperator; + return GenericLSI->IsInitializingExplicitOrImplicitCapture && + !getLambdaAwareParentOfDeclContext(GenericCallOp) + ->isDependentContext() && + isa(Func) && + cast(Func)->isCopyConstructor(); + } + return false; + }(Func, *this)); + + // C++11 [basic.def.odr]p3: A function whose name appears as a + // potentially-evaluated expression is odr-used if it is the unique lookup + // result or the selected member of a set of overloaded functions [...]. // // We (incorrectly) mark overload resolution as an unevaluated context, so we // can just check that here. Skip the rest of this function if we've already // marked the function as used. - if (Func->isUsed(false) || !IsPotentiallyEvaluatedContext(*this)) { - // C++11 [temp.inst]p3: - // Unless a function template specialization has been explicitly - // instantiated or explicitly specialized, the function template - // specialization is implicitly instantiated when the specialization is - // referenced in a context that requires a function definition to exist. + if (Func->isUsed(false) || + (!IsPotentiallyEvaluatedContext(*this) && + !IsInitializingExplicitOrImplicitByValCaptureOfGenericLambda)) { + // C++11 [temp.inst]p3: Unless a function template specialization has been + // explicitly instantiated or explicitly specialized, the function + // template specialization is implicitly instantiated when the + // specialization is referenced in a context that requires a function + // definition to exist. // // We consider constexpr function templates to be referenced in a context // that requires a definition to exist whenever they are referenced. @@ -11922,7 +11944,13 @@ IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.get()); assert(!IterationVarRef.isInvalid() && "Conversion of invented variable cannot fail!"); - + + // If we are capturing within a generic lambda and the enclosing context is + // not dependent, mark the iteration-var as used. + if (!IterationVar->isUsed(false) && S.getCurGenericLambda() && + !Lambda->getDeclContext()->isDependentContext()) + IterationVar->markUsed(S.Context); + // Subscript the array with this iteration variable. ExprResult Subscript = S.CreateBuiltinArraySubscriptExpr( Ref, Loc, IterationVarRef.get(), Loc); @@ -11935,7 +11963,27 @@ Ref = Subscript.get(); BaseType = Array->getElementType(); } + // We need to mark within the current lambda scope info that we will be + // copy-initializing a byvalue capture. This is necessary because for generic + // lambdas even though the current DeclContext (the generic lambda's call + // operator template) is dependent, any constructors that are referenced need + // to be marked as used since the initialization occurs within the enclosing + // closure object which is non-dependent if the enclosing ctx is. + // We can not move the initialization prior to the pushing of the generic + // lambda's call operator since we don't know which implicit captures to make + // unless we are processing the call operator's body. + struct ScopeGuardForMarkingByValCaptureInitialization { + LambdaScopeInfo *const CurLSI; + ScopeGuardForMarkingByValCaptureInitialization(LambdaScopeInfo *LSI) + : CurLSI(LSI) { + CurLSI->IsInitializingExplicitOrImplicitCapture = true; + } + ~ScopeGuardForMarkingByValCaptureInitialization() { + CurLSI->IsInitializingExplicitOrImplicitCapture = false; + } + } RAIIMarkByValCaptureInitializationInLambdaScopeInfo(LSI); + // 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. 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,35 @@ +// 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 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 + + +} // end PR20619_capturing_class_variables_within_generic_lambdas