[PATCH] PR 17946: warning message for suspect "a && MASK"

Thomas R. Truscott trt@cs.duke.edu
Tue Oct 12 14:23:00 GMT 2004


People sometimes code "a && MASK" when they intended "a & MASK".
gcc itself does not seem to have examples of this,
here are some in the linux-2.4.20 kernel:

drivers/scsi/cpqfcTSworker.c
          printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n",       
			  fchs->s_id &&0xFFFFFF);

drivers/usb/serial/pl2303.c
	if (cflag && CBAUD) {

drivers/tc/lk201.c
		handle_scancode(c, shift_state && LK_LOCK ? 1 : 0);
		handle_scancode(c, shift_state && LK_SHIFT ? 1 : 0);
                ...

Here is a patch that warns about A && B when

   A and B are both integer type (e.g. neither pointer nor real)
   A or B, but not both, is an integer constant
   Neither A nor B are (appear to be) limited to 0/1 (boolean).

I've used this warning for years with excellent results.
One might expect lots of false positives, but I cannot recall even one.

There is an ugly aspect to the patch.
c-parse.in converts A to truth value (A != 0) to update "skip_evaluation".
But the unconverted A is needed for this warning check.
To get around this, the patch does a temporary conversion. Twice. Yuck.
Perhaps there is a better way.


2004-10-08 Tom Truscott <trt@acm.org>

	PR 17946
	* c-parse.in: Pass unconverted lhs to parse_build_binary_op.
	* c-typeck.c (build_binary_op): Add new warning.
	* doc/invoke.texi: Document new warning.
	* testsuite/gcc.dg/wandand.c: New test.

Index: gcc/gcc/c-parse.in
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-parse.in,v
retrieving revision 1.245
diff -c -3 -p -r1.245 c-parse.in
*** gcc/gcc/c-parse.in	6 Oct 2004 04:47:26 -0000	1.245
--- gcc/gcc/c-parse.in	8 Oct 2004 14:15:48 -0000
*************** expr_no_commas:
*** 610,620 ****
  	| expr_no_commas '^' expr_no_commas
  		{ $$ = parser_build_binary_op ($2, $1, $3); }
  	| expr_no_commas ANDAND
! 		{ $1.value = lang_hooks.truthvalue_conversion
  		    (default_conversion ($1.value));
! 		  skip_evaluation += $1.value == truthvalue_false_node; }
  	  expr_no_commas
! 		{ skip_evaluation -= $1.value == truthvalue_false_node;
  		  $$ = parser_build_binary_op (TRUTH_ANDIF_EXPR, $1, $4); }
  	| expr_no_commas OROR
  		{ $1.value = lang_hooks.truthvalue_conversion
--- 610,622 ----
  	| expr_no_commas '^' expr_no_commas
  		{ $$ = parser_build_binary_op ($2, $1, $3); }
  	| expr_no_commas ANDAND
! 		{ tree t = lang_hooks.truthvalue_conversion
  		    (default_conversion ($1.value));
! 		  skip_evaluation += t == truthvalue_false_node; }
  	  expr_no_commas
! 		{ tree t = lang_hooks.truthvalue_conversion
! 		    (default_conversion ($1.value));
! 		  skip_evaluation -= t == truthvalue_false_node;
  		  $$ = parser_build_binary_op (TRUTH_ANDIF_EXPR, $1, $4); }
  	| expr_no_commas OROR
  		{ $1.value = lang_hooks.truthvalue_conversion

Index: gcc/gcc/c-typeck.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.386
diff -c -3 -p -r1.386 c-typeck.c
*** gcc/gcc/c-typeck.c	6 Oct 2004 22:16:26 -0000	1.386
--- gcc/gcc/c-typeck.c	8 Oct 2004 14:15:48 -0000
*************** build_binary_op (enum tree_code code, tr
*** 7154,7159 ****
--- 7154,7168 ----
        break;
  
      case TRUTH_ANDIF_EXPR:
+       if (extra_warnings
+           && code0 == INTEGER_TYPE && code1 == INTEGER_TYPE
+           && CONSTANT_CLASS_P (op0) != CONSTANT_CLASS_P (op1)
+           && !COMPARISON_CLASS_P (op0) && !integer_zerop (op0) && !integer_onep (op0)
+           && !COMPARISON_CLASS_P (op1) && !integer_zerop (op1) && !integer_onep (op1))
+         warning ("non-boolean constant in boolean context");
+ 
+       /* FALLTHRU */
+ 
      case TRUTH_ORIF_EXPR:
      case TRUTH_AND_EXPR:
      case TRUTH_OR_EXPR:

Index: gcc/gcc/doc/invoke.texi
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.543
diff -c -3 -p -r1.543 invoke.texi
*** gcc/gcc/doc/invoke.texi	5 Oct 2004 07:15:03 -0000	1.543
--- gcc/gcc/doc/invoke.texi	8 Oct 2004 14:31:27 -0000
*************** but @samp{x[(void)i,j]} will not.
*** 2653,2658 ****
--- 2653,2662 ----
  An unsigned value is compared against zero with @samp{<} or @samp{>=}.
  
  @item
+ An expression like @samp{a&&b} appears in a context where @samp{a&b}
+ may have been intended.
+ 
+ @item
  Storage-class specifiers like @code{static} are not the first things in
  a declaration.  According to the C Standard, this usage is obsolescent.
  


Index: gcc/gcc/testsuite/gcc.dg/wandand.c
===================================================================
diff -c3p /dev/null gcc/gcc/testsuite/gcc.dg/wandand.c
*** /dev/null	Fri Aug 30 19:31:37 2002
--- gcc/gcc/testsuite/gcc.dg/wandand.c	Fri Oct  8 09:36:45 2004
***************
*** 0 ****
--- 1,15 ----
+ /* { dg-do compile } */
+ /* { dg-options "-Wextra" } */
+ 
+ 
+ void subr (int a, char *p)
+ {
+   if (a && 0x200) return; /* { dg-warning "non-boolean constant" } */
+ 
+   if (p && 0x200) return; /* { dg-bogus "non-boolean constant" } */
+   if (a && p) return;     /* { dg-bogus "non-boolean constant" } */
+   if (a && 0) return;     /* { dg-bogus "non-boolean constant" } */
+   if (a && 1) return;     /* { dg-bogus "non-boolean constant" } */
+   if (3 && 4) return;     /* { dg-bogus "non-boolean constant" } */
+   if (a && 1.1) return;   /* { dg-bogus "non-boolean constant" } */
+ }



More information about the Gcc-patches mailing list