/* 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);
+ returned reference or prvalue result object ...
+ When we use a local to hold this, it is decltype(auto). */
+ tree gro_type
+ = finish_decltype_type (get_ro, /*id_expression_or_member_access_p*/false,
+ tf_warning_or_error);
if (VOID_TYPE_P (gro_type) && !void_ramp_p)
{
error_at (fn_start, "no viable conversion from %<void%> provided by"
= coro_build_and_push_artificial_var (loc, "_Coro_gro", gro_type,
orig_fn_decl, NULL_TREE);
- r = cp_build_init_expr (coro_gro, get_ro);
+ r = cp_build_init_expr (coro_gro, STRIP_REFERENCE_REF (get_ro));
finish_expr_stmt (r);
tree coro_gro_cleanup
= cxx_maybe_build_cleanup (coro_gro, tf_warning_or_error);
/* The ramp is done, we just need the return statement, which we build from
the return object we constructed before we called the function body. */
- finish_return_stmt (void_ramp_p ? NULL_TREE : coro_gro);
+ r = void_ramp_p ? NULL_TREE : convert_from_reference (coro_gro);
+ finish_return_stmt (r);
if (flag_exceptions)
{
+// { dg-do run }
+
+// With the changes to deal with CWG2563 (and PR119916) we now use the
+// referenced promise in the return expression. It is quite reasonable
+// for a body implementation to complete before control is returned to
+// the ramp - and in that case we would be creating the ramp return object
+// from an already-deleted promise object.
+// This is recognised to be a poor situation and resolution via a core
+// issue is planned.
+
+// In this test we explicitly trigger the circumstance mentioned above.
+// { dg-xfail-run-if "" { *-*-* } }
+
#include <coroutine>
#ifdef OUTPUT
struct Promise;
-bool promise_live = false;
+int promise_life = 0;
struct Handle : std::coroutine_handle<Promise> {
+
Handle(Promise &p) : std::coroutine_handle<Promise>(Handle::from_promise(p)) {
- if (!promise_live)
- __builtin_abort ();
#ifdef OUTPUT
- std::cout << "Handle(Promise &)\n";
+ std::cout << "Handle(Promise &) " << promise_life << std::endl;
#endif
- }
- Handle(Promise &&p) : std::coroutine_handle<Promise>(Handle::from_promise(p)) {
- if (!promise_live)
+ if (promise_life <= 0)
__builtin_abort ();
+ }
+
+ Handle(Promise &&p) : std::coroutine_handle<Promise>(Handle::from_promise(p)) {
#ifdef OUTPUT
- std::cout << "Handle(Promise &&)\n";
+ std::cout << "Handle(Promise &&) " << promise_life << std::endl;
#endif
- }
+ if (promise_life <= 0)
+ __builtin_abort ();
+ }
using promise_type = Promise;
};
struct Promise {
Promise() {
#ifdef OUTPUT
- std::cout << "Promise()\n";
+ std::cout << "Promise()" << std::endl;
+#endif
+ promise_life++;
+ }
+
+ Promise(Promise& p){
+#ifdef OUTPUT
+ std::cout << "Promise(Promise&)" << std::endl;
#endif
- promise_live = true;
+ promise_life++;
}
+
~Promise() {
#ifdef OUTPUT
- std::cout << "~Promise()\n";
+ std::cout << "~Promise()" << std::endl;
#endif
- if (!promise_live)
+ if (promise_life <= 0)
__builtin_abort ();
- promise_live = false;
+ promise_life--;
}
+
Promise& get_return_object() noexcept {
#ifdef OUTPUT
- std::cout << "get_return_object()\n";
+ std::cout << "get_return_object() " << promise_life << std::endl;
#endif
- if (!promise_live)
+ if (promise_life <= 0)
__builtin_abort ();
return *this;
}
- std::suspend_never initial_suspend() const noexcept { return {}; }
- std::suspend_never final_suspend() const noexcept { return {}; }
+
+ std::suspend_never initial_suspend() const noexcept {
+#ifdef OUTPUT
+ std::cout << "initial_suspend()" << std::endl;
+#endif
+ return {};
+ }
+ std::suspend_never final_suspend() const noexcept {
+#ifdef OUTPUT
+ std::cout << "final_suspend()" << std::endl;
+#endif
+ return {};
+ }
void return_void() const noexcept {
- if (!promise_live)
+ if (!promise_life)
__builtin_abort ();
#ifdef OUTPUT
- std::cout << "return_void()\n";
+ std::cout << "return_void()" << std::endl;
#endif
}
void unhandled_exception() const noexcept {}
};
Handle Coro() {
+
+#ifdef OUTPUT
+ std::cout << "Coro()" << std::endl;
+#endif
co_return;
}
int main() {
- Coro();
- if (promise_live)
+ Coro();
+#ifdef OUTPUT
+ std::cout << "done Coro()" << std::endl;
+#endif
+ if (promise_life)
__builtin_abort ();
return 0;
}