* tree.h (TARGET_EXPR_SLOT, TARGET_EXPR_INITIAL): New macros.
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 1 Mar 2002 01:49:00 +0000 (01:49 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 1 Mar 2002 01:49:00 +0000 (01:49 +0000)
        (TARGET_EXPR_CLEANUP): New macro.
cp/
        * except.c: Don't include decl.h or obstack.h.  Do include
        tree-inline.h.
        (build_throw): Destroy temporaries from the thrown
        expression before calling __cxa_throw.  Construct a thrown
        temporary directly into the exception object.
        (stabilize_throw_expr): New function.
        (wrap_cleanups_r): New function.
        * tree.c (stabilize_expr): New function.
        * init.c (build_init): New function.
        * Make-lang.in (cp/except.o): Adjust .h deps.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@50177 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/Make-lang.in
gcc/cp/except.c
gcc/cp/init.c
gcc/cp/tree.c
gcc/tree.h

index 5aa2209..2066310 100644 (file)
@@ -1,3 +1,8 @@
+2002-03-01  Jason Merrill  <jason@redhat.com>
+
+       * tree.h (TARGET_EXPR_SLOT, TARGET_EXPR_INITIAL): New macros.
+       (TARGET_EXPR_CLEANUP): New macro.
+
 2002-02-28  Steve Ellcey  <sje@cup.hp.com>
 
        * doc/rtl.texi (SUBREG_PROMOTED_UNSIGNED_P): Change definition
@@ -78,7 +83,7 @@
        (STARTFILE_SPEC): Add 64 bit files.
        (ENDFILE_SPEC): Likewise.
 
-2002-02-25  Jason Merrill  <jason@redhat.com>
+2002-02-28  Jason Merrill  <jason@redhat.com>
 
        * c-decl.c (finish_function): Only warn about missing return
        statement with -Wreturn-type.
index 85f2547..540e874 100644 (file)
@@ -1,3 +1,16 @@
+2002-03-01  Jason Merrill  <jason@redhat.com>
+
+       * except.c: Don't include decl.h or obstack.h.  Do include
+       tree-inline.h.
+       (build_throw): Destroy temporaries from the thrown
+       expression before calling __cxa_throw.  Construct a thrown 
+       temporary directly into the exception object.
+       (stabilize_throw_expr): New function.
+       (wrap_cleanups_r): New function.
+       * tree.c (stabilize_expr): New function.
+       * init.c (build_init): New function.
+       * Make-lang.in (cp/except.o): Adjust .h deps.
+
 2002-02-28  Jason Merrill  <jason@redhat.com>
 
        * search.c (lookup_base_r): Don't clear is_non_public just because
index f8d023a..1e721b6 100644 (file)
@@ -277,7 +277,7 @@ cp/tree.o: cp/tree.c $(CXX_TREE_H) flags.h toplev.h $(GGC_H) $(RTL_H) \
 cp/ptree.o: cp/ptree.c $(CXX_TREE_H) $(SYSTEM_H)
 cp/rtti.o: cp/rtti.c $(CXX_TREE_H) flags.h toplev.h
 cp/except.o: cp/except.c $(CXX_TREE_H) flags.h $(RTL_H) except.h toplev.h \
-  cp/cfns.h $(EXPR_H) libfuncs.h cp/decl.h $(OBSTACK_H)
+  cp/cfns.h $(EXPR_H) libfuncs.h tree-inline.h
 cp/expr.o: cp/expr.c $(CXX_TREE_H) $(RTL_H) flags.h $(EXPR_H) toplev.h \
   except.h $(TM_P_H)
 cp/pt.o: cp/pt.c $(CXX_TREE_H) cp/decl.h cp/parse.h cp/lex.h toplev.h \
index 3f3cdcf..8cbbfa9 100644 (file)
@@ -35,6 +35,7 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "except.h"
 #include "toplev.h"
+#include "tree-inline.h"
 
 static void push_eh_cleanup PARAMS ((tree));
 static tree prepare_eh_type PARAMS ((tree));
@@ -46,15 +47,14 @@ static void push_eh_cleanup PARAMS ((tree));
 static bool decl_is_java_type PARAMS ((tree decl, int err));
 static void initialize_handler_parm PARAMS ((tree, tree));
 static tree do_allocate_exception PARAMS ((tree));
+static tree stabilize_throw_expr PARAMS ((tree, tree *));
+static tree wrap_cleanups_r PARAMS ((tree *, int *, void *));
 static int complete_ptr_ref_or_void_ptr_p PARAMS ((tree, tree));
 static bool is_admissible_throw_operand PARAMS ((tree));
 static int can_convert_eh PARAMS ((tree, tree));
 static void check_handlers_1 PARAMS ((tree, tree));
 static tree cp_protect_cleanup_actions PARAMS ((void));
 
-#include "decl.h"
-#include "obstack.h"
-
 /* Sets up all the global eh stuff that needs to be initialized at the
    start of compilation.  */
 
@@ -518,7 +518,7 @@ do_allocate_exception (type)
 
 #if 0
 /* Call __cxa_free_exception from a cleanup.  This is never invoked
-   directly.  */
+   directly, but see the comment for stabilize_throw_expr.  */
 
 static tree
 do_free_exception (ptr)
@@ -540,6 +540,89 @@ do_free_exception (ptr)
 }
 #endif
 
