Patchwork Fix C ICEs on truthvalue conversions of some expressions with integer constant operands (PR c/54103)

login
register
mail settings
Submitter Joseph S. Myers
Date Sept. 14, 2012, 5 p.m.
Message ID <Pine.LNX.4.64.1209141659050.5142@digraph.polyomino.org.uk>
Download mbox | patch
Permalink /patch/183974/
State New
Headers show

Comments

Joseph S. Myers - Sept. 14, 2012, 5 p.m.
Bug 54103 is a C front-end regression involving ICEs in certain cases
of expressions such as 0 / 0 being converted to truthvalues.

c_common_truthvalue_conversion, or
c_objc_common_truthvalue_conversion, received 0 / 0 directly as a
TRUNC_DIV_EXPR, without any wrapping C_MAYBE_CONST_EXPR to indicate
that the expression has integer constant operands, so did not know
that it had to produce a result valid for an expression with integer
constant operands (that is, one satisfying EXPR_INT_CONST_OPERANDS -
meaning either an INTEGER_CST, or a C_MAYBE_CONST_EXPR with
C_MAYBE_CONST_EXPR_INT_OPERANDS set, but not anything with
C_MAYBE_CONST_EXPR deeper in the expression).  As a result it returned
an expression with a C_MAYBE_CONST_EXPR not at top level - but the
callers assumed this could not occur, so created their own wrapping
C_MAYBE_CONST_EXPR (and C_MAYBE_CONST_EXPR should never be nested).

This is fixed by ensuring that a properly marked expression gets
passed to c_objc_common_truthvalue_conversion; ensuring
c_objc_common_truthvalue_conversion handes such expressions directly
so c_common_truthvalue_conversion doesn't have to; and avoiding direct
calls to c_common_truthvalue_conversion in relevant places.

Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  Applied
to mainline.  Will apply to 4.7 (when not frozen) and 4.6 branches
subject to testing there.

c:
2012-09-14  Joseph Myers  <joseph@codesourcery.com>

	PR c/54103
	* c-typeck.c (build_unary_op): Pass original argument of
	TRUTH_NOT_EXPR to c_objc_common_truthvalue_conversion, then remove
	any C_MAYBE_CONST_EXPR, if it has integer operands.
	(build_binary_op): Pass original arguments of TRUTH_ANDIF_EXPR,
	TRUTH_ORIF_EXPR, TRUTH_AND_EXPR, TRUTH_OR_EXPR and TRUTH_XOR_EXPR
	to c_objc_common_truthvalue_conversion, then remove any
	C_MAYBE_CONST_EXPR, if they have integer operands.  Use
	c_objc_common_truthvalue_conversion not
	c_common_truthvalue_conversion.
	(c_objc_common_truthvalue_conversion): Build NE_EXPR directly and
	call note_integer_operands for arguments with integer operands
	that are not integer constants.

testsuite:
2012-09-14  Joseph Myers  <joseph@codesourcery.com>

	PR c/54103
	* gcc.c-torture/compile/pr54103-1.c,
	gcc.c-torture/compile/pr54103-2.c,
	gcc.c-torture/compile/pr54103-3.c,
	gcc.c-torture/compile/pr54103-4.c,
	gcc.c-torture/compile/pr54103-5.c,
	gcc.c-torture/compile/pr54103-6.c: New tests.
	* gcc.dg/c90-const-expr-8.c: Update expected column number.

Patch

Index: c/c-typeck.c
===================================================================
--- c/c-typeck.c	(revision 191291)
+++ c/c-typeck.c	(working copy)
@@ -3553,7 +3553,13 @@  build_unary_op (location_t location,
 		    "wrong type argument to unary exclamation mark");
 	  return error_mark_node;
 	}
-      arg = c_objc_common_truthvalue_conversion (location, arg);
+      if (int_operands)
+	{
+	  arg = c_objc_common_truthvalue_conversion (location, xarg);
+	  arg = remove_c_maybe_const_expr (arg);
+	}
+      else
+	arg = c_objc_common_truthvalue_conversion (location, arg);
       ret = invert_truthvalue_loc (location, arg);
       /* If the TRUTH_NOT_EXPR has been folded, reset the location.  */
       if (EXPR_P (ret) && EXPR_HAS_LOCATION (ret))
@@ -9807,8 +9813,20 @@  build_binary_op (location_t location, enum tree_co
 	     but that does not mean the operands should be
 	     converted to ints!  */
 	  result_type = integer_type_node;
-	  op0 = c_common_truthvalue_conversion (location, op0);
-	  op1 = c_common_truthvalue_conversion (location, op1);
+	  if (op0_int_operands)
+	    {
+	      op0 = c_objc_common_truthvalue_conversion (location, orig_op0);
+	      op0 = remove_c_maybe_const_expr (op0);
+	    }
+	  else
+	    op0 = c_objc_common_truthvalue_conversion (location, op0);
+	  if (op1_int_operands)
+	    {
+	      op1 = c_objc_common_truthvalue_conversion (location, orig_op1);
+	      op1 = remove_c_maybe_const_expr (op1);
+	    }
+	  else
+	    op1 = c_objc_common_truthvalue_conversion (location, op1);
 	  converted = 1;
 	  boolean_op = true;
 	}
