re PR c/81783 (-Wtautological-compare could do better)
authorMarek Polacek <polacek@redhat.com>
Mon, 4 Sep 2017 14:05:01 +0000 (14:05 +0000)
committerMarek Polacek <mpolacek@gcc.gnu.org>
Mon, 4 Sep 2017 14:05:01 +0000 (14:05 +0000)
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
gcc/c-family/ChangeLog
gcc/c-family/c-warn.c
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/Wtautological-compare-5.c [new file with mode: 0644]

index 5170417bbb025008b620b4b8046bd9195af0a33d..721b0b96f4a5451d52f94ed8ec594b8dd32c99fb 100644 (file)
@@ -1,3 +1,8 @@
+2017-09-04  Marek Polacek  <polacek@redhat.com>
+
+       PR c/81783
+       * doc/invoke.texi: Update -Wtautological-compare documentation.
+
 2017-09-04  Jeff Law  <law@redhat.com>
 
        PR tree-optimization/64910
index 33cb1871699e71d04ae537b571477db4fcec3bd0..9886dcd86b29f06a6b76d726a93e088c90087885 100644 (file)
@@ -1,3 +1,9 @@
+2017-09-04  Marek Polacek  <polacek@redhat.com>
+
+       PR c/81783
+       * c-warn.c (warn_tautological_bitwise_comparison): New function.
+       (warn_tautological_cmp): Call it.
+
 2017-09-01  Boris Kolpackov <boris@codesynthesis.com>
 
        * c-opts.c (c_common_finish): Write dependency information even if
index 9c3073444cf50860f1b331ad2c09b06825857914..0749d16a50fb0fa022196640a01afcdab3187edb 100644 (file)
@@ -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))
index d15497c054709593027181acf8b607e7922457f4..ed438d4bfc8058616c3278c426f3ce4e02052ebc 100644 (file)
@@ -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
index 8920c76f8c5d94aec0e62d0ebc9557ff94ec9f6c..04a95f91b6529c8f08be31910eb658353ff0d006 100644 (file)
@@ -1,3 +1,8 @@
+2017-09-04  Marek Polacek  <polacek@redhat.com>
+
+       PR c/81783
+       * c-c++-common/Wtautological-compare-5.c: New test.
+
 2017-09-04  Jeff Law  <law@redhat.com>
 
        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 (file)
index 0000000..4664bfd
--- /dev/null
@@ -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;
+}