diff options
author | Jason Merrill <jason@redhat.com> | 2004-03-10 21:32:50 +0000 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2004-03-10 21:32:50 +0000 |
commit | 65c1e488d24c2d7ca5c71cdc18552c4422e1a900 (patch) | |
tree | a86b1cc711a8982111fcc803e78272c636ab6a16 | |
parent | 58e236e6e28239a7f084359a3641b7a760414c04 (diff) |
PR c++/14452
* tree.c (stabilize_init): Return whether or not it worked.
* init.c (build_new_1): If not, use a sentry.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/tree-ssa-20020619-branch@79275 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/cp/ChangeLog.tree-ssa | 6 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 2 | ||||
-rw-r--r-- | gcc/cp/except.c | 7 | ||||
-rw-r--r-- | gcc/cp/init.c | 63 | ||||
-rw-r--r-- | gcc/cp/tree.c | 13 |
5 files changed, 76 insertions, 15 deletions
diff --git a/gcc/cp/ChangeLog.tree-ssa b/gcc/cp/ChangeLog.tree-ssa index f092d87adc4..25f19a7c38e 100644 --- a/gcc/cp/ChangeLog.tree-ssa +++ b/gcc/cp/ChangeLog.tree-ssa @@ -1,3 +1,9 @@ +2004-03-10 Jason Merrill <jason@redhat.com> + + PR c++/14452 + * tree.c (stabilize_init): Return whether or not it worked. + * init.c (build_new_1): If not, use a sentry. + 2004-03-01 Jeff Law <law@redhat.com> * init.c (build_vec_delete_1): Convert 2nd argument to NE_EXPR to diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index cf83fdfabd8..f6282105daf 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4085,7 +4085,7 @@ extern void lang_check_failed (const char *, int, const char *); extern tree stabilize_expr (tree, tree *); extern void stabilize_call (tree, tree *); -extern void stabilize_init (tree, tree *); +extern bool stabilize_init (tree, tree *); extern tree cxx_unsave_expr_now (tree); extern tree cxx_maybe_build_cleanup (tree); extern void init_tree (void); diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 10a99dd94ec..aa21b6c3fc2 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -678,7 +678,12 @@ build_throw (tree exp) it does. But that conflicted with expectations (PR 13944) and the EDG compiler; now we wrap the initialization in a TRY_CATCH_EXPR to call do_free_exception rather than in a MUST_NOT_THROW_EXPR, - for this case only. */ + for this case only. + + Note that we don't check the return value from stabilize_init + because it will only return false in cases where elided is true, + and therefore we don't need to work around the failure to + preevaluate. */ stabilize_init (exp, &temp_expr); if (elided) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 1a5a950d0c2..04e70bcc89d 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2183,6 +2183,8 @@ build_new_1 (tree exp) placement delete. */ if (is_initialized) { + bool stable; + init_expr = build_indirect_ref (data_addr, NULL); if (init == void_zero_node) @@ -2191,18 +2193,25 @@ build_new_1 (tree exp) pedwarn ("ISO C++ forbids initialization in array new"); if (has_array) - init_expr - = build_vec_init (init_expr, - cp_build_binary_op (MINUS_EXPR, outer_nelts, - integer_one_node), - init, /*from_array=*/0); + { + init_expr + = build_vec_init (init_expr, + cp_build_binary_op (MINUS_EXPR, outer_nelts, + integer_one_node), + init, /*from_array=*/0); + + /* An array initialization is stable because the initialization + of each element is a full-expression, so the temporaries don't + leak out. */ + stable = true; + } else if (TYPE_NEEDS_CONSTRUCTING (type)) { init_expr = build_special_member_call (init_expr, complete_ctor_identifier, init, TYPE_BINFO (true_type), LOOKUP_NORMAL); - stabilize_init (init_expr, &init_preeval_expr); + stable = stabilize_init (init_expr, &init_preeval_expr); } else { @@ -2217,7 +2226,7 @@ build_new_1 (tree exp) abort (); init_expr = build_modify_expr (init_expr, INIT_EXPR, init); - stabilize_init (init_expr, &init_preeval_expr); + stable = stabilize_init (init_expr, &init_preeval_expr); } if (init_expr == error_mark_node) @@ -2244,11 +2253,45 @@ build_new_1 (tree exp) (placement_allocation_fn_p ? alloc_call : NULL_TREE)); - /* This is much simpler now that we've preevaluated all of the - arguments to the constructor call. */ - if (cleanup) + if (!cleanup) + /* We're done. */; + else if (stable) + /* This is much simpler if we were able to preevaluate all of + the arguments to the constructor call. */ init_expr = build (TRY_CATCH_EXPR, void_type_node, init_expr, cleanup); + else + /* Ack! First we allocate the memory. Then we set our sentry + variable to true, and expand a cleanup that deletes the + memory if sentry is true. Then we run the constructor, and + finally clear the sentry. + + We need to do this because we allocate the space first, so + if there are any temporaries with cleanups in the + constructor args and we weren't able to preevaluate them, we + need this EH region to extend until end of full-expression + to preserve nesting. */ + { + tree end, sentry, begin; + + begin = get_target_expr (boolean_true_node); + CLEANUP_EH_ONLY (begin) = 1; + + sentry = TARGET_EXPR_SLOT (begin); + + TARGET_EXPR_CLEANUP (begin) + = build (COND_EXPR, void_type_node, sentry, + cleanup, void_zero_node); + + end = build (MODIFY_EXPR, TREE_TYPE (sentry), + sentry, boolean_false_node); + + init_expr + = build (COMPOUND_EXPR, void_type_node, begin, + build (COMPOUND_EXPR, void_type_node, init_expr, + end)); + } + } } else diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 84414b64442..2c232f389cb 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2463,13 +2463,13 @@ stabilize_call (tree call, tree *initp) so we look past the TARGET_EXPR and stabilize the arguments of the call instead. */ -void +bool stabilize_init (tree init, tree *initp) { tree t = init; if (t == error_mark_node) - return; + return true; if (TREE_CODE (t) == INIT_EXPR && TREE_CODE (TREE_OPERAND (t, 1)) != TARGET_EXPR) @@ -2485,11 +2485,18 @@ stabilize_init (tree init, tree *initp) { /* Default-initialization. */ *initp = NULL_TREE; - return; + return true; } + /* If the initializer is a COND_EXPR, we can't preevaluate + anything. */ + if (TREE_CODE (t) == COND_EXPR) + return false; + stabilize_call (t, initp); } + + return true; } |