* c-family PATCH to improve -Wtautological-compare (PR c/81783)
@ 2017-08-16 15:20 Marek Polacek
2017-08-16 15:35 ` David Malcolm
2017-09-01 16:41 ` Jeff Law
0 siblings, 2 replies; 7+ messages in thread
From: Marek Polacek @ 2017-08-16 15:20 UTC (permalink / raw)
To: GCC Patches; +Cc: Joseph Myers, David Malcolm, Jason Merrill
This patch improves -Wtautological-compare so that it also detects
bitwise comparisons involving & and | that are always true or false, e.g.
if ((a & 16) == 10)
return 1;
can never be true. Note that e.g. "(a & 9) == 8" is *not* always false
or true.
I think it's pretty straightforward with one snag: we shouldn't warn if
the constant part of the bitwise operation comes from a macro, but currently
that's not possible, so I XFAILed this in the new test.
This has found one issue in the GCC codebase and it's a genuine bug:
<https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00757.html>.
Bootstrapped/regtested on x86_64-linux, ok for trunk?
2017-08-16 Marek Polacek <polacek@redhat.com>
PR c/81783
* c-warn.c (warn_tautological_bitwise_comparison): New function.
(warn_tautological_cmp): Call it.
* doc/invoke.texi: Update -Wtautological-compare documentation.
* c-c++-common/Wtautological-compare-5.c: New test.
diff --git gcc/c-family/c-warn.c gcc/c-family/c-warn.c
index 9c3073444cf..0749d16a50f 100644
--- gcc/c-family/c-warn.c
+++ gcc/c-family/c-warn.c
@@ -321,6 +321,59 @@ find_array_ref_with_const_idx_r (tree *expr_p, int *, void *)
return NULL_TREE;
}
+/* Subroutine of warn_tautological_cmp. Warn about bitwise comparison
+ that always evaluate to true or false. LOC is the location of the
+ ==/!= comparison specified by CODE; LHS and RHS are the usual operands
+ of this comparison. */
+
+static void
+warn_tautological_bitwise_comparison (location_t loc, tree_code code,
+ tree lhs, tree rhs)
+{
+ if (code != EQ_EXPR && code != NE_EXPR)
+ return;
+
+ /* Extract the operands from e.g. (x & 8) == 4. */
+ tree bitop;
+ tree cst;
+ if ((TREE_CODE (lhs) == BIT_AND_EXPR
+ || TREE_CODE (lhs) == BIT_IOR_EXPR)
+ && TREE_CODE (rhs) == INTEGER_CST)
+ bitop = lhs, cst = rhs;
+ else if ((TREE_CODE (rhs) == BIT_AND_EXPR
+ || TREE_CODE (rhs) == BIT_IOR_EXPR)
+ && TREE_CODE (lhs) == INTEGER_CST)
+ bitop = rhs, cst = lhs;
+ else
+ return;
+
+ tree bitopcst;
+ if (TREE_CODE (TREE_OPERAND (bitop, 0)) == INTEGER_CST)
+ bitopcst = TREE_OPERAND (bitop, 0);
+ else if (TREE_CODE (TREE_OPERAND (bitop, 1)) == INTEGER_CST)
+ bitopcst = TREE_OPERAND (bitop, 1);
+ else
+ return;
+
+ wide_int res;
+ if (TREE_CODE (bitop) == BIT_AND_EXPR)
+ res = wi::bit_and (bitopcst, cst);
+ else
+ res = wi::bit_or (bitopcst, cst);
+
+ /* For BIT_AND only warn if (CST2 & CST1) != CST1, and
+ for BIT_OR only if (CST2 | CST1) != CST1. */
+ if (res == cst)
+ return;
+
+ if (code == EQ_EXPR)
+ warning_at (loc, OPT_Wtautological_compare,
+ "bitwise comparison always evaluates to false");
+ else
+ warning_at (loc, OPT_Wtautological_compare,
+ "bitwise comparison always evaluates to true");
+}
+
/* Warn if a self-comparison always evaluates to true or false. LOC
is the location of the comparison with code CODE, LHS and RHS are
operands of the comparison. */
@@ -337,6 +390,8 @@ warn_tautological_cmp (location_t loc, enum tree_code code, tree lhs, tree rhs)
|| from_macro_expansion_at (EXPR_LOCATION (rhs)))
return;
+ warn_tautological_bitwise_comparison (loc, code, lhs, rhs);
+
/* We do not warn for constants because they are typical of macro
expansions that test for features, sizeof, and similar. */
if (CONSTANT_CLASS_P (fold_for_warn (lhs))
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index ec29f1d629e..72a16a19711 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -5484,6 +5484,14 @@ int i = 1;
@dots{}
if (i > i) @{ @dots{} @}
@end smallexample
+
+This warning also warns about bitwise comparisons that always evaluate
+to true or false, for instance:
+@smallexample
+if ((a & 16) == 10) @{ @dots{} @}
+@end smallexample
+will always be false.
+
This warning is enabled by @option{-Wall}.
@item -Wtrampolines
diff --git gcc/testsuite/c-c++-common/Wtautological-compare-5.c gcc/testsuite/c-c++-common/Wtautological-compare-5.c
index e69de29bb2d..4664bfdeae6 100644
--- gcc/testsuite/c-c++-common/Wtautological-compare-5.c
+++ gcc/testsuite/c-c++-common/Wtautological-compare-5.c
@@ -0,0 +1,106 @@
+/* PR c/81783 */
+/* { dg-do compile } */
+/* { dg-options "-Wtautological-compare" } */
+
+enum E { FOO = 128 };
+
+int
+f (int a)
+{
+ if ((a & 16) == 10) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+ if ((16 & a) == 10) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+ if (10 == (a & 16)) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+ if (10 == (16 & a)) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+
+ if ((a & 16) != 10) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+ if ((16 & a) != 10) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+ if (10 != (a & 16)) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+ if (10 != (16 & a)) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+
+ if ((a & 9) == 8)
+ return 1;
+ if ((9 & a) == 8)
+ return 1;
+ if (8 == (a & 9))
+ return 1;
+ if (8 == (9 & a))
+ return 1;
+
+ if ((a & 9) != 8)
+ return 1;
+ if ((9 & a) != 8)
+ return 1;
+ if (8 != (a & 9))
+ return 1;
+ if (8 != (9 & a))
+ return 1;
+
+ if ((a | 16) == 10) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+ if ((16 | a) == 10) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+ if (10 == (a | 16)) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+ if (10 == (16 | a)) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+
+ if ((a | 16) != 10) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+ if ((16 | a) != 10) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+ if (10 != (a | 16)) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+ if (10 != (16 | a)) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+
+ if ((a | 9) == 8) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+ if ((9 | a) == 8) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+ if (8 == (a | 9)) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+ if (8 == (9 | a)) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+
+ if ((a | 9) != 8) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+ if ((9 | a) != 8) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+ if (8 != (a | 9)) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+ if (8 != (9 | a)) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+
+ if ((a & 128) != 1) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+ if ((128 & a) != 1) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+ if ((a & FOO) != 1) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+ if ((FOO & a) != 1) /* { dg-warning "bitwise comparison always evaluates to true" } */
+ return 1;
+ if ((a & 128) == 1) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+ if ((128 & a) == 1) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+ if ((a & FOO) == 1) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+ if ((FOO & a) == 1) /* { dg-warning "bitwise comparison always evaluates to false" } */
+ return 1;
+
+#define N 0x10
+ if ((a & N) == 10) /* { dg-bogus "bitwise comparison always evaluates to false" "" { xfail *-*-* } } */
+ return 1;
+ if ((a | N) == 10) /* { dg-bogus "bitwise comparison always evaluates to false" "" { xfail *-*-* } } */
+ return 1;
+
+ return 0;
+}
Marek
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: c-family PATCH to improve -Wtautological-compare (PR c/81783)
2017-08-16 15:20 c-family PATCH to improve -Wtautological-compare (PR c/81783) Marek Polacek
@ 2017-08-16 15:35 ` David Malcolm
2017-08-16 16:10 ` Eric Gallager
2017-08-16 16:12 ` Marek Polacek
2017-09-01 16:41 ` Jeff Law
1 sibling, 2 replies; 7+ messages in thread
From: David Malcolm @ 2017-08-16 15:35 UTC (permalink / raw)
To: Marek Polacek, GCC Patches; +Cc: Joseph Myers, Jason Merrill
On Wed, 2017-08-16 at 16:29 +0200, Marek Polacek wrote:
> This patch improves -Wtautological-compare so that it also detects
> bitwise comparisons involving & and | that are always true or false,
> e.g.
>
> if ((a & 16) == 10)
> return 1;
>
> can never be true. Note that e.g. "(a & 9) == 8" is *not* always
> false
> or true.
>
> I think it's pretty straightforward with one snag: we shouldn't warn
> if
> the constant part of the bitwise operation comes from a macro, but
> currently
> that's not possible, so I XFAILed this in the new test.
Maybe I'm missing something here, but why shouldn't it warn when the
constant comes from a macro?
At the end of your testcase you have this example:
#define N 0x10
if ((a & N) == 10) /* { dg-bogus "bitwise comparison always evaluates to false" "" { xfail *-*-* } } */
return 1;
if ((a | N) == 10) /* { dg-bogus "bitwise comparison always evaluates to false" "" { xfail *-*-* } } */
return 1;
That code looks bogus to me (and if the defn of "N" is further away,
it's harder to spot that it's wrong): shouldn't we warn about it?
>
> This has found one issue in the GCC codebase and it's a genuine bug:
> <https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00757.html>.Â
In this example GOVD_WRITTEN is from an enum, not a macro, but if
GOVD_WRITTEN had been a macro, shouldn't we still issue a warning?
Hope this is constructive
Dave
> Bootstrapped/regtested on x86_64-linux, ok for trunk?
>
> 2017-08-16 Marek Polacek <polacek@redhat.com>
>
> PR c/81783
> * c-warn.c (warn_tautological_bitwise_comparison): New
> function.
> (warn_tautological_cmp): Call it.
>
> * doc/invoke.texi: Update -Wtautological-compare documentation.
>
> * c-c++-common/Wtautological-compare-5.c: New test.
>
> diff --git gcc/c-family/c-warn.c gcc/c-family/c-warn.c
> index 9c3073444cf..0749d16a50f 100644
> --- gcc/c-family/c-warn.c
> +++ gcc/c-family/c-warn.c
> @@ -321,6 +321,59 @@ find_array_ref_with_const_idx_r (tree *expr_p,
> int *, void *)
> return NULL_TREE;
> }
>
> +/* Subroutine of warn_tautological_cmp. Warn about bitwise
> comparison
> + that always evaluate to true or false. LOC is the location of
> the
> + ==/!= comparison specified by CODE; LHS and RHS are the usual
> operands
> + of this comparison. */
> +
> +static void
> +warn_tautological_bitwise_comparison (location_t loc, tree_code
> code,
> + tree lhs, tree rhs)
> +{
> + if (code != EQ_EXPR && code != NE_EXPR)
> + return;
> +
> + /* Extract the operands from e.g. (x & 8) == 4. */
> + tree bitop;
> + tree cst;
> + if ((TREE_CODE (lhs) == BIT_AND_EXPR
> + || TREE_CODE (lhs) == BIT_IOR_EXPR)
> + && TREE_CODE (rhs) == INTEGER_CST)
> + bitop = lhs, cst = rhs;
> + else if ((TREE_CODE (rhs) == BIT_AND_EXPR
> + || TREE_CODE (rhs) == BIT_IOR_EXPR)
> + && TREE_CODE (lhs) == INTEGER_CST)
> + bitop = rhs, cst = lhs;
> + else
> + return;
> +
> + tree bitopcst;
> + if (TREE_CODE (TREE_OPERAND (bitop, 0)) == INTEGER_CST)
> + bitopcst = TREE_OPERAND (bitop, 0);
> + else if (TREE_CODE (TREE_OPERAND (bitop, 1)) == INTEGER_CST)
> + bitopcst = TREE_OPERAND (bitop, 1);
> + else
> + return;
> +
> + wide_int res;
> + if (TREE_CODE (bitop) == BIT_AND_EXPR)
> + res = wi::bit_and (bitopcst, cst);
> + else
> + res = wi::bit_or (bitopcst, cst);
> +
> + /* For BIT_AND only warn if (CST2 & CST1) != CST1, and
> + for BIT_OR only if (CST2 | CST1) != CST1. */
> + if (res == cst)
> + return;
> +
> + if (code == EQ_EXPR)
> + warning_at (loc, OPT_Wtautological_compare,
> + "bitwise comparison always evaluates to false");
> + else
> + warning_at (loc, OPT_Wtautological_compare,
> + "bitwise comparison always evaluates to true");
> +}
> +
> /* Warn if a self-comparison always evaluates to true or false. LOC
> is the location of the comparison with code CODE, LHS and RHS are
> operands of the comparison. */
> @@ -337,6 +390,8 @@ warn_tautological_cmp (location_t loc, enum
> tree_code code, tree lhs, tree rhs)
> || from_macro_expansion_at (EXPR_LOCATION (rhs)))
> return;
>
> + warn_tautological_bitwise_comparison (loc, code, lhs, rhs);
> +
> /* We do not warn for constants because they are typical of macro
> expansions that test for features, sizeof, and similar. */
> if (CONSTANT_CLASS_P (fold_for_warn (lhs))
> diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
> index ec29f1d629e..72a16a19711 100644
> --- gcc/doc/invoke.texi
> +++ gcc/doc/invoke.texi
> @@ -5484,6 +5484,14 @@ int i = 1;
> @dots{}
> if (i > i) @{ @dots{} @}
> @end smallexample
> +
> +This warning also warns about bitwise comparisons that always
> evaluate
> +to true or false, for instance:
> +@smallexample
> +if ((a & 16) == 10) @{ @dots{} @}
> +@end smallexample
> +will always be false.
> +
> This warning is enabled by @option{-Wall}.
>
> @item -Wtrampolines
> diff --git gcc/testsuite/c-c++-common/Wtautological-compare-5.c
> gcc/testsuite/c-c++-common/Wtautological-compare-5.c
> index e69de29bb2d..4664bfdeae6 100644
> --- gcc/testsuite/c-c++-common/Wtautological-compare-5.c
> +++ gcc/testsuite/c-c++-common/Wtautological-compare-5.c
> @@ -0,0 +1,106 @@
> +/* PR c/81783 */
> +/* { dg-do compile } */
> +/* { dg-options "-Wtautological-compare" } */
> +
> +enum E { FOO = 128 };
> +
> +int
> +f (int a)
> +{
> + if ((a & 16) == 10) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> + if ((16 & a) == 10) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> + if (10 == (a & 16)) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> + if (10 == (16 & a)) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> +
> + if ((a & 16) != 10) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> + if ((16 & a) != 10) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> + if (10 != (a & 16)) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> + if (10 != (16 & a)) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> +
> + if ((a & 9) == 8)
> + return 1;
> + if ((9 & a) == 8)
> + return 1;
> + if (8 == (a & 9))
> + return 1;
> + if (8 == (9 & a))
> + return 1;
> +
> + if ((a & 9) != 8)
> + return 1;
> + if ((9 & a) != 8)
> + return 1;
> + if (8 != (a & 9))
> + return 1;
> + if (8 != (9 & a))
> + return 1;
> +
> + if ((a | 16) == 10) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> + if ((16 | a) == 10) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> + if (10 == (a | 16)) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> + if (10 == (16 | a)) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> +
> + if ((a | 16) != 10) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> + if ((16 | a) != 10) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> + if (10 != (a | 16)) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> + if (10 != (16 | a)) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> +
> + if ((a | 9) == 8) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> + if ((9 | a) == 8) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> + if (8 == (a | 9)) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> + if (8 == (9 | a)) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> +
> + if ((a | 9) != 8) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> + if ((9 | a) != 8) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> + if (8 != (a | 9)) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> + if (8 != (9 | a)) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> +
> + if ((a & 128) != 1) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> + if ((128 & a) != 1) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> + if ((a & FOO) != 1) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> + if ((FOO & a) != 1) /* { dg-warning "bitwise comparison always
> evaluates to true" } */
> + return 1;
> + if ((a & 128) == 1) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> + if ((128 & a) == 1) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> + if ((a & FOO) == 1) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> + if ((FOO & a) == 1) /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> + return 1;
> +
> +#define N 0x10
> + if ((a & N) == 10) /* { dg-bogus "bitwise comparison always
> evaluates to false" "" { xfail *-*-* } } */
> + return 1;
> + if ((a | N) == 10) /* { dg-bogus "bitwise comparison always
> evaluates to false" "" { xfail *-*-* } } */
> + return 1;
> +
> + return 0;
> +}
>
> Marek
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: c-family PATCH to improve -Wtautological-compare (PR c/81783)
2017-08-16 15:35 ` David Malcolm
@ 2017-08-16 16:10 ` Eric Gallager
2017-08-16 16:12 ` Marek Polacek
1 sibling, 0 replies; 7+ messages in thread
From: Eric Gallager @ 2017-08-16 16:10 UTC (permalink / raw)
To: David Malcolm; +Cc: Marek Polacek, GCC Patches, Joseph Myers, Jason Merrill
On 8/16/17, David Malcolm <dmalcolm@redhat.com> wrote:
> On Wed, 2017-08-16 at 16:29 +0200, Marek Polacek wrote:
>> This patch improves -Wtautological-compare so that it also detects
>> bitwise comparisons involving & and | that are always true or false,
>> e.g.
>>
>> if ((a & 16) == 10)
>> return 1;
>>
>> can never be true. Note that e.g. "(a & 9) == 8" is *not* always
>> false
>> or true.
>>
>> I think it's pretty straightforward with one snag: we shouldn't warn
>> if
>> the constant part of the bitwise operation comes from a macro, but
>> currently
>> that's not possible, so I XFAILed this in the new test.
>
> Maybe I'm missing something here, but why shouldn't it warn when the
> constant comes from a macro?
>
> At the end of your testcase you have this example:
>
> #define N 0x10
> if ((a & N) == 10) /* { dg-bogus "bitwise comparison always evaluates to
> false" "" { xfail *-*-* } } */
> return 1;
> if ((a | N) == 10) /* { dg-bogus "bitwise comparison always evaluates to
> false" "" { xfail *-*-* } } */
> return 1;
>
> That code looks bogus to me (and if the defn of "N" is further away,
> it's harder to spot that it's wrong): shouldn't we warn about it?
>
What about:
#ifdef SOME_PREPROCESSOR_CONDITIONAL
# define N 0x10
#else
# define N 0x11
#endif
or
#define N __LINE__
or
#define N __COUNTER__
or something else like that?
>>
>> This has found one issue in the GCC codebase and it's a genuine bug:
>> <https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00757.html>.
>
> In this example GOVD_WRITTEN is from an enum, not a macro, but if
> GOVD_WRITTEN had been a macro, shouldn't we still issue a warning?
>
> Hope this is constructive
> Dave
>
>> Bootstrapped/regtested on x86_64-linux, ok for trunk?
>>
>> 2017-08-16 Marek Polacek <polacek@redhat.com>
>>
>> PR c/81783
>> * c-warn.c (warn_tautological_bitwise_comparison): New
>> function.
>> (warn_tautological_cmp): Call it.
>>
>> * doc/invoke.texi: Update -Wtautological-compare documentation.
>>
>> * c-c++-common/Wtautological-compare-5.c: New test.
>>
>> diff --git gcc/c-family/c-warn.c gcc/c-family/c-warn.c
>> index 9c3073444cf..0749d16a50f 100644
>> --- gcc/c-family/c-warn.c
>> +++ gcc/c-family/c-warn.c
>> @@ -321,6 +321,59 @@ find_array_ref_with_const_idx_r (tree *expr_p,
>> int *, void *)
>> return NULL_TREE;
>> }
>>
>> +/* Subroutine of warn_tautological_cmp. Warn about bitwise
>> comparison
>> + that always evaluate to true or false. LOC is the location of
>> the
>> + ==/!= comparison specified by CODE; LHS and RHS are the usual
>> operands
>> + of this comparison. */
>> +
>> +static void
>> +warn_tautological_bitwise_comparison (location_t loc, tree_code
>> code,
>> + tree lhs, tree rhs)
>> +{
>> + if (code != EQ_EXPR && code != NE_EXPR)
>> + return;
>> +
>> + /* Extract the operands from e.g. (x & 8) == 4. */
>> + tree bitop;
>> + tree cst;
>> + if ((TREE_CODE (lhs) == BIT_AND_EXPR
>> + || TREE_CODE (lhs) == BIT_IOR_EXPR)
>> + && TREE_CODE (rhs) == INTEGER_CST)
>> + bitop = lhs, cst = rhs;
>> + else if ((TREE_CODE (rhs) == BIT_AND_EXPR
>> + || TREE_CODE (rhs) == BIT_IOR_EXPR)
>> + && TREE_CODE (lhs) == INTEGER_CST)
>> + bitop = rhs, cst = lhs;
>> + else
>> + return;
>> +
>> + tree bitopcst;
>> + if (TREE_CODE (TREE_OPERAND (bitop, 0)) == INTEGER_CST)
>> + bitopcst = TREE_OPERAND (bitop, 0);
>> + else if (TREE_CODE (TREE_OPERAND (bitop, 1)) == INTEGER_CST)
>> + bitopcst = TREE_OPERAND (bitop, 1);
>> + else
>> + return;
>> +
>> + wide_int res;
>> + if (TREE_CODE (bitop) == BIT_AND_EXPR)
>> + res = wi::bit_and (bitopcst, cst);
>> + else
>> + res = wi::bit_or (bitopcst, cst);
>> +
>> + /* For BIT_AND only warn if (CST2 & CST1) != CST1, and
>> + for BIT_OR only if (CST2 | CST1) != CST1. */
>> + if (res == cst)
>> + return;
>> +
>> + if (code == EQ_EXPR)
>> + warning_at (loc, OPT_Wtautological_compare,
>> + "bitwise comparison always evaluates to false");
>> + else
>> + warning_at (loc, OPT_Wtautological_compare,
>> + "bitwise comparison always evaluates to true");
>> +}
>> +
>> /* Warn if a self-comparison always evaluates to true or false. LOC
>> is the location of the comparison with code CODE, LHS and RHS are
>> operands of the comparison. */
>> @@ -337,6 +390,8 @@ warn_tautological_cmp (location_t loc, enum
>> tree_code code, tree lhs, tree rhs)
>> || from_macro_expansion_at (EXPR_LOCATION (rhs)))
>> return;
>>
>> + warn_tautological_bitwise_comparison (loc, code, lhs, rhs);
>> +
>> /* We do not warn for constants because they are typical of macro
>> expansions that test for features, sizeof, and similar. */
>> if (CONSTANT_CLASS_P (fold_for_warn (lhs))
>> diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
>> index ec29f1d629e..72a16a19711 100644
>> --- gcc/doc/invoke.texi
>> +++ gcc/doc/invoke.texi
>> @@ -5484,6 +5484,14 @@ int i = 1;
>> @dots{}
>> if (i > i) @{ @dots{} @}
>> @end smallexample
>> +
>> +This warning also warns about bitwise comparisons that always
>> evaluate
>> +to true or false, for instance:
>> +@smallexample
>> +if ((a & 16) == 10) @{ @dots{} @}
>> +@end smallexample
>> +will always be false.
>> +
>> This warning is enabled by @option{-Wall}.
>>
>> @item -Wtrampolines
>> diff --git gcc/testsuite/c-c++-common/Wtautological-compare-5.c
>> gcc/testsuite/c-c++-common/Wtautological-compare-5.c
>> index e69de29bb2d..4664bfdeae6 100644
>> --- gcc/testsuite/c-c++-common/Wtautological-compare-5.c
>> +++ gcc/testsuite/c-c++-common/Wtautological-compare-5.c
>> @@ -0,0 +1,106 @@
>> +/* PR c/81783 */
>> +/* { dg-do compile } */
>> +/* { dg-options "-Wtautological-compare" } */
>> +
>> +enum E { FOO = 128 };
>> +
>> +int
>> +f (int a)
>> +{
>> + if ((a & 16) == 10) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> + if ((16 & a) == 10) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> + if (10 == (a & 16)) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> + if (10 == (16 & a)) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> +
>> + if ((a & 16) != 10) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> + if ((16 & a) != 10) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> + if (10 != (a & 16)) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> + if (10 != (16 & a)) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> +
>> + if ((a & 9) == 8)
>> + return 1;
>> + if ((9 & a) == 8)
>> + return 1;
>> + if (8 == (a & 9))
>> + return 1;
>> + if (8 == (9 & a))
>> + return 1;
>> +
>> + if ((a & 9) != 8)
>> + return 1;
>> + if ((9 & a) != 8)
>> + return 1;
>> + if (8 != (a & 9))
>> + return 1;
>> + if (8 != (9 & a))
>> + return 1;
>> +
>> + if ((a | 16) == 10) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> + if ((16 | a) == 10) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> + if (10 == (a | 16)) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> + if (10 == (16 | a)) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> +
>> + if ((a | 16) != 10) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> + if ((16 | a) != 10) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> + if (10 != (a | 16)) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> + if (10 != (16 | a)) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> +
>> + if ((a | 9) == 8) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> + if ((9 | a) == 8) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> + if (8 == (a | 9)) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> + if (8 == (9 | a)) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> +
>> + if ((a | 9) != 8) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> + if ((9 | a) != 8) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> + if (8 != (a | 9)) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> + if (8 != (9 | a)) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> +
>> + if ((a & 128) != 1) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> + if ((128 & a) != 1) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> + if ((a & FOO) != 1) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> + if ((FOO & a) != 1) /* { dg-warning "bitwise comparison always
>> evaluates to true" } */
>> + return 1;
>> + if ((a & 128) == 1) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> + if ((128 & a) == 1) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> + if ((a & FOO) == 1) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> + if ((FOO & a) == 1) /* { dg-warning "bitwise comparison always
>> evaluates to false" } */
>> + return 1;
>> +
>> +#define N 0x10
>> + if ((a & N) == 10) /* { dg-bogus "bitwise comparison always
>> evaluates to false" "" { xfail *-*-* } } */
>> + return 1;
>> + if ((a | N) == 10) /* { dg-bogus "bitwise comparison always
>> evaluates to false" "" { xfail *-*-* } } */
>> + return 1;
>> +
>> + return 0;
>> +}
>>
>> Marek
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: c-family PATCH to improve -Wtautological-compare (PR c/81783)
2017-08-16 15:35 ` David Malcolm
2017-08-16 16:10 ` Eric Gallager
@ 2017-08-16 16:12 ` Marek Polacek
2017-08-25 14:30 ` Marek Polacek
1 sibling, 1 reply; 7+ messages in thread
From: Marek Polacek @ 2017-08-16 16:12 UTC (permalink / raw)
To: David Malcolm; +Cc: GCC Patches, Joseph Myers, Jason Merrill
On Wed, Aug 16, 2017 at 11:07:36AM -0400, David Malcolm wrote:
> On Wed, 2017-08-16 at 16:29 +0200, Marek Polacek wrote:
> > This patch improves -Wtautological-compare so that it also detects
> > bitwise comparisons involving & and | that are always true or false,
> > e.g.
> >
> > if ((a & 16) == 10)
> > return 1;
> >
> > can never be true. Note that e.g. "(a & 9) == 8" is *not* always
> > false
> > or true.
> >
> > I think it's pretty straightforward with one snag: we shouldn't warn
> > if
> > the constant part of the bitwise operation comes from a macro, but
> > currently
> > that's not possible, so I XFAILed this in the new test.
>
> Maybe I'm missing something here, but why shouldn't it warn when the
> constant comes from a macro?
Just my past experience. Sometimes you can't really control the macro
and then you get annoying warnings.
E.g. I had to tweak the warning that warns about if (i == i) to not warn about
#define N 2
if (a[N] == a[2]) {}
because that gave bogus warning during bootstrap, if I recall well.
> At the end of your testcase you have this example:
>
> #define N 0x10
> if ((a & N) == 10) /* { dg-bogus "bitwise comparison always evaluates to false" "" { xfail *-*-* } } */
> return 1;
> if ((a | N) == 10) /* { dg-bogus "bitwise comparison always evaluates to false" "" { xfail *-*-* } } */
> return 1;
>
> That code looks bogus to me (and if the defn of "N" is further away,
> it's harder to spot that it's wrong): shouldn't we warn about it?
I'm glad you think so. More than happy to make it an expected warning.
> > This has found one issue in the GCC codebase and it's a genuine bug:
> > <https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00757.html>.Â
>
> In this example GOVD_WRITTEN is from an enum, not a macro, but if
> GOVD_WRITTEN had been a macro, shouldn't we still issue a warning?
I feel like we should, but some might feel otherwise.
Thanks,
Marek
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: c-family PATCH to improve -Wtautological-compare (PR c/81783)
2017-08-16 16:12 ` Marek Polacek
@ 2017-08-25 14:30 ` Marek Polacek
2017-09-01 12:57 ` Marek Polacek
0 siblings, 1 reply; 7+ messages in thread
From: Marek Polacek @ 2017-08-25 14:30 UTC (permalink / raw)
To: David Malcolm; +Cc: GCC Patches, Joseph Myers, Jason Merrill
Ping.
On Wed, Aug 16, 2017 at 05:24:56PM +0200, Marek Polacek wrote:
> On Wed, Aug 16, 2017 at 11:07:36AM -0400, David Malcolm wrote:
> > On Wed, 2017-08-16 at 16:29 +0200, Marek Polacek wrote:
> > > This patch improves -Wtautological-compare so that it also detects
> > > bitwise comparisons involving & and | that are always true or false,
> > > e.g.
> > >
> > > if ((a & 16) == 10)
> > > return 1;
> > >
> > > can never be true. Note that e.g. "(a & 9) == 8" is *not* always
> > > false
> > > or true.
> > >
> > > I think it's pretty straightforward with one snag: we shouldn't warn
> > > if
> > > the constant part of the bitwise operation comes from a macro, but
> > > currently
> > > that's not possible, so I XFAILed this in the new test.
> >
> > Maybe I'm missing something here, but why shouldn't it warn when the
> > constant comes from a macro?
>
> Just my past experience. Sometimes you can't really control the macro
> and then you get annoying warnings.
>
> E.g. I had to tweak the warning that warns about if (i == i) to not warn about
>
> #define N 2
> if (a[N] == a[2]) {}
>
> because that gave bogus warning during bootstrap, if I recall well.
>
> > At the end of your testcase you have this example:
> >
> > #define N 0x10
> > if ((a & N) == 10) /* { dg-bogus "bitwise comparison always evaluates to false" "" { xfail *-*-* } } */
> > return 1;
> > if ((a | N) == 10) /* { dg-bogus "bitwise comparison always evaluates to false" "" { xfail *-*-* } } */
> > return 1;
> >
> > That code looks bogus to me (and if the defn of "N" is further away,
> > it's harder to spot that it's wrong): shouldn't we warn about it?
>
> I'm glad you think so. More than happy to make it an expected warning.
>
> > > This has found one issue in the GCC codebase and it's a genuine bug:
> > > <https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00757.html>.Â
> >
> > In this example GOVD_WRITTEN is from an enum, not a macro, but if
> > GOVD_WRITTEN had been a macro, shouldn't we still issue a warning?
>
> I feel like we should, but some might feel otherwise.
>
> Thanks,
>
> Marek
Marek
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: c-family PATCH to improve -Wtautological-compare (PR c/81783)
2017-08-25 14:30 ` Marek Polacek
@ 2017-09-01 12:57 ` Marek Polacek
0 siblings, 0 replies; 7+ messages in thread
From: Marek Polacek @ 2017-09-01 12:57 UTC (permalink / raw)
To: GCC Patches; +Cc: Joseph Myers, Jason Merrill, David Malcolm
Ping.
On Fri, Aug 25, 2017 at 02:47:45PM +0200, Marek Polacek wrote:
> Ping.
>
> On Wed, Aug 16, 2017 at 05:24:56PM +0200, Marek Polacek wrote:
> > On Wed, Aug 16, 2017 at 11:07:36AM -0400, David Malcolm wrote:
> > > On Wed, 2017-08-16 at 16:29 +0200, Marek Polacek wrote:
> > > > This patch improves -Wtautological-compare so that it also detects
> > > > bitwise comparisons involving & and | that are always true or false,
> > > > e.g.
> > > >
> > > > if ((a & 16) == 10)
> > > > return 1;
> > > >
> > > > can never be true. Note that e.g. "(a & 9) == 8" is *not* always
> > > > false
> > > > or true.
> > > >
> > > > I think it's pretty straightforward with one snag: we shouldn't warn
> > > > if
> > > > the constant part of the bitwise operation comes from a macro, but
> > > > currently
> > > > that's not possible, so I XFAILed this in the new test.
> > >
> > > Maybe I'm missing something here, but why shouldn't it warn when the
> > > constant comes from a macro?
> >
> > Just my past experience. Sometimes you can't really control the macro
> > and then you get annoying warnings.
> >
> > E.g. I had to tweak the warning that warns about if (i == i) to not warn about
> >
> > #define N 2
> > if (a[N] == a[2]) {}
> >
> > because that gave bogus warning during bootstrap, if I recall well.
> >
> > > At the end of your testcase you have this example:
> > >
> > > #define N 0x10
> > > if ((a & N) == 10) /* { dg-bogus "bitwise comparison always evaluates to false" "" { xfail *-*-* } } */
> > > return 1;
> > > if ((a | N) == 10) /* { dg-bogus "bitwise comparison always evaluates to false" "" { xfail *-*-* } } */
> > > return 1;
> > >
> > > That code looks bogus to me (and if the defn of "N" is further away,
> > > it's harder to spot that it's wrong): shouldn't we warn about it?
> >
> > I'm glad you think so. More than happy to make it an expected warning.
> >
> > > > This has found one issue in the GCC codebase and it's a genuine bug:
> > > > <https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00757.html>.Â
> > >
> > > In this example GOVD_WRITTEN is from an enum, not a macro, but if
> > > GOVD_WRITTEN had been a macro, shouldn't we still issue a warning?
> >
> > I feel like we should, but some might feel otherwise.
> >
> > Thanks,
> >
> > Marek
>
> Marek
Marek
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: c-family PATCH to improve -Wtautological-compare (PR c/81783)
2017-08-16 15:20 c-family PATCH to improve -Wtautological-compare (PR c/81783) Marek Polacek
2017-08-16 15:35 ` David Malcolm
@ 2017-09-01 16:41 ` Jeff Law
1 sibling, 0 replies; 7+ messages in thread
From: Jeff Law @ 2017-09-01 16:41 UTC (permalink / raw)
To: Marek Polacek, GCC Patches; +Cc: Joseph Myers, David Malcolm, Jason Merrill
On 08/16/2017 08:29 AM, Marek Polacek wrote:
> This patch improves -Wtautological-compare so that it also detects
> bitwise comparisons involving & and | that are always true or false, e.g.
>
> if ((a & 16) == 10)
> return 1;
>
> can never be true. Note that e.g. "(a & 9) == 8" is *not* always false
> or true.
>
> I think it's pretty straightforward with one snag: we shouldn't warn if
> the constant part of the bitwise operation comes from a macro, but currently
> that's not possible, so I XFAILed this in the new test.
>
> This has found one issue in the GCC codebase and it's a genuine bug:
> <https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00757.html>.
>
> Bootstrapped/regtested on x86_64-linux, ok for trunk?
>
> 2017-08-16 Marek Polacek <polacek@redhat.com>
>
> PR c/81783
> * c-warn.c (warn_tautological_bitwise_comparison): New function.
> (warn_tautological_cmp): Call it.
>
> * doc/invoke.texi: Update -Wtautological-compare documentation.
>
> * c-c++-common/Wtautological-compare-5.c: New test.
OK.
jeff
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2017-09-01 16:41 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-16 15:20 c-family PATCH to improve -Wtautological-compare (PR c/81783) Marek Polacek
2017-08-16 15:35 ` David Malcolm
2017-08-16 16:10 ` Eric Gallager
2017-08-16 16:12 ` Marek Polacek
2017-08-25 14:30 ` Marek Polacek
2017-09-01 12:57 ` Marek Polacek
2017-09-01 16:41 ` Jeff Law
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).