From bc7fe95200214ce70419fde6f965dc88bbd645a6 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Mon, 4 Sep 2017 14:05:01 +0000 Subject: [PATCH] re PR c/81783 (-Wtautological-compare could do better) 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. From-SVN: r251660 --- gcc/ChangeLog | 5 + gcc/c-family/ChangeLog | 6 + gcc/c-family/c-warn.c | 55 +++++++++ gcc/doc/invoke.texi | 8 ++ gcc/testsuite/ChangeLog | 5 + .../c-c++-common/Wtautological-compare-5.c | 106 ++++++++++++++++++ 6 files changed, 185 insertions(+) create mode 100644 gcc/testsuite/c-c++-common/Wtautological-compare-5.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5170417bbb0..721b0b96f4a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2017-09-04 Marek Polacek + + PR c/81783 + * doc/invoke.texi: Update -Wtautological-compare documentation. + 2017-09-04 Jeff Law PR tree-optimization/64910 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 33cb1871699..9886dcd86b2 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2017-09-04 Marek Polacek + + PR c/81783 + * c-warn.c (warn_tautological_bitwise_comparison): New function. + (warn_tautological_cmp): Call it. + 2017-09-01 Boris Kolpackov * c-opts.c (c_common_finish): Write dependency information even if diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c index 9c3073444cf..0749d16a50f 100644 --- a/gcc/c-family/c-warn.c +++ b/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 a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index d15497c0547..ed438d4bfc8 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -5492,6 +5492,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 a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8920c76f8c5..04a95f91b65 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-09-04 Marek Polacek + + PR c/81783 + * c-c++-common/Wtautological-compare-5.c: New test. + 2017-09-04 Jeff Law PR tree-optimization/64910 diff --git a/gcc/testsuite/c-c++-common/Wtautological-compare-5.c b/gcc/testsuite/c-c++-common/Wtautological-compare-5.c new file mode 100644 index 00000000000..4664bfdeae6 --- /dev/null +++ b/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; +} -- 2.30.2