This patch marks the declarations with initializations in condition expressions such as
if (int var = init) as unused and unreferenced so that -Wunused can warn on them.
Details
- Reviewers
aaron.ballman tbaeder shafik cor3ntin NoQ - Group Reviewers
Restricted Project - Commits
- rG92023b150990: Reland "[Clang][SemaCXX] Add unused warning for variables declared in condition…
rG8e329caa944c: Reland "[Clang][SemaCXX] Add unused warning for variables declared in condition…
rGbd0ed0abc31f: [Clang][SemaCXX] Add unused warning for variables declared in condition…
Diff Detail
Event Timeline
clang/lib/CodeGen/CGExpr.cpp | ||
---|---|---|
2852 ↗ | (On Diff #529824) | Question for other reviewers: If we want to keep this assertion, would it instead make sense to mark the decl as used after emitting the diagnostic, in https://github.com/llvm/llvm-project/blob/main/clang/lib/Sema/SemaDecl.cpp#L2154 ? |
clang/lib/Sema/SemaExprCXX.cpp | ||
---|---|---|
4020–4021 |
clang/lib/Sema/SemaExprCXX.cpp | ||
---|---|---|
4020–4021 | That seem a bit over the top given that it's the only boolean parameter. |
clang/lib/Sema/SemaExprCXX.cpp | ||
---|---|---|
4020–4021 | Yeah, in this case it is blindingly obvious but I do see many cases in the code where folks use bugprone-argument-comment for single bool parameters and I just use it everywhere for consistency sake. |
This is a bit of an odd situation -- the condition variable *is* used (e.g., its value is loaded to determine whether to go into the if branch or the else branch), so we should not be marking it as unused in Sema::CheckConditionVariable(). Instead, I think we need to decide what constitutes "unused" in this case. Consider:
struct RAII { int &x; RAII(int &ref) : x(ref) {} ~RAII() { x = 0; } operator bool() const { return true; } }; void func() { int i = 12; if (RAII name{i}) { } }
I don't think name is unused in the same way that i is unused in if (int i = 1) {}. So I think we only want this to apply to scalars and not class types. I think the changes should be happening in Sema::ShouldDiagnoseUnusedDecl() (and you might need to thread the Scope object through to that call -- my naive thinking is that a variable declaration in a condition scope should be diagnosed as unused if it is used but not referenced, but I could be off-base).
clang/docs/ReleaseNotes.rst | ||
---|---|---|
130 |
Thank you for the insightful feedback!
I agree that we should not be emitting Wunused warnings in condition expressions when the declaration is of class type.
About the Scope object, if you mean ConditionVarScope flag by "condition scope", it seems to be used only for the condition of for-statements. (https://github.com/llvm/llvm-project/blob/f36b0169b8821e431644cb240f081538eb2b55ef/clang/lib/Parse/ParseExprCXX.cpp#L2045-L2057) Also it does not push new scope but modifies the flag of the current scope.
So it does not seem to be usable for our purpose here.
Instead, I think used-but-not-referenced variable declarations can be diagnosed as unused regardless of whether they are declared in condition expressions. This saves us from deleting the assertion from CodeGen and modifying AST tests.
- Stop marking condition variable declarations as unused and diagnose all VarDecl that is marked used but not referenced
- Added test not to warn when the declaration is not aggregate type
- NFC changes (comments, typo)
clang/lib/Sema/SemaExprCXX.cpp | ||
---|---|---|
4018–4021 | isAggregateType() includes arrays and I think we still want to diagnose an unused array. | |
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | ||
5355 | Which test case covers this change? | |
clang/test/SemaCXX/warn-unused-variables.cpp | ||
2 | ||
317–318 | This should diagnose the decomposition declaration as being unused, but that already works today (so let's make sure we don't get duplicate diagnostics for this case): https://godbolt.org/z/6jP6sW1x6 An additional test case after this would be to add: else if (auto [a, b] = (int[2]){ 1, 2 }; a) return; which should get no diagnostics. We should also have these tests for the other kinds of conditions (for, switch). | |
321 | Can you also add coverage for switch? |
clang/lib/Sema/SemaExprCXX.cpp | ||
---|---|---|
4018–4021 | Should it not be Condition->hasSideEffects() ? |
clang/lib/Sema/SemaExprCXX.cpp | ||
---|---|---|
4018–4021 | The condition here only applies to condition variables. | |
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | ||
5355 | I wanted to suppress warnings against implicitly declared variables in range statements like __range2. I'll add a test for this. |
clang/lib/Sema/SemaExprCXX.cpp | ||
---|---|---|
4018–4021 | After a chat with Aaron, I have a few questions: Do we call Scope::AddDecl - or PushOnScopeChains somewhere? Can you just remove that if statement (just set setReferenced(false)) and see if it works? Otherwise, i think we need to understand why it doesn't but trying to reimplement the logic of ShouldDiagnoseUnusedDeclseems fraught with unbounded complexity. |
Address comments from Aaron and Corentin
- Call ConditionVar->setReferenced(false) without any checks
- Added some more tests
clang/lib/Sema/SemaExprCXX.cpp | ||
---|---|---|
4018–4021 | It didn't break any tests locally, but when the record type does not have a user-provided dtor, it is diagnosed as unused, which seems not nice. (example written in the test trivial_dtor) |
This looks reasonable to me now.
I'll wait next week before approving it so other get a chance to look at it :)
clang/lib/Sema/SemaExprCXX.cpp | ||
---|---|---|
4018–4021 | It's still a declaration that does nothing, so diagnosing let you remove it |
clang/lib/Sema/SemaExprCXX.cpp | ||
---|---|---|
4018–4021 | Ah, I see. Thanks! |
I reverted this change because it broke sanitizer buildbots.
https://lab.llvm.org/buildbot/#/builders/19/builds/18369
The cause of the errors here are relatively clear and I can speculatively replace if (std::error_code EC = makeCanonical(Path)) with if (makeCanonical(Path))
https://lab.llvm.org/buildbot/#/builders/94/builds/15865
https://lab.llvm.org/buildbot/#/builders/240/builds/12947
These 2 are not clear for me, so I'll take time to find the cause.
That changes makes sense to me.
https://lab.llvm.org/buildbot/#/builders/94/builds/15865
https://lab.llvm.org/buildbot/#/builders/240/builds/12947
These 2 are not clear for me, so I'll take time to find the cause.
Neither of these are problems with your patch -- they're flaky tests in this case.
Thanks! I'll reland this patch with the unused std::error_code fix. I'll revert again if the same CI keeps failing for a few hours.
Would this cause many warnings in Clang/LLVM tree?
https://lab.llvm.org/buildbot/#/builders/36/builds/36560
I hope you to fix possible warnings at first.
Thanks. I'll revert this change.
I was thinking of pushing speculative fixes upstream, but the lines that need fixing are not only a few lines, so I now think it needs a review.
Fixed newly-issued warnings when trying check-clang,llvm,lld,compiler-rt,cxx,cxxabi with -Werror=unused-variable locally using local build of clang
there is a number of unused vaiables in conditional loops that are firing now, I have submitted https://github.com/llvm/llvm-project/commit/74f4daef0412be33002bd4e24a30cb47d0187ecf but I suspect it's just a start.
How did you checked the project code for that?
Per rG01b88dd66d9d52d3f531a7d490e18c549f36f445, unused dyn_cast results should turn into isa.
due to this change we have a enourmous number of new warnings, on the other hand -Wunused-variable is a valuable warning. I am not sure what is the policy and best practices for warnings but maybe there is a possiblity to make a transition period for enabling this type of warning separetely and to allow updating existing code?
I suppose it is technically, but I'm not sure the fix reads like an improvement to me... I guess that's often the case with unused variables vs. asserts though.
The usual policy is to put new warnings behind new flags so users can disable them selectively. It gets trickier when it's existing warnings getting enhanced like this. Would it be possible to put this new functionality behind a flag?
That might not be a bad idea in this case -- perhaps -Wunused-condition-variable and group it under -Wunused-variable?
Yeah, this has been a recurring issue when existing warnings get enhanced. It's often not feasible to fix all new instances right away, but you don't want to disable or -Wno-error the warning either cos then new issues can start creeping in, leaving you with no good options. Maybe we should have a policy around even enhancements to existing warnings always going in their own subgroup, so that we can disable them selectively while not regressing anything? @aaron.ballman, what are your thoughts?
Sounds god to me conceptually. (I don't know the code, so don't know how hard it is practically.)
(I haven't really read the technical side of this patch yet.)
Yes, from me observing how we internally treat such warnings.
Maybe we should have a policy around even enhancements to existing warnings always going in their own subgroup, so that we can disable them selectively while not regressing anything? @aaron.ballman, what are your thoughts?
Sometimes an improved diagnostic just triggers in very few new places that can be easily handled.
Sometimes there are many more places so that it is difficult to fix in a satisfactory timeline (as a rolling update user doesn't want to postpone releases a long time).
I think sometimes it's just difficult for contributors to figure out whether a diagnostic is going to require substantial cleanup or just a little effort. In this case rolling update users (like we) providing feedback is useful whether a new sub -Wxxx is needed.
I agree -Wunused-condition-variable sounds like a good idea. There are still numerous instances of this warning/error showing up when doing a self-build of LLVM, let alone warnings/errors that are showing up in internal code bases who are using LLVM HEAD for compiling their codebases. -Wunused-condition-variable would make this transition smoother.
Here's a more blatant regression caused by this patch.
https://godbolt.org/z/q19Ge64G3
Causing breakage for the Linux kernel:
https://github.com/ClangBuiltLinux/linux/issues/1926
Because of the amount of disruption and the fact that we're trying to get 17.x out the door while transitioning to a new code review workflow, let's revert this for now. The __attribute__((used)) problem seems to be something deeper, as [[maybe_unused]] does work properly (https://godbolt.org/z/e7YK1G69e), and putting this diagnostic under its own warning group will help folks adjust to the new behavior.
Thank you for the feedback and the revert!
Distinguishing condition variables from other unused variables in Wunused warnings was something I was trying initially, and I agree that it's the best way forward.
The difficulty is in how to know whether an unused VarDecl is a condition variable or not in the phase of emitting Wunused-variable. We may need to add a boolean flag IsConditionVar in VarDecl or something.
The reason [[maybe_unused]] works well is that it is explicitly handled in Sema::ShouldDiagnoseUnusedDecl (https://github.com/llvm/llvm-project/blob/e7bd43675753476e97e63aa13c13b3498407ed1c/clang/lib/Sema/SemaDecl.cpp#L2005-L2007)
The used attribute regression was caused by the "used but not-referenced variables should be diagnosed as unused" change. Once we have some way of knowing that a VarDecl is a condition variable, we should only apply this change to condition variables, thereby avoiding regression.