diff options
author | kan <kan@FreeBSD.org> | 2003-07-11 04:00:23 +0000 |
---|---|---|
committer | kan <kan@FreeBSD.org> | 2003-07-11 04:00:23 +0000 |
commit | 4e7ac24200e18bbd6367139a46c1286294a70474 (patch) | |
tree | c567c233a70a71a655646549c59efb4bd5c61d04 /contrib/gcc/cp | |
parent | b664230ac178e69c3c146968ee0c3300a4009f60 (diff) | |
download | FreeBSD-src-4e7ac24200e18bbd6367139a46c1286294a70474.zip FreeBSD-src-4e7ac24200e18bbd6367139a46c1286294a70474.tar.gz |
FreeBSD uses stock versions of these GCC files.
Diffstat (limited to 'contrib/gcc/cp')
-rw-r--r-- | contrib/gcc/cp/except.c | 173 |
1 files changed, 127 insertions, 46 deletions
diff --git a/contrib/gcc/cp/except.c b/contrib/gcc/cp/except.c index 5de9f4c..747cc1a 100644 --- a/contrib/gcc/cp/except.c +++ b/contrib/gcc/cp/except.c @@ -31,10 +31,10 @@ Boston, MA 02111-1307, USA. */ #include "libfuncs.h" #include "cp-tree.h" #include "flags.h" -#include "obstack.h" #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 +46,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. */ @@ -118,7 +117,7 @@ prepare_eh_type (type) } /* Build the address of a typeinfo decl for use in the runtime - matching field of the exception model. */ + matching field of the exception model. */ static tree build_eh_type_type (type) @@ -175,17 +174,13 @@ static int dtor_nothrow (type) tree type; { - tree fn; - if (type == NULL_TREE) return 0; if (! TYPE_HAS_DESTRUCTOR (type)) return 1; - fn = lookup_member (type, dtor_identifier, 0, 0); - fn = TREE_VALUE (fn); - return TREE_NOTHROW (fn); + return TREE_NOTHROW (CLASSTYPE_DESTRUCTORS (type)); } /* Build up a call to __cxa_end_catch, to destroy the exception object @@ -518,7 +513,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 +535,92 @@ 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 = TREE_VALUE (args); + tree arg_init_expr; + + arg = stabilize_expr (arg, &arg_init_expr); + + if (TREE_SIDE_EFFECTS (arg_init_expr)) + init_expr = build (COMPOUND_EXPR, void_type_node, init_expr, + arg_init_expr); + *p = tree_cons (NULL_TREE, arg, 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 +666,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 +694,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 +711,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))); @@ -671,9 +752,9 @@ build_throw (exp) { cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), complete_dtor_identifier, 0); - cleanup = TREE_VALUE (cleanup); + cleanup = BASELINK_FUNCTIONS (cleanup); mark_used (cleanup); - mark_addressable (cleanup); + cxx_mark_addressable (cleanup); /* Pretend it's a normal function. */ cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup); } @@ -686,13 +767,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 +787,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); } @@ -718,7 +799,7 @@ build_throw (exp) /* Make sure TYPE is complete, pointer to complete, reference to complete, or pointer to cv void. Issue diagnostic on failure. - Return the zero on failure and non-zero on success. FROM can be + Return the zero on failure and nonzero on success. FROM can be the expr or decl from whence TYPE came, if available. */ static int |