This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

C++ PATCH: Fix PR 218



Expressions like:

  i ? 7 : throw 1

are leagal in C++, even though `throw 1' has type `void' and not type
`int'.

Our constant-folding code, however, wanted to change:

  j + (i ? 7 : throw 1)

into:

  i ? (j + 7) : (j + throw 1)

which the rest of the middle-end didn't like very much.

Furthermore, in a display of cut-and-paste ugliness in the extreme,
the code that did this was replicated for the case where `j' came
first and the case where the conditional `i ? a : b' came first.

I broke out the code into a separate function, and fixed the bug
involving the `throw' expressions by avoiding the addition in that
case.

This was a regression from 2.95.2.

Bootstrapped and tested on i686-pc-linux-gnu, applied on the mainline
and the branch.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

Index: gcc/fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.146
diff -c -p -r1.146 fold-const.c
*** fold-const.c	2001/02/11 17:56:39	1.146
--- fold-const.c	2001/02/18 06:39:54
*************** static tree strip_compound_expr PARAMS (
*** 101,107 ****
  static int multiple_of_p	PARAMS ((tree, tree, tree));
  static tree constant_boolean_node PARAMS ((int, tree));
  static int count_cond		PARAMS ((tree, int));
! 
  #ifndef BRANCH_COST
  #define BRANCH_COST 1
  #endif
--- 101,109 ----
  static int multiple_of_p	PARAMS ((tree, tree, tree));
  static tree constant_boolean_node PARAMS ((int, tree));
  static int count_cond		PARAMS ((tree, int));
! static tree fold_binary_op_with_conditional_arg 
!   PARAMS ((enum tree_code, tree, tree, tree, int));
! 							 
  #ifndef BRANCH_COST
  #define BRANCH_COST 1
  #endif
*************** count_cond (expr, lim)
*** 4691,4696 ****
--- 4693,4827 ----
    false = count_cond (TREE_OPERAND (expr, 2), lim - 1 - true);
    return MIN (lim, 1 + true + false);
  }
