-
Notifications
You must be signed in to change notification settings - Fork 12k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
release/18x: [clang] Avoid -Wshadow warning when init-capture named same as class … #84912
Conversation
@llvm/pr-subscribers-clang Author: Neil Henning (sheredom) Changes…field (#74512) Shadowing warning doesn't make much sense since field is not available in lambda's body without capturing this. Fixes #71976 Full diff: https://github.com/llvm/llvm-project/pull/84912.diff 4 Files Affected:
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}}
+ }();
+}
+
+}
|
As far as I can tell, this isn't fixing a regression in Clang17, and thus isn't really a candidate for inclusion into the 18.x branches. |
Yeah indeed - its not a clang 17 regression. It's a clang 16 regression. At the minute we're holding our internal compiler toolchain on clang 16, and for our users we've got to special case disable the warning entirely for clang 17. |
@erichkeane @cor3ntin Can we have a final decision on if we should merge this or not? |
From the POV of Sony, we'd be happy to see this merged in. We've heard from frustrated users on this point. |
Just got back from WG21, so sorry for the delay. While we don't USUALLY do backports like this that fix something that was present in the last release, I think this ends up being reasonably low risk, we haven't seen any bugs regarding this SINCE, and worst-case it breaks |
…field (llvm#74512) Shadowing warning doesn't make much sense since field is not available in lambda's body without capturing this. Fixes llvm#71976
…field (#74512)
Shadowing warning doesn't make much sense since field is not available in lambda's body without capturing this.
Fixes #84898