From e5a942312327b2ef428e7d2d7fc97b5150c7c04a Mon Sep 17 00:00:00 2001
From: Joseph Myers <joseph@codesourcery.com>
Date: Thu, 8 Oct 2009 01:32:51 +0100
Subject: [PATCH] re PR c/41182 (Revision 145254 caused ICE: tree check:
 expected integer_cst, have nop_expr in tree_int_cst_lt, at tree.c:5259)

	PR c/41182
	* c-common.c (c_fully_fold_internal): Strip nops from the result
	of recursive calls to c_fully_fold_internal.
	(c_wrap_maybe_const): New.
	(c_save_expr): Use c_wrap_maybe_const.
	* c-common.h (c_wrap_maybe_const): Declare.
	* c-typeck.c (build_conditional_expr, c_finish_stmt_expr,
	build_binary_op): Use c_wrap_maybe_const.

testsuite:
	* gcc.c-torture/compile/pr41182-1.c: New.

From-SVN: r152548
---
 gcc/ChangeLog                                 | 11 +++++
 gcc/c-common.c                                | 41 +++++++++++++++++--
 gcc/c-common.h                                |  1 +
 gcc/c-typeck.c                                | 27 +++---------
 gcc/testsuite/ChangeLog                       |  5 +++
 .../gcc.c-torture/compile/pr41182-1.c         |  6 +++
 6 files changed, 65 insertions(+), 26 deletions(-)
 create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr41182-1.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d381c7023122..885532b2fd8f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2009-10-07  Joseph Myers  <joseph@codesourcery.com>
+
+	PR c/41182
+	* c-common.c (c_fully_fold_internal): Strip nops from the result
+	of recursive calls to c_fully_fold_internal.
+	(c_wrap_maybe_const): New.
+	(c_save_expr): Use c_wrap_maybe_const.
+	* c-common.h (c_wrap_maybe_const): Declare.
+	* c-typeck.c (build_conditional_expr, c_finish_stmt_expr,
+	build_binary_op): Use c_wrap_maybe_const.
+
 2009-10-07  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
 	* real.c: Fix comment to reflect actual exponent size.
diff --git a/gcc/c-common.c b/gcc/c-common.c
index bf57cb8a2df0..fb2a84ebbf46 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -1219,6 +1219,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
       op2 = TREE_OPERAND (expr, 2);
       op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
 				   maybe_const_itself);
+      STRIP_TYPE_NOPS (op0);
       if (op0 != orig_op0)
 	ret = build3 (COMPONENT_REF, TREE_TYPE (expr), op0, op1, op2);
       if (ret != expr)
@@ -1235,8 +1236,10 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
       op3 = TREE_OPERAND (expr, 3);
       op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
 				   maybe_const_itself);
+      STRIP_TYPE_NOPS (op0);
       op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands,
 				   maybe_const_itself);
+      STRIP_TYPE_NOPS (op1);
       op1 = decl_constant_value_for_optimization (op1);
       if (op0 != orig_op0 || op1 != orig_op1)
 	ret = build4 (ARRAY_REF, TREE_TYPE (expr), op0, op1, op2, op3);
@@ -1293,6 +1296,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
       orig_op1 = op1 = TREE_OPERAND (expr, 1);
       op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
 				   maybe_const_itself);
+      STRIP_TYPE_NOPS (op0);
       if (code != MODIFY_EXPR
 	  && code != PREDECREMENT_EXPR
 	  && code != PREINCREMENT_EXPR
@@ -1304,6 +1308,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
       if (code != MODIFY_EXPR)
 	op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands,
 				     maybe_const_itself);
+      STRIP_TYPE_NOPS (op1);
       op1 = decl_constant_value_for_optimization (op1);
       if (op0 != orig_op0 || op1 != orig_op1 || in_init)
 	ret = in_init
@@ -1333,6 +1338,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
       orig_op0 = op0 = TREE_OPERAND (expr, 0);
       op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
 				   maybe_const_itself);
+      STRIP_TYPE_NOPS (op0);
       if (code != ADDR_EXPR && code != REALPART_EXPR && code != IMAGPART_EXPR)
 	op0 = decl_constant_value_for_optimization (op0);
       if (op0 != orig_op0 || in_init)
@@ -1372,12 +1378,14 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
       orig_op0 = op0 = TREE_OPERAND (expr, 0);
       orig_op1 = op1 = TREE_OPERAND (expr, 1);
       op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self);
+      STRIP_TYPE_NOPS (op0);
 
       unused_p = (op0 == (code == TRUTH_ANDIF_EXPR
 			  ? truthvalue_false_node
 			  : truthvalue_true_node));
       c_inhibit_evaluation_warnings += unused_p;
       op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self);
+      STRIP_TYPE_NOPS (op1);
       c_inhibit_evaluation_warnings -= unused_p;
 
       if (op0 != orig_op0 || op1 != orig_op1 || in_init)
@@ -1409,12 +1417,15 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
       orig_op2 = op2 = TREE_OPERAND (expr, 2);
       op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self);
 
+      STRIP_TYPE_NOPS (op0);
       c_inhibit_evaluation_warnings += (op0 == truthvalue_false_node);
       op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self);
+      STRIP_TYPE_NOPS (op1);
       c_inhibit_evaluation_warnings -= (op0 == truthvalue_false_node);
 
       c_inhibit_evaluation_warnings += (op0 == truthvalue_true_node);
       op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self);
