C++ PATCH: PR 28523

Mark Mitchell mark@codesourcery.com
Tue Aug 1 20:18:00 GMT 2006


This patch fixes PR c++/28523, an ICE-on-valid.  We were calling
stabilize_call with something that was not a call, which caused an
assertion to trip.  I find the comments in build_throw (the caller of
stabilize_call) difficult to understand, but the bottom line is that
using stabilize_init in this situation is just an optimization.  So,
we don't want stabilize_init to crash when handed something it can't
pre-evaluate; we just want it to indicate that it couldn't
pre-evaluate it.  I tried to clean up the comments around stabilize_*;
the previous comments didn't really explain what these functions did
and didn't document the return values in all cases.

Tested on x86_64-unknown-linux-gnu, applied on the mainline and on the
4.1 branch.

--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

2006-07-31  Mark Mitchell  <mark@codesourcery.com>

	PR c++/28523
	* tree.c (stabilize_expr): Tweak documentation.  Add assertion.
	(stabilize_call): Tweak documentation.
	(stabilize_init): Only call stabilize_call for calls.

2006-07-31  Mark Mitchell  <mark@codesourcery.com>

	PR c++/28523
	* g++.dg/eh/cast1.C: New test.

Index: gcc/cp/tree.c
===================================================================
--- gcc/cp/tree.c	(revision 115850)
+++ gcc/cp/tree.c	(working copy)
@@ -2229,9 +2229,11 @@ decl_linkage (tree decl)
   return lk_internal;
 }
 
-/* EXP is an expression that we want to pre-evaluate.  Returns via INITP an
-   expression to perform the pre-evaluation, and returns directly an
-   expression to use the precalculated result.  */
+/* EXP is an expression that we want to pre-evaluate.  Returns (in
+   *INITP) an expression that will perform the pre-evaluation.  The
+   value returned by this function is a side-effect free expression
+   equivalent to the pre-evaluated expression.  Callers must ensure
+   that *INITP is evaluated before EXP.  */
 
 tree
 stabilize_expr (tree exp, tree* initp)
@@ -2239,9 +2241,7 @@ stabilize_expr (tree exp, tree* initp)
   tree init_expr;
 
   if (!TREE_SIDE_EFFECTS (exp))
-    {
-      init_expr = NULL_TREE;
-    }
+    init_expr = NULL_TREE;
   else if (!real_lvalue_p (exp)
 	   || !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (exp)))
     {
@@ -2255,8 +2255,9 @@ stabilize_expr (tree exp, tree* initp)
       exp = TARGET_EXPR_SLOT (init_expr);
       exp = build_indirect_ref (exp, 0);
     }
-
   *initp = init_expr;
+
+  gcc_assert (!TREE_SIDE_EFFECTS (exp));
   return exp;
 }
 
@@ -2273,8 +2274,10 @@ add_stmt_to_compound (tree orig, tree ne
   return build2 (COMPOUND_EXPR, void_type_node, orig, new);
 }
 
-/* Like stabilize_expr, but for a call whose args we want to
-   pre-evaluate.  */
+/* Like stabilize_expr, but for a call whose arguments we want to
+   pre-evaluate.  CALL is modified in place to use the pre-evaluated
+   arguments, while, upon return, *INITP contains an expression to
+   compute the arguments.  */
 
 void
 stabilize_call (tree call, tree *initp)
@@ -2299,50 +2302,58 @@ stabilize_call (tree call, tree *initp)
   *initp = inits;
 }
 
-/* Like stabilize_expr, but for an initialization.  If we are initializing
-   an object of class type, we don't want to introduce an extra temporary,
-   so we look past the TARGET_EXPR and stabilize the arguments of the call
-   instead.  */
+/* Like stabilize_expr, but for an initialization.  
+
+   If the initialization is for an object of class type, this function
+   takes care not to introduce additional temporaries.
+
+   Returns TRUE iff the expression was successfully pre-evaluated,
+   i.e., if INIT is now side-effect free, except for, possible, a
+   single call to a constructor.  */
 
 bool
 stabilize_init (tree init, tree *initp)
 {
   tree t = init;
 
+  *initp = NULL_TREE;
+
   if (t == error_mark_node)
     return true;
 
   if (TREE_CODE (t) == INIT_EXPR
       && TREE_CODE (TREE_OPERAND (t, 1)) != TARGET_EXPR)
-    TREE_OPERAND (t, 1) = stabilize_expr (TREE_OPERAND (t, 1), initp);
-  else
     {
-      if (TREE_CODE (t) == INIT_EXPR)
-	t = TREE_OPERAND (t, 1);
-      if (TREE_CODE (t) == TARGET_EXPR)
-	t = TARGET_EXPR_INITIAL (t);
-      if (TREE_CODE (t) == COMPOUND_EXPR)
-	t = expr_last (t);
-      if (TREE_CODE (t) == CONSTRUCTOR
-	  && EMPTY_CONSTRUCTOR_P (t))
-	{
-	  /* Default-initialization.  */
-	  *initp = NULL_TREE;
-	  return true;
-	}
-
-      /* If the initializer is a COND_EXPR, we can't preevaluate
-	 anything.  */
-      if (TREE_CODE (t) == COND_EXPR)
-	return false;
-
-      /* The TARGET_EXPR might be initializing via bitwise copy from
-	 another variable; leave that alone.  */
-      if (TREE_SIDE_EFFECTS (t))
-	stabilize_call (t, initp);
+      TREE_OPERAND (t, 1) = stabilize_expr (TREE_OPERAND (t, 1), initp);
+      return true;
+    }
+
+  if (TREE_CODE (t) == INIT_EXPR)
+    t = TREE_OPERAND (t, 1);
+  if (TREE_CODE (t) == TARGET_EXPR)
+    t = TARGET_EXPR_INITIAL (t);
+  if (TREE_CODE (t) == COMPOUND_EXPR)
+    t = expr_last (t);
+  if (TREE_CODE (t) == CONSTRUCTOR
+      && EMPTY_CONSTRUCTOR_P (t))
+    /* Default-initialization.  */
+    return true;
+
+  /* If the initializer is a COND_EXPR, we can't preevaluate
+     anything.  */
+  if (TREE_CODE (t) == COND_EXPR)
+    return false;
+
+  if (TREE_CODE (t) == CALL_EXPR
+      || TREE_CODE (t) == AGGR_INIT_EXPR)
+    {
+      stabilize_call (t, initp);
+      return true;
     }
 
-  return true;
+  /* The initialization is being performed via a bitwise copy -- and
+     the item copied may have side effects.  */
+  return TREE_SIDE_EFFECTS (init);
 }
 
 /* Like "fold", but should be used whenever we might be processing the
Index: gcc/testsuite/g++.dg/eh/cast1.C
===================================================================
--- gcc/testsuite/g++.dg/eh/cast1.C	(revision 0)
+++ gcc/testsuite/g++.dg/eh/cast1.C	(revision 0)
@@ -0,0 +1,10 @@
+// PR c++/28523
+
+class A {};
+class B : public A {};
+
+int main()
+{
+  throw (A) B();
+  return 0;
+}



More information about the Gcc-patches mailing list