[clang] [clang][Sema] Fix false positive -Wshadow with structured binding captures (PR #157667)

via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 9 06:08:41 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Ivan Murashko (ivanmurashko)

<details>
<summary>Changes</summary>

Fixes #<!-- -->68605.

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 = std::move(val)](){}();  // No warning (correct)
}

void foo2(std::pair<int, int> val) {
  auto [a, b] = val;
  [a = std::move(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.

---
Full diff: https://github.com/llvm/llvm-project/pull/157667.diff


2 Files Affected:

- (modified) clang/lib/Sema/SemaDecl.cpp (+6) 
- (added) clang/test/SemaCXX/PR68605.cpp (+71) 


``````````diff
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

``````````

</details>


https://github.com/llvm/llvm-project/pull/157667


More information about the cfe-commits mailing list