@@ -30,7 +30,6 @@ import stdexec;
3030# include " __optional.hpp"
3131# include " __schedulers.hpp"
3232# include " __task_scheduler.hpp"
33- # include " __with_awaitable_senders.hpp"
3433
3534# if !STDEXEC_USE_MODULES()
3635# include < cstddef>
@@ -218,6 +217,13 @@ namespace STDEXEC
218217 template <class _TaskEnv , class _ParentEnv >
219218 using __environment_type = __minvoke_or_q<__environment_t , env<>, _TaskEnv, _ParentEnv>;
220219
220+ template <class _Promise >
221+ concept __stoppable_promise = requires (_Promise& __promise) {
222+ {
223+ __promise.unhandled_stopped ()
224+ } noexcept -> __std::convertible_to<__std::coroutine_handle<>>;
225+ };
226+
221227 template <class _ParentEnv , class _Alloc >
222228 concept __has_allocator_compatible_with = requires (_ParentEnv const & __parent_env) {
223229 _Alloc (STDEXEC::get_allocator (__parent_env));
@@ -457,6 +463,9 @@ namespace STDEXEC
457463 [[nodiscard]]
458464 constexpr auto as_awaitable (_ParentPromise& __parent) && noexcept -> __awaiter<_ParentPromise>
459465 {
466+ static_assert (__task::__stoppable_promise<_ParentPromise>,
467+ " Cannot await task from this coroutine: the promise type of the parent "
468+ " coroutine does not implement unhandled_stopped()." );
460469 static_assert (__task::__has_compatible_allocator<env_of_t <_ParentPromise&>, allocator_type>,
461470 " Cannot await task from this coroutine: the allocator in the parent "
462471 " coroutine's environment is incompatible with the task's allocator." );
@@ -572,7 +581,7 @@ namespace STDEXEC
572581 constexpr explicit __awaiter (task&& __task, _ParentPromise& __parent) noexcept
573582 : __awaiter::__own_env_box{__task::__mk_own_env<_TaskEnv>(STDEXEC::get_env (__parent))}
574583 , __awaiter_base (static_cast <task&&>(__task), STDEXEC::get_env (__parent), this ->__own_env_ )
575- , __parent_ ( __parent)
584+ , __continuation_ (__std::coroutine_handle<_ParentPromise>:: from_promise ( __parent) )
576585 {}
577586
578587 static constexpr auto await_ready () noexcept -> bool
@@ -584,9 +593,9 @@ namespace STDEXEC
584593 noexcept (__nothrow_callback_registration<env_of_t <_ParentPromise>>)
585594 -> __std::coroutine_handle<>
586595 {
596+ STDEXEC_ASSERT (__continuation == this ->__continuation_ );
587597 auto & __task_promise = this ->__handle ().promise ();
588598 __task_promise.__state_ = this ;
589- __task_promise.set_continuation (__continuation);
590599 // If the following throws, the coroutine is immediately resumed and the exception
591600 // is rethrown at the suspension point.
592601 this ->__register_callback (STDEXEC::get_env (__continuation.promise ()),
@@ -615,20 +624,20 @@ namespace STDEXEC
615624 return STDEXEC::__coroutine_unhandled_stopped (this ->__handle ());
616625 }
617626 this ->__reset_callback ();
618- return this ->__handle (). promise (). continuation (). handle () ;
627+ return this ->__continuation_ ;
619628 }
620629
621630 [[nodiscard]]
622631 auto __canceled () noexcept -> __std::coroutine_handle<> final
623632 {
624633 this ->__reset_callback ();
625- auto const __continuation = this ->__handle () .promise (). continuation ();
626- auto const __coro = std::exchange (this ->__task_ .__coro_ , {});
634+ auto & __parent = this ->__continuation_ .promise ();
635+ auto const __coro = std::exchange (this ->__task_ .__coro_ , {});
627636 STDEXEC::__coroutine_destroy_nothrow (__coro);
628- return __continuation .unhandled_stopped ();
637+ return __parent .unhandled_stopped ();
629638 }
630639
631- _ParentPromise& __parent_ ;
640+ __std::coroutine_handle< _ParentPromise> __continuation_ ;
632641 };
633642
634643 // The operation state produced by connecting a task to a receiver. Like __awaiter,
@@ -774,7 +783,6 @@ namespace STDEXEC
774783 template <class _Ty , class _TaskEnv >
775784 struct STDEXEC_ATTRIBUTE (empty_bases) task<_Ty, _TaskEnv>::__promise
776785 : __task::__promise_base<__promise, _Ty>
777- , with_awaitable_senders<__promise>
778786 {
779787 private:
780788 struct __env ;
0 commit comments