+ 
+ /* Transform `a + (b ? x : y)' into `x ? (a + b) : (a + y)'.
+    Transform, `a + (x < y)' into `(x < y) ? (a + 1) : (a + 0)'.  Here
+    CODE corresponds to the `+', COND to the `(b ? x : y)' or `(x < y)'
+    expression, and ARG to `a'.  If COND_FIRST_P is non-zero, then the
+    COND is the first argument to CODE; otherwise (as in the example
+    given here), it is the second argument.  TYPE is the type of the
+    original expression.  */
+ 
+ static tree
+ fold_binary_op_with_conditional_arg (code, type, cond, arg, cond_first_p)
+      enum tree_code code;
+      tree type;
+      tree cond;
+      tree arg;
+      int cond_first_p;
+ {
+   tree test, true_value, false_value;
+   tree lhs = NULL_TREE;
+   tree rhs = NULL_TREE;
+   /* In the end, we'll produce a COND_EXPR.  Both arms of the
+      conditional expression will be binary operations.  The left-hand
+      side of the expression to be executed if the condition is true
+      will be pointed to by TRUE_LHS.  Similarly, the right-hand side
+      of the expression to be executed if the condition is true will be
+      pointed to by TRUE_RHS.  FALSE_LHS and FALSE_RHS are analagous --
+      but apply to the expression to be executed if the conditional is
+      false.  */
+   tree *true_lhs;
+   tree *true_rhs;
+   tree *false_lhs;
+   tree *false_rhs;
+   /* These are the codes to use for the left-hand side and right-hand
+      side of the COND_EXPR.  Normally, they are the same as CODE.  */
+   enum tree_code lhs_code = code;
+   enum tree_code rhs_code = code;
+   /* And these are the types of the expressions.  */
+   tree lhs_type = type;
+   tree rhs_type = type;
+ 
+   if (cond_first_p)
+     {
+       true_rhs = false_rhs = &arg;
+       true_lhs = &true_value;
+       false_lhs = &false_value;
+     }
+   else
+     {
+       true_lhs = false_lhs = &arg;
+       true_rhs = &true_value;
+       false_rhs = &false_value;
+     }
+ 
+   if (TREE_CODE (cond) == COND_EXPR)
+     {
+       test = TREE_OPERAND (cond, 0);
+       true_value = TREE_OPERAND (cond, 1);
+       false_value = TREE_OPERAND (cond, 2);
+       /* If this operand throws an expression, then it does not make
+ 	 sense to try to perform a logical or arithmetic operation
+ 	 involving it.  Instead of building `a + throw 3' for example,
+ 	 we simply build `a, throw 3'.  */
+       if (VOID_TYPE_P (TREE_TYPE (true_value)))
+ 	{
+ 	  lhs_code = COMPOUND_EXPR;
+ 	  if (!cond_first_p)
+ 	    lhs_type = void_type_node;
+ 	}
+       if (VOID_TYPE_P (TREE_TYPE (false_value)))
+ 	{
+ 	  rhs_code = COMPOUND_EXPR;
+ 	  if (!cond_first_p)
+ 	    rhs_type = void_type_node;
+ 	}
+     }
+   else
+     {
+       tree testtype = TREE_TYPE (cond);
+       test = cond;
+       true_value = convert (testtype, integer_one_node);
+       false_value = convert (testtype, integer_zero_node);
+     }
+   
+   /* If ARG is complex we want to make sure we only evaluate
+      it once.  Though this is only required if it is volatile, it
+      might be more efficient even if it is not.  However, if we
+      succeed in folding one part to a constant, we do not need
+      to make this SAVE_EXPR.  Since we do this optimization
+      primarily to see if we do end up with constant and this
+      SAVE_EXPR interferes with later optimizations, suppressing
+      it when we can is important.
+      
+      If we are not in a function, we can't make a SAVE_EXPR, so don't
+      try to do so.  Don't try to see if the result is a constant
+      if an arm is a COND_EXPR since we get exponential behavior
+      in that case.  */
+   
+   if (TREE_CODE (arg) != SAVE_EXPR && ! TREE_CONSTANT (arg)
+       && global_bindings_p () == 0
+       && ((TREE_CODE (arg) != VAR_DECL
+ 	   && TREE_CODE (arg) != PARM_DECL)
+ 	  || TREE_SIDE_EFFECTS (arg)))
+     {
+       if (TREE_CODE (true_value) != COND_EXPR)
+ 	lhs = fold (build (lhs_code, lhs_type, *true_lhs, *true_rhs));
+       
+       if (TREE_CODE (false_value) != COND_EXPR)
+ 	rhs = fold (build (rhs_code, rhs_type, *false_lhs, *false_rhs));
+       
+       if ((lhs == 0 || ! TREE_CONSTANT (lhs))
+ 	  && (rhs == 0 || !TREE_CONSTANT (rhs)))
+ 	arg = save_expr (arg), lhs = rhs = 0;
+     }
+   
+   if (lhs == 0)
+     lhs = fold (build (lhs_code, lhs_type, *true_lhs, *true_rhs));
+   if (rhs == 0)
+     rhs = fold (build (rhs_code, rhs_type, *false_lhs, *false_rhs));
+   
+   test = fold (build (COND_EXPR, type, test, lhs, rhs));
+   
+   if (TREE_CODE (arg) == SAVE_EXPR)
+     return build (COMPOUND_EXPR, type,
+ 		  convert (void_type_node, arg),
+ 		  strip_compound_expr (test, arg));
+   else
+     return convert (type, test);
+ }
+ 
  
  /* Perform constant folding and related simplification of EXPR.
     The related simplifications include x*1 => x, x*0 => 0, etc.,
*************** fold (expr)
*** 4912,4981 ****
  	       && (! TREE_SIDE_EFFECTS (arg0)
  		   || (global_bindings_p () == 0
  		       && ! contains_placeholder_p (arg0))))
! 	{
! 	  tree test, true_value, false_value;
! 	  tree lhs = 0, rhs = 0;
! 
! 	  if (TREE_CODE (arg1) == COND_EXPR)
! 	    {
! 	      test = TREE_OPERAND (arg1, 0);
! 	      true_value = TREE_OPERAND (arg1, 1);
! 	      false_value = TREE_OPERAND (arg1, 2);
! 	    }
! 	  else
! 	    {
! 	      tree testtype = TREE_TYPE (arg1);
! 	      test = arg1;
! 	      true_value = convert (testtype, integer_one_node);
! 	      false_value = convert (testtype, integer_zero_node);
! 	    }
! 
! 	  /* If ARG0 is complex we want to make sure we only evaluate
! 	     it once.  Though this is only required if it is volatile, it
! 	     might be more efficient even if it is not.  However, if we
! 	     succeed in folding one part to a constant, we do not need
! 	     to make this SAVE_EXPR.  Since we do this optimization
! 	     primarily to see if we do end up with constant and this
! 	     SAVE_EXPR interferes with later optimizations, suppressing
! 	     it when we can is important.
! 
! 	     If we are not in a function, we can't make a SAVE_EXPR, so don't
! 	     try to do so.  Don't try to see if the result is a constant
! 	     if an arm is a COND_EXPR since we get exponential behavior
! 	     in that case.  */
! 
! 	  if (TREE_CODE (arg0) != SAVE_EXPR && ! TREE_CONSTANT (arg0)
! 	      && global_bindings_p () == 0
! 	      && ((TREE_CODE (arg0) != VAR_DECL
! 		   && TREE_CODE (arg0) != PARM_DECL)
! 		  || TREE_SIDE_EFFECTS (arg0)))
! 	    {
! 	      if (TREE_CODE (true_value) != COND_EXPR)
! 		lhs = fold (build (code, type, arg0, true_value));
! 
! 	      if (TREE_CODE (false_value) != COND_EXPR)
! 		rhs = fold (build (code, type, arg0, false_value));
! 
! 	      if ((lhs == 0 || ! TREE_CONSTANT (lhs))
! 		  && (rhs == 0 || !TREE_CONSTANT (rhs)))
! 		arg0 = save_expr (arg0), lhs = rhs = 0;
! 	    }
! 
! 	  if (lhs == 0)
! 	    lhs = fold (build (code, type, arg0, true_value));
! 	  if (rhs == 0)
! 	    rhs = fold (build (code, type, arg0, false_value));
! 
! 	  test = fold (build (COND_EXPR, type, test, lhs, rhs));
! 
! 	  if (TREE_CODE (arg0) == SAVE_EXPR)
! 	    return build (COMPOUND_EXPR, type,
! 			  convert (void_type_node, arg0),
! 			  strip_compound_expr (test, arg0));
! 	  else
! 	    return convert (type, test);
! 	}
! 
        else if (TREE_CODE (arg0) == COMPOUND_EXPR)
  	return build (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
  		      fold (build (code, type, TREE_OPERAND (arg0, 1), arg1)));
