diff options
author | Jason Merrill <jason@redhat.com> | 2022-01-05 11:18:25 -0500 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2022-01-06 19:25:42 -0500 |
commit | 4c6afbbd48f0c40ddf949bc403d9bd5f5e14204f (patch) | |
tree | 68738365efc46a2ecbaf807eeebd45f39e1d9778 /gcc/cp/decl.c | |
parent | 2fbc45486e13facfeb05bd6ddf70ff9973a30a3c (diff) | |
download | gcc-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.c | 25 |
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); } |