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();
+}

Reply via email to