This revision was automatically updated to reflect the committed changes.
Closed by commit rL286354: [Sema] Avoid -Wshadow warnings for shadowed 
variables that aren't captured (authored by arphaman).

Changed prior to commit:
  https://reviews.llvm.org/D26278?vs=77205&id=77328#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D26278

Files:
  cfe/trunk/include/clang/Basic/DiagnosticGroups.td
  cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
  cfe/trunk/lib/Sema/SemaDecl.cpp
  cfe/trunk/test/SemaCXX/warn-shadow-in-lambdas.cpp

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<Shadow>, DefaultIgnore;
+def warn_decl_shadow_uncaptured_local :
+  Warning<warn_decl_shadow.Text>,
+  InGroup<ShadowUncapturedLocal>, DefaultIgnore;
 def warn_ctor_parm_shadows_field:
   Warning<"constructor parameter %0 shadows the field %1 of %2">,
   InGroup<ShadowFieldInConstructor>, 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/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}}
+}
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<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;
+      }
+    }
+  }
+
   // 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);
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to