@@ -10520,13 +10538,18 @@  c_objc_common_truthvalue_conversion (location_t lo
 
   int_const = (TREE_CODE (expr) == INTEGER_CST && !TREE_OVERFLOW (expr));
   int_operands = EXPR_INT_CONST_OPERANDS (expr);
-  if (int_operands)
-    expr = remove_c_maybe_const_expr (expr);
+  if (int_operands && TREE_CODE (expr) != INTEGER_CST)
+    {
+      expr = remove_c_maybe_const_expr (expr);
+      expr = build2 (NE_EXPR, integer_type_node, expr,
+		     convert (TREE_TYPE (expr), integer_zero_node));
+      expr = note_integer_operands (expr);
+    }
+  else
+    /* ??? Should we also give an error for vectors rather than leaving
+       those to give errors later?  */
+    expr = c_common_truthvalue_conversion (location, expr);
 
-  /* ??? Should we also give an error for vectors rather than leaving
-     those to give errors later?  */
-  expr = c_common_truthvalue_conversion (location, expr);
-
   if (TREE_CODE (expr) == INTEGER_CST && int_operands && !int_const)
     {
       if (TREE_OVERFLOW (expr))
Index: testsuite/gcc.c-torture/compile/pr54103-2.c
===================================================================
--- testsuite/gcc.c-torture/compile/pr54103-2.c	(revision 0)
+++ testsuite/gcc.c-torture/compile/pr54103-2.c	(revision 0)
@@ -0,0 +1,5 @@ 
+void
+f (void)
+{
+  0 / 0 || 0 ? : 0;
+}
Index: testsuite/gcc.c-torture/compile/pr54103-4.c
===================================================================
--- testsuite/gcc.c-torture/compile/pr54103-4.c	(revision 0)
+++ testsuite/gcc.c-torture/compile/pr54103-4.c	(revision 0)
@@ -0,0 +1,5 @@ 
+void
+f (void)
+{
+  0 / 0 && 1 ? : 0;
+}
Index: testsuite/gcc.c-torture/compile/pr54103-6.c
===================================================================
--- testsuite/gcc.c-torture/compile/pr54103-6.c	(revision 0)
+++ testsuite/gcc.c-torture/compile/pr54103-6.c	(revision 0)
@@ -0,0 +1,5 @@ 
+void
+f (void)
+{
+  0 || 65536*65536 ? : 0;
+}
Index: testsuite/gcc.c-torture/compile/pr54103-1.c
===================================================================
--- testsuite/gcc.c-torture/compile/pr54103-1.c	(revision 0)
+++ testsuite/gcc.c-torture/compile/pr54103-1.c	(revision 0)
@@ -0,0 +1,5 @@ 
+void
+f (void)
+{
+  0 || 0 / 0 ? : 0;
+}
Index: testsuite/gcc.c-torture/compile/pr54103-3.c
===================================================================
--- testsuite/gcc.c-torture/compile/pr54103-3.c	(revision 0)
+++ testsuite/gcc.c-torture/compile/pr54103-3.c	(revision 0)
@@ -0,0 +1,5 @@ 
+void
+f (void)
+{
+  1 && 0 / 0 ? : 0;
+}
Index: testsuite/gcc.c-torture/compile/pr54103-5.c
===================================================================
--- testsuite/gcc.c-torture/compile/pr54103-5.c	(revision 0)
+++ testsuite/gcc.c-torture/compile/pr54103-5.c	(revision 0)
@@ -0,0 +1,5 @@ 
+void
+f (void)
+{
+  !(0 / 0);
+}
Index: testsuite/gcc.dg/c90-const-expr-8.c
===================================================================
--- testsuite/gcc.dg/c90-const-expr-8.c	(revision 191291)
+++ testsuite/gcc.dg/c90-const-expr-8.c	(working copy)
@@ -22,6 +22,6 @@  enum e {
   E5 = 0 * -INT_MIN, /* { dg-warning "12:integer overflow in expression" } */
   /* { dg-error "3:overflow in constant expression" "constant" { target *-*-* } 22 } */
   E6 = 0 * !-INT_MIN, /* { dg-warning "13:integer overflow in expression" } */
-  /* { dg-error "3:not an integer constant" "constant" { target *-*-* } 24 } */
+  /* { dg-error "8:not an integer constant" "constant" { target *-*-* } 24 } */
   E7 = INT_MIN % -1 /* Not an overflow.  */
 };