+      STRIP_TYPE_NOPS (op2);
       c_inhibit_evaluation_warnings -= (op0 == truthvalue_true_node);
 
       if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2)
@@ -3790,6 +3801,31 @@ pointer_int_sum (location_t loc, enum tree_code resultcode,
   return ret;
 }
 
+/* Wrap a C_MAYBE_CONST_EXPR around an expression that is fully folded
+   and if NON_CONST is known not to be permitted in an evaluated part
+   of a constant expression.  */
+
+tree
+c_wrap_maybe_const (tree expr, bool non_const)
+{
+  bool nowarning = TREE_NO_WARNING (expr);
+  location_t loc = EXPR_LOCATION (expr);
+
+  /* This should never be called for C++.  */
+  if (c_dialect_cxx ())
+    gcc_unreachable ();
+
+  /* The result of folding may have a NOP_EXPR to set TREE_NO_WARNING.  */
+  STRIP_TYPE_NOPS (expr);
+  expr = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL, expr);
+  C_MAYBE_CONST_EXPR_NON_CONST (expr) = non_const;
+  if (nowarning)
+    TREE_NO_WARNING (expr) = 1;
+  protected_set_expr_location (expr, loc);
+
+  return expr;
+}
+
 /* Wrap a SAVE_EXPR around EXPR, if appropriate.  Like save_expr, but
    for C folds the inside expression and wraps a C_MAYBE_CONST_EXPR
    around the SAVE_EXPR if needed so that c_fully_fold does not need
@@ -3804,10 +3840,7 @@ c_save_expr (tree expr)
   expr = c_fully_fold (expr, false, &maybe_const);
   expr = save_expr (expr);
   if (!maybe_const)
-    {
-      expr = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL, expr);
-      C_MAYBE_CONST_EXPR_NON_CONST (expr) = 1;
-    }
+    expr = c_wrap_maybe_const (expr, true);
   return expr;
 }
 
diff --git a/gcc/c-common.h b/gcc/c-common.h
index db4f910e81b6..61d52c870fb0 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -792,6 +792,7 @@ extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int);
 extern bool decl_with_nonnull_addr_p (const_tree);
 extern tree c_fully_fold (tree, bool, bool *);
 extern tree decl_constant_value_for_optimization (tree);
+extern tree c_wrap_maybe_const (tree, bool);
 extern tree c_save_expr (tree);
 extern tree c_common_truthvalue_conversion (location_t, tree);
 extern void c_apply_type_quals_to_decl (int, tree);
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 4c55e587de3c..e7425a77d65e 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -3940,17 +3940,9 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
 				     "conditional expression"));
 		    }
 		  if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST)
-		    {
-		      op1 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op1),
-				    NULL, op1);
-		      C_MAYBE_CONST_EXPR_NON_CONST (op1) = !op1_maybe_const;
-		    }
+		    op1 = c_wrap_maybe_const (op1, !op1_maybe_const);
 		  if (!op2_maybe_const || TREE_CODE (op2) != INTEGER_CST)
-		    {
-		      op2 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op2),
-				    NULL, op2);
-		      C_MAYBE_CONST_EXPR_NON_CONST (op2) = !op2_maybe_const;
-		    }
+		    op2 = c_wrap_maybe_const (op2, !op2_maybe_const);
 		}
 	    }
 	}
@@ -8669,8 +8661,7 @@ c_finish_stmt_expr (location_t loc, tree body)
     {
       /* Even if this looks constant, do not allow it in a constant
 	 expression.  */
-      last = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (last), NULL_TREE, last);
-      C_MAYBE_CONST_EXPR_NON_CONST (last) = 1;
+      last = c_wrap_maybe_const (last, true);
       /* Do not warn if the return value of a statement expression is
 	 unused.  */
       TREE_NO_WARNING (last) = 1;
@@ -9545,17 +9536,9 @@ build_binary_op (location_t location, enum tree_code code,
 	      if (!in_late_binary_op)
 		{
 		  if (!op0_maybe_const || TREE_CODE (op0) != INTEGER_CST)
-		    {
-		      op0 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op0),
-				    NULL, op0);
-		      C_MAYBE_CONST_EXPR_NON_CONST (op0) = !op0_maybe_const;
-		    }
+		    op0 = c_wrap_maybe_const (op0, !op0_maybe_const);
 		  if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST)
-		    {
-		      op1 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op1),
-				    NULL, op1);
-		      C_MAYBE_CONST_EXPR_NON_CONST (op1) = !op1_maybe_const;
-		    }
+		    op1 = c_wrap_maybe_const (op1, !op1_maybe_const);
 		}
 	    }
 	}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index fe14298215eb..9b9b141b9f30 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2009-10-07  Joseph Myers  <joseph@codesourcery.com>
+
+	PR c/41182
+	* gcc.c-torture/compile/pr41182-1.c: New.
+
 2009-10-07  Jason Merrill  <jason@redhat.com>
 
 	* g++.dg/cpp0x/variadic95.C: New.
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr41182-1.c b/gcc/testsuite/gcc.c-torture/compile/pr41182-1.c
new file mode 100644
index 000000000000..017174938b3b
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr41182-1.c
@@ -0,0 +1,6 @@
+typedef long unsigned int size_t;
+int _lae_process_opts(char *pr, char *pe)
+{ 
+  return (strlen ("on") < ((size_t) ((pe-&pr[2])>(strlen("on"))                
+                                     ? (pe-&pr[2]) : (strlen("on")))));
+}
-- 
GitLab