https://gcc.gnu.org/g:7e576d5b64ae92432fc2749b8f66105cee8db356

commit r15-7837-g7e576d5b64ae92432fc2749b8f66105cee8db356
Author: Jason Merrill <ja...@redhat.com>
Date:   Wed Mar 5 08:45:34 2025 -0500

    c++: coroutines and return in registers [PR118874]
    
    Because coroutines insert a call to the resumer between the initialization
    of the return value and the actual return to the caller, we need to
    duplicate the work of gimplify_return_expr for the !aggregate_value_p case.
    
            PR c++/117364
            PR c++/118874
    
    gcc/cp/ChangeLog:
    
            * coroutines.cc (cp_coroutine_transform::build_ramp_function): For
            !aggregate_value_p return force return value into a local temp.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/coroutines/torture/pr118874.C: New test.
    
    Co-authored-by: Jakub Jelinek <ja...@redhat.com>

Diff:
---
 gcc/cp/coroutines.cc                               | 18 +++++++++++-
 gcc/testsuite/g++.dg/coroutines/torture/pr118874.C | 33 ++++++++++++++++++++++
 2 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index d3c7ff3bd72d..b92d09fa4ead 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -5161,6 +5161,7 @@ cp_coroutine_transform::build_ramp_function ()
 
   /* Used for return objects in the RESULT slot.  */
   tree ret_val_dtor = NULL_TREE;
+  tree retval = NULL_TREE;
 
   /* [dcl.fct.def.coroutine] / 7
      The expression promise.get_return_object() is used to initialize the
@@ -5189,6 +5190,21 @@ cp_coroutine_transform::build_ramp_function ()
       /* Check for bad things.  */
       if (!r || r == error_mark_node)
        return false;
+      if (!aggregate_value_p (fn_return_type, orig_fn_decl)
+         && TREE_CODE (r) == INIT_EXPR)
+       {
+         /* If fn_return_type doesn't need to be returned in memory, normally
+            gimplify_return_expr redirects the INIT_EXPR to a temporary.  But
+            r isn't wrapped in the RETURN_EXPR, so we need to do the
+            redirection here as well.  See PR118874.  */
+         tree temp = create_temporary_var (fn_return_type);
+         add_decl_expr (temp);
+         retval = copy_node (r);
+         TREE_OPERAND (r, 0) = temp;
+         TREE_OPERAND (retval, 1) = temp;
+       }
+      else
+       retval = DECL_RESULT (orig_fn_decl);
     }
 
   finish_expr_stmt (r);
@@ -5215,7 +5231,7 @@ cp_coroutine_transform::build_ramp_function ()
   /* The ramp is done, we just need the return statement, which we build from
      the return object we constructed before we called the actor.  */
 
-  r = void_ramp_p ? NULL_TREE : DECL_RESULT (orig_fn_decl);
+  r = retval;
 
   /* The reminder of finish_return_expr ().  */
   r = build_stmt (loc, RETURN_EXPR, r);
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/pr118874.C 
b/gcc/testsuite/g++.dg/coroutines/torture/pr118874.C
new file mode 100644
index 000000000000..925d56ae2ea2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/pr118874.C
@@ -0,0 +1,33 @@
+// PR c++/118874
+// { dg-do compile }
+// { dg-additional-options "-std=c++20" }
+
+#include <coroutine>
+
+struct B {
+  bool await_ready () const noexcept;
+  void await_suspend (std::coroutine_handle<> h) const noexcept;
+  void await_resume () const noexcept;
+};
+
+struct C {
+  struct promise_type {
+    const char *value;
+    std::suspend_never initial_suspend ();
+    std::suspend_always final_suspend () noexcept;
+    void return_value (const char *v);
+    void unhandled_exception ();
+    C get_return_object () { return C{this}; }
+  };
+  promise_type *p;
+  explicit C (promise_type *p) : p(p) {}
+  const char *get ();
+};
+
+C
+bar (bool x)
+{
+  if (x)
+    co_await B{};
+  co_return "foobar";
+}

Reply via email to