https://gcc.gnu.org/g:98364636c194398d5dccb477e5405cb1d02a55f1
commit r14-11725-g98364636c194398d5dccb477e5405cb1d02a55f1 Author: Iain Sandoe <i...@sandoe.co.uk> Date: Sat Aug 17 15:47:58 2024 +0100 c++, coroutines: Only allow void get_return_object if the ramp is void [PR100476]. Require that the value returned by get_return_object is convertible to the ramp return. This means that the only time we allow a void get_return_object, is when the ramp is also a void function. We diagnose this early to allow us to exit the ramp build if the return values are incompatible. PR c++/100476 gcc/cp/ChangeLog: * coroutines.cc (cp_coroutine_transform::build_ramp_function): Remove special handling of void get_return_object expressions. gcc/testsuite/ChangeLog: * g++.dg/coroutines/coro-bad-gro-01-void-gro-non-class-coro.C: Adjust expected diagnostic. * g++.dg/coroutines/pr102489.C: Avoid void get_return_object. * g++.dg/coroutines/pr103868.C: Likewise. * g++.dg/coroutines/pr94879-folly-1.C: Likewise. * g++.dg/coroutines/pr94883-folly-2.C: Likewise. * g++.dg/coroutines/pr96749-2.C: Likewise. Signed-off-by: Iain Sandoe <i...@sandoe.co.uk> (cherry picked from commit a0b431033c307982123abbff752045cfe7eda47f) Diff: --- gcc/cp/coroutines.cc | 49 ++++++++++------------ .../coro-bad-gro-01-void-gro-non-class-coro.C | 4 +- gcc/testsuite/g++.dg/coroutines/pr102489.C | 2 +- gcc/testsuite/g++.dg/coroutines/pr103868.C | 2 +- gcc/testsuite/g++.dg/coroutines/pr94879-folly-1.C | 3 +- gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C | 39 ++++++++--------- gcc/testsuite/g++.dg/coroutines/pr96749-2.C | 2 +- 7 files changed, 50 insertions(+), 51 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 3774e5595a0d..a6cbe07d1a28 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4646,8 +4646,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /* Create the coro frame type, as far as it can be known at this stage. 1. Types we already know. */ - tree fn_return_type = TREE_TYPE (TREE_TYPE (orig)); tree promise_type = get_coroutine_promise_type (orig); + tree fn_return_type = TREE_TYPE (TREE_TYPE (orig)); + bool void_ramp_p = VOID_TYPE_P (fn_return_type); /* 2. Types we need to define or look up. */ @@ -4951,7 +4952,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) tree cond = build1 (CONVERT_EXPR, coro_frame_ptr, nullptr_node); cond = build2 (EQ_EXPR, boolean_type_node, coro_fp, cond); finish_if_stmt_cond (cond, if_stmt); - if (VOID_TYPE_P (fn_return_type)) + if (void_ramp_p) { /* Execute the get-return-object-on-alloc-fail call... */ finish_expr_stmt (grooaf); @@ -5157,7 +5158,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) coro_get_return_object_identifier, fn_start, NULL, /*musthave=*/true); /* Without a return object we haven't got much clue what's going on. */ - if (get_ro == error_mark_node) + if (!get_ro || get_ro == error_mark_node) { BIND_EXPR_BODY (ramp_bind) = pop_stmt_list (ramp_body); DECL_SAVED_TREE (orig) = newbody; @@ -5165,10 +5166,20 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) suppress_warning (orig, OPT_Wreturn_type); return false; } + + /* Check for a bad get return object type. + [dcl.fct.def.coroutine] / 7 requires: + The expression promise.get_return_object() is used to initialize the + returned reference or prvalue result object ... */ + tree gro_type = TREE_TYPE (get_ro); + if (VOID_TYPE_P (gro_type) && !void_ramp_p) + { + error_at (fn_start, "no viable conversion from %<void%> provided by" + " %<get_return_object%> to return type %qT", fn_return_type); + return false; + } tree gro_context_body = push_stmt_list (); - tree gro_type = TREE_TYPE (get_ro); - bool gro_is_void_p = VOID_TYPE_P (gro_type); tree gro = NULL_TREE; tree gro_bind_vars = NULL_TREE; @@ -5177,8 +5188,11 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) tree gro_cleanup_stmt = NULL_TREE; /* We have to sequence the call to get_return_object before initial suspend. */ - if (gro_is_void_p) - r = get_ro; + if (void_ramp_p) + { + gcc_checking_assert (VOID_TYPE_P (gro_type)); + r = get_ro; + } else if (same_type_p (gro_type, fn_return_type)) { /* [dcl.fct.def.coroutine] / 7 @@ -5264,28 +5278,11 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) for an object of the return type. */ if (same_type_p (gro_type, fn_return_type)) - r = gro_is_void_p ? NULL_TREE : DECL_RESULT (orig); - else if (!gro_is_void_p) + r = void_ramp_p ? NULL_TREE : DECL_RESULT (orig); + else /* check_return_expr will automatically return gro as an rvalue via treat_lvalue_as_rvalue_p. */ r = gro; - else if (CLASS_TYPE_P (fn_return_type)) - { - /* For class type return objects, we can attempt to construct, - even if the gro is void. ??? Citation ??? c++/100476 */ - r = build_special_member_call (NULL_TREE, - complete_ctor_identifier, NULL, - fn_return_type, LOOKUP_NORMAL, - tf_warning_or_error); - r = build_cplus_new (fn_return_type, r, tf_warning_or_error); - } - else - { - /* We can't initialize a non-class return value from void. */ - error_at (input_location, "cannot initialize a return object of type" - " %qT with an rvalue of type %<void%>", fn_return_type); - r = error_mark_node; - } finish_return_stmt (r); diff --git a/gcc/testsuite/g++.dg/coroutines/coro-bad-gro-01-void-gro-non-class-coro.C b/gcc/testsuite/g++.dg/coroutines/coro-bad-gro-01-void-gro-non-class-coro.C index 2671ce7ca289..a7e3f3d1ac7d 100644 --- a/gcc/testsuite/g++.dg/coroutines/coro-bad-gro-01-void-gro-non-class-coro.C +++ b/gcc/testsuite/g++.dg/coroutines/coro-bad-gro-01-void-gro-non-class-coro.C @@ -27,11 +27,11 @@ struct std::coroutine_traits<R, HandleRef, T...> { }; int -my_coro (std::coroutine_handle<>& h) +my_coro (std::coroutine_handle<>& h) // { dg-error {no viable conversion from 'void' provided by 'get_return_object' to return type 'int'} } { PRINT ("coro1: about to return"); co_return; -} // { dg-error {cannot initialize a return object of type 'int' with an rvalue of type 'void'} } +} int main () { diff --git a/gcc/testsuite/g++.dg/coroutines/pr102489.C b/gcc/testsuite/g++.dg/coroutines/pr102489.C index 0ef06daa2112..15b85f4375b9 100644 --- a/gcc/testsuite/g++.dg/coroutines/pr102489.C +++ b/gcc/testsuite/g++.dg/coroutines/pr102489.C @@ -9,7 +9,7 @@ struct footask { std::suspend_never initial_suspend(); std::suspend_never final_suspend() noexcept; void unhandled_exception(); - void get_return_object(); + footask get_return_object(); }; std::suspend_always foo; footask taskfun() { co_await foo; } diff --git a/gcc/testsuite/g++.dg/coroutines/pr103868.C b/gcc/testsuite/g++.dg/coroutines/pr103868.C index fd05769db3db..0ce40b699ced 100644 --- a/gcc/testsuite/g++.dg/coroutines/pr103868.C +++ b/gcc/testsuite/g++.dg/coroutines/pr103868.C @@ -116,7 +116,7 @@ struct awaitable_frame_base { template <typename T> auto await_transform(T a) { return a; } }; template <> struct awaitable_frame<void> : awaitable_frame_base { - void get_return_object(); + awaitable<void> get_return_object(); }; } // namespace detail } // namespace asio diff --git a/gcc/testsuite/g++.dg/coroutines/pr94879-folly-1.C b/gcc/testsuite/g++.dg/coroutines/pr94879-folly-1.C index 6e091526fe77..2d886fd387d3 100644 --- a/gcc/testsuite/g++.dg/coroutines/pr94879-folly-1.C +++ b/gcc/testsuite/g++.dg/coroutines/pr94879-folly-1.C @@ -39,9 +39,10 @@ public: std::g initial_suspend(); l final_suspend() noexcept; }; +class n; class m : public j { public: - void get_return_object(); + n get_return_object(); void unhandled_exception(); }; class n { diff --git a/gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C b/gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C index 98c5a7e3eeef..f12897e86909 100644 --- a/gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C +++ b/gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C @@ -16,25 +16,7 @@ struct b { void await_resume(); }; } // namespace std - -template <typename d> auto ab(int ac, d ad) -> decltype(ad.e(ac)); -int f; -class h { - class j { - public: - bool await_ready() noexcept; - void await_suspend(std::coroutine_handle<>) noexcept; - void await_resume() noexcept; - }; - -public: - void get_return_object(); - std::b initial_suspend(); - j final_suspend() noexcept; - void unhandled_exception(); - template <typename g> - auto await_transform (g c) { return ab(f, c); } -}; +class h; template <typename, typename = int> class k { public: using promise_type = h; @@ -64,6 +46,25 @@ my_coro (k<aj, ak> am, ai) { ; } +template <typename d> auto ab(int ac, d ad) -> decltype(ad.e(ac)); +int f; +class h { + class j { + public: + bool await_ready() noexcept; + void await_suspend(std::coroutine_handle<>) noexcept; + void await_resume() noexcept; + }; + +public: + k<int> get_return_object(); + std::b initial_suspend(); + j final_suspend() noexcept; + void unhandled_exception(); + template <typename g> + auto await_transform (g c) { return ab(f, c); } +}; + void foo () { k<int> a; my_coro (a, [] {}); diff --git a/gcc/testsuite/g++.dg/coroutines/pr96749-2.C b/gcc/testsuite/g++.dg/coroutines/pr96749-2.C index 43052b57dd9c..3d7645272915 100644 --- a/gcc/testsuite/g++.dg/coroutines/pr96749-2.C +++ b/gcc/testsuite/g++.dg/coroutines/pr96749-2.C @@ -27,7 +27,7 @@ struct Task { struct promise_type { auto initial_suspend() { return std::suspend_always{}; } auto final_suspend() noexcept { return std::suspend_always{}; } - void get_return_object() {} + Task get_return_object() ; void unhandled_exception() {} }; };