summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/cp/except.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gcc/cp/except.c')
-rw-r--r--contrib/gcc/cp/except.c173
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
OpenPOWER on IntegriCloud