+/* Wrap all cleanups for TARGET_EXPRs in MUST_NOT_THROW_EXPR.
+   Called from build_throw via walk_tree_without_duplicates.  */
+
+static tree
+wrap_cleanups_r (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees ATTRIBUTE_UNUSED;
+     void *data ATTRIBUTE_UNUSED;
+{
+  tree exp = *tp;
+  tree cleanup;
+
+  /* Don't walk into types.  */
+  if (TYPE_P (exp))
+    {
+      *walk_subtrees = 0;
+      return NULL_TREE;
+    }
+  if (TREE_CODE (exp) != TARGET_EXPR)
+    return NULL_TREE;
+
+  cleanup = TARGET_EXPR_CLEANUP (exp);
+  if (cleanup)
+    {
+      cleanup = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (cleanup), cleanup);
+      TARGET_EXPR_CLEANUP (exp) = cleanup;
+    }
+
+  /* Keep iterating.  */
+  return NULL_TREE;
+}
+
+/* Like stabilize_expr, but specifically for a thrown expression.  When
+   throwing a temporary class object, we want to construct it directly into
+   the thrown exception, so we look past the TARGET_EXPR and stabilize the
+   arguments of the call instead.
+
+   The case where EXP is a call to a function returning a class is a bit of
+   a grey area in the standard; it's unclear whether or not it should be
+   allowed to throw.  I'm going to say no, as that allows us to optimize
+   this case without worrying about deallocating the exception object if it
+   does.  The alternatives would be either not optimizing this case, or
+   wrapping the initialization in a TRY_CATCH_EXPR to call do_free_exception
+   rather than in a MUST_NOT_THROW_EXPR, for this case only.  */
+
+static tree
+stabilize_throw_expr (exp, initp)
+     tree exp;
+     tree *initp;
+{
+  tree init_expr;
+
+  if (TREE_CODE (exp) == TARGET_EXPR
+      && TREE_CODE (TARGET_EXPR_INITIAL (exp)) == AGGR_INIT_EXPR
+      && flag_elide_constructors)
+    {
+      tree aggr_init = AGGR_INIT_EXPR_CHECK (TARGET_EXPR_INITIAL (exp));
+      tree args = TREE_OPERAND (aggr_init, 1);
+      tree newargs = NULL_TREE;
+      tree *p = &newargs;
+
+      init_expr = void_zero_node;
+      for (; args; args = TREE_CHAIN (args))
+       {
+         tree arg_init_expr;
+         tree newarg = stabilize_expr (TREE_VALUE (args), &arg_init_expr);
+
+         if (arg_init_expr != void_zero_node)
+           init_expr = build (COMPOUND_EXPR, void_type_node, arg_init_expr, init_expr);
+         *p = tree_cons (NULL_TREE, newarg, NULL_TREE);
+         p = &TREE_CHAIN (*p);
+       }
+      TREE_OPERAND (aggr_init, 1) = newargs;
+    }
+  else
+    {
+      exp = stabilize_expr (exp, &init_expr);
+    }
+
+  *initp = init_expr;
+  return exp;
+}
+
 /* Build a throw expression.  */
 
 tree
