Skip to content

Commit 27fc9b7

Browse files
committed
[Sema] Consolidate VarDecl and BindingDecl shadow detection using ValueDecl
Consolidate the handling of VarDecl and BindingDecl in shadow detection by using their common base class ValueDecl.
1 parent 74a2ff7 commit 27fc9b7

File tree

2 files changed

+35
-46
lines changed

2 files changed

+35
-46
lines changed

clang/lib/Sema/SemaDecl.cpp

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8382,7 +8382,7 @@ static ShadowedDeclKind computeShadowedDeclKind(const NamedDecl *ShadowedDecl,
83828382
/// Return the location of the capture if the given lambda captures the given
83838383
/// variable \p VD, or an invalid source location otherwise.
83848384
static SourceLocation getCaptureLocation(const LambdaScopeInfo *LSI,
8385-
const VarDecl *VD) {
8385+
const ValueDecl *VD) {
83868386
for (const Capture &Capture : LSI->Captures) {
83878387
if (Capture.isVariableCapture() && Capture.getVariable() == VD)
83888388
return Capture.getLocation();
@@ -8410,7 +8410,6 @@ NamedDecl *Sema::getShadowedDeclaration(const VarDecl *D,
84108410
return nullptr;
84118411

84128412
NamedDecl *ShadowedDecl = R.getFoundDecl();
8413-
84148413
return isa<VarDecl, FieldDecl, BindingDecl>(ShadowedDecl) ? ShadowedDecl
84158414
: nullptr;
84168415
}
@@ -8480,9 +8479,11 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
84808479
if (isa<VarDecl>(D) && NewDC && isa<CXXMethodDecl>(NewDC)) {
84818480
if (const auto *RD = dyn_cast<CXXRecordDecl>(NewDC->getParent())) {
84828481
if (RD->isLambda() && OldDC->Encloses(NewDC->getLexicalParent())) {
8483-
// Handle lambda capture logic for both VarDecl and BindingDecl
8484-
if (const auto *VD = dyn_cast<VarDecl>(ShadowedDecl)) {
8482+
// Handle both VarDecl and BindingDecl in lambda contexts
8483+
if (isa<VarDecl, BindingDecl>(ShadowedDecl)) {
8484+
const auto *VD = cast<ValueDecl>(ShadowedDecl);
84858485
const auto *LSI = cast<LambdaScopeInfo>(getCurFunction());
8486+
84868487
if (RD->getLambdaCaptureDefault() == LCD_None) {
84878488
// Try to avoid warnings for lambdas with an explicit capture
84888489
// list. Warn only when the lambda captures the shadowed decl
@@ -8498,21 +8499,6 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
84988499
->ShadowingDecls.push_back({D, VD});
84998500
return;
85008501
}
8501-
} else if (isa<BindingDecl>(ShadowedDecl)) {
8502-
// Apply lambda capture logic only when D is actually a lambda capture
8503-
if (isa<VarDecl>(D) && cast<VarDecl>(D)->isInitCapture()) {
8504-
if (RD->getLambdaCaptureDefault() == LCD_None) {
8505-
// BindingDecls cannot be explicitly captured, so always treat as
8506-
// uncaptured
8507-
WarningDiag = diag::warn_decl_shadow_uncaptured_local;
8508-
} else {
8509-
// Same deferred handling as VarDecl
8510-
cast<LambdaScopeInfo>(getCurFunction())
8511-
->ShadowingDecls.push_back({D, ShadowedDecl});
8512-
return;
8513-
}
8514-
}
8515-
// For non-init-capture cases, fall through to regular shadow logic
85168502
}
85178503
if (isa<FieldDecl>(ShadowedDecl)) {
85188504
// If lambda can capture this, then emit default shadowing warning,
@@ -8525,25 +8511,32 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
85258511
return;
85268512
}
85278513
}
8528-
// Apply scoping logic to both VarDecl and BindingDecl
8529-
bool shouldApplyScopingLogic = false;
8530-
if (const auto *VD = dyn_cast<VarDecl>(ShadowedDecl)) {
8531-
shouldApplyScopingLogic = VD->hasLocalStorage();
8532-
} else if (isa<BindingDecl>(ShadowedDecl)) {
8533-
shouldApplyScopingLogic = true;
8534-
}
8535-
8536-
if (shouldApplyScopingLogic) {
8537-
// A variable can't shadow a local variable or binding in an enclosing
8538-
// scope, if they are separated by a non-capturing declaration context.
8539-
for (DeclContext *ParentDC = NewDC;
8540-
ParentDC && !ParentDC->Equals(OldDC);
8541-
ParentDC = getLambdaAwareParentOfDeclContext(ParentDC)) {
8542-
// Only block literals, captured statements, and lambda expressions
8543-
// can capture; other scopes don't.
8544-
if (!isa<BlockDecl>(ParentDC) && !isa<CapturedDecl>(ParentDC) &&
8545-
!isLambdaCallOperator(ParentDC)) {
8546-
return;
8514+
// Apply scoping logic to both VarDecl and BindingDecl with local storage
8515+
if (isa<VarDecl, BindingDecl>(ShadowedDecl)) {
8516+
bool hasLocalStorage = false;
8517+
if (const auto *VD = dyn_cast<VarDecl>(ShadowedDecl)) {
8518+
hasLocalStorage = VD->hasLocalStorage();
8519+
} else {
8520+
// For BindingDecl, apply the same logic as
8521+
// VarDecl::hasLocalStorage(): local storage means not at file context
8522+
hasLocalStorage = !ShadowedDecl->getLexicalDeclContext()
8523+
->getRedeclContext()
8524+
->isFileContext();
8525+
}
8526+
8527+
if (hasLocalStorage) {
8528+
// A variable can't shadow a local variable or binding in an enclosing
8529+
// scope, if they are separated by a non-capturing declaration
8530+
// context.
8531+
for (DeclContext *ParentDC = NewDC;
8532+
ParentDC && !ParentDC->Equals(OldDC);
8533+
ParentDC = getLambdaAwareParentOfDeclContext(ParentDC)) {
8534+
// Only block literals, captured statements, and lambda expressions
8535+
// can capture; other scopes don't.
8536+
if (!isa<BlockDecl>(ParentDC) && !isa<CapturedDecl>(ParentDC) &&
8537+
!isLambdaCallOperator(ParentDC)) {
8538+
return;
8539+
}
85478540
}
85488541
}
85498542
}
@@ -8590,8 +8583,10 @@ void Sema::DiagnoseShadowingLambdaDecls(const LambdaScopeInfo *LSI) {
85908583
const NamedDecl *ShadowedDecl = Shadow.ShadowedDecl;
85918584
// Try to avoid the warning when the shadowed decl isn't captured.
85928585
const DeclContext *OldDC = ShadowedDecl->getDeclContext();
8593-
if (const auto *VD = dyn_cast<VarDecl>(ShadowedDecl)) {
8586+
if (isa<VarDecl, BindingDecl>(ShadowedDecl)) {
8587+
const auto *VD = cast<ValueDecl>(ShadowedDecl);
85948588
SourceLocation CaptureLoc = getCaptureLocation(LSI, VD);
8589+
85958590
Diag(Shadow.VD->getLocation(),
85968591
CaptureLoc.isInvalid() ? diag::warn_decl_shadow_uncaptured_local
85978592
: diag::warn_decl_shadow)
@@ -8601,12 +8596,6 @@ void Sema::DiagnoseShadowingLambdaDecls(const LambdaScopeInfo *LSI) {
86018596
Diag(CaptureLoc, diag::note_var_explicitly_captured_here)
86028597
<< Shadow.VD->getDeclName() << /*explicitly*/ 0;
86038598
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
8604-
} else if (isa<BindingDecl>(ShadowedDecl)) {
8605-
// BindingDecls cannot be explicitly captured, so always uncaptured-local
8606-
Diag(Shadow.VD->getLocation(), diag::warn_decl_shadow_uncaptured_local)
8607-
<< Shadow.VD->getDeclName()
8608-
<< computeShadowedDeclKind(ShadowedDecl, OldDC) << OldDC;
8609-
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
86108599
} else if (isa<FieldDecl>(ShadowedDecl)) {
86118600
Diag(Shadow.VD->getLocation(),
86128601
LSI->isCXXThisCaptured() ? diag::warn_decl_shadow

clang/test/SemaCXX/PR68605.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ void foo5() {
6363
auto [a, b] = Pair{1, 2}; // expected-note {{previous declaration is here}} all-note {{previous declaration is here}}
6464

6565
// This SHOULD still warn - it's actual shadowing within the lambda body
66-
auto lambda = [outer, a](){ // expected-note {{variable 'outer' is explicitly captured here}} all-note {{variable 'outer' is explicitly captured here}}
66+
auto lambda = [outer, a](){ // expected-note {{variable 'outer' is explicitly captured here}} all-note {{variable 'outer' is explicitly captured here}} expected-note {{variable 'a' is explicitly captured here}} all-note {{variable 'a' is explicitly captured here}}
6767
int outer = 10; // expected-warning {{declaration shadows a local variable}} all-warning {{declaration shadows a local variable}}
6868
int a = 20; // expected-warning {{declaration shadows a structured binding}} all-warning {{declaration shadows a structured binding}}
6969
};

0 commit comments

Comments
 (0)