Bug 77292 - Spurious warning: logical not is only applied to the left hand side of comparison
Summary: Spurious warning: logical not is only applied to the left hand side of compar...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 5.4.0
: P3 normal
Target Milestone: ---
Assignee: Marek Polacek
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2016-08-19 00:26 UTC by M Welinder
Modified: 2016-08-29 18:14 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 6.1.1
Last reconfirmed: 2016-08-19 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description M Welinder 2016-08-19 00:26:36 UTC
The warning introduced in bug 62183 is trigger-happy.

int
foo (int a, int b)
{
  // Make it obvious that these are booleans.
  a = !!a;
  b = !!b;

  return !a == b;
}


# gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

# gcc -c -Wall -O2 bbb.c 
bbb.c: In function ‘foo’:
bbb.c:8:13: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses]
   return !a == b;
             ^
This is silly and out-right illogical when "a" and "b" are booleans.
"!a == b" means the same as "!(a == b)", so the warning is pointing out
that I might have meant something else that, upon inspection, is seen
to be the same thing.

Note: by "boolean" I mean an integer with value 0 or 1.
Comment 1 Richard Biener 2016-08-19 07:25:22 UTC
Well,

  // Make it obvious that these are booleans.
  a = !!a;
  b = !!b;

this isn't visible to the compiler when it analyzes

  return !a == b;

to warn.  Your example is very specific and unlike from real code so are you
complaining about

  return !a == b;

