Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 40 additions & 33 deletions include/stdexec/__detail/__spawn.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,22 +137,21 @@ namespace STDEXEC
//! @brief A sender consumer that eagerly starts a sender and ties its
//! lifetime to an *async scope*.
//!
//! @c spawn is the standard "fire-and-forget into a scope" consumer.
//! You give it a sender, a @c scope_token (a handle to an async scope),
//! and optionally an environment, and @c spawn:
//! @c spawn is the standard "fire-and-forget into a scope" consumer. You give
//! it a sender, a @c scope_token (a handle to an async scope), and optionally
//! an environment, and @c spawn:
//!
//! 1. allocates an operation state on the heap (using an allocator
//! queried from the environment or the sender's own environment),
//! 1. allocates an operation state on the heap (using an allocator queried
//! from the environment or the sender's own environment),
//! 2. tries to associate the resulting operation with the scope via
//! `token.try_associate()`,
//! 3. if the association succeeds, eagerly @c start s the operation,
//! and on completion deallocates the state and releases the scope
//! association.
//! 3. if the association succeeds, eagerly @c start s the operation, and on
//! completion deallocates the state and releases the scope association.
//!
//! If association fails (typically because the scope has already begun
//! shutting down), @c spawn destroys the state and returns without
//! starting the operation. The result of the sender, if any, is
//! discarded — @c spawn returns @c void.
//! shutting down), @c spawn destroys the state and returns without starting
//! the operation. The result of the sender, if any, is discarded — @c spawn
//! returns @c void.
//!
//! See [exec.spawn] in the C++26 working draft for the normative
//! specification.
Expand All @@ -172,27 +171,27 @@ namespace STDEXEC
//!
//! The argument sender must not be able to complete with @c set_error
//! — @c spawn cannot deliver an error to a non-existent caller. The
//! @c requires clause enforces this with a
//! `__never_sends<set_error_t, ...>` check; the diagnostic
//! overload says "spawn expects a sender that cannot fail" if the check
//! fires.
//! @c requires clause enforces this with a `__never_sends<set_error_t, ...>`
//! check. The diagnostic overload first checks that the sender after scope
//! wrapping and environment injection is valid in the selected environment
//! and delegates to the sender diagnostics if that check fails; otherwise, it
//! reports that @c spawn expects a sender that cannot fail.
//!
//! Successful and stopped completions are both accepted; their results
//! are discarded.
//! Successful and stopped completions are both accepted; their results are
//! discarded.
//!
//! **Scope semantics.**
//!
//! The scope is the *owner of lifetime* for the spawned operation.
//! Calling code is expected to eventually @c join() the scope (or
//! otherwise wait for all spawned work to drain) before destroying it
//! — typically once at program shutdown, or once per logical unit of
//! related background work.
//! The scope is the *owner of lifetime* for the spawned operation. Calling
//! code is expected to eventually @c join() the scope (or otherwise wait for
//! all spawned work to drain) before destroying it — typically once at
//! program shutdown, or once per logical unit of related background work.
//!
//! @c spawn is the canonical fire-and-forget consumer for any work
//! that has a clear "owning context" (a request, a session, a worker).
//! For top-level work with no owning scope, use @c exec::start_detached
//! (an stdexec extension). For fire-and-forget work whose completion
//! you want to *observe* (without blocking), use
//! @c spawn is the canonical fire-and-forget consumer for any work that has a
//! clear "owning context" (a request, a session, a worker). For top-level
//! work with no owning scope, use @c exec::start_detached (an stdexec
//! extension). For fire-and-forget work whose completion you want to
//! *observe* (without blocking), use
//! @c stdexec::spawn_future.
//!
//! @see stdexec::spawn_future — like @c spawn, but returns a sender that
Expand Down Expand Up @@ -236,19 +235,27 @@ namespace STDEXEC
// with the primary three-argument overload above (they differ only by a
// constraint), which the Sphinx C++ domain cannot disambiguate.
# if !defined(STDEXEC_DOXYGEN_INVOKED)
//! @brief Diagnostic overload — selected when the sender's completion
//! signatures include @c set_error_t. Emits a @c static_assert
//! explaining that @c spawn expects a sender that cannot fail.
//! @brief Diagnostic overload selected when the no-error requirement fails.
//! If the sender after scope wrapping and environment injection is
//! not valid in the selected environment, delegates to the sender
//! diagnostics; otherwise, emits a @c static_assert explaining that
//! @c spawn expects a sender that cannot fail.
//!
//! Not normally called; the @c requires clause on the primary overload
//! steers compilation here on a constraint failure.
template <sender _Sender, scope_token _Token, class _Env>
void operator()(_Sender&&, _Token, _Env&&) const
{
using _spawn_sndr_t = spawn_t::_spawn_sndr_t<_Sender, _Token, _Env>;
static_assert(sender_in<_spawn_sndr_t, _Env>
&& __never_sends<STDEXEC::set_error_t, _spawn_sndr_t, _Env>,
"spawn expects a sender that cannot fail");
if constexpr (!sender_in<_spawn_sndr_t, _Env>)
{
__diagnose_sender_concept_failure<_spawn_sndr_t, _Env>();
}
else
{
static_assert(__never_sends<STDEXEC::set_error_t, _spawn_sndr_t, _Env>,
"spawn expects a sender that cannot fail");
}
}
# endif // !defined(STDEXEC_DOXYGEN_INVOKED)

Expand Down
5 changes: 5 additions & 0 deletions include/stdexec/__detail/__spawn_future.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,11 @@ namespace STDEXEC
using __alloc_t = decltype(__spawn_common::__choose_alloc(__env, STDEXEC::get_env(__sndr)));
using __senv_t = decltype(__spawn_common::__choose_senv(__env, STDEXEC::get_env(__sndr)));

if constexpr (!sender_in<_Sender, __senv_t>)
{
__diagnose_sender_concept_failure<_Sender, __senv_t>();
}

using __spawn_future_state_t =
__spawn_future::__spawn_future_state<__alloc_t,
std::remove_cvref_t<_Token>,
Expand Down
Loading