@@ -585,10 +668,9 @@ build_throw (exp)
     {
       tree throw_type;
       tree cleanup;
-      tree stmt_expr;
-      tree compound_stmt;
       tree object, ptr;
       tree tmp;
+      tree temp_expr, allocate_expr;
 
       fn = get_identifier ("__cxa_throw");
       if (IDENTIFIER_GLOBAL_VALUE (fn))
@@ -614,8 +696,6 @@ build_throw (exp)
          fn = push_throw_library_fn (fn, tmp);
        }
 
-      begin_init_stmts (&stmt_expr, &compound_stmt);
-
       /* throw expression */
       /* First, decay it.  */
       exp = decay_conversion (exp);
@@ -633,37 +713,40 @@ build_throw (exp)
         the call to __cxa_allocate_exception first (which doesn't
         matter, since it can't throw).  */
 
-      my_friendly_assert (stmts_are_full_exprs_p () == 1, 19990926);
-
-      /* Store the throw expression into a temp.  This can be less
-        efficient than storing it into the allocated space directly, but
-        if we allocated the space first we would have to deal with
-        cleaning it up if evaluating this expression throws.  */
-      if (TREE_SIDE_EFFECTS (exp))
-       {
-         tmp = create_temporary_var (TREE_TYPE (exp));
-         DECL_INITIAL (tmp) = exp;
-         cp_finish_decl (tmp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
-         exp = tmp;
-       }
+      /* Pre-evaluate the thrown expression first, since if we allocated
+        the space first we would have to deal with cleaning it up if
+        evaluating this expression throws.  */
+      exp = stabilize_throw_expr (exp, &temp_expr);
 
       /* Allocate the space for the exception.  */
-      ptr = create_temporary_var (ptr_type_node);
-      DECL_REGISTER (ptr) = 1;
-      cp_finish_decl (ptr, NULL_TREE, NULL_TREE, LOOKUP_ONLYCONVERTING);
-      tmp = do_allocate_exception (TREE_TYPE (exp));
-      tmp = build_modify_expr (ptr, INIT_EXPR, tmp);
-      finish_expr_stmt (tmp);
-
+      allocate_expr = do_allocate_exception (TREE_TYPE (exp));
+      allocate_expr = get_target_expr (allocate_expr);
+      ptr = TARGET_EXPR_SLOT (allocate_expr);
       object = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (exp)), ptr);
       object = build_indirect_ref (object, NULL);
 
-      exp = build_modify_expr (object, INIT_EXPR, exp);
+      /* And initialize the exception object.  */
+      exp = build_init (object, exp, LOOKUP_ONLYCONVERTING);
       if (exp == error_mark_node)
-       error ("  in thrown expression");
+       {
+         error ("  in thrown expression");
+         return error_mark_node;
+       }
 
       exp = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (exp), exp);
-      finish_expr_stmt (exp);
+      /* Prepend the allocation.  */
+      exp = build (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp);
+      if (temp_expr != void_zero_node)
+       {
+         /* Prepend the calculation of the throw expression.  Also, force
+            any cleanups from the expression to be evaluated here so that
+            we don't have to do them during unwinding.  But first wrap
+            them in MUST_NOT_THROW_EXPR, since they are run after the
+            exception object is initialized.  */
+         walk_tree_without_duplicates (&temp_expr, wrap_cleanups_r, 0);
+         exp = build (COMPOUND_EXPR, TREE_TYPE (exp), temp_expr, exp);
+         exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
+       }
 
       throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object)));
 
