aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2004-03-10 21:32:50 +0000
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2004-03-10 21:32:50 +0000
commit001b04b7ba2ca7cde8327b91d03bd1d0704f730d (patch)
treea86b1cc711a8982111fcc803e78272c636ab6a16
parenta22714fbabde165f4fecd205bd7a150de25ee995 (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: svn+ssh://gcc.gnu.org/svn/gcc/branches/tree-ssa-20020619-branch@79275 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/cp/ChangeLog.tree-ssa6
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/except.c7
-rw-r--r--gcc/cp/init.c63
-rw-r--r--gcc/cp/tree.c13
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;
}