Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -8684,6 +8684,8 @@ /// template substitution or instantiation. Scope *getCurScope() const { return CurScope; } + void setCurScope(Scope *S) { CurScope = S; } + void incrementMSLocalManglingNumber() const { return CurScope->incrementMSLocalManglingNumber(); } Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -15,6 +15,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/ASTLambda.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" @@ -1169,10 +1170,22 @@ if (FunctionScopes.empty()) return nullptr; - auto CurLSI = dyn_cast(FunctionScopes.back()); - if (CurLSI && CurLSI->Lambda && - !CurLSI->Lambda->Encloses(CurContext)) { - // We have switched contexts due to template instantiation. + auto *CurLSI = dyn_cast(FunctionScopes.back()); + if (CurLSI && CurLSI->Lambda && !CurLSI->Lambda->Encloses(CurContext)) { + // We might have temporarily jumped out to an enclosing lambda's context + // when initializing explicit or implicit captures of that lambda. Check if + // that enclosing context is a lambda, and if so return its corresponding + // LambdaScopeInfo. + if (CurContext->Encloses(CurLSI->Lambda)) { + if (!isLambdaCallOperator(CurContext)) + return nullptr; + for (FunctionScopeInfo *FSI : FunctionScopes) { + if (auto *LSI = dyn_cast(FSI)) + if (LSI->CallOperator == CurContext) + return LSI; + } + } + // ... Or we have switched contexts due to template instantiation assert(!ActiveTemplateInstantiations.empty()); return nullptr; } @@ -1179,8 +1192,8 @@ return CurLSI; } -// We have a generic lambda if we parsed auto parameters, or we have -// an associated template parameter list. +// We have a generic lambda if we parsed auto parameters, or we have an +// associated template parameter list. LambdaScopeInfo *Sema::getCurGenericLambda() { if (LambdaScopeInfo *LSI = getCurLambda()) { return (LSI->AutoTemplateParams.size() || Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -12079,7 +12079,17 @@ 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) && + LSI->CallOperator->isDependentContext() && + !Lambda->getDeclContext()->isDependentContext()) { + assert(S.getCurGenericLambda() && + "How can this occur if the lambda is not generic!"); + IterationVar->markUsed(S.Context); + } + // Subscript the array with this iteration variable. ExprResult Subscript = S.CreateBuiltinArraySubscriptExpr( Ref, Loc, IterationVarRef.get(), Loc); @@ -12093,9 +12103,40 @@ 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. + // Before performing the initialization of the capture, temporarily jump out + // to the capturing LambdaScopeInfo's enclosing context (this is not + // necessarily the CurContext's lambda's enclosing context, since when + // processing implicit captures, we might have to capture in enclosing + // lambdas, while processing inner lambdas) since the initialization of the + // capture has to occur within the enclosing context - this can have + // consequences on what gets marked odr-used depending on whether the + // enclosing context is dependent or not. 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 TemporarilyJumpOutToDeclContextScopeGuard { + Sema &S; + Scope *CurScope; + DeclContext *CurContext; + TemporarilyJumpOutToDeclContextScopeGuard(Sema &S, LambdaScopeInfo *LSI) + : S(S), CurScope(S.getCurScope()), CurContext(S.CurContext) { + S.CurContext = LSI->Lambda->getDeclContext(); + // FVQUESTION: Do we really need to mess with the Scope - or can I just + // ignore it since, unless I am entirely mistake, its raison d'ĂȘtre seems + // to be to aid the Parser, which will not be invoked from the ensuing + // sequence? + S.setCurScope(S.getScopeForContext(S.CurContext)); + } + ~TemporarilyJumpOutToDeclContextScopeGuard() { + S.CurContext = CurContext; + S.setCurScope(CurScope); + } + } DeclContextScopeGuard(S, 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. SmallVector Entities; Entities.reserve(1 + IndexVariables.size()); Entities.push_back( @@ -12110,6 +12151,9 @@ = InitializationKind::CreateDirect(Loc, Loc, Loc); InitializationSequence Init(S, Entities.back(), InitKind, Ref); ExprResult Result(true); + // The Initialization should occur in the lambda's enclosing context - this + // ensures that variables get marked as used even if the current lambda's + // declaration context is dependent - but the enclosing context is not. if (!Init.Diagnose(S, Entities.back(), InitKind, Ref)) Result = Init.Perform(S, Entities.back(), InitKind, Ref); 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