Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1765,6 +1765,10 @@ "the function it overrides (class type %1 is more qualified than class " "type %2">; +// C++ lambdas +def note_implicitly_capturing_var_first_used_here : Note< + "implicitly capturing %0, first used here">; + // C++ implicit special member functions def note_in_declaration_of_implicit_special_member : Note< "while declaring the implicit %sub{select_special_member_kind}1" Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -7178,7 +7178,10 @@ /// Memoization means we are _not_ instantiating a template because /// it is already instantiated (but we entered a context where we /// would have had to if it was not already instantiated). - Memoization + Memoization, + + /// We are initializing an implicit capture for a lambda. + ImplicitLambdaCaptureInitialization, } Kind; /// Was the enclosing context a non-instantiation SFINAE context? Index: clang/lib/Frontend/FrontendActions.cpp =================================================================== --- clang/lib/Frontend/FrontendActions.cpp +++ clang/lib/Frontend/FrontendActions.cpp @@ -351,6 +351,8 @@ return "DefiningSynthesizedFunction"; case CodeSynthesisContext::Memoization: return "Memoization"; + case CodeSynthesisContext::ImplicitLambdaCaptureInitialization: + return "ImplicitLambdaCaptureInitialization"; } return ""; } Index: clang/lib/Sema/SemaLambda.cpp =================================================================== --- clang/lib/Sema/SemaLambda.cpp +++ clang/lib/Sema/SemaLambda.cpp @@ -21,6 +21,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaLambda.h" +#include "llvm/ADT/ScopeExit.h" using namespace clang; using namespace sema; @@ -1401,6 +1402,18 @@ SourceLocation Loc = IsImplicitCapture ? ImplicitCaptureLoc : Capture.getLocation(); + if (IsImplicitCapture) { + Sema::CodeSynthesisContext Ctx; + Ctx.Entity = Var; + Ctx.Kind = Sema::CodeSynthesisContext::ImplicitLambdaCaptureInitialization; + Ctx.PointOfInstantiation = Capture.getLocation(); + S.pushCodeSynthesisContext(Ctx); + } + auto PopCodeSynthesisStackOnExit = llvm::make_scope_exit([&] { + if (IsImplicitCapture) + S.popCodeSynthesisContext(); + }); + // 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 Index: clang/lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiate.cpp +++ clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -200,6 +200,7 @@ case DeclaringSpecialMember: case DefiningSynthesizedFunction: case ExceptionSpecEvaluation: + case ImplicitLambdaCaptureInitialization: return false; // This function should never be called when Kind's value is Memoization. @@ -653,6 +654,13 @@ break; } + case CodeSynthesisContext::ImplicitLambdaCaptureInitialization: { + Diags.Report(Active->PointOfInstantiation, + diag::note_implicitly_capturing_var_first_used_here) + << cast(Active->Entity); + break; + } + case CodeSynthesisContext::Memoization: break; } @@ -698,6 +706,7 @@ case CodeSynthesisContext::DeclaringSpecialMember: case CodeSynthesisContext::DefiningSynthesizedFunction: + case CodeSynthesisContext::ImplicitLambdaCaptureInitialization: // This happens in a context unrelated to template instantiation, so // there is no SFINAE. return None; Index: clang/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp =================================================================== --- clang/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp +++ clang/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp @@ -16,7 +16,7 @@ void capture_by_copy(NonCopyable nc, NonCopyable &ncr, const NonConstCopy nco) { (void)[nc] { }; // expected-error{{capture of variable 'nc' as type 'NonCopyable' calls private copy constructor}} (void)[=] { // expected-error{{capture of variable 'ncr' as type 'NonCopyable' calls private copy constructor}} - ncr.foo(); + ncr.foo(); // expected-note{{implicitly capturing 'ncr', first used here}} }(); [nco] {}(); // expected-error{{no matching constructor for initialization of 'const NonConstCopy'}} Index: clang/test/SemaCXX/lambda-expressions.cpp =================================================================== --- clang/test/SemaCXX/lambda-expressions.cpp +++ clang/test/SemaCXX/lambda-expressions.cpp @@ -77,8 +77,18 @@ struct G { G(); G(G&); int a; }; // expected-note 6 {{not viable}} G g; [=]() { const G* gg = &g; return gg->a; }; - [=]() { return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error {{no matching constructor for initialization of 'G'}} - (void)^{ return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error 2 {{no matching constructor for initialization of 'const G'}} + [=]() { + return [=]{ // expected-error {{no matching constructor for initialization of 'G'}} + const G* gg = &g; // expected-note {{implicitly capturing 'g', first used here}} + return gg->a; + }(); + }; + (void)^{ + return [=]{ // expected-error {{no matching constructor for initialization of 'const G'}} + const G* gg = &g; // expected-error {{no matching constructor for initialization of 'const G'}} expected-note {{implicitly capturing 'g', first used here}} + return gg->a; + }(); + }; const int h = a; // expected-note {{declared}} []() { return h; }; // expected-error {{variable 'h' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}} @@ -378,7 +388,9 @@ namespace PR18473 { template void f() { T t(0); - (void) [=]{ int n = t; }; // expected-error {{deleted}} + (void)[=] { // expected-error {{call to deleted constructor of 'PR18473::NoCopy'}} + int n = t; // expected-note {{implicitly capturing 't', first used here}} + }; } template void f();