summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/cp/ChangeLog13
-rw-r--r--gcc/cp/Make-lang.in2
-rw-r--r--gcc/cp/except.c155
-rw-r--r--gcc/cp/init.c20
-rw-r--r--gcc/cp/tree.c33
-rw-r--r--gcc/tree.h5
7 files changed, 197 insertions, 38 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5aa2209e581..2066310cc36 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 85f254704ec..540e8749d44 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index f8d023a1cb7..1e721b6ac56 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -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 \
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 3f3cdcfd3be..8cbbfa916cb 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -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);
}
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 017b8943906..7eaafc99354 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -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;
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 8b0a1984780..a49a2dcc664 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2497,3 +2497,36 @@ decl_linkage (decl)
/* Everything else has internal linkage. */
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. */
+
+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;
+}
diff --git a/gcc/tree.h b/gcc/tree.h
index 06d9815ba15..b13fc53cdb5 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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;