aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/decl.c
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2022-01-05 11:18:25 -0500
committerJason Merrill <jason@redhat.com>2022-01-06 19:25:42 -0500
commit4c6afbbd48f0c40ddf949bc403d9bd5f5e14204f (patch)
tree68738365efc46a2ecbaf807eeebd45f39e1d9778 /gcc/cp/decl.c
parent2fbc45486e13facfeb05bd6ddf70ff9973a30a3c (diff)
downloadgcc-4c6afbbd48f0c40ddf949bc403d9bd5f5e14204f.zip
gcc-4c6afbbd48f0c40ddf949bc403d9bd5f5e14204f.tar.gz
gcc-4c6afbbd48f0c40ddf949bc403d9bd5f5e14204f.tar.bz2
c++: clean up ref-extended temp on throwing dtor [PR53868]
We have wrap_temporary_cleanups to handle the EH region nesting problems between cleanups for complete variables and cleanups for temporaries used in their construction, but we weren't calling it for temporaries extended from binding to a reference. We still don't want this for array cleanups (since my PR94041 fix), so I move that exception from initialize_local_var to wrap_temporary_cleanups. PR c++/53868 gcc/cp/ChangeLog: * decl.c (cp_finish_decl): Use wrap_temporary_cleanups for cleanups from set_up_extended_ref_temp. (wrap_temporary_cleanups): Ignore array cleanups. (initialize_local_var): Don't check for array here. * cp-tree.h (BIND_EXPR_VEC_DTOR): New. * init.c (build_vec_delete_1): Set it. gcc/testsuite/ChangeLog: * g++.dg/eh/ref-temp1.C: New test. * g++.dg/eh/ref-temp2.C: New test.
Diffstat (limited to 'gcc/cp/decl.c')
-rw-r--r--gcc/cp/decl.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b16a4f9..5fe341e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -7451,11 +7451,24 @@ wrap_cleanups_r (tree *stmt_p, int *walk_subtrees, void *data)
they are run on the normal path, but not if they are run on the
exceptional path. We implement this by telling
honor_protect_cleanup_actions to strip the variable cleanup from the
- exceptional path. */
+ exceptional path.
+
+ Another approach could be to make the variable cleanup region enclose
+ initialization, but depend on a flag to indicate that the variable is
+ initialized; that's effectively what we do for arrays. But the current
+ approach works fine for non-arrays, and has no code overhead in the usual
+ case where the temporary destructors are noexcept. */
static void
wrap_temporary_cleanups (tree init, tree guard)
{
+ if (TREE_CODE (guard) == BIND_EXPR)
+ {
+ /* An array cleanup region already encloses any temporary cleanups,
+ don't wrap it around them again. */
+ gcc_checking_assert (BIND_EXPR_VEC_DTOR (guard));
+ return;
+ }
cp_walk_tree_without_duplicates (&init, wrap_cleanups_r, (void *)guard);
}
@@ -7518,8 +7531,8 @@ initialize_local_var (tree decl, tree init)
/* If we're only initializing a single object, guard the
destructors of any temporaries used in its initializer with
- its destructor. But arrays are handled in build_vec_init. */
- if (cleanup && TREE_CODE (type) != ARRAY_TYPE)
+ its destructor. */
+ if (cleanup)
wrap_temporary_cleanups (init, cleanup);
gcc_assert (building_stmt_list_p ());
@@ -8367,7 +8380,11 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
if (cleanups)
{
for (tree t : *cleanups)
- push_cleanup (decl, t, false);
+ {
+ push_cleanup (decl, t, false);
+ /* As in initialize_local_var. */
+ wrap_temporary_cleanups (init, t);
+ }
release_tree_vector (cleanups);
}