This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: Fix PR 218
- To: gcc-patches at gcc dot gnu dot org
- Subject: C++ PATCH: Fix PR 218
- From: Mark Mitchell <mark at codesourcery dot com>
- Date: Sat, 17 Feb 2001 22:50:56 -0800
- Organization: CodeSourcery, LLC
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);
+ }
+