diff options
author | Iain Sandoe <iain@sandoe.co.uk> | 2024-08-17 15:47:58 +0100 |
---|---|---|
committer | Iain Sandoe <iain@sandoe.co.uk> | 2024-08-24 19:53:51 +0100 |
commit | a0b431033c307982123abbff752045cfe7eda47f (patch) | |
tree | 3b7dd5ee47d823152a0a6849aabf2cb395dc59db /gcc | |
parent | efc99ab2d5fdb7f2a942199b0e5b16e1e2bb8c27 (diff) | |
download | gcc-a0b431033c307982123abbff752045cfe7eda47f.zip gcc-a0b431033c307982123abbff752045cfe7eda47f.tar.gz gcc-a0b431033c307982123abbff752045cfe7eda47f.tar.bz2 |
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 <iain@sandoe.co.uk>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/coroutines.cc | 47 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/coroutines/coro-bad-gro-01-void-gro-non-class-coro.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/coroutines/pr102489.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/coroutines/pr103868.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/coroutines/pr94879-folly-1.C | 3 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C | 39 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/coroutines/pr96749-2.C | 2 |
7 files changed, 48 insertions, 49 deletions
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index cbe99ac..e46b8b6 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4604,6 +4604,7 @@ cp_coroutine_transform::build_ramp_function () tree promise_type = get_coroutine_promise_type (orig_fn_decl); tree fn_return_type = TREE_TYPE (TREE_TYPE (orig_fn_decl)); + bool void_ramp_p = VOID_TYPE_P (fn_return_type); /* [dcl.fct.def.coroutine] / 10 (part1) The unqualified-id get_return_object_on_allocation_failure is looked up @@ -4766,7 +4767,7 @@ cp_coroutine_transform::build_ramp_function () tree cond = build1 (CONVERT_EXPR, frame_ptr_type, 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); @@ -4966,17 +4967,27 @@ cp_coroutine_transform::build_ramp_function () 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_outer_bind); /* Suppress warnings about the missing return value. */ suppress_warning (orig_fn_decl, 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; @@ -4985,8 +4996,11 @@ cp_coroutine_transform::build_ramp_function () 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 @@ -5067,28 +5081,11 @@ cp_coroutine_transform::build_ramp_function () 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_fn_decl); - else if (!gro_is_void_p) + r = void_ramp_p ? NULL_TREE : DECL_RESULT (orig_fn_decl); + 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 (fn_start, "cannot initialize a return object of type" - " %qT with an rvalue of type %<void%>", fn_return_type); - return false; - } 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 85aadad..a7e3f3d 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,7 +27,7 @@ struct std::coroutine_traits<R, HandleRef, T...> { }; int -my_coro (std::coroutine_handle<>& h) // { dg-error {cannot initialize a return object of type 'int' with an rvalue of type 'void'} } +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; diff --git a/gcc/testsuite/g++.dg/coroutines/pr102489.C b/gcc/testsuite/g++.dg/coroutines/pr102489.C index 0ef06da..15b85f4 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 fd05769..0ce40b6 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 6e09152..2d886fd 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 98c5a7e..f12897e 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 43052b5..3d76452 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() {} }; }; |