This patch adds a function to warn when there's a bitwise operation
between a boolean and any other type. This kind of operation is
probably a programmer mistake that may lead to unexpected behavior
because possibily the logical operation was intended.
The test was adapted from PR c/17896.

gcc/c-family/ChangeLog
2019-05-24  Rafael Tsuha <rafael.ts...@usp.br>

    * c-warn.c (warn_logical_operator): Check for missplaced bitwise op.

gcc/testsuite/ChangeLog
2019-05-24  Rafael Tsuha <rafael.ts...@usp.br>

    PR c/17896
    * gcc.dg/boolean-bitwise.c: New test.
Index: gcc/c-family/c-warn.c
===================================================================
--- gcc/c-family/c-warn.c	(revision 268782)
+++ gcc/c-family/c-warn.c	(working copy)
@@ -167,10 +167,10 @@
 }
 
 /* Warn about uses of logical || / && operator in a context where it
-   is likely that the bitwise equivalent was intended by the
-   programmer.  We have seen an expression in which CODE is a binary
-   operator used to combine expressions OP_LEFT and OP_RIGHT, which before folding
-   had CODE_LEFT and CODE_RIGHT, into an expression of type TYPE.  */
+   is likely that the bitwise equivalent was intended by the programmer or vice
+   versa.  We have seen an expression in which CODE is a binary operator used to
+   combine expressions OP_LEFT and OP_RIGHT, which before folding had CODE_LEFT
+   and CODE_RIGHT, into an expression of type TYPE.  */
 
 void
 warn_logical_operator (location_t location, enum tree_code code, tree type,
@@ -178,6 +178,7 @@
 		       enum tree_code ARG_UNUSED (code_right), tree op_right)
 {
   int or_op = (code == TRUTH_ORIF_EXPR || code == TRUTH_OR_EXPR);
+  int and_op = (code == TRUTH_ANDIF_EXPR || code == TRUTH_AND_EXPR);
   int in0_p, in1_p, in_p;
   tree low0, low1, low, high0, high1, high, lhs, rhs, tem;
   bool strict_overflow_p = false;
@@ -188,7 +189,9 @@
   if (code != TRUTH_ANDIF_EXPR
       && code != TRUTH_AND_EXPR
       && code != TRUTH_ORIF_EXPR
-      && code != TRUTH_OR_EXPR)
+      && code != TRUTH_OR_EXPR
+      && code != BIT_AND_EXPR
+      && code != BIT_IOR_EXPR)
     return;
 
   /* We don't want to warn if either operand comes from a macro
@@ -219,7 +222,7 @@
 	  if (or_op)
 	    warning_at (location, OPT_Wlogical_op, "logical %<or%>"
 			" applied to non-boolean constant");
-	  else
+	  else if (and_op)
 	    warning_at (location, OPT_Wlogical_op, "logical %<and%>"
 			" applied to non-boolean constant");
 	  TREE_NO_WARNING (op_left) = true;
@@ -227,6 +230,26 @@
 	}
     }
 
+  /* Warn if &/| are being used in a context where it is
+     likely that the logical equivalent was intended by the
+     programmer. That is, an expression such as op_1 & op_2
+     where op_n should not be any boolean expression. */
+  if ( TREE_CODE (TREE_TYPE (op_right)) == BOOLEAN_TYPE
+      || TREE_CODE (TREE_TYPE (op_left)) == BOOLEAN_TYPE 
+	  || COMPARISON_CLASS_P ((op_left))
+	  || COMPARISON_CLASS_P ((op_right)))
+    {
+      tree folded_op_right = fold_for_warn (op_right);
+	  if (code == BIT_IOR_EXPR)
+	    warning_at (location, OPT_Wlogical_op, "bitwise %<or%>"
+			" applied to boolean type");
+	  else if (code == BIT_AND_EXPR)
+	    warning_at (location, OPT_Wlogical_op, "bitwise %<and%>"
+			" applied to boolean type");
+	  TREE_NO_WARNING (op_left) = true;
+	  return;
+	}
+
   /* We do not warn for constants because they are typical of macro
      expansions that test for features.  */
   if (CONSTANT_CLASS_P (fold_for_warn (op_left))
Index: gcc/testsuite/gcc.dg/boolean-bitwise.c
===================================================================
--- gcc/testsuite/gcc.dg/boolean-bitwise.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/boolean-bitwise.c	(working copy)
@@ -0,0 +1,28 @@
+/* Test operation of -Wparentheses.  booleans joined by & or | */
+
+/* { dg-do compile } */
+/* { dg-options "-Wlogical-op" } */
+
+int foo (int);
+
+int
+bar (int a, int b, int c)
+{
+  foo (a == b & b == c);     /* { dg-warning "boolean" "correct warning" } */
+  foo (a == b & (b == c));   /* { dg-warning "boolean" "correct warning" } */
+  foo ((a == b) & b == c);   /* { dg-warning "boolean" "correct warning" } */
+  foo (++a == b & b == c);   /* { dg-warning "boolean" "correct warning" } */
+  foo ((a == b) & (b == c)); /* { dg-warning "boolean" "correct warning" } */
+  foo (a == b && b == c);
+  foo (a & b);
+
+  foo (a == b | b == c);     /* { dg-warning "boolean" "correct warning" } */
+  foo (a == b | (b == c));   /* { dg-warning "boolean" "correct warning" } */
+  foo ((a == b) | b == c);   /* { dg-warning "boolean" "correct warning" } */
+  foo (++a == b | b == c);   /* { dg-warning "boolean" "correct warning" } */
+  foo ((a == b) | (b == c)); /* { dg-warning "boolean" "correct warning" } */
+  foo (a == b || b == c);
+  foo (a | b);
+
+  return 0;
+}

Reply via email to