@@ -686,13 +769,11 @@ build_throw (exp)
       tmp = tree_cons (NULL_TREE, cleanup, NULL_TREE);
       tmp = tree_cons (NULL_TREE, throw_type, tmp);
       tmp = tree_cons (NULL_TREE, ptr, tmp);
-      tmp = build_function_call (fn, tmp);
-
       /* ??? Indicate that this function call throws throw_type.  */
+      tmp = build_function_call (fn, tmp);
 
-      finish_expr_stmt (tmp);
-
-      exp = finish_init_stmts (stmt_expr, compound_stmt);
+      /* Tack on the initialization stuff.  */
+      exp = build (COMPOUND_EXPR, TREE_TYPE (tmp), exp, tmp);
     }
   else
     {
@@ -708,6 +789,8 @@ build_throw (exp)
            (fn, build_function_type (void_type_node, void_list_node));
        }
 
+      /* ??? Indicate that this function call allows exceptions of the type
+        of the enclosing catch block (if known).  */    
       exp = build_function_call (fn, NULL_TREE);
     }
 
index 017b894..7eaafc9 100644 (file)
@@ -1201,6 +1201,26 @@ build_aggr_init (exp, init, flags)
   return stmt_expr;
 }
 
+/* Like build_aggr_init, but not just for aggregates.  */
+
+tree
+build_init (decl, init, flags)
+     tree decl, init;
+     int flags;
+{
+  tree expr;
+
+  if (IS_AGGR_TYPE (TREE_TYPE (decl))
+      || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+    expr = build_aggr_init (decl, init, flags);
+  else
+    {
+      expr = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
+      TREE_SIDE_EFFECTS (expr) = 1;
+    }
+  return expr;
+}
+
 static void
 expand_default_init (binfo, true_exp, exp, init, flags)
      tree binfo;
index 8b0a198..a49a2dc 100644 (file)
@@ -2497,3 +2497,36 @@ decl_linkage (decl)
   /* Everything else has internal linkage.  */
   return lk_internal;
 }
+\f
+/* 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.  */
+
+tree
+stabilize_expr (exp, initp)
+     tree exp;
+     tree *initp;
+{
+  tree init_expr;
+
+  if (!TREE_SIDE_EFFECTS (exp))
+    {
+      init_expr = void_zero_node;
+    }
+  else if (!real_lvalue_p (exp)
+          || !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (exp)))
+    {
+      init_expr = get_target_expr (exp);
+      exp = TARGET_EXPR_SLOT (init_expr);
+    }
+  else
+    {
+      exp = build_unary_op (ADDR_EXPR, exp, 1);
+      init_expr = get_target_expr (exp);
+      exp = TARGET_EXPR_SLOT (init_expr);
+      exp = build_indirect_ref (exp, 0);
+    }
+
+  *initp = init_expr;
+  return exp;
+}
index 06d9815..b13fc53 100644 (file)
@@ -868,6 +868,11 @@ struct tree_vec
 #define EXPR_WFL_SET_LINECOL(NODE, LINE, COL) \
   (EXPR_WFL_LINECOL(NODE) = ((LINE) << 12) | ((COL) & 0xfff))
 
+/* In a TARGET_EXPR node.  */
+#define TARGET_EXPR_SLOT(NODE) TREE_OPERAND (TARGET_EXPR_CHECK (NODE), 0)
+#define TARGET_EXPR_INITIAL(NODE) TREE_OPERAND (TARGET_EXPR_CHECK (NODE), 1)
+#define TARGET_EXPR_CLEANUP(NODE) TREE_OPERAND (TARGET_EXPR_CHECK (NODE), 2)
+
 struct tree_exp
 {
   struct tree_common common;