diff options
author | Jason Merrill <jason@redhat.com> | 2025-03-05 08:45:34 -0500 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2025-03-05 11:58:56 -0500 |
commit | 7e576d5b64ae92432fc2749b8f66105cee8db356 (patch) | |
tree | ddebe7073e4511415278e0d6b215a044ae5b7588 | |
parent | 4d0a333ef13e2da140cd44c4941b20f48a80dc0f (diff) | |
download | gcc-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.cc | 18 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/coroutines/torture/pr118874.C | 33 |
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"; +} |