https://gcc.gnu.org/g:ce3f523f9cb4c20704bc5f41b8fbc34b5b84ed88
commit r14-11727-gce3f523f9cb4c20704bc5f41b8fbc34b5b84ed88 Author: Iain Sandoe <i...@sandoe.co.uk> Date: Sun Aug 18 22:54:50 2024 +0100 c++, coroutines: Rework handling of throwing_cleanups [PR102051]. In the fix for PR95822 (r11-7402) we set throwing_cleanup false in the top level of the coroutine transform code. However, as the current PR shows, that is not sufficient. Any use of cxx_maybe_build_cleanup() can reset the flag, which causes the check_return_expr () logic to try to add a guard variable and set it. For the coroutine code, we need to handle the cleanups separately, since the responsibility for them changes after the first resume point, which we handle in the ramp exception processing. Fix this by forcing the "throwing_cleanup" flag false right before the processing of the return expression. PR c++/102051 gcc/cp/ChangeLog: * coroutines.cc (cp_coroutine_transform::build_ramp_function): Handle "throwing_cleanup" here instead of ... (cp_coroutine_transform::apply_transforms): ... here. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr102051.C: New test. Signed-off-by: Iain Sandoe <i...@sandoe.co.uk> (cherry picked from commit f0315f7a325ffccb446fe378fcdfccda6eead8ba) Diff: --- gcc/cp/coroutines.cc | 15 ++++----------- gcc/testsuite/g++.dg/coroutines/pr102051.C | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 00a016d1bd31..82ba96f65674 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4632,17 +4632,6 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) TREE_OPERAND (body_start, 0) = push_stmt_list (); } - /* If the original function has a return value with a non-trivial DTOR - and the body contains a var with a DTOR that might throw, the decl is - marked "throwing_cleanup". - We do not [in the ramp, which is synthesised here], use any body var - types with DTORs that might throw. - The original body is transformed into the actor function which only - contains void returns, and is also wrapped in a try-catch block. - So (a) the 'throwing_cleanup' is not correct for the ramp and (b) we do - not need to transfer it to the actor which only contains void returns. */ - cp_function_chain->throwing_cleanup = false; - /* Create the coro frame type, as far as it can be known at this stage. 1. Types we already know. */ @@ -5270,6 +5259,10 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) either as the return value (if it's the same type) or to the CTOR for an object of the return type. */ + /* We must manage the cleanups ourselves, because the responsibility for + them changes after the initial suspend. However, any use of + cxx_maybe_build_cleanup () can set the throwing_cleanup flag. */ + cp_function_chain->throwing_cleanup = false; if (same_type_p (gro_type, fn_return_type)) r = void_ramp_p ? NULL_TREE : DECL_RESULT (orig); else diff --git a/gcc/testsuite/g++.dg/coroutines/pr102051.C b/gcc/testsuite/g++.dg/coroutines/pr102051.C new file mode 100644 index 000000000000..bba98b691cc2 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr102051.C @@ -0,0 +1,16 @@ +#include <coroutine> + +struct Foo { + ~Foo() noexcept(false); // true succeeds + struct promise_type { + Foo get_return_object() { return {}; } + std::suspend_never initial_suspend() { return {}; } + void return_void() {} + void unhandled_exception() {} + std::suspend_always final_suspend() noexcept { return {}; } + }; +}; + +Foo bar() { + co_return; +}