tree.h (TARGET_EXPR_SLOT, [...]): New macros.

* tree.h (TARGET_EXPR_SLOT, TARGET_EXPR_INITIAL): New macros.
        (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.

From-SVN: r50177
This commit is contained in:
Jason Merrill 2002-02-28 20:49:00 -05:00 committed by Jason Merrill
parent e38ff265da
commit 6f30f1f13c
7 changed files with 197 additions and 38 deletions

View 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.

View 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

View 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 \

View 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);
/* ??? Indicate that this function call throws throw_type. */
tmp = build_function_call (fn, tmp);
/* ??? Indicate that this function call throws throw_type. */
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);
}

View 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;

View File

@ -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;
}

View 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;