mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-16 11:06:33 +00:00
[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
This commit is contained in:
parent
f249092ef2
commit
c13b7485b8
@ -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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -925,8 +925,8 @@ public:
|
||||
/// 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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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}}
|
||||
}();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user