aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/init.c
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2022-01-01 16:00:22 -0500
committerJason Merrill <jason@redhat.com>2022-01-06 19:23:17 -0500
commitbeaee0a871b6485d20573fe050b1fd425581e56a (patch)
tree5b5a1320fcbead17619a0dfdfdf701528f8a5ca9 /gcc/cp/init.c
parentce0ab8fb46f07b0bde56aa31e46d57b81379fde3 (diff)
downloadgcc-beaee0a871b6485d20573fe050b1fd425581e56a.zip
gcc-beaee0a871b6485d20573fe050b1fd425581e56a.tar.gz
gcc-beaee0a871b6485d20573fe050b1fd425581e56a.tar.bz2
c++: temporary lifetime with array aggr init [PR94041]
The previous patch fixed temporary lifetime for aggregate initialization of classes; this one extends that fix to arrays. This specifically reverses my r74790, the patch for PR12253, which was made wrong when these semantics were specified in DR201. Since the array cleanup region encloses the regions for any temporaries, we don't need to add an additional region for the array object itself in either initialize_local_var or split_nonconstant_init; we do, however, need to tell split_nonconstant_init how to disable the cleanup once an enclosing object is fully constructed, at which point we want to run that destructor instead. PR c++/94041 gcc/cp/ChangeLog: * decl.c (initialize_local_var): Fix comment. * init.c (build_new_1): Do stabilize array init. (build_vec_init): Use TARGET_EXPR for cleanup. Initialization of an element from an explicit initializer is not a full-expression. * tree.c (expand_vec_init_expr): Pass flags through. * typeck2.c (split_nonconstant_init_1): Handle VEC_INIT_EXPR. (split_nonconstant_init): Handle array cleanups. * cp-tree.h: Adjust. gcc/testsuite/ChangeLog: * g++.dg/init/array12.C: * g++.dg/init/aggr7-eh2.C: New test. * g++.dg/init/aggr7-eh3.C: New test.
Diffstat (limited to 'gcc/cp/init.c')
-rw-r--r--gcc/cp/init.c84
1 files changed, 49 insertions, 35 deletions
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 2a7dfe2b..7c7b810 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -4292,7 +4292,9 @@ finish_length_check (tree atype, tree iterator, tree obase, unsigned n)
tree
build_vec_init (tree base, tree maxindex, tree init,
bool explicit_value_init_p,
- int from_array, tsubst_flags_t complain)
+ int from_array,
+ tsubst_flags_t complain,
+ vec<tree, va_gc>** flags /* = nullptr */)
{
tree rval;
tree base2 = NULL_TREE;
@@ -4310,7 +4312,6 @@ build_vec_init (tree base, tree maxindex, tree init,
tree stmt_expr;
tree compound_stmt;
int destroy_temps;
- tree try_block = NULL_TREE;
HOST_WIDE_INT num_initialized_elts = 0;
bool is_global;
tree obase = base;
@@ -4447,7 +4448,9 @@ build_vec_init (tree base, tree maxindex, tree init,
current_stmt_tree ()->stmts_are_full_exprs_p = 0;
rval = get_temp_regvar (ptype, base);
base = get_temp_regvar (ptype, rval);
- iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
+ tree iterator_targ = get_target_expr (maxindex);
+ add_stmt (iterator_targ);
+ iterator = TARGET_EXPR_SLOT (iterator_targ);
/* If initializing one array from another, initialize element by
element. We rely upon the below calls to do the argument
@@ -4470,7 +4473,37 @@ build_vec_init (tree base, tree maxindex, tree init,
if (flag_exceptions && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
&& from_array != 2)
{
- try_block = begin_try_block ();
+ tree e;
+ tree m = cp_build_binary_op (input_location,
+ MINUS_EXPR, maxindex, iterator,
+ complain);
+
+ /* Flatten multi-dimensional array since build_vec_delete only
+ expects one-dimensional array. */
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ m = cp_build_binary_op (input_location,
+ MULT_EXPR, m,
+ /* Avoid mixing signed and unsigned. */
+ convert (TREE_TYPE (m),
+ array_type_nelts_total (type)),
+ complain);
+
+ e = build_vec_delete_1 (input_location, rval, m,
+ inner_elt_type, sfk_complete_destructor,
+ /*use_global_delete=*/0, complain);
+ if (e == error_mark_node)
+ errors = true;
+ TARGET_EXPR_CLEANUP (iterator_targ) = e;
+ CLEANUP_EH_ONLY (iterator_targ) = true;
+
+ /* Since we push this cleanup before doing any initialization, cleanups
+ for any temporaries in the initialization are naturally within our
+ cleanup region, so we don't want wrap_temporary_cleanups to do
+ anything for arrays. But if the array is a subobject, we need to
+ tell split_nonconstant_init how to turn off this cleanup in favor of
+ the cleanup for the complete object. */
+ if (flags)
+ vec_safe_push (*flags, build_tree_list (iterator, maxindex));
}
/* Should we try to create a constant initializer? */
@@ -4520,11 +4553,10 @@ build_vec_init (tree base, tree maxindex, tree init,
num_initialized_elts++;
- current_stmt_tree ()->stmts_are_full_exprs_p = 1;
if (digested)
one_init = build2 (INIT_EXPR, type, baseref, elt);
else if (TREE_CODE (elt) == VEC_INIT_EXPR)
- one_init = expand_vec_init_expr (baseref, elt, complain);
+ one_init = expand_vec_init_expr (baseref, elt, complain, flags);
else if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
one_init = build_aggr_init (baseref, elt, 0, complain);
else
@@ -4560,7 +4592,6 @@ build_vec_init (tree base, tree maxindex, tree init,
if (one_init)
finish_expr_stmt (one_init);
- current_stmt_tree ()->stmts_are_full_exprs_p = 0;
one_init = cp_build_unary_op (PREINCREMENT_EXPR, base, false,
complain);
@@ -4782,6 +4813,17 @@ build_vec_init (tree base, tree maxindex, tree init,
}
}
+ /* [class.temporary]: "There are three contexts in which temporaries are
+ destroyed at a different point than the end of the full-
+ expression. The first context is when a default constructor is called
+ to initialize an element of an array with no corresponding
+ initializer. The second context is when a copy constructor is called
+ to copy an element of an array while the entire array is copied. In
+ either case, if the constructor has one or more default arguments, the
+ destruction of every temporary created in a default argument is
+ sequenced before the construction of the next array element, if any."
+
+ So, for this loop, statements are full-expressions. */
current_stmt_tree ()->stmts_are_full_exprs_p = 1;
if (elt_init && !errors)
elt_init = build2 (COMPOUND_EXPR, void_type_node, elt_init, decr);
@@ -4799,34 +4841,6 @@ build_vec_init (tree base, tree maxindex, tree init,
finish_for_stmt (for_stmt);
}
- /* Make sure to cleanup any partially constructed elements. */
- if (flag_exceptions && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
- && from_array != 2)
- {
- tree e;
- tree m = cp_build_binary_op (input_location,
- MINUS_EXPR, maxindex, iterator,
- complain);
-
- /* Flatten multi-dimensional array since build_vec_delete only
- expects one-dimensional array. */
- if (TREE_CODE (type) == ARRAY_TYPE)
- m = cp_build_binary_op (input_location,
- MULT_EXPR, m,
- /* Avoid mixing signed and unsigned. */
- convert (TREE_TYPE (m),
- array_type_nelts_total (type)),
- complain);
-
- finish_cleanup_try_block (try_block);
- e = build_vec_delete_1 (input_location, rval, m,
- inner_elt_type, sfk_complete_destructor,
- /*use_global_delete=*/0, complain);
- if (e == error_mark_node)
- errors = true;
- finish_cleanup (e, try_block);
- }
-
/* The value of the array initialization is the array itself, RVAL
is a pointer to the first element. */
finish_stmt_expr_expr (rval, stmt_expr);