diff options
| author | Alex Lorenz <arphaman@gmail.com> | 2016-11-10 16:19:11 +0000 |
|---|---|---|
| committer | Alex Lorenz <arphaman@gmail.com> | 2016-11-10 16:19:11 +0000 |
| commit | d60bb2830797460acc7d061d1f81eddf22d7b857 (patch) | |
| tree | 3e563225d7ac41768cd976205804f49ad25a3f66 | |
| parent | 115a61560e24e08ecca0b3e2d16e8f1491b47f61 (diff) | |
| download | bcm5719-llvm-d60bb2830797460acc7d061d1f81eddf22d7b857.tar.gz bcm5719-llvm-d60bb2830797460acc7d061d1f81eddf22d7b857.zip | |
[Sema] Avoid -Wshadow warnings for shadowed variables that
aren't captured by lambdas with a default capture specifier
This commit is a follow-up to r286354. It avoids the -Wshadow warning for
variables which shadow variables that aren't captured by lambdas with a default
capture specifier. It provides an additional note that points to location of
the capture.
The old behaviour is preserved with -Wshadow-all or -Wshadow-uncaptured-local.
rdar://14984176
Differential Revision: https://reviews.llvm.org/D26448
llvm-svn: 286465
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 | ||||
| -rw-r--r-- | clang/include/clang/Sema/ScopeInfo.h | 11 | ||||
| -rw-r--r-- | clang/include/clang/Sema/Sema.h | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 46 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaLambda.cpp | 3 | ||||
| -rw-r--r-- | clang/test/SemaCXX/warn-shadow-in-lambdas.cpp | 54 |
6 files changed, 105 insertions, 15 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 0ff1a6fbe66..db8bda5265d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6233,8 +6233,8 @@ let CategoryName = "Lambda Issue" in { 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">; + def note_var_explicitly_captured_here : Note<"variable %0 is" + "%select{| explicitly}1 captured here">; // C++14 lambda init-captures. def warn_cxx11_compat_init_capture : Warning< diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h index b4e09fac229..4b54807ab66 100644 --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -735,7 +735,16 @@ public: /// to local variables that are usable as constant expressions and /// do not involve an odr-use (they may still need to be captured /// if the enclosing full-expression is instantiation dependent). - llvm::SmallSet<Expr*, 8> NonODRUsedCapturingExprs; + llvm::SmallSet<Expr *, 8> NonODRUsedCapturingExprs; + + /// Contains all of the variables defined in this lambda that shadow variables + /// that were defined in parent contexts. Used to avoid warnings when the + /// shadowed variables are uncaptured by this lambda. + struct ShadowedOuterDecl { + const VarDecl *VD; + const VarDecl *ShadowedDecl; + }; + llvm::SmallVector<ShadowedOuterDecl, 4> ShadowingDecls; SourceLocation PotentialThisCaptureLocation; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 6c1059c05cd..2f4befc8b71 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1716,6 +1716,8 @@ public: /// to a shadowing declaration. void CheckShadowingDeclModification(Expr *E, SourceLocation Loc); + void DiagnoseShadowingLambdaDecls(const sema::LambdaScopeInfo *LSI); + private: /// Map of current shadowing declarations to shadowed declarations. Warn if /// it looks like the user is trying to modify the shadowing declaration. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 1859b7f0116..662d19aa8c2 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6655,14 +6655,21 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { SourceLocation CaptureLoc; if (isa<VarDecl>(ShadowedDecl) && NewDC && isa<CXXMethodDecl>(NewDC)) { if (const auto *RD = dyn_cast<CXXRecordDecl>(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<LambdaScopeInfo>(getCurFunction()); - // Warn only when the lambda captures the shadowed decl explicitly. - CaptureLoc = getCaptureLocation(LSI, cast<VarDecl>(ShadowedDecl)); - if (CaptureLoc.isInvalid()) - WarningDiag = diag::warn_decl_shadow_uncaptured_local; + if (RD->isLambda() && OldDC->Encloses(NewDC->getLexicalParent())) { + if (RD->getLambdaCaptureDefault() == LCD_None) { + // Try to avoid warnings for lambdas with an explicit capture list. + const auto *LSI = cast<LambdaScopeInfo>(getCurFunction()); + // Warn only when the lambda captures the shadowed decl explicitly. + CaptureLoc = getCaptureLocation(LSI, cast<VarDecl>(ShadowedDecl)); + if (CaptureLoc.isInvalid()) + WarningDiag = diag::warn_decl_shadow_uncaptured_local; + } else { + // Remember that this was shadowed so we can avoid the warning if the + // shadowed decl isn't captured and the warning settings allow it. + cast<LambdaScopeInfo>(getCurFunction()) + ->ShadowingDecls.push_back({D, cast<VarDecl>(ShadowedDecl)}); + return; + } } } } @@ -6690,10 +6697,31 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { ShadowedDeclKind Kind = computeShadowedDeclKind(ShadowedDecl, OldDC); Diag(R.getNameLoc(), WarningDiag) << Name << Kind << OldDC; if (!CaptureLoc.isInvalid()) - Diag(CaptureLoc, diag::note_var_explicitly_captured_here) << Name; + Diag(CaptureLoc, diag::note_var_explicitly_captured_here) + << Name << /*explicitly*/ 1; Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); } +/// Diagnose shadowing for variables shadowed in the lambda record \p LambdaRD +/// when these variables are captured by the lambda. +void Sema::DiagnoseShadowingLambdaDecls(const LambdaScopeInfo *LSI) { + for (const auto &Shadow : LSI->ShadowingDecls) { + const VarDecl *ShadowedDecl = Shadow.ShadowedDecl; + // Try to avoid the warning when the shadowed decl isn't captured. + SourceLocation CaptureLoc = getCaptureLocation(LSI, ShadowedDecl); + const DeclContext *OldDC = ShadowedDecl->getDeclContext(); + Diag(Shadow.VD->getLocation(), CaptureLoc.isInvalid() + ? diag::warn_decl_shadow_uncaptured_local + : diag::warn_decl_shadow) + << Shadow.VD->getDeclName() + << computeShadowedDeclKind(ShadowedDecl, OldDC) << OldDC; + if (!CaptureLoc.isInvalid()) + Diag(CaptureLoc, diag::note_var_explicitly_captured_here) + << Shadow.VD->getDeclName() << /*explicitly*/ 0; + Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); + } +} + /// \brief Check -Wshadow without the advantage of a previous lookup. void Sema::CheckShadow(Scope *S, VarDecl *D) { if (Diags.isIgnored(diag::warn_decl_shadow, D->getLocation())) diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 9be8fe51887..da4ba8b2a26 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -1620,6 +1620,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, CheckConstexprFunctionBody(CallOperator, CallOperator->getBody())); } + // Emit delayed shadowing warnings now that the full capture list is known. + DiagnoseShadowingLambdaDecls(LSI); + if (!CurContext->isDependentContext()) { switch (ExprEvalContexts.back().Context) { // C++11 [expr.prim.lambda]p2: diff --git a/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp b/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp index 24f1a34de11..575664482db 100644 --- a/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp +++ b/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp @@ -5,12 +5,48 @@ 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. + // Avoid warnings for variables that aren't implicitly captured. { +#ifdef AVOID + auto f1 = [=] { int var = 1; }; // no warning + auto f2 = [&] { int var = 2; }; // no warning + auto f3 = [=] (int param) { ; }; // no warning + auto f4 = [&] (int param) { ; }; // no warning +#else 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}} +#endif + } + + // Warn for variables that are implicitly captured. + { + auto f1 = [=] () { + { + int var = 1; // expected-warning {{declaration shadows a local variable}} + } + int x = var; // expected-note {{variable 'var' is captured here}} + }; + auto f2 = [&] +#ifdef AVOID + (int param) { +#else + (int param) { // expected-warning {{declaration shadows a local variable}} +#endif + int x = var; // expected-note {{variable 'var' is captured here}} + int var = param; // expected-warning {{declaration shadows a local variable}} + }; + } + + // Warn for variables that are explicitly captured when a lambda has a default + // capture specifier. + { + auto f1 = [=, &var] () { // expected-note {{variable 'var' is captured here}} + int x = param; // expected-note {{variable 'param' is captured here}} + int var = 0; // expected-warning {{declaration shadows a local variable}} + int param = 0; // expected-warning {{declaration shadows a local variable}} + }; } // Warn normally inside of lambdas. @@ -72,20 +108,32 @@ void foo(int param) { // expected-note 1+ {{previous declaration is here}} }; #ifdef AVOID auto f1 = [] { int var = 1; }; // no warning + auto f2 = [=] { 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}} +#endif auto f3 = [var] // expected-note {{variable 'var' is explicitly captured here}} { int var = 1; }; // expected-warning {{declaration shadows a local variable}} + auto f4 = [&] { + int x = var; // expected-note {{variable 'var' is captured here}} + int var = 2; // expected-warning {{declaration shadows a local variable}} + }; + }; + auto l6 = [&] { + auto f1 = [param] { // expected-note {{variable 'param' is explicitly captured here}} + int param = 0; // expected-warning {{declaration shadows a local variable}} + }; }; // Generic lambda arguments should work. #ifdef AVOID auto g1 = [](auto param) { ; }; // no warning + auto g2 = [=](auto param) { ; }; // no warning #else auto g1 = [](auto param) { ; }; // expected-warning {{declaration shadows a local variable}} + auto g2 = [=](auto param) { ; }; // expected-warning {{declaration shadows a local variable}} #endif - auto g2 = [param] // expected-note {{variable 'param' is explicitly captured here}} + auto g3 = [param] // expected-note {{variable 'param' is explicitly captured here}} (auto param) { ; }; // expected-warning {{declaration shadows a local variable}} } |

