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 <[email protected]>
---
gcc/cp/coroutines.cc | 48 +++++++++----------
.../coro-bad-gro-01-void-gro-non-class-coro.C | 2 +-
gcc/testsuite/g++.dg/coroutines/pr102489.C | 2 +-
gcc/testsuite/g++.dg/coroutines/pr103868.C | 2 +-
.../g++.dg/coroutines/pr94879-folly-1.C | 3 +-
.../g++.dg/coroutines/pr94883-folly-2.C | 39 +++++++--------
gcc/testsuite/g++.dg/coroutines/pr96749-2.C | 2 +-
7 files changed, 48 insertions(+), 50 deletions(-)
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 2faf198c206..d152ad20dca 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -4640,6 +4640,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
@@ -4720,6 +4721,19 @@ cp_coroutine_transform::build_ramp_function ()
return;
}
+ /* Check for a bad get return object type. */
+ tree gro_return_type = FUNC_OR_METHOD_TYPE_P (TREE_TYPE (get_ro_meth))
+ ? TREE_TYPE (TREE_TYPE (get_ro_meth))
+ : TREE_TYPE (get_ro_meth);
+ if (VOID_TYPE_P (gro_return_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);
+ valid_coroutine = false;
+ input_location = save_input_loc;
+ return;
+ }
+
/* So now construct the Ramp: */
tree stmt = begin_function_body ();
/* Now build the ramp function pieces. */
@@ -4816,7 +4830,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);
@@ -5028,7 +5042,6 @@ cp_coroutine_transform::build_ramp_function ()
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;
@@ -5037,8 +5050,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
@@ -5122,31 +5138,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);
- r = error_mark_node;
- valid_coroutine = false;
- input_location = save_input_loc;
- return;
- }
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 85aadad93b2..a7e3f3d1ac7 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 0ef06daa211..15b85f4375b 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 fd05769db3d..0ce40b699ce 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 6e091526fe7..2d886fd387d 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 98c5a7e3eee..f12897e8690 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 43052b57dd9..3d764527291 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() {}
};
};
--
2.39.2 (Apple Git-143)