thanks
Iain
--- 8< ---
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>
---
gcc/cp/coroutines.cc | 47 +++++++++----------
.../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(+), 49 deletions(-)
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 2f128db42e1..3c0757403ce 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -4605,6 +4605,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
@@ -4771,7 +4772,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);
@@ -4971,17 +4972,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;
@@ -4990,8 +5001,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
@@ -5072,28 +5086,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;
- }
/* Without a relevant location, bad conversions in finish_return_stmt result
in unusable diagnostics, since there is not even a mention of the
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() {}
};
};