-
Notifications
You must be signed in to change notification settings - Fork 15k
[clang][Sema] Fix false positive -Wshadow with structured binding captures #157667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[clang][Sema] Fix false positive -Wshadow with structured binding captures #157667
Conversation
@llvm/pr-subscribers-clang Author: Ivan Murashko (ivanmurashko) ChangesFixes #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: 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 Full diff: https://github.com/llvm/llvm-project/pull/157667.diff 2 Files Affected:
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
|
…tures 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.
1e8d884
to
6aa3e64
Compare
Can you tell why there is false positive with structured bindings only, but without variables? |
IIUC we shouldn't emit any warning on "lambda captures shadow something". It is a better approach for me that removing emitting this warning and performing code cleanup (there must be some checks preventing false positive with shadowing variables). |
Structured bindings (
This makes regular variables appear to "not warn" in typical usage (since most users use
My fix was focused on the simplest solution to make behavior consistent for the most popular case (basic |
@zwuis You're right! That's a much cleaner approach. Lambda init captures like
This single-line change eliminates all shadow warnings for lambda init captures across all warning flags ( The fix is much simpler conceptually - lambda captures are deliberate syntax, so no shadow warnings should apply to them at all. What do you think about this approach? It addresses both the original issue and provides the code cleanup you mentioned. |
Oh, I missed "-Wshadow-uncaptured-local". Thanks for pointing out!
So this is wrong.
So current fix will introduce false negative with "-Wshadow-uncaptured-local" and shadowing structured bindings, and, hide the underlying issue. It would be great to find the difference of handling shadowing |
…red bindings Lambda captures that shadow structured bindings were incorrectly classified as regular shadow warnings (shown with -Wshadow) while regular parameter captures were classified as uncaptured-local warnings (shown only with -Wshadow-all). This created inconsistent behavior between semantically equivalent code patterns. This change extends the existing lambda capture classification logic to handle BindingDecl consistently with VarDecl: - Lambda init captures of structured bindings now show as uncaptured-local - Regular variable declarations inside lambda bodies still show as shadow - All existing shadow warning functionality is preserved The fix ensures consistent behavior between: void func(std::pair<int,int> val) { [val = val](){}; } // no -Wshadow, warns with -Wshadow-all void func(std::pair<int,int> val) { auto [a,b] = val; [a = a](){}; } // no -Wshadow, warns with -Wshadow-all Previously the structured binding case incorrectly produced warnings with basic -Wshadow, preventing structured bindings from being used in lambda captures consistently with regular parameters.
The new commit c0723fe addresses this by extending the existing lambda capture classification logic at lines 8501-8515 in Previously, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! It looks better.
Please add a release note entry to "clang/docs/ReleaseNotes.rst".
clang/lib/Sema/SemaDecl.cpp
Outdated
@@ -8410,6 +8410,7 @@ NamedDecl *Sema::getShadowedDeclaration(const VarDecl *D, | |||
return nullptr; | |||
|
|||
NamedDecl *ShadowedDecl = R.getFoundDecl(); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems unrelated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems unrelated.
Restored at 27fc9b7
…ueDecl Consolidate the handling of VarDecl and BindingDecl in shadow detection by using their common base class ValueDecl.
…>hasLocalStorage()
LGTM if PR description is updated. |
Ah, I forgot to update the PR description, that was just fixed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just style nits, otherwise LGTM
clang/test/SemaCXX/PR68605.cpp
Outdated
}; | ||
} | ||
|
||
} // namespace issue_68605 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a newline at the end of the file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed at ef25bd2
Code style fixes applied Co-authored-by: Mariya Podchishchaeva <[email protected]>
Hi everyone, As the PR has been already accepted, I'll wait until Monday (15 Sep) to provide additional time for review. If there are no further comments by then, I'll proceed with merging the PR. |
Previously, lambda init captures of structured bindings were incorrectly classified as regular shadow warnings (shown with
-Wshadow
), while regular parameter captures were correctly classified asuncaptured-local
warnings (shown only with-Wshadow-all
). This created inconsistent behavior:The fix extends the existing lambda capture classification logic in
CheckShadow()
to handleBindingDecl
consistently withVarDecl
, ensuring both cases show no warnings with-Wshadow
anduncaptured-local
warnings with-Wshadow-all
.Fixes #68605.