aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2025-03-05 08:45:34 -0500
committerJason Merrill <jason@redhat.com>2025-03-05 11:58:56 -0500
commit7e576d5b64ae92432fc2749b8f66105cee8db356 (patch)
treeddebe7073e4511415278e0d6b215a044ae5b7588
parent4d0a333ef13e2da140cd44c4941b20f48a80dc0f (diff)
downloadgcc-7e576d5b64ae92432fc2749b8f66105cee8db356.zip
gcc-7e576d5b64ae92432fc2749b8f66105cee8db356.tar.gz
gcc-7e576d5b64ae92432fc2749b8f66105cee8db356.tar.bz2
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 <jakub@redhat.com>
-rw-r--r--gcc/cp/coroutines.cc18
-rw-r--r--gcc/testsuite/g++.dg/coroutines/torture/pr118874.C33
2 files changed, 50 insertions, 1 deletions
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index d3c7ff3..b92d09f 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 0000000..925d56a
--- /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";
+}