warning even when it is not immediately preceeded by a a = !!a; stmt?  Then
we've discussed this to death already.
Comment 2 Marek Polacek 2016-08-19 10:59:21 UTC
Not a bug, IMHO.
Comment 3 M Welinder 2016-08-19 11:35:22 UTC
The actual code I got this warning from was...

		if (!lower_tail == (p > phalf)) {

where lower_tail is an int and p and phalf are doubles.

That's simply a comparison of two booleans.  Note, that the hinted-at code

   !(lower_tail == (p > phalf))

is dubious: comparing an int to a booleans.

> this isn't visible to the compiler when it analyzes
>   return !a == b;

I am not aware of a rule that requires the compiler to ignore context
when considering warnings.  It certainly does consider context when
it issues "might be used uninitialized" warnings, so why not here?
Comment 4 Manuel López-Ibáñez 2016-08-19 11:46:23 UTC
Note that Clang suggests two ways to silence the warning:

prog.cc:9:10: note: add parentheses after the '!' to evaluate the comparison first
  return !a == b;
         ^
          (     )
prog.cc:9:10: note: add parentheses around left hand side expression to silence this warning
  return !a == b;
         ^
         ( )


Also, we do not warn for actual booleans (bool).

To be able to not warn based on the runtime range of variables, we would need something like VRP in the FE, and that is unlikely to be implemented in the medium future.
Comment 5 Richard Biener 2016-08-19 11:49:41 UTC
(In reply to M Welinder from comment #3)
> The actual code I got this warning from was...
> 
> 		if (!lower_tail == (p > phalf)) {
> 
> where lower_tail is an int and p and phalf are doubles.

Well, that changes things because I agree that in the above case the
warning is bogus.


> That's simply a comparison of two booleans.  Note, that the hinted-at code
> 
>    !(lower_tail == (p > phalf))
> 
> is dubious: comparing an int to a booleans.
> 
> > this isn't visible to the compiler when it analyzes
> >   return !a == b;
> 
> I am not aware of a rule that requires the compiler to ignore context
> when considering warnings.  It certainly does consider context when
> it issues "might be used uninitialized" warnings, so why not here?

Because it's not done as in the frontend there is no data-flow available.

So, testcase:

int
foo (int a, int b)
{
  return !a == (a < b);
}

t.c: In function ‘foo’:
t.c:4:13: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses]
   return !a == (a < b);
             ^~
Comment 6 Marek Polacek 2016-08-19 11:50:29 UTC
(In reply to Manuel López-Ibáñez from comment #4)
> Note that Clang suggests two ways to silence the warning:
> 
> prog.cc:9:10: note: add parentheses after the '!' to evaluate the comparison
> first
>   return !a == b;
>          ^
>           (     )
> prog.cc:9:10: note: add parentheses around left hand side expression to
> silence this warning
>   return !a == b;
>          ^
>          ( )

I guess I should employ here the fix-it feature we now have...

> Also, we do not warn for actual booleans (bool).

This is intentional.

> To be able to not warn based on the runtime range of variables, we would
> need something like VRP in the FE, and that is unlikely to be implemented in
> the medium future.

...if ever.
Comment 7 Richard Biener 2016-08-19 11:51:15 UTC
Clang doesn't warn about this.
Comment 8 Marek Polacek 2016-08-19 11:52:40 UTC
Neither does cc1plus because comparison result has a boolean type...

I'll see what I can do here.
Comment 9 Manuel López-Ibáñez 2016-08-19 11:58:58 UTC
(In reply to M Welinder from comment #3)
> I am not aware of a rule that requires the compiler to ignore context
> when considering warnings.  It certainly does consider context when
> it issues "might be used uninitialized" warnings, so why not here?

Wuninitialized warnings are implemented in the middle-end. They benefit from the analysis done by optimization, but also suffer from the optimizations transforming and removing code (PR18501 and http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings).

Warnings in the FE, like this one, are more consistent but there is very limited analysis done in the FE (because it is harder to implement in the FE, it may slow down the compiler and would duplicate the analysis done in the middle-end for optimization).
Comment 10 Manuel López-Ibáñez 2016-08-19 12:04:40 UTC
(In reply to Richard Biener from comment #5)
> int
> foo (int a, int b)
> {
>   return !a == (a < b);
> }
> 
> t.c: In function ‘foo’:
> t.c:4:13: warning: logical not is only applied to the left hand side of
> comparison [-Wlogical-not-parentheses]
>    return !a == (a < b);
>              ^~

Why is this not a valid warning?

#include <stdio.h>
void
foo (int a, bool b)
{
  printf("(!a) == b -> %d\n", (int) (!a) == b);
  printf("!(a == b) -> %d\n", (int) !(a == b));
}

int main()
{
    foo(2,1);
}

(!a) == b -> 0
!(a == b) -> 1
Comment 11 Segher Boessenkool 2016-08-19 12:32:21 UTC
(In reply to Manuel López-Ibáñez from comment #4)
> Note that Clang suggests two ways to silence the warning:
> 
> prog.cc:9:10: note: add parentheses after the '!' to evaluate the comparison
> first
>   return !a == b;
>          ^
>           (     )
> prog.cc:9:10: note: add parentheses around left hand side expression to
> silence this warning
>   return !a == b;
>          ^
>          ( )

Both of these suggestions are not so good.  "!(a == b)" is better written
as "a != b", and "!(a) == b" is just horrible.
Comment 12 Manuel López-Ibáñez 2016-08-19 12:39:40 UTC
(In reply to Segher Boessenkool from comment #11)
> Both of these suggestions are not so good.  "!(a == b)" is better written
> as "a != b", and "!(a) == b" is just horrible.

Agreed for the former, but the latter is suggesting (!a) == b, which is IMHO clearer than ! a == b.
Comment 13 Segher Boessenkool 2016-08-19 16:35:16 UTC
(In reply to Manuel López-Ibáñez from comment #12)
> (In reply to Segher Boessenkool from comment #11)
> > Both of these suggestions are not so good.  "!(a == b)" is better written
> > as "a != b", and "!(a) == b" is just horrible.
> 
> Agreed for the former, but the latter is suggesting (!a) == b, which is IMHO
> clearer than ! a == b.

Ah.  The parens are placed suggestively around the "a" in the suggestion, so
it is misleading even :-/  (Or maybe I'm just not very good at reading).
Comment 14 Manuel López-Ibáñez 2016-08-24 22:04:53 UTC
(In reply to Manuel López-Ibáñez from comment #10)
> > t.c:4:13: warning: logical not is only applied to the left hand side of
> > comparison [-Wlogical-not-parentheses]
> >    return !a == (a < b);
> >              ^~
> 
> Why is this not a valid warning?

Ah, this is on purpose to avoid too many false positives. Sorry for the noise.
Comment 15 Marek Polacek 2016-08-29 18:13:46 UTC
Author: mpolacek
Date: Mon Aug 29 18:13:13 2016
New Revision: 239833

URL: https://gcc.gnu.org/viewcvs?rev=239833&root=gcc&view=rev
Log:
	PR c/77292
	* c-common.c (warn_logical_not_parentheses): Don't warn for
	a comparison or a logical operator.

	* c-c++-common/Wlogical-not-parentheses-1.c: New test.

Added:
    trunk/gcc/testsuite/c-c++-common/Wlogical-not-parentheses-1.c
Modified:
    trunk/gcc/c-family/ChangeLog
    trunk/gcc/c-family/c-common.c
    trunk/gcc/testsuite/ChangeLog
Comment 16 Marek Polacek 2016-08-29 18:14:36 UTC
Fixed.