These are intended to mimic warnings available in gcc.
Details
- Reviewers
george.burgess.iv cjdb aeubanks rtrieu aaron.ballman efriedma rsmith lebedev.ri - Commits
- rGcf49cae278b4: [Clang] -Wunused-but-set-parameter and -Wunused-but-set-variable
rG14dfb3831c42: [Clang] -Wunused-but-set-parameter and -Wunused-but-set-variable
rG9b0501abc7b5: [Clang] -Wunused-but-set-parameter and -Wunused-but-set-variable
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
There is no such requirement. I don't recall that happening basically ever, actually.
Of course, but I would have wanted to see this discussed on the mailing list since the pool of the affected actors by this is very big.
reverted
regarding having a reviewer who is knowledgable in clang diagnostics, I assumed that george.burgess.iv was knowledgable and was happy with the change after his comments, perhaps I should have waited for an explicit LGTM
So it seems there are 3 issues here:
- local variables declared extern should not trigger this warning. I'll fix this.
- Should x in this code trigger the warning:
int x; int y = (x = 0);
These are essentially the "false positives" reported in the Linux kernel. I find it questionable to consider these "false positives"; it seems to me that x is not really used. But gcc's behavior is to not trigger here so maybe following it is best.
- If x above should not trigger the warning, it might be difficult to detect this case with an AST walk using the current data. Would it be acceptable to add a bit to VarDecl or Decl indicating whether it's ever read (not just referenced), which could then be set, maybe in Sema::ActOnFinishFullExpr ? This would then remove the need for the new AST walk altogether. (it seems gcc has such a bit)
Yes, the best solution. Also consider to check gcc’s test-suite - if they have this type of testcase, then this is wanted behaviour.
When this change returns, I'd like to see a different implementation strategy. Running a recursive AST visitation after the fact is generally not the right way to look for this kind of issue; adding an extra pass to speculatively hunt for each kind of warning we might want to issue is too expensive. Instead, I think we should do something simpler and cheaper, such as tracking, for each variable in scope, the number of potentially-evaluated non-assignment references to that variable. For example:
- in DoMarkVarDeclReferenced, increment a per-variable counter if the variable is a local and the reference is an odr-use
- in IgnoredValueConversions, if we're discarding a potentially-evaluated assignment or increment expression acting on a local variable, decrement the counter for that variable
- in ActOnPopScope, or perhaps in DiagnoseUnusedDecl, when we're diagnosing unused variables, also diagnose set-but-not-used variables (where the variable is marked as used but the counter is equal to zero)
Yes, the best solution. Also consider to check gcc’s test-suite - if they have this type of testcase, then this is wanted behaviour.
gcc has the test Wunused-var-5.c, where the warning -Wunused-but-set-variable is applied but
void bar (int, ...); void f18 (void) { _Atomic int x = 0; int y = 3; bar (x = y); }
is not expected to trigger the warning, which does seem to imply this is intentional.
Another try at these warnings, using the implementation strategy outlined by rsmith.
A couple other notes:
- At the moment I've removed these warnings from the diagnostic groups -Wextra and -Wunused. It was suggested by aeubanks that the groups could be added in a later commit, once these warnings have been determined to not be too disruptive. Of course I can change this now if requested.
- I've just tried to mimic gcc's behavior as closely as possible, including not warning if an assignment is used, and not warning on nonscalar types in C++ (except that in some cases gcc inexplicably does warn on nonscalar types; test on the file vector-gcc-compat.c to compare... I haven't determined any rationale to when it chooses to warn in these cases).
Got a link/examples of cases GCC does and doesn't warn about? I'd assume it'd have something to do with the triviality or non-triviality of certain operations of the nonscalar types (eg: is the type trivially assignable/trivially destructible)
I've removed these warnings from the diagnostic groups -Wextra
But to remove all false positives, you need reports from users of -Wextra. Otherwise this would be dead code with no users.
I suggest keeping it in groups. Now you can ask folks to try this patch with kernel, Firefox, Chrome, XYZ and of course LLVM. Also you can try gcc’s testcases for this warning. If it is OK, I see no reasons to remove it from those groups.
Got a link/examples of cases GCC does and doesn't warn about? I'd assume it'd have something to do with the triviality or non-triviality of certain operations of the nonscalar types (eg: is the type trivially assignable/trivially destructible)
This doesn't seem to be what determines it. AFAICT it never warns for a struct in C++. However, if I do
gcc -fsyntax-only -Wunused-but-set-variable clang/test/Sema/vector-gcc-compat.c
I get warnings for the variables v2i64_r and v4i32_r.
But if I do
g++ -fsyntax-only -Wunused-but-set-variable clang/test/Sema/vector-gcc-compat.c
I only get warnings for the variable v2i64_r.
I will investigate a little more tomorrow.
Will also make a new revision tomorrow with these warnings added to the appropriate groups.
regarding adding these to a warning group in a separate change, it's easier to revert a smaller second change that adds this to warning groups, and easier to iterate upon in tree when there are discovered issues
it's not dead code if it has tests
I meant dead code in terms of users if second patch are not gonna come anytime soon after first one :)
You can always commit this patch as two - first with new warning, second - add to groups.
clang/include/clang/Basic/DiagnosticGroups.td | ||
---|---|---|
880 | llvm-project/clang/include/clang/Basic/DiagnosticGroups.td:874:25: error: Variable not defined: 'UnusedButSetVariable' UnusedButSetVariable, UnusedPropertyIvar]>, ^ |
Apparently arc and/or Phabricator doesn't like my attempt to split this review into two separate commits. Next revision will have only one commit.
Correct struct and vector behavior.
gcc doesn't warn for any structs in C++. However, it _does_ warn for vector types. Those warnings are sometimes masked by other errors, leading to my earlier belief that it is inconsistent about warning for vector types.
I see lots of instances from the kernel that look like this when reduced:
$ cat foo.c int page; int put_page_testzero(int); void foo (void) { int zeroed; zeroed = put_page_testzero(page); ((void)(sizeof(( long)(!zeroed)))); } $ clang -c -Wall foo.c foo.c:4:7: warning: variable 'zeroed' set but not used [-Wunused-but-set-variable] int zeroed; ^
Count a non-ODR use as a reference, so that examples like that of nickdesaulniers don't warn.
Any idea what the purpose of this code is/why it's not a reasonable thing to warn on?
The additions of -Wno-unused-but-set-variable to:
- clang/test/SemaObjC/foreach.m
- clang/test/SemaCXX/sizeless-1.cpp
- clang/test/SemaCXX/shift.cpp
- clang/test/SemaCXX/goto.cpp
- clang/test/Sema/vector-gcc-compat.cpp
- clang/test/Sema/vector-gcc-compat.c
- clang/test/FixIt/fixit.cpp
- clang/test/CodeGen/builtins-arm.c
- clang/test/CodeGen/builtins-riscv.c
- clang/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp
...
all the one line changes to tests that add this warning flag to the run line look questionable to me; we generally don't add new warning flags to a ton of existing tests. Were those cases that were previously failing? Were those accidentally committed? I would have expected this change to be:
- changes to enable the flag and do something
- block of additional test cases
- changes to existing tests if they were failing this new check inadvertantly.
But adding a new warning flags to a handful of existing tests' RUN lines is unusual.
Testing Diff 342071 on the mainline Linux kernel, just building x86_64 defconfig triggers 19 instances of this warning; all look legit. ;)
include/linux/build_bug.h:
25 /* 26 * BUILD_BUG_ON_INVALID() permits the compiler to check the validity of the 27 * expression but avoids the generation of any code, even if that expression 28 * has side-effects. 29 */ 30 #define BUILD_BUG_ON_INVALID(e) ((void)(sizeof((__force long)(e))))
include/linux/mmdebug.h:
57 #define VM_BUG_ON(cond) BUILD_BUG_ON_INVALID(cond)
mm/internal.h:
410 static inline unsigned long 411 vma_address(struct page *page, struct vm_area_struct *vma) 412 { 413 unsigned long start, end; 414 415 start = __vma_address(page, vma); 416 end = start + thp_size(page) - PAGE_SIZE; 417 418 /* page should be within @vma mapping range */ 419 VM_BUG_ON_VMA(end < vma->vm_start || start >= vma->vm_end, vma);
The warning (in previous revisions was triggering on end in vma_address.
But adding a new warning flags to a handful of existing tests' RUN lines is unusual.
These tests use -Wall for whatever reason, and they assign but don't use several variables, so we'll get warnings on them unless I add -Wno-unused-but-set-variable. Other alternatives:
- add an expected-warning;
- use a pragma to disable the warning;
- put an unused attribute on the variables in question;
- introduce an artificial use of these variables.
I previously used item 1, but somebody earlier in an earlier comment requested that instead I add -Wno-unused-but-set-variable instead.
Ah, I missed that they were _disabling_ the warning; I was thinking they were _enabling_ it. Sorry for the noise; LGTM.
Ah, fair enough. I guess this means the warning has the same false positive with a value that's initialized unconditional, but then read only in an assert (& thus unread in a non-asserts build)? As much as we're used to accepting that as a limitation of assert, I can see how that'd be good to avoid for new warnings to reduce false positives/code that would require modifications despite there being no bug in it.
casting to void is the normal way to get around these warnings, these new warnings should also not diagnose anything with a cast to void
FWIW gcc does not warn in this case regardless of any cast:
void f() { int x; x = 0; sizeof(x); }
If you'd like you can split this into separate changes, one for adding the warning and another for adding it into warning groups, either way is fine.
Seems like the reported false positives have been addressed.
This warning seems to have a lot of false positives on things like reference arguments that are used as output parameters. For example here is a small sample of output from a stage2 build of part of LLVM:
In file included from ../llvm/lib/BinaryFormat/Minidump.cpp:9: In file included from ../llvm/include/llvm/BinaryFormat/Minidump.h:21: In file included from ../llvm/include/llvm/ADT/BitmaskEnum.h:16: ../llvm/include/llvm/Support/MathExtras.h:822:9: warning: variable 'Overflowed' set but not used [-Wunused-but-set-variable] bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy; ^ ../llvm/include/llvm/Support/MathExtras.h:936:72: warning: parameter 'Result' set but not used [-Wunused-but-set-parameter] std::enable_if_t<std::is_signed<T>::value, T> MulOverflow(T X, T Y, T &Result) { ^ In file included from ../llvm/lib/BinaryFormat/Minidump.cpp:9: In file included from ../llvm/include/llvm/BinaryFormat/Minidump.h:22: In file included from ../llvm/include/llvm/ADT/DenseMapInfo.h:20: ../llvm/include/llvm/ADT/StringRef.h:511:37: warning: parameter 'Result' set but not used [-Wunused-but-set-parameter] getAsInteger(unsigned Radix, T &Result) const { ^ ../llvm/include/llvm/ADT/StringRef.h:522:37: warning: parameter 'Result' set but not used [-Wunused-but-set-parameter] getAsInteger(unsigned Radix, T &Result) const { ^ ../llvm/include/llvm/ADT/StringRef.h:545:39: warning: parameter 'Result' set but not used [-Wunused-but-set-parameter] consumeInteger(unsigned Radix, T &Result) { ^ ../llvm/include/llvm/ADT/StringRef.h:556:39: warning: parameter 'Result' set but not used [-Wunused-but-set-parameter] consumeInteger(unsigned Radix, T &Result) { ^ 6 warnings generated.
Could you please take a look?
Don't warn for reference or dependent types (fixing false positives).
Also fix a few places where this warning is correctly triggered. In a couple
places I did that by adding attribute((unused)) rather than removing the
unused variable.
Also fix a few places where this warning is correctly triggered.
Create new patch please - dont mix fixes with new warning within one patch.
Removing from queue - i don't expect to review this.
Looks like this has been reverted twice now, presumably llvm stage 2/linux kernel/chrome
should be enough of a coverage to be sure there isn't any obvious false-positives this time.
I think there is a false positive with this @george.burgess.iv:
In this we have the warning triggered:
mozglue/baseprofiler/core/platform-linux-android.cpp:216:9: error: variable 'r' set but not used [-Werror,-Wunused-but-set-variable]
SigHandlerCoordinator() { PodZero(&mUContext); int r = sem_init(&mMessage2, /* pshared */ 0, 0); r |= sem_init(&mMessage3, /* pshared */ 0, 0); r |= sem_init(&mMessage4, /* pshared */ 0, 0); MOZ_ASSERT(r == 0); }
If MOZ_ASSERT is expanded to nothing, than the warning is correct. (void)r; trick should work here..
Hello! There are still some false positives, for example this one is breaking the libc++ CI: https://buildkite.com/llvm-project/libcxx-ci/builds/3530#8679608a-200b-4a48-beb4-a9e9924a8848
Would it be possible to either fix this quickly or revert the change until the issue has been fixed? Our pre-commit CI is going to be stalled until this is fixed. Thanks!
Looks like a true positive in libc++ ( https://github.com/llvm/llvm-project/blob/main/libcxx/include/regex ) - the "j" variable is initialized, then incremented, but never read (except to increment). Is that a bug in libc++? Was j meant to be used for something?
Oh, you're right! I was tripped by the fact that we did in fact "use" __j (in the sense that we do __j += ...), but indeed we never read the result. I'll work on fixing that issue. I'm not sure whether it's a bug or not yet, that code was modified 11 years ago, but I'll do my research.
Is it intentional that this warns about volatile variables as in
void f(char * p) { volatile char c = 0; c ^= *p; }
(I see that GCC warns about volatile too, at least when you replace the ^= with =, so assume the answer is "yes", but would just like to see that confirmed (ideally with a test case even?).)
http://sprunge.us/FJzZXL is a file from harfbuzz and it warns
a.cc:28670:32: error: variable 'supp_size' set but not used [-Werror,-Wunused-but-set-variable] unsigned int size0, size1, supp_size = 0;
I do not have -Werror enabled but it still is reported as error. There is no way to disable this warning ?
You have, with pragma gcc error, look at hb.hh. The problem is that clang has an error dealing with cascading pragma when setting different levels.
I do not have -Werror enabled but it still is reported as error. There is no way to disable this warning ?
Go to the hb GitHub repo, I’ve fixed this in master branch, it will propagate soon to a new release.