https://gcc.gnu.org/g:4042cecd6245dc773fc150d5fd839968674e4500
commit r14-11728-g4042cecd6245dc773fc150d5fd839968674e4500 Author: Iain Sandoe <i...@sandoe.co.uk> Date: Mon Aug 19 20:50:54 2024 +0100 c++, coroutines: Look through initial_await target exprs [PR110635]. In the case that the initial awaiter returns an object, the initial await can be a target expression and we need to look at its initializer to cast the await_resume() to void and to wrap in a compound expression that sets the initial_await_resume_called flag. PR c++/110635 gcc/cp/ChangeLog: * coroutines.cc (cp_coroutine_transform::wrap_original_function_body): Look through initial await target expressions to find the actual co_await_expr that we need to update. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr110635.C: New test. Signed-off-by: Iain Sandoe <i...@sandoe.co.uk> (cherry picked from commit c442a9b78bdbebdbcb4a8f91bc36961eb732fbdf) Diff: --- gcc/cp/coroutines.cc | 8 +++- gcc/testsuite/g++.dg/coroutines/pr110635.C | 72 ++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 82ba96f65674..ee0fbc454e6e 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4442,7 +4442,13 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig, a reference type, look past the indirection. */ if (INDIRECT_REF_P (initial_await)) initial_await = TREE_OPERAND (initial_await, 0); - tree vec = TREE_OPERAND (initial_await, 3); + /* In the case that the initial_await returns a target expression + we might need to look through that to update the await expr. */ + tree iaw = initial_await; + if (TREE_CODE (iaw) == TARGET_EXPR) + iaw = TARGET_EXPR_INITIAL (iaw); + gcc_checking_assert (TREE_CODE (iaw) == CO_AWAIT_EXPR); + tree vec = TREE_OPERAND (iaw, 3); tree aw_r = TREE_VEC_ELT (vec, 2); aw_r = convert_to_void (aw_r, ICV_STATEMENT, tf_warning_or_error); tree update = build2 (MODIFY_EXPR, boolean_type_node, i_a_r_c, diff --git a/gcc/testsuite/g++.dg/coroutines/pr110635.C b/gcc/testsuite/g++.dg/coroutines/pr110635.C new file mode 100644 index 000000000000..ea4e0e853eb5 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr110635.C @@ -0,0 +1,72 @@ + +#define CASE 0 +#include <coroutine> +#include <iostream> + +struct Coroutine { + + struct promise_type; + + using handler_type = std::coroutine_handle<promise_type>; + + struct initial_suspend_awaiter { + + bool await_ready() noexcept { + std::cout << "await_ready" << std::endl; + return false; + } + + void await_suspend(handler_type h) noexcept { + std::cout << "await_suspend" << std::endl; + } + +#if CASE == 0 + struct await_resume_return_object { + await_resume_return_object() noexcept { + std::cout << "await_resume_return_object" << std::endl; + } + + ~await_resume_return_object() noexcept { + std::cout << "~await_resume_return_object" << std::endl; + } + }; +#elif CASE == 1 + using await_resume_return_object = struct{}; +#elif CASE == 2 + using await_resume_return_object = int; +#else + using await_resume_return_object = void; +#endif + await_resume_return_object await_resume() noexcept { + std::cout << "await_resume" << std::endl; +#if CASE == 0 || CASE == 1 || CASE == 2 + return {}; +#endif + } + + initial_suspend_awaiter() noexcept { + std::cout << "initial_suspend_awaiter" << std::endl; + } + + ~initial_suspend_awaiter() noexcept { + std::cout << "~initial_suspend_awaiter" << std::endl; + } + }; + + struct promise_type { + void return_void() noexcept {} + void unhandled_exception() noexcept { std::terminate();} + initial_suspend_awaiter initial_suspend() noexcept { return {}; } + std::suspend_never final_suspend() noexcept { return {}; } + Coroutine get_return_object() { + return Coroutine{handler_type::from_promise(*this)}; + } + }; + + handler_type handler; +}; + +int main() { + auto coro = []()->Coroutine { co_return; }(); + coro.handler.resume(); +}