Index: cfe/trunk/include/clang/Basic/DiagnosticGroups.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td @@ -348,12 +348,14 @@ def ShadowFieldInConstructor : DiagGroup<"shadow-field-in-constructor", [ShadowFieldInConstructorModified]>; def ShadowIvar : DiagGroup<"shadow-ivar">; +def ShadowUncapturedLocal : DiagGroup<"shadow-uncaptured-local">; // -Wshadow-all is a catch-all for all shadowing. -Wshadow is just the // shadowing that we think is unsafe. def Shadow : DiagGroup<"shadow", [ShadowFieldInConstructorModified, ShadowIvar]>; -def ShadowAll : DiagGroup<"shadow-all", [Shadow, ShadowFieldInConstructor]>; +def ShadowAll : DiagGroup<"shadow-all", [Shadow, ShadowFieldInConstructor, + ShadowUncapturedLocal]>; def Shorten64To32 : DiagGroup<"shorten-64-to-32">; def : DiagGroup<"sign-promo">; Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -357,6 +357,9 @@ "static data member of %2|" "field of %2}1">, InGroup, DefaultIgnore; +def warn_decl_shadow_uncaptured_local : + Warning, + InGroup, DefaultIgnore; def warn_ctor_parm_shadows_field: Warning<"constructor parameter %0 shadows the field %1 of %2">, InGroup, DefaultIgnore; @@ -6230,6 +6233,8 @@ def note_lambda_to_block_conv : Note< "implicit capture of lambda object due to conversion to block pointer " "here">; + def note_var_explicitly_captured_here : Note<"variable %0 is explicitly " + "captured here">; // C++14 lambda init-captures. def warn_cxx11_compat_init_capture : Warning< Index: cfe/trunk/lib/Sema/SemaDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -6582,6 +6582,17 @@ return OldDC->isFileContext() ? SDK_Global : SDK_Local; } +/// Return the location of the capture if the given lambda captures the given +/// variable \p VD, or an invalid source location otherwise. +static SourceLocation getCaptureLocation(const LambdaScopeInfo *LSI, + const VarDecl *VD) { + for (const LambdaScopeInfo::Capture &Capture : LSI->Captures) { + if (Capture.isVariableCapture() && Capture.getVariable() == VD) + return Capture.getLocation(); + } + return SourceLocation(); +} + /// \brief Diagnose variable or built-in function shadowing. Implements /// -Wshadow. /// @@ -6640,6 +6651,22 @@ DeclContext *OldDC = ShadowedDecl->getDeclContext(); + unsigned WarningDiag = diag::warn_decl_shadow; + SourceLocation CaptureLoc; + if (isa(ShadowedDecl) && NewDC && isa(NewDC)) { + if (const auto *RD = dyn_cast(NewDC->getParent())) { + // Try to avoid warnings for lambdas with an explicit capture list. + if (RD->isLambda() && OldDC->Encloses(NewDC->getLexicalParent()) && + RD->getLambdaCaptureDefault() == LCD_None) { + const auto *LSI = cast(getCurFunction()); + // Warn only when the lambda captures the shadowed decl explicitly. + CaptureLoc = getCaptureLocation(LSI, cast(ShadowedDecl)); + if (CaptureLoc.isInvalid()) + WarningDiag = diag::warn_decl_shadow_uncaptured_local; + } + } + } + // Only warn about certain kinds of shadowing for class members. if (NewDC && NewDC->isRecord()) { // In particular, don't warn about shadowing non-class members. @@ -6661,7 +6688,9 @@ if (getSourceManager().isInSystemMacro(R.getNameLoc())) return; ShadowedDeclKind Kind = computeShadowedDeclKind(ShadowedDecl, OldDC); - Diag(R.getNameLoc(), diag::warn_decl_shadow) << Name << Kind << OldDC; + Diag(R.getNameLoc(), WarningDiag) << Name << Kind << OldDC; + if (!CaptureLoc.isInvalid()) + Diag(CaptureLoc, diag::note_var_explicitly_captured_here) << Name; Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); } Index: cfe/trunk/test/SemaCXX/warn-shadow-in-lambdas.cpp =================================================================== --- cfe/trunk/test/SemaCXX/warn-shadow-in-lambdas.cpp +++ cfe/trunk/test/SemaCXX/warn-shadow-in-lambdas.cpp @@ -0,0 +1,91 @@ +// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -D AVOID %s +// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -Wshadow-uncaptured-local %s +// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow-all %s + +void foo(int param) { // expected-note 1+ {{previous declaration is here}} + int var = 0; // expected-note 1+ {{previous declaration is here}} + + // Warn for lambdas with a default capture specifier. + { + auto f1 = [=] { int var = 1; }; // expected-warning {{declaration shadows a local variable}} + auto f2 = [&] { int var = 2; }; // expected-warning {{declaration shadows a local variable}} + auto f3 = [=] (int param) { ; }; // expected-warning {{declaration shadows a local variable}} + auto f4 = [&] (int param) { ; }; // expected-warning {{declaration shadows a local variable}} + } + + // Warn normally inside of lambdas. + auto l1 = [] { // expected-note {{previous declaration is here}} + int x = 1; // expected-note {{previous declaration is here}} + { int x = 2; } // expected-warning {{declaration shadows a local variable}} + }; + auto l2 = [] (int x) { // expected-note {{previous declaration is here}} + { int x = 1; } // expected-warning {{declaration shadows a local variable}} + }; + + // Avoid warnings for variables that aren't explicitly captured. + { +#ifdef AVOID + auto f1 = [] { int var = 1; }; // no warning + auto f2 = [] (int param) { ; }; // no warning + auto f3 = [param] () { int var = 1; }; // no warning + auto f4 = [var] (int param) { ; }; // no warning +#else + auto f1 = [] { int var = 1; }; // expected-warning {{declaration shadows a local variable}} + auto f2 = [] (int param) { ; }; // expected-warning {{declaration shadows a local variable}} + auto f3 = [param] () { int var = 1; }; // expected-warning {{declaration shadows a local variable}} + auto f4 = [var] (int param) { ; }; // expected-warning {{declaration shadows a local variable}} +#endif + }; + + // Warn for variables that are explicitly captured. + { + auto f1 = [var] () { // expected-note {{variable 'var' is explicitly captured here}} + int var = 1; // expected-warning {{declaration shadows a local variable}} + }; + auto f2 = [param] // expected-note {{variable 'param' is explicitly captured here}} + (int param) { ; }; // expected-warning {{declaration shadows a local variable}} + } + + // Warn for variables defined in the capture list. + auto l3 = [z = var] { // expected-note {{previous declaration is here}} +#ifdef AVOID + int var = 1; // no warning +#else + int var = 1; // expected-warning {{declaration shadows a local variable}} +#endif + { int z = 1; } // expected-warning {{declaration shadows a local variable}} + }; +#ifdef AVOID + auto l4 = [var = param] (int param) { ; }; // no warning +#else + auto l4 = [var = param] (int param) { ; }; // expected-warning {{declaration shadows a local variable}} +#endif + + // Make sure that inner lambdas work as well. + auto l5 = [var, l1] { // expected-note {{variable 'l1' is explicitly captured here}} + auto l1 = [] { // expected-warning {{declaration shadows a local variable}} +#ifdef AVOID + int var = 1; // no warning +#else + int var = 1; // expected-warning {{declaration shadows a local variable}} +#endif + }; +#ifdef AVOID + auto f1 = [] { int var = 1; }; // no warning +#else + auto f1 = [] { int var = 1; }; // expected-warning {{declaration shadows a local variable}} +#endif + auto f2 = [=] { int var = 1; }; // expected-warning {{declaration shadows a local variable}} + auto f3 = [var] // expected-note {{variable 'var' is explicitly captured here}} + { int var = 1; }; // expected-warning {{declaration shadows a local variable}} + }; + + // Generic lambda arguments should work. +#ifdef AVOID + auto g1 = [](auto param) { ; }; // no warning +#else + auto g1 = [](auto param) { ; }; // expected-warning {{declaration shadows a local variable}} +#endif + auto g2 = [param] // expected-note {{variable 'param' is explicitly captured here}} + (auto param) { ; }; // expected-warning {{declaration shadows a local variable}} +}