This fix PR37919
The below code produces -Wconstant-logical-operand for the first statement,
but not the second.
void foo(int x) {
if (x && 5) {}
if (5 && x) {}
}
Differential D142609
[Clang] Fix -Wconstant-logical-operand when LHS is a constant xgupta on Jan 26 2023, 2:36 AM. Authored by
Details This fix PR37919 The below code produces -Wconstant-logical-operand for the first statement, void foo(int x) {
Diff Detail
Event TimelineComment Actions WIP && TODO- Fixed test Failed Tests (7): Clang :: C/drs/dr4xx.c Clang :: Modules/explicit-build-extra-files.cpp Clang :: Parser/cxx2a-concept-declaration.cpp Clang :: SemaCXX/expressions.cpp Clang :: SemaCXX/warn-unsequenced.cpp Clang :: SemaObjC/unguarded-availability.m Clang :: SemaTemplate/dependent-expr.cpp Comment Actions Thanks for the patch! If the current diff is causing test failures, please mark this "Changes Planned" in phabricator (Under the Add Action dropdown in the bottom left) so the reviewers know that there's outstanding issues. Or post but don't cc explicit reviewers yet.
Comment Actions I did kernel builds of x86_64 and aarch64 defconfigs. This found new instance:
Comment Actions Hmm...looking at some of the commits to the related code, it might be very intentional that we don't warn symmetrically: 938533db602b32ab435078e723b656ac6e779a1b
Comment Actions Address comments
Comment Actions We should not warn for macros. if (ENABLE_XYZ && x) {} This pattern is used in real world codebases. Comment Actions I took the most recent version for a spin against the Linux kernel. The couple of issues that a previous revision of the warning flagged (https://github.com/ClangBuiltLinux/linux/issues/1806, https://github.com/ClangBuiltLinux/linux/issues/1807) are no longer visible (that seems intentional because both of those came from macro expressions) but I see a new one along a similar line as those: https://elixir.bootlin.com/linux/v6.5-rc2/source/drivers/gpu/drm/v3d/v3d_drv.h#L343 In file included from drivers/gpu/drm/v3d/v3d_bo.c:25: drivers/gpu/drm/v3d/v3d_drv.h:343:24: warning: use of logical '&&' with constant operand [-Wconstant-logical-operand] 343 | if (NSEC_PER_SEC % HZ && | ~~~~~~~~~~~~~~~~~ ^ drivers/gpu/drm/v3d/v3d_drv.h:343:24: note: use '&' for a bitwise operation 343 | if (NSEC_PER_SEC % HZ && | ^~ | & drivers/gpu/drm/v3d/v3d_drv.h:343:24: note: remove constant to silence this warning 1 warning generated. Another minimized example showing how the warning can trigger with different configurations: $ cat x.c #define A 1000 #define B 300 #define C 250 #define D 100 int bar(void); int baz(void); int foo(void) { if (A % B && bar()) // 1000 % 300 = 100, warning return -3; if (A % C && bar()) // 1000 % 250 = 0, no warning return -2; if (A % D && bar()) // 1000 % 100 = 0, no warning return -1; return baz(); } $ clang -Wall -fsyntax-only x.c x.c:11:12: warning: use of logical '&&' with constant operand [-Wconstant-logical-operand] 11 | if (A % B && bar()) | ~~~~~ ^ x.c:11:12: note: use '&' for a bitwise operation 11 | if (A % B && bar()) | ^~ | & x.c:11:12: note: remove constant to silence this warning 1 warning generated. I am sure we can send a patch making that a boolean expression (although it is duplicated in a few places it seems so multiple patches will be needed) but I figured I would report it just in case there was something that should be changed with the warning, since I see there was already some discussion around not warning for macros and this seems along a similar line. Comment Actions In my opinion it makes sense to adjust that kernel code based on this warning in the current inplementation state. Comment Actions I think that use of macros for any of the constant values in the expression should silence the diagnostic on the assumption that the macro value changes with different configurations and so it's only constant in one configuration mode. Alternatively, I could see an argument to use a different diagnostic group when macros are involved so that users can silence macro-related constant warnings while not losing non-macro cases. WDYT? Comment Actions IIUC in this patch I am making more like an NFC change and this could be a separate issue. WDYT @nickdesaulniers? Please review it so we can commit it soon. Comment Actions I only see 4 instances of NSEC_PER_SEC % HZ in mainline. 2 already use the C preprocessor (inconsistently), and 2 don't. I think the 2 that don't could be converted to use the preprocessor, then that issue goes away. So I think we can clean that up on the kernel side. @nathanchance were there many other instances of warnings triggered by this patch beyond that? Comment Actions Is this diff what you had in mind? diff --git a/drivers/gpu/drm/i915/gem/i915_gem_wait.c b/drivers/gpu/drm/i915/gem/i915_gem_wait.c index 4a33ad2d122b..d7dd93da2511 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_wait.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_wait.c @@ -186,9 +186,10 @@ i915_gem_object_wait(struct drm_i915_gem_object *obj, static inline unsigned long nsecs_to_jiffies_timeout(const u64 n) { /* nsecs_to_jiffies64() does not guard against overflow */ - if (NSEC_PER_SEC % HZ && - div_u64(n, NSEC_PER_SEC) >= MAX_JIFFY_OFFSET / HZ) +#if (NSEC_PER_SEC % HZ) != 0 + if (div_u64(n, NSEC_PER_SEC) >= MAX_JIFFY_OFFSET / HZ) return MAX_JIFFY_OFFSET; +#endif return min_t(u64, MAX_JIFFY_OFFSET, nsecs_to_jiffies64(n) + 1); } diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index b74b1351bfc8..af1470ee477d 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -340,9 +340,10 @@ struct v3d_submit_ext { static inline unsigned long nsecs_to_jiffies_timeout(const u64 n) { /* nsecs_to_jiffies64() does not guard against overflow */ - if (NSEC_PER_SEC % HZ && - div_u64(n, NSEC_PER_SEC) >= MAX_JIFFY_OFFSET / HZ) +#if (NSEC_PER_SEC % HZ) != 0 + if (div_u64(n, NSEC_PER_SEC) >= MAX_JIFFY_OFFSET / HZ) return MAX_JIFFY_OFFSET; +#endif return min_t(u64, MAX_JIFFY_OFFSET, nsecs_to_jiffies64(n) + 1); } Not sure how the kernel maintainers will like that, they generally do not like to use preprocessing for hiding warnings. Alternatively, we could just turn the checks into booleans, which is what I tested earlier. diff --git a/drivers/gpu/drm/i915/gem/i915_gem_wait.c b/drivers/gpu/drm/i915/gem/i915_gem_wait.c index 4a33ad2d122b..d4b918fb11ce 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_wait.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_wait.c @@ -186,7 +186,7 @@ i915_gem_object_wait(struct drm_i915_gem_object *obj, static inline unsigned long nsecs_to_jiffies_timeout(const u64 n) { /* nsecs_to_jiffies64() does not guard against overflow */ - if (NSEC_PER_SEC % HZ && + if ((NSEC_PER_SEC % HZ) != 0 && div_u64(n, NSEC_PER_SEC) >= MAX_JIFFY_OFFSET / HZ) return MAX_JIFFY_OFFSET; diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index b74b1351bfc8..7f664a4b2a75 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -340,7 +340,7 @@ struct v3d_submit_ext { static inline unsigned long nsecs_to_jiffies_timeout(const u64 n) { /* nsecs_to_jiffies64() does not guard against overflow */ - if (NSEC_PER_SEC % HZ && + if ((NSEC_PER_SEC % HZ) != 0 && div_u64(n, NSEC_PER_SEC) >= MAX_JIFFY_OFFSET / HZ) return MAX_JIFFY_OFFSET; I don't really have a strong preference either way but warnings that show up with certain configuration values and not others are annoying for things like randconfig testing, although I suppose that is always the nature of certain warnings...
No, those were the only two instances that I saw across my whole build matrix with the current version of the patch. Comment Actions Thanks, @nickdesaulniers for reviewing and @nathanchance for testing the change. @aaron.ballman, I also agree with @xbolva00 seems warning in kernel code is valid but I also agree with your comment about macro, may be better to track the macro-related issue with another GitHub issue. Comment Actions For the record, I have sent https://lore.kernel.org/20230718-nsecs_to_jiffies_timeout-constant-logical-operand-v1-0-36ed8fc8faea@kernel.org/ to address those warnings for the kernel. Comment Actions Concerns have been raised in https://github.com/llvm/llvm-project/issues/64356 that this is an undesirable change in diagnostic behavior. The diagnostic is supposed to fire when misusing a logical operand that most likely should have been a bitwise operand. There's a feeling that true && expr is plausibly done intentionally more often than true & expr. I think we should revert the changes from this patch and in the Clang 17.x branch so that we can reevaluate the approach taken in this patch. CC @porglezomp @cjdb Comment Actions This got reverted and cherry-pick request is made - https://github.com/llvm/llvm-project/issues/64515. Comment Actions Thank you! There's been some more discussion about the design on the github issue, in case you're interested in continuing to pursue this patch. |
Instead of LHS and RHS, should we rename these to Op1 and Op2 (short for operand one and operand two)? That way there's no confusion since this is called twice with LHS/RHS swapped the second time?