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:
parent
e38ff265da
commit
6f30f1f13c
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
155
gcc/cp/except.c
155
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);
|
||||
/* ??? 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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user