]> granicus.if.org Git - clang/commitdiff
[Sema] Avoid -Wshadow warnings for shadowed variables that
authorAlex Lorenz <arphaman@gmail.com>
Thu, 10 Nov 2016 16:19:11 +0000 (16:19 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Thu, 10 Nov 2016 16:19:11 +0000 (16:19 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@286465 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/ScopeInfo.h
include/clang/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaLambda.cpp
test/SemaCXX/warn-shadow-in-lambdas.cpp

index 0ff1a6fbe668e8f68e77d6f4887e5cd31079f967..db8bda5265dcb3bfcbf36fba18f347fef393ab40 100644 (file)
@@ -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<
index b4e09fac229124d8200b03763ceeeba5d1bb9ae6..4b54807ab660ea332407a4097f6052c5390dec26 100644 (file)
@@ -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;
 
index 6c1059c05cdb9168a439db0d2e0a858918bcc4c7..2f4befc8b716b77159d420aba3d93022c2df6ac3 100644 (file)
@@ -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.
index 1859b7f0116b562513e3f8bb9aebc7d0f6bc652a..662d19aa8c242d9ab7cb3bee03644a2835cb0c9f 100644 (file)
@@ -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()))
index 9be8fe51887cbdc511fa69e0514f57fa437fab57..da4ba8b2a26bbb152154439c5c28b0f1b3d6e908 100644 (file)
@@ -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:
index 24f1a34de11cd5aafd9be01ed519ef644e0a8e04..575664482dbe1fa8322a0a28a35fac51c9f063ca 100644 (file)
@@ -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}}
 }