summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Lorenz <arphaman@gmail.com>2016-11-10 16:19:11 +0000
committerAlex Lorenz <arphaman@gmail.com>2016-11-10 16:19:11 +0000
commitd60bb2830797460acc7d061d1f81eddf22d7b857 (patch)
tree3e563225d7ac41768cd976205804f49ad25a3f66
parent115a61560e24e08ecca0b3e2d16e8f1491b47f61 (diff)
downloadbcm5719-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.td4
-rw-r--r--clang/include/clang/Sema/ScopeInfo.h11
-rw-r--r--clang/include/clang/Sema/Sema.h2
-rw-r--r--clang/lib/Sema/SemaDecl.cpp46
-rw-r--r--clang/lib/Sema/SemaLambda.cpp3
-rw-r--r--clang/test/SemaCXX/warn-shadow-in-lambdas.cpp54
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}}
}
OpenPOWER on IntegriCloud