[clang] [clang][Sema] Fix false positive -Wshadow with structured binding captures (PR #157667)
Ivan Murashko via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 9 06:34:39 PDT 2025
https://github.com/ivanmurashko updated https://github.com/llvm/llvm-project/pull/157667
>From 6aa3e6424865a5fc53489612ecb7f656f7165b9c Mon Sep 17 00:00:00 2001
From: Ivan Murashko <ivan.murashko at gmail.com>
Date: Tue, 9 Sep 2025 13:42:46 +0100
Subject: [PATCH] [clang][Sema] Fix false positive -Wshadow with structured
binding captures
Previously, lambda init captures that captured structured bindings would
incorrectly emit shadow warnings, even though regular parameter captures
don't emit such warnings. This created inconsistent behavior:
```cpp
void foo1(std::pair<int, int> val) {
[val = val](){}(); // No warning (correct)
}
void foo2(std::pair<int, int> val) {
auto [a, b] = val;
[a = a](){}(); // Warning (incorrect)
}
```
The fix modifies getShadowedDeclaration() for VarDecl to return nullptr
when a lambda init capture would shadow a BindingDecl, ensuring consistent
behavior between regular captures and structured binding captures.
---
clang/lib/Sema/SemaDecl.cpp | 6 ++
clang/test/SemaCXX/PR68605.cpp | 71 +++++++++++++++++++
clang/test/SemaCXX/warn-shadow-in-lambdas.cpp | 5 +-
3 files changed, 79 insertions(+), 3 deletions(-)
create mode 100644 clang/test/SemaCXX/PR68605.cpp
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 365ebb63b1559..311105f31e3e3 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -8410,6 +8410,12 @@ NamedDecl *Sema::getShadowedDeclaration(const VarDecl *D,
return nullptr;
NamedDecl *ShadowedDecl = R.getFoundDecl();
+
+ // Don't warn when lambda captures shadow structured bindings.
+ // This ensures consistency with regular parameter captures.
+ if (isa<BindingDecl>(ShadowedDecl) && D->isInitCapture())
+ return nullptr;
+
return isa<VarDecl, FieldDecl, BindingDecl>(ShadowedDecl) ? ShadowedDecl
: nullptr;
}
diff --git a/clang/test/SemaCXX/PR68605.cpp b/clang/test/SemaCXX/PR68605.cpp
new file mode 100644
index 0000000000000..90e4876b3e394
--- /dev/null
+++ b/clang/test/SemaCXX/PR68605.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -std=c++20 -Wshadow %s
+
+// Test for issue #68605: False positive warning with `-Wshadow` when using
+// structured binding and lambda capture.
+//
+// The issue is that structured bindings should behave consistently with
+// regular variables when used in lambda captures - no shadow warning should
+// be emitted when a lambda capture variable has the same name as the captured
+// structured binding, just like with regular parameters.
+
+namespace std {
+ template<typename T> T&& move(T&& t) { return static_cast<T&&>(t); }
+}
+
+namespace issue_68605 {
+
+// Simple pair-like struct for testing
+struct Pair {
+ int first;
+ int second;
+ Pair(int f, int s) : first(f), second(s) {}
+};
+
+// Test case 1: Regular parameter - should NOT produce warning (baseline)
+void foo1(Pair val) {
+ [val = std::move(val)](){}(); // No warning expected
+}
+
+// Test case 2: Structured binding - should NOT produce warning
+void foo2(Pair val) {
+ auto [a,b] = val;
+ [a = std::move(a)](){}(); // No warning - consistent with regular parameter behavior
+}
+
+// Test case 3: More complex example with multiple captures
+void foo3() {
+ Pair data{42, 100};
+ auto [id, value] = data;
+
+ // Both of these should NOT produce warnings
+ auto lambda1 = [id = id](){ return id; }; // No warning
+ auto lambda2 = [value = value](){ return value; }; // No warning
+}
+
+// Test case 4: Mixed scenario with regular var and structured binding
+void foo4() {
+ int regular_var = 10;
+ Pair pair_data{1, 2};
+ auto [x, y] = pair_data;
+
+ // Regular variable capture - no warning expected (current behavior)
+ auto lambda1 = [regular_var = regular_var](){};
+
+ // Structured binding captures - should be consistent
+ auto lambda2 = [x = x](){}; // No warning - consistent behavior
+ auto lambda3 = [y = y](){}; // No warning - consistent behavior
+}
+
+// Test case 5: Ensure we don't break existing shadow detection for actual shadowing
+void foo5() {
+ int outer = 5; // expected-note {{previous declaration is here}}
+ auto [a, b] = Pair{1, 2}; // expected-note {{previous declaration is here}}
+
+ // This SHOULD still warn - it's actual shadowing within the lambda body
+ auto lambda = [outer, a](){ // expected-note {{variable 'outer' is explicitly captured here}}
+ int outer = 10; // expected-warning {{declaration shadows a local variable}}
+ int a = 20; // expected-warning {{declaration shadows a structured binding}}
+ };
+}
+
+} // namespace issue_68605
\ No newline at end of file
diff --git a/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp b/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
index d54b394df4eb8..2221c3f6d1049 100644
--- a/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
+++ b/clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
@@ -258,9 +258,8 @@ struct S {
};
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}}
+ auto [a] = S{0}; // cxx14-warning {{decomposition declarations are a C++17 extension}}
+ [a = a] () { // No warning - consistent with regular parameter captures
}();
}
More information about the cfe-commits
mailing list