--- 5043,5051 ----
  	       && (! TREE_SIDE_EFFECTS (arg0)
  		   || (global_bindings_p () == 0
  		       && ! contains_placeholder_p (arg0))))
! 	return 
! 	  fold_binary_op_with_conditional_arg (code, type, arg1, arg0,
! 					       /*cond_first_p=*/0);
        else if (TREE_CODE (arg0) == COMPOUND_EXPR)
  	return build (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
  		      fold (build (code, type, TREE_OPERAND (arg0, 1), arg1)));
*************** fold (expr)
*** 4987,5041 ****
  	       && (! TREE_SIDE_EFFECTS (arg1)
  		   || (global_bindings_p () == 0
  		       && ! contains_placeholder_p (arg1))))
! 	{
! 	  tree test, true_value, false_value;
! 	  tree lhs = 0, rhs = 0;
! 
! 	  if (TREE_CODE (arg0) == COND_EXPR)
! 	    {
! 	      test = TREE_OPERAND (arg0, 0);
! 	      true_value = TREE_OPERAND (arg0, 1);
! 	      false_value = TREE_OPERAND (arg0, 2);
! 	    }
! 	  else
! 	    {
! 	      tree testtype = TREE_TYPE (arg0);
! 	      test = arg0;
! 	      true_value = convert (testtype, integer_one_node);
! 	      false_value = convert (testtype, integer_zero_node);
! 	    }
! 
! 	  if (TREE_CODE (arg1) != SAVE_EXPR && ! TREE_CONSTANT (arg0)
! 	      && global_bindings_p () == 0
! 	      && ((TREE_CODE (arg1) != VAR_DECL
! 		   && TREE_CODE (arg1) != PARM_DECL)
! 		  || TREE_SIDE_EFFECTS (arg1)))
! 	    {
! 	      if (TREE_CODE (true_value) != COND_EXPR)
! 		lhs = fold (build (code, type, true_value, arg1));
! 
! 	      if (TREE_CODE (false_value) != COND_EXPR)
! 		rhs = fold (build (code, type, false_value, arg1));
! 
! 	      if ((lhs == 0 || ! TREE_CONSTANT (lhs))
! 		  && (rhs == 0 || !TREE_CONSTANT (rhs)))
! 		arg1 = save_expr (arg1), lhs = rhs = 0;
! 	    }
! 
! 	  if (lhs == 0)
! 	    lhs = fold (build (code, type, true_value, arg1));
! 
! 	  if (rhs == 0)
! 	    rhs = fold (build (code, type, false_value, arg1));
! 
! 	  test = fold (build (COND_EXPR, type, test, lhs, rhs));
! 	  if (TREE_CODE (arg1) == SAVE_EXPR)
! 	    return build (COMPOUND_EXPR, type,
! 			  convert (void_type_node, arg1),
! 			  strip_compound_expr (test, arg1));
! 	  else
! 	    return convert (type, test);
! 	}
      }
    else if (TREE_CODE_CLASS (code) == '<'
  	   && TREE_CODE (arg0) == COMPOUND_EXPR)
