aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIain Sandoe <iain@sandoe.co.uk>2024-08-19 20:50:54 +0100
committerIain Sandoe <iain@sandoe.co.uk>2024-08-24 19:56:28 +0100
commitc442a9b78bdbebdbcb4a8f91bc36961eb732fbdf (patch)
tree68fa467e9528c5638883f3e6940abade29ab838d
parentf0315f7a325ffccb446fe378fcdfccda6eead8ba (diff)
downloadgcc-c442a9b78bdbebdbcb4a8f91bc36961eb732fbdf.zip
gcc-c442a9b78bdbebdbcb4a8f91bc36961eb732fbdf.tar.gz
gcc-c442a9b78bdbebdbcb4a8f91bc36961eb732fbdf.tar.bz2
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 <iain@sandoe.co.uk>
-rw-r--r--gcc/cp/coroutines.cc8
-rw-r--r--gcc/testsuite/g++.dg/coroutines/pr110635.C72
2 files changed, 79 insertions, 1 deletions
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 3991de1..c3e0822 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -4283,7 +4283,13 @@ cp_coroutine_transform::wrap_original_function_body ()
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 0000000..ea4e0e8
--- /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();
+}