aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimplify.c
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2020-01-10 17:14:12 -0500
committerJason Merrill <jason@redhat.com>2020-01-13 12:50:12 -0500
commit7c82dd6c02d44d9d2cd84dda137c00b1a3cd6c90 (patch)
treed5bf3e04c5a748eb795b36dd2aa133add540fa74 /gcc/gimplify.c
parentf1acad4e43908e90ca2b5155a878639cbea4c4e1 (diff)
downloadgcc-7c82dd6c02d44d9d2cd84dda137c00b1a3cd6c90.zip
gcc-7c82dd6c02d44d9d2cd84dda137c00b1a3cd6c90.tar.gz
gcc-7c82dd6c02d44d9d2cd84dda137c00b1a3cd6c90.tar.bz2
PR c++/33799 - destroy return value if local cleanup throws.
This is a pretty rare situation since the C++11 change to make all destructors default to noexcept, but it is still possible to define throwing destructors, and if a destructor for a local variable throws during the return, we've already constructed the return value, so now we need to destroy it. I handled this somewhat like the new-expression cleanup; as in that case, this cleanup can't properly nest with the cleanups for local variables, so I introduce a cleanup region around the whole function and a flag variable to indicate whether the return value actually needs to be destroyed. Setting the flag requires giving a COMPOUND_EXPR as the operand of a RETURN_EXPR, so I adjust gimplify_return_expr to handle that. This doesn't currently work with deduced return type because we don't know the type when we're deciding whether to introduce the cleanup region. gcc/ * gimplify.c (gimplify_return_expr): Handle COMPOUND_EXPR. gcc/cp/ * cp-tree.h (current_retval_sentinel): New macro. * decl.c (start_preparsed_function): Set up cleanup for retval. * typeck.c (check_return_expr): Set current_retval_sentinel.
Diffstat (limited to 'gcc/gimplify.c')
-rw-r--r--gcc/gimplify.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index fe7236d..05d7922 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1599,6 +1599,14 @@ gimplify_return_expr (tree stmt, gimple_seq *pre_p)
if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
result_decl = NULL_TREE;
+ else if (TREE_CODE (ret_expr) == COMPOUND_EXPR)
+ {
+ /* Used in C++ for handling EH cleanup of the return value if a local
+ cleanup throws. Assume the front-end knows what it's doing. */
+ result_decl = DECL_RESULT (current_function_decl);
+ /* But crash if we end up trying to modify ret_expr below. */
+ ret_expr = NULL_TREE;
+ }
else
{
result_decl = TREE_OPERAND (ret_expr, 0);