--- 5057,5065 ----
  	       && (! TREE_SIDE_EFFECTS (arg1)
  		   || (global_bindings_p () == 0
  		       && ! contains_placeholder_p (arg1))))
! 	return 
! 	  fold_binary_op_with_conditional_arg (code, type, arg0, arg1,
! 					       /*cond_first_p=*/1);
      }
    else if (TREE_CODE_CLASS (code) == '<'
  	   && TREE_CODE (arg0) == COMPOUND_EXPR)
Index: gcc/tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.35
diff -c -p -r1.35 tree.def
*** tree.def	2001/01/02 18:19:28	1.35
--- tree.def	2001/02/18 06:40:02
*************** DEFTREECODE (TARGET_EXPR, "target_expr",
*** 425,432 ****
     Operand 0 is the condition.
     Operand 1 is the then-value.
     Operand 2 is the else-value.
!    Operand 0 may be of any type, but the types of operands 1 and 2
!    must be the same and the same as the type of this expression.  */
  DEFTREECODE (COND_EXPR, "cond_expr", 'e', 3)
  
  /* Declare local variables, including making RTL and allocating space.
--- 425,434 ----
     Operand 0 is the condition.
     Operand 1 is the then-value.
     Operand 2 is the else-value.
!    Operand 0 may be of any type.
!    Operand 1 must have the same type as the entire expression, unless
!    it unconditionally throws an exception, in which case it should
!    have VOID_TYPE.  The same constraints apply to operand 2.  */
  DEFTREECODE (COND_EXPR, "cond_expr", 'e', 3)
  
  /* Declare local variables, including making RTL and allocating space.
Index: gcc/cp/ChangeLog
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/ChangeLog,v
retrieving revision 1.2227.2.17
diff -c -p -r1.2227.2.17 ChangeLog
*** ChangeLog	2001/02/18 05:04:59	1.2227.2.17
--- ChangeLog	2001/02/18 06:40:08
*************** Sun Feb  4 15:52:44 2001  Richard Kenner
*** 967,973 ****
  
  	* class.c (check_field_decls): Don't special case anonymous
  	fields in error messages.
! 	(note_name_declared_in_class): Use %D on diagnostic.
  
  	* tree.c (pod_type_p): Use strip_array_types.
  	(cp_valid_lang_attribute): Likewise.
--- 967,974 ----
  
  	* class.c (check_field_decls): Don't special case anonymous
  	fields in error messages.
! 	(note_name_declared_inpwdpwd
! 	_class): Use %D on diagnostic.
  
  	* tree.c (pod_type_p): Use strip_array_types.
  	(cp_valid_lang_attribute): Likewise.
Index: gcc/testsuite/g++.old-deja/g++.eh/crash5.C
===================================================================
RCS file: crash5.C
diff -N crash5.C
*** /dev/null	Tue May  5 13:32:27 1998
--- crash5.C	Sat Feb 17 22:40:14 2001
***************
*** 0 ****
--- 1,12 ----
+ // Build don't link:
+ // Origin: Mark Mitchell <mark@codesourcery.com>
+ 
+ int i;
+ int j;
+ 
+ void
+ f ()
+ {
+   j = j + (i ? 7 : throw 1);
+ }
+  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]