Skip to content

Commit c13b748

Browse files
Fznamznontstellar
authored andcommitted
[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 #71976
1 parent f249092 commit c13b748

File tree

4 files changed

+141
-31
lines changed

4 files changed

+141
-31
lines changed

clang/docs/ReleaseNotes.rst

+3
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,9 @@ Bug Fixes in This Version
899899
- Clang now doesn't produce false-positive warning `-Wconstant-logical-operand`
900900
for logical operators in C23.
901901
Fixes (`#64356 <https://github.com/llvm/llvm-project/issues/64356>`_).
902+
- Clang's ``-Wshadow`` no longer warns when an init-capture is named the same as
903+
a class field unless the lambda can capture this.
904+
Fixes (`#71976 <https://github.com/llvm/llvm-project/issues/71976>`_)
902905

903906
Bug Fixes to Compiler Builtins
904907
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Sema/ScopeInfo.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -925,8 +925,8 @@ class LambdaScopeInfo final :
925925
/// that were defined in parent contexts. Used to avoid warnings when the
926926
/// shadowed variables are uncaptured by this lambda.
927927
struct ShadowedOuterDecl {
928-
const VarDecl *VD;
929-
const VarDecl *ShadowedDecl;
928+
const NamedDecl *VD;
929+
const NamedDecl *ShadowedDecl;
930930
};
931931
llvm::SmallVector<ShadowedOuterDecl, 4> ShadowingDecls;
932932

clang/lib/Sema/SemaDecl.cpp

+47-26
Original file line numberDiff line numberDiff line change
@@ -8396,28 +8396,40 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
83968396

83978397
unsigned WarningDiag = diag::warn_decl_shadow;
83988398
SourceLocation CaptureLoc;
8399-
if (isa<VarDecl>(D) && isa<VarDecl>(ShadowedDecl) && NewDC &&
8400-
isa<CXXMethodDecl>(NewDC)) {
8399+
if (isa<VarDecl>(D) && NewDC && isa<CXXMethodDecl>(NewDC)) {
84018400
if (const auto *RD = dyn_cast<CXXRecordDecl>(NewDC->getParent())) {
84028401
if (RD->isLambda() && OldDC->Encloses(NewDC->getLexicalParent())) {
8403-
if (RD->getLambdaCaptureDefault() == LCD_None) {
8404-
// Try to avoid warnings for lambdas with an explicit capture list.
8402+
if (const auto *VD = dyn_cast<VarDecl>(ShadowedDecl)) {
84058403
const auto *LSI = cast<LambdaScopeInfo>(getCurFunction());
8406-
// Warn only when the lambda captures the shadowed decl explicitly.
8407-
CaptureLoc = getCaptureLocation(LSI, cast<VarDecl>(ShadowedDecl));
8408-
if (CaptureLoc.isInvalid())
8409-
WarningDiag = diag::warn_decl_shadow_uncaptured_local;
8410-
} else {
8411-
// Remember that this was shadowed so we can avoid the warning if the
8412-
// shadowed decl isn't captured and the warning settings allow it.
8404+
if (RD->getLambdaCaptureDefault() == LCD_None) {
8405+
// Try to avoid warnings for lambdas with an explicit capture
8406+
// list. Warn only when the lambda captures the shadowed decl
8407+
// explicitly.
8408+
CaptureLoc = getCaptureLocation(LSI, VD);
8409+
if (CaptureLoc.isInvalid())
8410+
WarningDiag = diag::warn_decl_shadow_uncaptured_local;
8411+
} else {
8412+
// Remember that this was shadowed so we can avoid the warning if
8413+
// the shadowed decl isn't captured and the warning settings allow
8414+
// it.
8415+
cast<LambdaScopeInfo>(getCurFunction())
8416+
->ShadowingDecls.push_back({D, VD});
8417+
return;
8418+
}
8419+
}
8420+
if (isa<FieldDecl>(ShadowedDecl)) {
8421+
// If lambda can capture this, then emit default shadowing warning,
8422+
// Otherwise it is not really a shadowing case since field is not
8423+
// available in lambda's body.
8424+
// At this point we don't know that lambda can capture this, so
8425+
// remember that this was shadowed and delay until we know.
84138426
cast<LambdaScopeInfo>(getCurFunction())
8414-
->ShadowingDecls.push_back(
8415-
{cast<VarDecl>(D), cast<VarDecl>(ShadowedDecl)});
8427+
->ShadowingDecls.push_back({D, ShadowedDecl});
84168428
return;
84178429
}
84188430
}
8419-
8420-
if (cast<VarDecl>(ShadowedDecl)->hasLocalStorage()) {
8431+
if (const auto *VD = dyn_cast<VarDecl>(ShadowedDecl);
8432+
VD && VD->hasLocalStorage()) {
84218433
// A variable can't shadow a local variable in an enclosing scope, if
84228434
// they are separated by a non-capturing declaration context.
84238435
for (DeclContext *ParentDC = NewDC;
@@ -8468,19 +8480,28 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
84688480
/// when these variables are captured by the lambda.
84698481
void Sema::DiagnoseShadowingLambdaDecls(const LambdaScopeInfo *LSI) {
84708482
for (const auto &Shadow : LSI->ShadowingDecls) {
8471-
const VarDecl *ShadowedDecl = Shadow.ShadowedDecl;
8483+
const NamedDecl *ShadowedDecl = Shadow.ShadowedDecl;
84728484
// Try to avoid the warning when the shadowed decl isn't captured.
8473-
SourceLocation CaptureLoc = getCaptureLocation(LSI, ShadowedDecl);
84748485
const DeclContext *OldDC = ShadowedDecl->getDeclContext();
8475-
Diag(Shadow.VD->getLocation(), CaptureLoc.isInvalid()
8476-
? diag::warn_decl_shadow_uncaptured_local
8477-
: diag::warn_decl_shadow)
8478-
<< Shadow.VD->getDeclName()
8479-
<< computeShadowedDeclKind(ShadowedDecl, OldDC) << OldDC;
8480-
if (!CaptureLoc.isInvalid())
8481-
Diag(CaptureLoc, diag::note_var_explicitly_captured_here)
8482-
<< Shadow.VD->getDeclName() << /*explicitly*/ 0;
8483-
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
8486+
if (const auto *VD = dyn_cast<VarDecl>(ShadowedDecl)) {
8487+
SourceLocation CaptureLoc = getCaptureLocation(LSI, VD);
8488+
Diag(Shadow.VD->getLocation(),
8489+
CaptureLoc.isInvalid() ? diag::warn_decl_shadow_uncaptured_local
8490+
: diag::warn_decl_shadow)
8491+
<< Shadow.VD->getDeclName()
8492+
<< computeShadowedDeclKind(ShadowedDecl, OldDC) << OldDC;
8493+
if (CaptureLoc.isValid())
8494+
Diag(CaptureLoc, diag::note_var_explicitly_captured_here)
8495+
<< Shadow.VD->getDeclName() << /*explicitly*/ 0;
8496+
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
8497+
} else if (isa<FieldDecl>(ShadowedDecl)) {
8498+
Diag(Shadow.VD->getLocation(),
8499+
LSI->isCXXThisCaptured() ? diag::warn_decl_shadow
8500+
: diag::warn_decl_shadow_uncaptured_local)
8501+
<< Shadow.VD->getDeclName()
8502+
<< computeShadowedDeclKind(ShadowedDecl, OldDC) << OldDC;
8503+
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
8504+
}
84848505
}
84858506
}
84868507

clang/test/SemaCXX/warn-shadow-in-lambdas.cpp

+89-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -D AVOID %s
2-
// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -Wshadow-uncaptured-local %s
3-
// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow-all %s
1+
// RUN: %clang_cc1 -std=c++14 -verify=expected,cxx14 -fsyntax-only -Wshadow -D AVOID %s
2+
// RUN: %clang_cc1 -std=c++14 -verify=expected,cxx14 -fsyntax-only -Wshadow -Wshadow-uncaptured-local %s
3+
// RUN: %clang_cc1 -std=c++14 -verify=expected,cxx14 -fsyntax-only -Wshadow-all %s
44
// RUN: %clang_cc1 -std=c++17 -verify -fsyntax-only -Wshadow-all %s
55
// RUN: %clang_cc1 -std=c++20 -verify -fsyntax-only -Wshadow-all %s
66

@@ -179,3 +179,89 @@ void f() {
179179
#endif
180180
}
181181
}
182+
183+
namespace GH71976 {
184+
#ifdef AVOID
185+
struct A {
186+
int b = 5;
187+
int foo() {
188+
return [b = b]() { return b; }(); // no -Wshadow diagnostic, init-capture does not shadow b due to not capturing this
189+
}
190+
};
191+
192+
struct B {
193+
int a;
194+
void foo() {
195+
auto b = [a = this->a] {}; // no -Wshadow diagnostic, init-capture does not shadow a due to not capturing his
196+
}
197+
};
198+
199+
struct C {
200+
int b = 5;
201+
int foo() {
202+
return [a = b]() {
203+
return [=, b = a]() { // no -Wshadow diagnostic, init-capture does not shadow b due to outer lambda
204+
return b;
205+
}();
206+
}();
207+
}
208+
};
209+
210+
#else
211+
struct A {
212+
int b = 5; // expected-note {{previous}}
213+
int foo() {
214+
return [b = b]() { return b; }(); // expected-warning {{declaration shadows a field}}
215+
}
216+
};
217+
218+
struct B {
219+
int a; // expected-note {{previous}}
220+
void foo() {
221+
auto b = [a = this->a] {}; // expected-warning {{declaration shadows a field}}
222+
}
223+
};
224+
225+
struct C {
226+
int b = 5; // expected-note {{previous}}
227+
int foo() {
228+
return [a = b]() {
229+
return [=, b = a]() { // expected-warning {{declaration shadows a field}}
230+
return b;
231+
}();
232+
}();
233+
}
234+
};
235+
236+
struct D {
237+
int b = 5; // expected-note {{previous}}
238+
int foo() {
239+
return [b = b, this]() { return b; }(); // expected-warning {{declaration shadows a field}}
240+
}
241+
};
242+
243+
struct E {
244+
int b = 5;
245+
int foo() {
246+
return [a = b]() { // expected-note {{previous}}
247+
return [=, a = a]() { // expected-warning {{shadows a local}}
248+
return a;
249+
}();
250+
}();
251+
}
252+
};
253+
254+
#endif
255+
256+
struct S {
257+
int a ;
258+
};
259+
260+
int foo() {
261+
auto [a] = S{0}; // expected-note {{previous}} \
262+
// cxx14-warning {{decomposition declarations are a C++17 extension}}
263+
[a = a] () { // expected-warning {{declaration shadows a structured binding}}
264+
}();
265+
}
266+
267+
}

0 commit comments

Comments
 (0)