[llvm-branch-commits] [clang] [clang] Avoid -Wshadow warning when init-capture named same as class … (PR #84912)
Neil Henning via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Mar 12 06:41:59 PDT 2024
https://github.com/sheredom created https://github.com/llvm/llvm-project/pull/84912
…field (#74512)
Shadowing warning doesn't make much sense since field is not available in lambda's body without capturing this.
Fixes https://github.com/llvm/llvm-project/issues/71976
>From d2740d74a34982f21ec18e2cc494d67187d5c7f2 Mon Sep 17 00:00:00 2001
From: Mariya Podchishchaeva <mariya.podchishchaeva at intel.com>
Date: Mon, 12 Feb 2024 12:44:20 +0300
Subject: [PATCH] [clang] Avoid -Wshadow warning when init-capture named same
as class field (#74512)
Shadowing warning doesn't make much sense since field is not available
in lambda's body without capturing this.
Fixes https://github.com/llvm/llvm-project/issues/71976
---
clang/docs/ReleaseNotes.rst | 3 +
clang/include/clang/Sema/ScopeInfo.h | 4 +-
clang/lib/Sema/SemaDecl.cpp | 73 +++++++++------
clang/test/SemaCXX/warn-shadow-in-lambdas.cpp | 92 ++++++++++++++++++-
4 files changed, 141 insertions(+), 31 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index fc27297aea2d6c..14703e23ba0be0 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -899,6 +899,9 @@ Bug Fixes in This Version
- Clang now doesn't produce false-positive warning `-Wconstant-logical-operand`
for logical operators in C23.
Fixes (`#64356 <https://github.com/llvm/llvm-project/issues/64356>`_).
+- Clang's ``-Wshadow`` no longer warns when an init-capture is named the same as
+ a class field unless the lambda can capture this.
+ Fixes (`#71976 <https://github.com/llvm/llvm-project/issues/71976>`_)
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index 6eaa74382685ba..06e47eed4e93b6 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -925,8 +925,8 @@ class LambdaScopeInfo final :
/// 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;
+ const NamedDecl *VD;
+ const NamedDecl *ShadowedDecl;
};
llvm::SmallVector<ShadowedOuterDecl, 4> ShadowingDecls;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index a300badc6d0260..f5bb3e0b42e26c 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -8396,28 +8396,40 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
unsigned WarningDiag = diag::warn_decl_shadow;
SourceLocation CaptureLoc;
- if (isa<VarDecl>(D) && isa<VarDecl>(ShadowedDecl) && NewDC &&
- isa<CXXMethodDecl>(NewDC)) {
+ if (isa<VarDecl>(D) && NewDC && isa<CXXMethodDecl>(NewDC)) {
if (const auto *RD = dyn_cast<CXXRecordDecl>(NewDC->getParent())) {
if (RD->isLambda() && OldDC->Encloses(NewDC->getLexicalParent())) {
- if (RD->getLambdaCaptureDefault() == LCD_None) {
- // Try to avoid warnings for lambdas with an explicit capture list.
+ if (const auto *VD = dyn_cast<VarDecl>(ShadowedDecl)) {
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.
+ if (RD->getLambdaCaptureDefault() == LCD_None) {
+ // Try to avoid warnings for lambdas with an explicit capture
+ // list. Warn only when the lambda captures the shadowed decl
+ // explicitly.
+ CaptureLoc = getCaptureLocation(LSI, VD);
+ 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, VD});
+ return;
+ }
+ }
+ if (isa<FieldDecl>(ShadowedDecl)) {
+ // If lambda can capture this, then emit default shadowing warning,
+ // Otherwise it is not really a shadowing case since field is not
+ // available in lambda's body.
+ // At this point we don't know that lambda can capture this, so
+ // remember that this was shadowed and delay until we know.
cast<LambdaScopeInfo>(getCurFunction())
- ->ShadowingDecls.push_back(
- {cast<VarDecl>(D), cast<VarDecl>(ShadowedDecl)});
+ ->ShadowingDecls.push_back({D, ShadowedDecl});
return;
}
}
-
- if (cast<VarDecl>(ShadowedDecl)->hasLocalStorage()) {
+ if (const auto *VD = dyn_cast<VarDecl>(ShadowedDecl);
+ VD && VD->hasLocalStorage()) {
// A variable can't shadow a local variable in an enclosing scope, if
// they are separated by a non-capturing declaration context.
for (DeclContext *ParentDC = NewDC;
@@ -8468,19 +8480,28 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
/// 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;
+ const NamedDecl *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);
+ if (const auto *VD = dyn_cast<VarDecl>(ShadowedDecl)) {
+ SourceLocation CaptureLoc = getCaptureLocation(LSI, VD);
+ 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.isValid())
+ Diag(CaptureLoc, diag::note_var_explicitly_captured_here)
+ << Shadow.VD->getDeclName() << /*explicitly*/ 0;
+ Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
+ } else if (isa<FieldDecl>(ShadowedDecl)) {
+ Diag(Shadow.VD->getLocation(),
+ LSI->isCXXThisCaptured() ? diag::warn_decl_shadow
+ : diag::warn_decl_shadow_uncaptured_local)
+ << Shadow.VD->getDeclName()
+ << computeShadowedDeclKind(ShadowedDecl, OldDC) << OldDC;
+ Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
+ }
}
}
diff --git a/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp b/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
index bda6a65c02168b..d54b394df4eb84 100644
--- a/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
+++ b/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
@@ -1,6 +1,6 @@
-// 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
+// RUN: %clang_cc1 -std=c++14 -verify=expected,cxx14 -fsyntax-only -Wshadow -D AVOID %s
+// RUN: %clang_cc1 -std=c++14 -verify=expected,cxx14 -fsyntax-only -Wshadow -Wshadow-uncaptured-local %s
+// RUN: %clang_cc1 -std=c++14 -verify=expected,cxx14 -fsyntax-only -Wshadow-all %s
// RUN: %clang_cc1 -std=c++17 -verify -fsyntax-only -Wshadow-all %s
// RUN: %clang_cc1 -std=c++20 -verify -fsyntax-only -Wshadow-all %s
@@ -179,3 +179,89 @@ void f() {
#endif
}
}
+
+namespace GH71976 {
+#ifdef AVOID
+struct A {
+ int b = 5;
+ int foo() {
+ return [b = b]() { return b; }(); // no -Wshadow diagnostic, init-capture does not shadow b due to not capturing this
+ }
+};
+
+struct B {
+ int a;
+ void foo() {
+ auto b = [a = this->a] {}; // no -Wshadow diagnostic, init-capture does not shadow a due to not capturing his
+ }
+};
+
+struct C {
+ int b = 5;
+ int foo() {
+ return [a = b]() {
+ return [=, b = a]() { // no -Wshadow diagnostic, init-capture does not shadow b due to outer lambda
+ return b;
+ }();
+ }();
+ }
+};
+
+#else
+struct A {
+ int b = 5; // expected-note {{previous}}
+ int foo() {
+ return [b = b]() { return b; }(); // expected-warning {{declaration shadows a field}}
+ }
+};
+
+struct B {
+ int a; // expected-note {{previous}}
+ void foo() {
+ auto b = [a = this->a] {}; // expected-warning {{declaration shadows a field}}
+ }
+};
+
+struct C {
+ int b = 5; // expected-note {{previous}}
+ int foo() {
+ return [a = b]() {
+ return [=, b = a]() { // expected-warning {{declaration shadows a field}}
+ return b;
+ }();
+ }();
+ }
+};
+
+struct D {
+ int b = 5; // expected-note {{previous}}
+ int foo() {
+ return [b = b, this]() { return b; }(); // expected-warning {{declaration shadows a field}}
+ }
+};
+
+struct E {
+ int b = 5;
+ int foo() {
+ return [a = b]() { // expected-note {{previous}}
+ return [=, a = a]() { // expected-warning {{shadows a local}}
+ return a;
+ }();
+ }();
+ }
+};
+
+#endif
+
+struct S {
+ int a ;
+};
+
+int foo() {
+ auto [a] = S{0}; // expected-note {{previous}} \
+ // cxx14-warning {{decomposition declarations are a C++17 extension}}
+ [a = a] () { // expected-warning {{declaration shadows a structured binding}}
+ }();
+}
+
+}
More information about the llvm-branch-commits
mailing list