%!TEX root = std.tex
\rSec0[exec]{Execution control library}

\rSec1[exec.general]{General}

\pnum
This Clause describes components
supporting execution of function objects\iref{function.objects}.

\pnum
The following subclauses describe
the requirements, concepts, and components
for execution control primitives as summarized in \tref{exec.summary}.

\begin{libsumtab}{Execution control library summary}{exec.summary}
\ref{exec.sched}     & Schedulers   & \tcode{<execution>} \\
\ref{exec.recv}      & Receivers    & \\
\ref{exec.opstate}   & Operation states & \\
\ref{exec.snd}       & Senders & \\
\end{libsumtab}

\pnum
\tref{exec.pos} shows
the types of customization point objects\iref{customization.point.object}
used in the execution control library.

\begin{floattable}{Types of customization point objects in the execution control library}{exec.pos}{lx{0.23\hsize}x{0.45\hsize}}
\topline
\lhdr{Customization point} & \chdr{Purpose} & \rhdr{Examples} \\
\lhdr{object type} & &  \\
\capsep
core &
  provide core execution functionality, and connection between core components &
  e.g., \tcode{connect}, \tcode{start} \\
completion functions &
  called by senders to announce the completion of the work (success, error, or cancellation) &
  \tcode{set_value}, \tcode{set_error}, \tcode{set_stopped} \\
senders &
  allow the specialization of the provided sender algorithms &
  \begin{itemize}
  \item sender factories (e.g., \tcode{schedule}, \tcode{just}, \tcode{read_env})
  \item sender adaptors (e.g., \tcode{continues_on}, \tcode{then}, \tcode{let_value})
  \item sender consumers (e.g., \tcode{sync_wait})
  \end{itemize}
    \\
queries &
  allow querying different properties of objects &
  \begin{itemize}
  \item general queries (e.g., \tcode{get_allocator}, \tcode{get_stop_token})
  \item environment queries (e.g., \tcode{get_scheduler}, \tcode{get_delegation_scheduler})
  \item scheduler queries (e.g., \tcode{get_forward_progress_guarantee})
  \item sender attribute queries (e.g., \tcode{get_completion_scheduler})
  \end{itemize}
    \\
\end{floattable}

\pnum
This clause makes use of the following exposition-only entities.

\pnum
For a subexpression \tcode{expr},
let \tcode{\exposid{MANDATE-NOTHROW}(expr)} be
expression-equivalent to \tcode{expr}.

\mandates
\tcode{noexcept(expr)} is \tcode{true}.

\pnum
\begin{codeblock}
namespace std {
  template<class T>
    concept @\defexposconcept{movable-value}@ =                                     // \expos
      @\libconcept{move_constructible}@<decay_t<T>> &&
      @\libconcept{constructible_from}@<decay_t<T>, T> &&
      (!is_array_v<remove_reference_t<T>>);
}
\end{codeblock}

\pnum
For function types \tcode{F1} and \tcode{F2} denoting
\tcode{R1(Args1...)} and \tcode{R2(Args2...)}, respectively,
\tcode{\exposid{MATCHING-SIG}(F1, F2)} is \tcode{true} if and only if
\tcode{\libconcept{same_as}<R1(Args1\&\&...), R2(Args2\&\&...)>}
is \tcode{true}.

\pnum
For a subexpression \tcode{err},
let \tcode{Err} be \tcode{decltype((err))} and
let \tcode{\exposid{AS-EXCEPT-PTR}(err)} be:
\begin{itemize}
\item
\tcode{err} if \tcode{decay_t<Err>} denotes the type \tcode{exception_ptr}.

\expects
\tcode{!err} is \tcode{false}.
\item
Otherwise,
\tcode{make_exception_ptr(system_error(err))}
if \tcode{decay_t<Err>} denotes the type \tcode{error_code}.
\item
Otherwise, \tcode{make_exception_ptr(err)}.
\end{itemize}

\pnum
For a subexpression \tcode{expr},
let \tcode{\exposid{AS-CONST}(expr)} be expression-equivalent to
\begin{codeblock}
[](const auto& x) noexcept -> const auto& { return x; }(expr)
\end{codeblock}

\rSec1[exec.queryable]{Queries and queryables}

\rSec2[exec.queryable.general]{General}

\pnum
A \defnadj{queryable}{object} is
a read-only collection of key/value pair
where each key is a customization point object known as a \defn{query object}.
A \defn{query} is an invocation of a query object
with a queryable object as its first argument and
a (possibly empty) set of additional arguments.
A query imposes syntactic and semantic requirements on its invocations.

\pnum
Let \tcode{q} be a query object,
let \tcode{args} be a (possibly empty) pack of subexpressions,
let \tcode{env} be a subexpression
that refers to a queryable object \tcode{o} of type \tcode{O}, and
let \tcode{cenv} be a subexpression referring to \tcode{o}
such that \tcode{decltype((cenv))} is \tcode{const O\&}.
The expression \tcode{q(env, args...)} is equal to\iref{concepts.equality}
the expression \tcode{q(cenv, args...)}.

\pnum
The type of a query expression cannot be \tcode{void}.

\pnum
The expression \tcode{q(env, args...)} is
equality-preserving\iref{concepts.equality} and
does not modify the query object or the arguments.

\pnum
If the expression \tcode{env.query(q, args...)} is well-formed,
then it is expression-equivalent to \tcode{q(env, args...)}.

\pnum
Unless otherwise specified,
the result of a query is valid as long as the queryable object is valid.

\rSec2[exec.queryable.concept]{\tcode{queryable} concept}

\begin{codeblock}
namespace std {
  template<class T>
    concept @\defexposconcept{queryable}@ = @\libconcept{destructible}@<T>;   // \expos
}
\end{codeblock}

\pnum
The exposition-only \exposconcept{queryable} concept specifies
the constraints on the types of queryable objects.

\pnum
Let \tcode{env} be an object of type \tcode{Env}.
The type \tcode{Env} models \exposconcept{queryable}
if for each callable object \tcode{q} and a pack of subexpressions \tcode{args},
if \tcode{requires \{ q(env, args...) \}} is \tcode{true} then
\tcode{q(env, args...)} meets any semantic requirements imposed by \tcode{q}.

\rSec1[exec.async.ops]{Asynchronous operations}

\pnum
An \defnadj{execution}{resource} is a program entity that manages
a (possibly dynamic) set of execution agents\iref{thread.req.lockable.general},
which it uses to execute parallel work on behalf of callers.
\begin{example}
The currently active thread,
a system-provided thread pool, and
uses of an API associated with an external hardware accelerator
are all examples of execution resources.
\end{example}
Execution resources execute asynchronous operations.
An execution resource is either valid or invalid.

\pnum
An \defnadj{asynchronous}{operation} is
a distinct unit of program execution that
\begin{itemize}
\item
is explicitly created;
\item
can be explicitly started once at most;
\item
once started, eventually completes exactly once
with a (possibly empty) set of result datums and
in exactly one of three \defnx{dispositions}{disposition}:
success, failure, or cancellation;
\begin{itemize}
\item
A successful completion, also known as a \defnadj{value}{completion},
can have an arbitrary number of result datums.
\item
A failure completion, also known as an \defnadj{error}{completion},
has a single result datum.
\item
A cancellation completion, also known as a \defnadj{stopped}{completion},
has no result datum.
\end{itemize}
An asynchronous operation's \defnadj{async}{result}
is its disposition and its (possibly empty) set of result datums.
\item
can complete on a different execution resource
than the execution resource on which it started; and
\item
can create and start other asynchronous operations
called \defnadj{child}{operations}.
A child operation is an asynchronous operation
that is created by the parent operation and,
if started, completes before the parent operation completes.
A \defnadj{parent}{operation} is the asynchronous operation
that created a particular child operation.
\end{itemize}
\begin{note}
An asynchronous operation can execute synchronously;
that is, it can complete during the execution of its start operation
on the thread of execution that started it.
\end{note}

\pnum
An asynchronous operation has associated state
known as its \defnadj{operation}{state}.

\pnum
An asynchronous operation has an associated environment.
An \defn{environment} is a queryable object\iref{exec.queryable}
representing the execution-time properties of the operation's caller.
The caller of an asynchronous operation is
its parent operation or the function that created it.

\pnum
An asynchronous operation has an associated receiver.
A \defn{receiver} is an aggregation of three handlers
for the three asynchronous completion dispositions:
\begin{itemize}
\item a value completion handler for a value completion,
\item an error completion handler for an error completion, and
\item a stopped completion handler for a stopped completion.
\end{itemize}
A receiver has an associated environment.
An asynchronous operation's operation state owns the operation's receiver.
The environment of an asynchronous operation
is equal to its receiver's environment.

\pnum
For each completion disposition, there is a \defnadj{completion}{function}.
A completion function is
a customization point object\iref{customization.point.object}
that accepts an asynchronous operation's receiver as the first argument and
the result datums of the asynchronous operation as additional arguments.
The value completion function invokes
the receiver's value completion handler with the value result datums;
likewise for the error completion function and the stopped completion function.
A completion function has
an associated type known as its \defnadj{completion}{tag}
that is the unqualified type of the completion function.
A valid invocation of a completion function is called
a \defnadj{completion}{operation}.

\pnum
The \defn{lifetime of an asynchronous operation},
also known as the operation's \defn{async lifetime},
begins when its start operation begins executing and
ends when its completion operation begins executing.
If the lifetime of an asynchronous operation's associated operation state
ends before the lifetime of the asynchronous operation,
the behavior is undefined.
After an asynchronous operation executes a completion operation,
its associated operation state is invalid.
Accessing any part of an invalid operation state is undefined behavior.

\pnum
An asynchronous operation shall not execute a completion operation
before its start operation has begun executing.
After its start operation has begun executing,
exactly one completion operation shall execute.
The lifetime of an asynchronous operation's operation state can end
during the execution of the completion operation.

\pnum
A \defn{sender} is a factory for one or more asynchronous operations.
\defnx{Connecting}{connect} a sender and a receiver creates
an asynchronous operation.
The asynchronous operation's associated receiver is equal to
the receiver used to create it, and
its associated environment is equal to
the environment associated with the receiver used to create it.
The lifetime of an asynchronous operation's associated operation state
does not depend on the lifetimes of either the sender or the receiver
from which it was created.
A sender is started when it is connected to a receiver and
the resulting asynchronous operation is started.
A sender's async result is the async result of the asynchronous operation
created by connecting it to a receiver.
A sender sends its results by way of the asynchronous operation(s) it produces,
and a receiver receives those results.
A sender is either valid or invalid;
it becomes invalid when its parent sender (see below) becomes invalid.

\pnum
A \defn{scheduler} is an abstraction of an execution resource
with a uniform, generic interface for scheduling work onto that resource.
It is a factory for senders
whose asynchronous operations execute value completion operations
on an execution agent belonging to
the scheduler's associated execution resource.
A \defn{schedule-expression} obtains such a sender from a scheduler.
A \defn{schedule sender} is the result of a schedule expression.
On success, an asynchronous operation produced by a schedule sender executes
a value completion operation with an empty set of result datums.
Multiple schedulers can refer to the same execution resource.
A scheduler can be valid or invalid.
A scheduler becomes invalid when the execution resource to which it refers
becomes invalid,
as do any schedule senders obtained from the scheduler, and
any operation states obtained from those senders.

\pnum
An asynchronous operation has one or more associated completion schedulers
for each of its possible dispositions.
A \defn{completion scheduler} is a scheduler
whose associated execution resource is used to execute
a completion operation for an asynchronous operation.
A value completion scheduler is a scheduler
on which an asynchronous operation's value completion operation can execute.
Likewise for error completion schedulers and stopped completion schedulers.

\pnum
A sender has an associated queryable object\iref{exec.queryable}
known as its \defnx{attributes}{attribute}
that describes various characteristics of the sender and
of the asynchronous operation(s) it produces.
For each disposition,
there is a query object for reading the associated completion scheduler
from a sender's attributes;
i.e., a value completion scheduler query object
for reading a sender's value completion scheduler, etc.
If a completion scheduler query is well-formed,
the returned completion scheduler is unique
for that disposition for any asynchronous operation the sender creates.
A schedule sender is required to have a value completion scheduler attribute
whose value is equal to the scheduler that produced the schedule sender.

\pnum
A \defn{completion signature} is a function type
that describes a completion operation.
An asynchronous operation has a finite set of possible completion signatures
corresponding to the completion operations
that the asynchronous operation potentially evaluates\iref{basic.def.odr}.
For a completion function \tcode{set},
receiver \tcode{rcvr}, and
pack of arguments \tcode{args},
let \tcode{c} be the completion operation \tcode{set(rcvr, args...)}, and
let \tcode{F} be
the function type \tcode{decltype(auto(set))(decltype((args))...)}.
A completion signature \tcode{Sig} is associated with \tcode{c}
if and only if
\tcode{\exposid{MATCHING-SIG}(Sig, F)} is \tcode{true}\iref{exec.general}.
Together, a sender type and an environment type \tcode{Env} determine
the set of completion signatures of an asynchronous operation
that results from connecting the sender with a receiver
that has an environment of type \tcode{Env}.
The type of the receiver does not affect
an asynchronous operation's completion signatures,
only the type of the receiver's environment.
A \defnadj{non-dependent}{sender} is a sender type
whose completion signatures are knowable
independent of an execution environment.

\pnum
A sender algorithm is a function that takes and/or returns a sender.
There are three categories of sender algorithms:
\begin{itemize}
\item
A \defn{sender factory} is a function
that takes non-senders as arguments and that returns a sender.
\item
A \defn{sender adaptor} is a function
that constructs and returns a parent sender
from a set of one or more child senders and
a (possibly empty) set of additional arguments.
An asynchronous operation created by a parent sender is
a parent operation to the child operations created by the child senders.
\item
A \defn{sender consumer} is a function
that takes one or more senders and
a (possibly empty) set of additional arguments, and
whose return type is not the type of a sender.
\end{itemize}

\rSec1[execution.syn]{Header \tcode{<execution>} synopsis}

\indexheader{execution}%
\begin{codeblock}
namespace std {
  // \ref{execpol.type}, execution policy type trait
  template<class T> struct is_execution_policy;                 // freestanding
  template<class T> constexpr bool @\libglobal{is_execution_policy_v}@ =      // freestanding
      is_execution_policy<T>::value;
}

namespace std::execution {
  // \ref{execpol.seq}, sequenced execution policy
  class sequenced_policy;

  // \ref{execpol.par}, parallel execution policy
  class parallel_policy;

  // \ref{execpol.parunseq}, parallel and unsequenced execution policy
  class parallel_unsequenced_policy;

  // \ref{execpol.unseq}, unsequenced execution policy
  class unsequenced_policy;

  // \ref{execpol.objects}, execution policy objects
  inline constexpr sequenced_policy            seq{ @\unspec@ };
  inline constexpr parallel_policy             par{ @\unspec@ };
  inline constexpr parallel_unsequenced_policy par_unseq{ @\unspec@ };
  inline constexpr unsequenced_policy          unseq{ @\unspec@ };
}

namespace std {
  // \ref{exec.general}, helper concepts
  template<class T>
    concept @\exposconceptnc{movable-value}@ = @\seebelownc@;                          // \expos

  template<class From, class To>
    concept @\defexposconceptnc{decays-to}@ = @\libconcept{same_as}@<decay_t<From>, To>;             // \expos

  template<class T>
    concept @\defexposconceptnc{class-type}@ = @\exposconceptnc{decays-to}@<T, T> && is_class_v<T>;      // \expos

  // \ref{exec.queryable}, queryable objects
  template<class T>
    concept @\exposconceptnc{queryable}@ = @\seebelownc@;                              // \expos

  // \ref{exec.queries}, queries
  struct @\libglobal{forwarding_query_t}@ { @\unspec@ };
  struct @\libglobal{get_allocator_t}@ { @\unspec@ };
  struct @\libglobal{get_stop_token_t}@ { @\unspec@ };

  inline constexpr forwarding_query_t @\libglobal{forwarding_query}@{};
  inline constexpr get_allocator_t @\libglobal{get_allocator}@{};
  inline constexpr get_stop_token_t @\libglobal{get_stop_token}@{};

  template<class T>
    using stop_token_of_t = remove_cvref_t<decltype(get_stop_token(declval<T>()))>;

  template<class T>
    concept @\defexposconceptnc{forwarding-query}@ = forwarding_query(T{});           // \expos
}

namespace std::execution {
  // \ref{exec.queries}, queries
  struct @\libglobal{get_domain_t}@ { @\unspec@ };
  struct @\libglobal{get_scheduler_t}@ { @\unspec@ };
  struct @\libglobal{get_start_scheduler_t}@ { @\unspec@ };
  struct @\libglobal{get_delegation_scheduler_t}@ { @\unspec@ };
  struct @\libglobal{get_forward_progress_guarantee_t}@ { @\unspec@ };
  template<class CPO>
    struct @\libglobal{get_completion_scheduler_t}@ { @\unspec@ };
  template<class CPO = void>
    struct @\libglobal{get_completion_domain_t}@ { @\unspec@ };
  struct get_await_completion_adaptor_t { @\unspec@ };

  inline constexpr get_domain_t @\libglobal{get_domain}@{};
  inline constexpr get_scheduler_t @\libglobal{get_scheduler}@{};
  inline constexpr get_start_scheduler_t @\libglobal{get_start_scheduler}@{};
  inline constexpr get_delegation_scheduler_t @\libglobal{get_delegation_scheduler}@{};
  enum class forward_progress_guarantee;
  inline constexpr get_forward_progress_guarantee_t @\libglobal{get_forward_progress_guarantee}@{};
  template<class CPO>
    constexpr get_completion_scheduler_t<CPO> @\libglobal{get_completion_scheduler}@{};
  template<class CPO = void>
    constexpr get_completion_domain_t<CPO> @\libglobal{get_completion_domain}@{};
  inline constexpr get_await_completion_adaptor_t get_await_completion_adaptor{};

  struct @\libglobal{get_env_t}@ { @\unspec@ };
  inline constexpr get_env_t @\libglobal{get_env}@{};

  template<class T>
    using @\libglobal{env_of_t}@ = decltype(get_env(declval<T>()));

  // \ref{exec.domain.indeterminate}, execution domains
  template<class... Domains>
    struct indeterminate_domain;

  // \ref{exec.domain.default}, execution domains
  struct default_domain;

  // \ref{exec.sched}, schedulers
  struct @\libglobal{scheduler_tag}@ {};

  template<class Sch>
    concept @\libconcept{scheduler}@ = @\seebelow@;

  // \ref{exec.recv}, receivers
  struct @\libglobal{receiver_tag}@ {};

  template<class Rcvr>
    concept @\libconcept{receiver}@ = @\seebelow@;

  template<class Rcvr, class Completions>
    concept @\exposconceptnc{receiver-of}@ = @\seebelownc@;                            // \expos

  template<class Rcvr, class ChildOp>
    concept @\libconcept{inlinable_receiver}@ = @\seebelow@;

  struct @\libglobal{set_value_t}@ { @\unspec@ };
  struct @\libglobal{set_error_t}@ { @\unspec@ };
  struct @\libglobal{set_stopped_t}@ { @\unspec@ };

  inline constexpr set_value_t @\libglobal{set_value}@{};
  inline constexpr set_error_t @\libglobal{set_error}@{};
  inline constexpr set_stopped_t @\libglobal{set_stopped}@{};

  // \ref{exec.opstate}, operation states
  struct @\libglobal{operation_state_tag}@ {};

  template<class O>
    concept @\libconcept{operation_state}@ = @\seebelow@;

  struct @\libglobal{start_t}@;
  inline constexpr start_t @\libglobal{start}@{};

  // \ref{exec.snd}, senders
  struct @\libglobal{sender_tag}@ {};

  template<class Sndr>
    inline constexpr bool enable_sender = @\seebelow@;

  template<class Sndr>
    concept @\libconcept{sender}@ = @\seebelow@;

  template<class Sndr, class... Env>
    concept @\libconcept{sender_in}@ = @\seebelow@;

  template<class Sndr>
    concept @\libconcept{dependent_sender}@ = @\seebelow@;

  template<class Sndr, class Rcvr>
    concept @\exposconceptnc{sender-to}@ = @\seebelownc@;                              // \expos

  template<class... Ts>
    struct @\exposidnc{type-list}@;                                           // \expos

  template<class... Ts>
    using @\exposidnc{decayed-tuple}@ = tuple<decay_t<Ts>...>;                // \expos

  template<class... Ts>
    using @\exposidnc{variant-or-empty}@ = @\seebelownc@;                         // \expos

  template<class Sndr, class Env = env<>,
           template<class...> class Tuple = @\exposid{decayed-tuple}@,
           template<class...> class Variant = @\exposid{variant-or-empty}@>
      requires @\libconcept{sender_in}@<Sndr, Env>
    using value_types_of_t = @\seebelow@;

  template<class Sndr, class Env = env<>,
           template<class...> class Variant = @\exposid{variant-or-empty}@>
      requires @\libconcept{sender_in}@<Sndr, Env>
    using error_types_of_t = @\seebelow@;

  template<class Sndr, class Env = env<>>
      requires @\libconcept{sender_in}@<Sndr, Env>
    constexpr bool sends_stopped = @\seebelow@;

  template<class Sndr, class... Env>
    using @\exposidnc{single-sender-value-type}@ = @\seebelownc@;                 // \expos

  template<class Sndr, class... Env>
    concept @\exposconceptnc{single-sender}@ = @\seebelownc@;                          // \expos

  template<@\libconcept{sender}@ Sndr>
    using tag_of_t = @\seebelow@;

  // \ref{exec.snd.transform}, sender transformations
  template<@\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env>
    constexpr decltype(auto) transform_sender(Sndr&& sndr,
      const Env& env) noexcept(@\seebelow@);

  // \ref{exec.snd.apply}, sender algorithm application
  template<class Domain, class Tag, @\libconcept{sender}@ Sndr, class... Args>
    constexpr decltype(auto) apply_sender(
      Domain dom, Tag, Sndr&& sndr, Args&&... args) noexcept(@\seebelow@);

  // \ref{exec.getcomplsigs}, get completion signatures
  template<class Sndr, class... Env>
    consteval auto get_completion_signatures() -> @\exposconcept{valid-completion-signatures}@ auto;

  template<class Sndr, class... Env>
      requires @\libconcept{sender_in}@<Sndr, Env...>
    using completion_signatures_of_t = decltype(get_completion_signatures<Sndr, Env...>());

  // \ref{exec.connect}, the connect sender algorithm
  struct @\libglobal{connect_t}@;
  inline constexpr connect_t @\libglobal{connect}@{};

  template<class Sndr, class Rcvr>
    using @\libglobal{connect_result_t}@ =
      decltype(connect(declval<Sndr>(), declval<Rcvr>()));

  // \ref{exec.factories}, sender factories
  struct @\libglobal{just_t}@ { @\unspec@ };
  struct @\libglobal{just_error_t}@ { @\unspec@ };
  struct @\libglobal{just_stopped_t}@ { @\unspec@ };
  struct @\libglobal{schedule_t}@ { @\unspec@ };

  inline constexpr just_t @\libglobal{just}@{};
  inline constexpr just_error_t @\libglobal{just_error}@{};
  inline constexpr just_stopped_t @\libglobal{just_stopped}@{};
  inline constexpr schedule_t @\libglobal{schedule}@{};
  inline constexpr @\unspec@ @\libglobal{read_env}@{};

  template<@\libconcept{scheduler}@ Sch>
    using @\libglobal{schedule_result_t}@ = decltype(schedule(declval<Sch>()));

  // \ref{exec.adapt}, sender adaptors
  template<@\exposconcept{class-type}@ D>
    struct @\libglobal{sender_adaptor_closure}@ { };

  struct @\libglobal{starts_on_t}@ { @\unspec@ };
  struct @\libglobal{continues_on_t}@ { @\unspec@ };
  struct @\libglobal{on_t}@ { @\unspec@ };
  struct @\libglobal{schedule_from_t}@ { @\unspec@ };
  struct @\libglobal{then_t}@ { @\unspec@ };
  struct @\libglobal{upon_error_t}@ { @\unspec@ };
  struct @\libglobal{upon_stopped_t}@ { @\unspec@ };
  struct @\libglobal{let_value_t}@ { @\unspec@ };
  struct @\libglobal{let_error_t}@ { @\unspec@ };
  struct @\libglobal{let_stopped_t}@ { @\unspec@ };
  struct @\libglobal{bulk_t}@ { @\unspec@ };
  struct @\libglobal{bulk_chunked_t}@ { @\unspec@ };
  struct @\libglobal{bulk_unchunked_t}@ { @\unspec@ };
  struct @\libglobal{when_all_t}@ { @\unspec@ };
  struct @\libglobal{when_all_with_variant_t}@ { @\unspec@ };
  struct @\libglobal{into_variant_t}@ { @\unspec@ };
  struct @\libglobal{stopped_as_optional_t}@ { @\unspec@ };
  struct @\libglobal{stopped_as_error_t}@ { @\unspec@ };
  struct @\libglobal{associate_t}@ { @\unspec@ };
  struct @\libglobal{spawn_future_t}@ { @\unspec@ };

  inline constexpr @\unspec@ @\libglobal{write_env}@{};
  inline constexpr @\unspec@ @\libglobal{unstoppable}@{};
  inline constexpr starts_on_t @\libglobal{starts_on}@{};
  inline constexpr continues_on_t @\libglobal{continues_on}@{};
  inline constexpr on_t @\libglobal{on}@{};
  inline constexpr schedule_from_t @\libglobal{schedule_from}@{};
  inline constexpr then_t @\libglobal{then}@{};
  inline constexpr upon_error_t @\libglobal{upon_error}@{};
  inline constexpr upon_stopped_t @\libglobal{upon_stopped}@{};
  inline constexpr let_value_t @\libglobal{let_value}@{};
  inline constexpr let_error_t @\libglobal{let_error}@{};
  inline constexpr let_stopped_t @\libglobal{let_stopped}@{};
  inline constexpr bulk_t @\libglobal{bulk}@{};
  inline constexpr bulk_chunked_t @\libglobal{bulk_chunked}@{};
  inline constexpr bulk_unchunked_t @\libglobal{bulk_unchunked}@{};
  inline constexpr when_all_t @\libglobal{when_all}@{};
  inline constexpr when_all_with_variant_t @\libglobal{when_all_with_variant}@{};
  inline constexpr into_variant_t @\libglobal{into_variant}@{};
  inline constexpr stopped_as_optional_t @\libglobal{stopped_as_optional}@{};
  inline constexpr stopped_as_error_t @\libglobal{stopped_as_error}@{};
  inline constexpr associate_t @\libglobal{associate}@{};
  inline constexpr spawn_future_t @\libglobal{spawn_future}@{};
}

namespace std::this_thread {
  // \ref{exec.consumers}, consumers
  struct @\libglobal{sync_wait_t}@ { @\unspec@ };
  struct @\libglobal{sync_wait_with_variant_t}@ { @\unspec@ };

  inline constexpr sync_wait_t @\libglobal{sync_wait}@{};
  inline constexpr sync_wait_with_variant_t @\libglobal{sync_wait_with_variant}@{};
}

namespace std::execution {
  // \ref{exec.consumers}, consumers
  struct @\libglobal{spawn_t}@ { @\unspec@ };
  inline constexpr spawn_t spawn{};

  // \ref{exec.cmplsig}, completion signatures
  template<class Fn>
    concept @\exposconceptnc{completion-signature}@ = @\seebelownc@;                   // \expos

  template<@\exposconcept{completion-signature}@... Fns>
    struct @\libglobal{completion_signatures}@;

  template<class Sigs>
    concept @\exposconceptnc{valid-completion-signatures}@ = @\seebelownc@;            // \expos

  struct dependent_sender_error : exception {};

  // \ref{exec.prop}, class template \tcode{prop}
  template<class QueryTag, class ValueType>
    struct prop;

  // \ref{exec.env}, class template \tcode{env}
  template<@\exposconcept{queryable}@... Envs>
    struct env;

  // \ref{exec.run.loop}, run_loop
  class run_loop;

  // \ref{exec.as.awaitable}, coroutine utility \tcode{as_awaitable}
  struct @\libglobal{as_awaitable_t}@ { @\unspec@ };
  inline constexpr as_awaitable_t @\libglobal{as_awaitable}@{};

  // \ref{exec.with.awaitable.senders}, coroutine utility \tcode{with_awaitable_senders}
  template<@\exposconcept{class-type}@ Promise>
    struct with_awaitable_senders;

  // \ref{exec.affine}, coroutine utility \tcode{affine}
  struct @\libglobal{affine_t}@ { @\unspec@ };
  inline constexpr affine_t @\libglobal{affine}@{};

  // \ref{exec.inline.scheduler}, inline scheduler
  class @\libglobal{inline_scheduler}@;

  // \ref{exec.task.scheduler}, task scheduler
  class @\libglobal{task_scheduler}@;

  template<class E>
  struct @\libglobal{with_error}@ {
    using type = remove_cvref_t<E>;
    type error;
  };
  template<class E>
    with_error(E) -> with_error<E>;

  // \ref{exec.task}, class template \tcode{task}
  template<class T, class Environment>
    class @\libglobal{task}@;

  // \ref{exec.scope.concepts}, scope concepts
  template<class Token>
    concept @\libconcept{scope_association}@ = @\seebelow@;
  template<class Token>
    concept @\libconcept{scope_token}@ = @\seebelow@;

  // \ref{exec.scope.simple.counting}, simple counting scope
  class simple_counting_scope;

  // \ref{exec.scope.counting}, counting scope
  class counting_scope;

  // \ref{exec.par.scheduler}, parallel scheduler
  class @\libglobal{parallel_scheduler}@;
  parallel_scheduler get_parallel_scheduler();

  // \ref{exec.parschedrepl}, namespace \tcode{parallel_scheduler_replacement}
  namespace @\libglobal{parallel_scheduler_replacement}@ {
    struct receiver_proxy;
    struct bulk_item_receiver_proxy;
    struct parallel_scheduler_backend;

    shared_ptr<parallel_scheduler_backend> query_parallel_scheduler_backend();
  }
}
\end{codeblock}

\pnum
The exposition-only type \tcode{\exposid{variant-or-empty}<Ts...>}
is defined as follows:
\begin{itemize}
\item
If \tcode{sizeof...(Ts)} is greater than zero,
\tcode{\exposid{variant-or-empty}<Ts...>} denotes \tcode{variant<Us...>}
where \tcode{Us...} is the pack \tcode{decay_t<Ts>...}
with duplicate types removed.
\item
Otherwise, \tcode{\exposid{variant-or-empty}<Ts...>} denotes
the exposition-only class type:
\begin{codeblock}
namespace std::execution {
  struct @\exposidnc{empty-variant}@ {        // \expos
    @\exposidnc{empty-variant}@() = delete;
  };
}
\end{codeblock}
\end{itemize}

\pnum
For type \tcode{Sndr} and pack of types \tcode{Env},
let \tcode{CS} be \tcode{completion_signatures_of_t<Sndr, Env...>}.
Then \tcode{\exposid{single-sender-value-type}<Sndr, Env...>} is ill-formed
if \tcode{CS} is ill-formed;
otherwise, it is an alias for:
\begin{itemize}
\item
\tcode{\exposid{gather-signatures}<set_value_t, CS, decay_t, type_identity_t>}
if that type is well-formed,
\item
Otherwise, \tcode{void}
if \tcode{\exposid{gather-signatures}<set_value_t, CS, tuple, variant>} is
\tcode{variant<tuple<>>} or \tcode{variant<>},
\item
Otherwise, \tcode{\exposid{gather-signatures}<set_value_t, CS, \exposid{decayed-tuple}, type_identity_t>}
if that\linebreak{} type is well-formed,
\item
Otherwise, \tcode{\exposid{single-sender-value-type}<Sndr, Env...>} is ill-formed.
\end{itemize}

\pnum
The exposition-only concept \exposconcept{single-sender} is defined as follows:
\begin{codeblock}
namespace std::execution {
  template<class Sndr, class... Env>
    concept @\defexposconcept{single-sender}@ = @\libconcept{sender_in}@<Sndr, Env...> &&
      requires {
        typename @\exposid{single-sender-value-type}@<Sndr, Env...>;
      };
}
\end{codeblock}

\pnum
A type satisfies and models the exposition-only concept
\defexposconcept{valid-completion-signatures} if
it is a specialization of the \tcode{completion_signatures} class template.

\rSec1[exec.queries]{Queries}

\rSec2[exec.queries.expos]{Query utilities}

\pnum
Subclause \ref{exec.queries} makes use of the following exposition-only entities.

\pnum
For subexpressions \tcode{q} and \tcode{tag} and pack \tcode{args},
let \tcode{\exposid{TRY-QUERY}(q, tag, args...)} be expression-equivalent to
\tcode{\exposid{AS-CONST}(q).query(tag, args...)}
if that expression is well-formed, and
\tcode{\exposid{AS-CONST}(q).query(tag)} otherwise
except that \tcode{args...} is evaluated.

\pnum
For subexpressions \tcode{q} and \tcode{tag} and pack \tcode{args},
let \tcode{\exposid{HIDE-SCHED}(q)} be an object \tcode{o} such that
\tcode{o.query(\brk{}tag, args...)} is ill-formed when the decayed type of \tcode{tag} is
\tcode{get_scheduler_t} or \tcode{get_domain_t}, and
\tcode{q.query(tag, args...)} otherwise.

\rSec2[exec.fwd.env]{\tcode{forwarding_query}}

\pnum
\tcode{forwarding_query} asks a query object
whether it should be forwarded through queryable adaptors.

\pnum
The name \tcode{forwarding_query} denotes a query object.
For some query object \tcode{q} of type \tcode{Q},
\tcode{forwarding_query(q)} is expression-equivalent to:
\begin{itemize}
\item
\tcode{\exposid{MANDATE-NOTHROW}(q.query(forwarding_query))}
if that expression is well-formed.

\mandates
The expression above has type \tcode{bool} and
is a core constant expression if \tcode{q} is a core constant expression.
\item
Otherwise, \tcode{true} if \tcode{\libconcept{derived_from}<Q, forwarding_query_t>} is \tcode{true}.
\item
Otherwise, \tcode{false}.
\end{itemize}

\rSec2[exec.get.allocator]{\tcode{get_allocator}}

\pnum
\tcode{get_allocator} asks a queryable object for its associated allocator.

\pnum
The name \tcode{get_allocator} denotes a query object.
For a subexpression \tcode{env},
\tcode{get_allocator(env)} is expression-equivalent to
\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env).query(get_allocator))}.

\mandates
If the expression above is well-formed,
its type satisfies
\exposconcept{simple-allocator}\iref{allocator.requirements.general}.

\pnum
\tcode{forwarding_query(get_allocator)} is a core constant expression and
has value \tcode{true}.

\rSec2[exec.get.stop.token]{\tcode{get_stop_token}}

\pnum
\tcode{get_stop_token} asks a queryable object for an associated stop token.

\pnum
The name \tcode{get_stop_token} denotes a query object.
For a subexpression \tcode{env},
\tcode{get_stop_token(env)} is expression-equivalent to:
\begin{itemize}
\item
\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env).query(get_stop_token))}
if that expression is well-formed.

\mandates
The type of the expression above satisfies \libconcept{stoppable_token}.

\item
Otherwise, \tcode{never_stop_token\{\}}.
\end{itemize}

\pnum
\tcode{forwarding_query(get_stop_token)} is a core constant expression and
has value \tcode{true}.

\rSec2[exec.get.env]{\tcode{execution::get_env}}

\pnum
\tcode{execution::get_env} is a customization point object.
For a subexpression \tcode{o},
\tcode{execution::get_env(o)} is expression-equivalent to:
\begin{itemize}
\item
\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(o).get_env())}
if that expression is well-formed.

\mandates
The type of the expression above satisfies
\exposconcept{queryable}\iref{exec.queryable}.
\item
Otherwise, \tcode{env<>\{\}}.
\end{itemize}

\pnum
The value of \tcode{get_env(o)} shall be valid while \tcode{o} is valid.

\pnum
\begin{note}
When passed a sender object,
\tcode{get_env} returns the sender's associated attributes.
When passed a receiver,
\tcode{get_env} returns the receiver's associated execution environment.
\end{note}

\rSec2[exec.get.domain]{\tcode{execution::get_domain}}

\pnum
\tcode{get_domain} asks a queryable object
for its associated execution domain tag.

\pnum
The name \tcode{get_domain} denotes a query object.
For a subexpression \tcode{env},
\tcode{get_domain(env)} is expression-equivalent to
\tcode{\exposid{MANDATE-NOTHROW}(D())},
where \tcode{D} is the type of the first
of the following expressions that is well-formed:
\begin{itemize}
\item \tcode{auto(\exposid{AS-CONST}(env).query(get_domain))}.
\item \tcode{get_completion_domain<set_value_t>(get_scheduler(env), \exposid{HIDE-SCHED}(env))}.
\item \tcode{default_domain()}, except that \tcode{env} is evaluated.
\end{itemize}

\pnum
\tcode{forwarding_query(execution::get_domain)} is
a core constant expression and has value \tcode{true}.

\rSec2[exec.get.scheduler]{\tcode{execution::get_scheduler}}

\pnum
\tcode{get_scheduler} asks a queryable object for its associated scheduler.

\pnum
The name \tcode{get_scheduler} denotes a query object.
For a subexpression \tcode{env},
\tcode{get_scheduler(env)} is expression-equivalent to
\tcode{get_completion_scheduler<set_value_t>(
\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env)\brk{}.query(get_scheduler)),
\exposid{HIDE-SCHED}(env))}.

\mandates
If the expression above is well-formed,
its type satisfies \libconcept{scheduler}.

\pnum
\tcode{forwarding_query(execution::get_scheduler)} is
a core constant expression and has value \tcode{true}.

\rSec2[exec.get.start.scheduler]{\tcode{execution::get_start_scheduler}}

\pnum
\tcode{get_start_scheduler} asks a queryable object
for the scheduler an operation will be or was started on.

\pnum
The name \tcode{get_start_scheduler} denotes a query object.
For a subexpression \tcode{env},
\tcode{get_start_scheduler(\brk{}env)} is expression-equivalent to
\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env).query(get_start_scheduler))}.

\mandates
If the expression above is well-formed,
its type satisfies \libconcept{scheduler}.

\pnum
\tcode{forwarding_query(execution::get_start_scheduler)}
is a core constant expression and has value \tcode{true}.

\pnum
Given subexpressions \tcode{sndr} and \tcode{rcvr}
such that \tcode{\exposid{sender-to}<decltype((sndr)), decltype((rcvr))>} is \tcode{true}
and the expression \tcode{get_start_scheduler(get_env(rcvr))} is well-formed,
an operation state that is the result of calling \tcode{connect(sndr, rcvr)}
shall, if it is started, be started on an execution agent
associated with the scheduler \tcode{get_start_scheduler(get_env(rcvr))}.

\rSec2[exec.get.delegation.scheduler]{\tcode{execution::get_delegation_scheduler}}

\pnum
\tcode{get_delegation_scheduler} asks a queryable object for a scheduler
that can be used to delegate work to
for the purpose of forward progress delegation\iref{intro.progress}.

\pnum
The name \tcode{get_delegation_scheduler} denotes a query object.
For a subexpression \tcode{env},
\tcode{get_delegation_scheduler(env)} is expression-equivalent to
\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env).query(get_delegation_scheduler))}.

\mandates
If the expression above is well-formed,
its type satisfies \libconcept{scheduler}.

\pnum
\tcode{forwarding_query(execution::get_delegation_scheduler)} is
a core constant expression and has value \tcode{true}.

\rSec2[exec.get.fwd.progress]{\tcode{execution::get_forward_progress_guarantee}}

\begin{codeblock}
namespace std::execution {
  enum class @\libglobal{forward_progress_guarantee}@ {
    concurrent,
    parallel,
    weakly_parallel
  };
}
\end{codeblock}

\pnum
\tcode{get_forward_progress_guarantee} asks a scheduler about
the forward progress guarantee of execution agents
created by that scheduler's associated execution resource\iref{intro.progress}.

\pnum
The name \tcode{get_forward_progress_guarantee} denotes a query object.
For a subexpression \tcode{sch}, let \tcode{Sch} be \tcode{decltype((sch))}.
If \tcode{Sch} does not satisfy \libconcept{scheduler},
\tcode{get_forward_progress_guarantee} is ill-formed.
Otherwise,
\tcode{get_forward_progress_guarantee(sch)} is expression-equivalent to:
\begin{codeblock}
@\exposid{MANDATE-NOTHROW}@(@\exposid{AS-CONST}@(sch).query(get_forward_progress_guarantee))
\end{codeblock}

\mandates
The type of the expression above is \tcode{forward_progress_guarantee}.

\pnum
If \tcode{get_forward_progress_guarantee(sch)} for some scheduler \tcode{sch}
returns \tcode{forward_progress_guaran\-tee::concurrent},
all execution agents created by that scheduler's associated execution resource
shall provide the concurrent forward progress guarantee.
If it returns \tcode{forward_progress_guarantee::parallel},
all such execution agents
shall provide at least the parallel forward progress guarantee.

\rSec2[exec.get.compl.sched]{\tcode{execution::get_completion_scheduler}}

\pnum
The name \tcode{get_completion_scheduler} denotes a query object template.

\pnum
Let \exposid{completion-fn} be a completion function\iref{exec.async.ops};
let \exposid{completion-fn-tag} be
the associated completion tag of \exposid{completion-fn};
let \tcode{args} and \tcode{envs} be packs of subexpressions; and
let \tcode{sndr} be a subexpression
such that \tcode{\libconcept{sender}<decltype((sndr))>} is \tcode{true} and
\tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(get_env(sndr), envs...)}
is well-formed and denotes a scheduler \tcode{sch}.

\pnum
\tcode{get_completion_scheduler<\exposid{completion-fn-tag>}} obtains
the completion scheduler associated with a completion tag
from a sender's attributes.

\pnum
For subexpression \tcode{sch1} and pack \tcode{envs},
let \tcode{sch2} be
\tcode{\exposid{TRY-QUERY}(sch1, get_completion_scheduler<set_value_t>, envs...)} and
let \tcode{\exposid{RECURSE-QUERY}(sch1, envs...)} be
expression-equivalent to \tcode{sch1}
if \tcode{sch2} is ill-formed or
if \tcode{sch1} and \tcode{sch2} have the same type and compare equal;
otherwise, \tcode{\exposid{RECURSE-QUERY}(sch2, envs...)}.

\pnum
For a subexpression \tcode{q} and pack \tcode{envs},
the expression \tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(q, envs...)}
is ill-formed if \exposid{completion-fn-tag} is not one of
\tcode{set_value_t}, \tcode{set_error_t}, or \tcode{set_stopped_t}.
Otherwise, the expression
is expression-equivalent to:
\begin{itemize}
\item
\begin{codeblock}
@\exposid{MANDATE-NOTHROW}@(@\exposid{RECURSE-QUERY}@(
  @\exposid{TRY-QUERY}@(q, get_completion_scheduler<@\exposid{completion-fn-tag}@>, envs...), envs...))
\end{codeblock}
if that expression is well-formed,
except that \tcode{envs...} is evaluated only once.
\item
Otherwise, \tcode{auto(q)}
if the type of \tcode{q} satisfies \libconcept{scheduler} and
\tcode{envs} is not an empty pack,
except that \tcode{envs...} is evaluated.
\item
Otherwise, \tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(q, envs...)}
is ill-formed.
\end{itemize}
\mandates
If \tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(q, envs...)}
is well-formed,
its type satisfies \libconcept{scheduler}.

\pnum
For a type \tcode{Tag}, subexpression \tcode{sndr}, and pack \tcode{envs},
let \tcode{CS} be
\tcode{completion_signatures_of_t<decay_t<decltype((sndr))>, decltype((envs))...>}.
If both \tcode{get_completion_scheduler<Tag>(get_env(\newline sndr), envs...)} and
\tcode{CS} are well-formed and
\tcode{CS().\exposid{count-of}(Tag()) == 0} is \tcode{true},
the program is ill-formed.

\pnum
If an asynchronous operation
created by connecting \tcode{sndr} with a receiver \tcode{rcvr}
causes the evaluation of \tcode{\exposid{completion-fn}(rcvr, args...)},
the behavior is undefined
unless the evaluation happens on an execution agent
that belongs to \tcode{sch}'s associated execution resource.

\pnum
The expression
\tcode{forwarding_query(get_completion_scheduler<\exposid{completion-fn-tag}>)}
is a core constant expression and has value \tcode{true}.

\rSec2[exec.get.compl.domain]{\tcode{execution::get_completion_domain}}

\pnum
\tcode{get_completion_domain<\exposid{completion-tag}>}
obtains the completion domain associated with a completion tag
from a sender's attributes.

\pnum
The name \tcode{get_completion_domain} denotes a query object template.
For a subexpression \tcode{attrs} and pack \tcode{envs},
the expression \tcode{get_completion_domain<\exposid{completion-tag}>(attrs, envs...)}
is ill-formed if \exposid{completion-tag} is not one of
\tcode{void},
\tcode{set_value_t},
\tcode{set_error_t}, or
\tcode{set_stopped_t}.
Otherwise, the expression is expression-equivalent to
\tcode{\exposid{MANDATE-NOTHROW}(D())},
where \tcode{D} is:
\begin{itemize}
\item
The type of
\tcode{\exposid{TRY-QUERY}(attrs, get_completion_domain<\exposid{completion-tag}>, envs...)}
if that expression is well-formed.
\item
Otherwise, the type of
\tcode{get_completion_domain<set_value_t>(attrs, envs...)}
if \exposid{completion-tag} is \tcode{void}.
\item
Otherwise, the type of
\begin{codeblock}
@\exposidnc{TRY-QUERY}@(get_completion_scheduler<@\exposid{completion-tag}@>(attrs, envs...),
          get_completion_domain<set_value_t>, envs...)
\end{codeblock}
if that expression is well-formed.
\item
Otherwise, \tcode{default_domain} if
\tcode{\libconcept{scheduler}<decltype((attrs))>} is \tcode{true} and
\tcode{envs} is not an empty pack.
\item
Otherwise, \tcode{get_completion_domain<\exposid{completion-tag}>(attrs, envs...)}
is ill-formed.
\end{itemize}

\pnum
For a type \tcode{Tag}, subexpression \tcode{sndr}, and pack \tcode{envs},
let \tcode{CS} be
\tcode{completion_signatures_of_t<decay_t<decltype((sndr))>, decltype((envs))...>}.
If both \tcode{get_completion_domain<Tag>(get_env(sndr), envs...)} and
\tcode{CS} are well-formed and
\tcode{CS().\exposid{count-of}(Tag()) == 0} is \tcode{true},
the program is ill-formed.

\pnum
Let \exposid{completion-fn} be a completion function\iref{exec.async.ops};
let \exposid{completion-tag} be the associated completion tag of \exposid{completion-fn};
let \tcode{args} and \tcode{envs} be packs of subexpressions; and
let \tcode{sndr} be a subexpression such that
\tcode{\libconcept{sender}<decltype((sndr))>} is \tcode{true} and
\tcode{get_completion_domain<\exposid{completion-tag}>(get_env(sndr), envs...)}
is well-formed and denotes a domain tag \tcode{D}.
If an asynchronous operation created by connecting
\tcode{sndr} with a receiver \tcode{rcvr}
causes the evaluation of \tcode{\exposid{completion-fn}(rcvr, args...)},
the behavior is undefined
unless the evaluation happens on an execution agent of an execution resource
whose associated execution domain tag is \tcode{D}.

The expression
\tcode{forwarding_query(get_completion_domain<\exposid{completion-tag}>)}
is a core constant expression and has value \tcode{true}.

\rSec2[exec.get.await.adapt]{\tcode{execution::get_await_completion_adaptor}}

\pnum
\tcode{get_await_completion_adaptor} asks a queryable object for
its associated awaitable completion adaptor.

\pnum
The name \tcode{get_await_completion_adaptor} denotes a query object.
For a subexpression \tcode{env},
\begin{codeblock}
get_await_completion_adaptor(env)
\end{codeblock}
is expression-equivalent to
\begin{codeblock}
@\exposidnc{MANDATE-NOTHROW}@(@\exposid{AS-CONST}@(env).query(get_await_completion_adaptor))
\end{codeblock}

\pnum
\tcode{forwarding_query(execution::get_await_completion_adaptor)}
is a core constant expression and has value \tcode{true}.

\rSec1[exec.sched]{Schedulers}

\pnum
The \libconcept{scheduler} concept defines
the requirements of a scheduler type\iref{exec.async.ops}.
\tcode{schedule} is a customization point object
that accepts a scheduler.
A valid invocation of \tcode{schedule} is a schedule-expression.
\begin{codeblock}
namespace std::execution {
  template<class Sch>
    concept @\deflibconcept{scheduler}@ =
      @\libconcept{derived_from}@<typename remove_cvref_t<Sch>::scheduler_concept, scheduler_tag> &&
      @\exposconcept{queryable}@<Sch> &&
      requires(Sch&& sch) {
        { schedule(std::forward<Sch>(sch)) } -> @\libconcept{sender}@;
        { get_forward_progress_guarantee(sch) } -> @\libconcept{same_as}@<forward_progress_guarantee>;
      } &&
      @\libconcept{equality_comparable}@<remove_cvref_t<Sch>> &&
      @\libconcept{copyable}@<remove_cvref_t<Sch>>;
}
\end{codeblock}

\pnum
Let \tcode{Sch} be the type of a scheduler and
let \tcode{Env} be the type of an execution environment
for which \tcode{\libconcept{sender_in}<schedule_result_t<Sch>, Env>}
is satisfied.
Then \tcode{\exposconcept{sender-in-of}<schedule_result_t<Sch>, Env>}
shall be modeled.

\pnum
No operation required by
\tcode{\libconcept{copyable}<remove_cvref_t<Sch>>} and
\tcode{\libconcept{equality_comparable}<remove_cvref_t<Sch>>}
shall exit via an exception.
None of these operations,
nor a scheduler type's \tcode{schedule} function,
shall introduce data races
as a result of potentially concurrent\iref{intro.races} invocations
of those operations from different threads.

\pnum
For any two values \tcode{sch1} and \tcode{sch2}
of some scheduler type \tcode{Sch},
\tcode{sch1 == sch2} shall return \tcode{true}
only if both \tcode{sch1} and \tcode{sch2} share
the same associated execution resource.

\pnum
For a given scheduler expression \tcode{sch},
if the expression
\tcode{get_completion_scheduler<set_value_t>(get_env(schedule(sch)))}
is well-formed,
it shall compare equal to \tcode{sch}.

\pnum
For a given scheduler expression \tcode{sch},
type \tcode{T}, and
pack of subexpressions \tcode{envs},
the following expressions are either both ill-formed, or
both well-formed with the same type:
\begin{itemize}
\item \tcode{get_completion_domain<T>(sch, envs...)}
\item \tcode{get_completion_domain<T>(get_env(schedule(sch)), envs...)}
\end{itemize}
Likewise, the following expressions are either both ill-formed, or
both well-formed with the same type and value:
\begin{itemize}
\item \tcode{get_completion_scheduler<T>(sch, envs...)}
\item \tcode{get_completion_scheduler<T>(get_env(schedule(sch)), envs...)}
\end{itemize}

\pnum
A scheduler type's destructor shall not block
pending completion of any receivers
connected to the sender objects returned from \tcode{schedule}.

\pnum
The exposition-only \exposconcept{infallible-scheduler} concept
defines the requirements of a scheduler type
whose \tcode{schedule} asynchronous operation
can only complete with \tcode{set_value} unless stop can be requested:
\begin{codeblock}
template<class Sch, class Env>
  concept @\defexposconcept{infallible-scheduler}@ =
    @\libconcept{scheduler}@<Sch> &&
    (@\libconcept{same_as}@<completion_signatures<set_value_t()>,
             completion_signatures_of_t<decltype(schedule(declval<Sch>())), Env>> ||
     (!@\libconcept{unstoppable_token}@<stop_token_of_t<Env>> &&
      (@\libconcept{same_as}@<completion_signatures<set_value_t(), set_stopped_t()>,
               completion_signatures_of_t<decltype(schedule(declval<Sch>())), Env>> ||
       @\libconcept{same_as}@<completion_signatures<set_stopped_t(), set_value_t()>,
               completion_signatures_of_t<decltype(schedule(declval<Sch>())), Env>>)));
\end{codeblock}

\rSec1[exec.recv]{Receivers}

\rSec2[exec.recv.concepts]{Receiver concepts}

\pnum
A receiver represents the continuation of an asynchronous operation.
The \libconcept{receiver} concept defines
the requirements for a receiver type\iref{exec.async.ops}.
The exposition-only concept \exposconcept{receiver-of} defines
the requirements for a receiver type that is usable as
the first argument of a set of completion operations
corresponding to a set of completion signatures.
The \tcode{get_env} customization point object is used to access
a receiver's associated environment.
\begin{codeblock}
namespace std::execution {
  template<class Rcvr>
    concept @\deflibconcept{receiver}@ =
      @\libconcept{derived_from}@<typename remove_cvref_t<Rcvr>::receiver_concept, receiver_tag> &&
      requires(const remove_cvref_t<Rcvr>& rcvr) {
        { get_env(rcvr) } -> @\exposconcept{queryable}@;
      } &&
      @\libconcept{move_constructible}@<remove_cvref_t<Rcvr>> &&               // rvalues are movable, and
      @\libconcept{constructible_from}@<remove_cvref_t<Rcvr>, Rcvr> &&         // lvalues are copyable, and
      is_nothrow_move_constructible_v<remove_cvref_t<Rcvr>>;    // no-throw-movable

  template<class Signature, class Rcvr>
    concept @\defexposconceptnc{valid-completion-for}@ =                              // \expos
      requires (Signature* sig) {
        []<class Tag, class... Args>(Tag(*)(Args...))
            requires @\exposconcept{callable}@<Tag, remove_cvref_t<Rcvr>, Args...>
        {}(sig);
      };

  template<class Rcvr, class Completions>
    concept @\defexposconceptnc{has-completions}@ =                                   // \expos
      requires (Completions* completions) {
        []<@\exposconcept{valid-completion-for}@<Rcvr>...Sigs>(completion_signatures<Sigs...>*)
        {}(completions);
      };

  template<class Rcvr, class Completions>
    concept @\defexposconceptnc{receiver-of}@ =                                       // \expos
      @\libconcept{receiver}@<Rcvr> && @\exposconcept{has-completions}@<Rcvr, Completions>;
}
\end{codeblock}

\pnum
Class types that are marked \tcode{final} do not model the \libconcept{receiver} concept.

\pnum
Let \tcode{rcvr} be a receiver and
let \tcode{op_state} be an operation state associated with
an asynchronous operation created by connecting \tcode{rcvr} with a sender.
Let \tcode{token} be a stop token equal to
\tcode{get_stop_token(get_env(rcvr))}.
\tcode{token} shall remain valid
for the duration of the asynchronous operation's lifetime\iref{exec.async.ops}.
\begin{note}
This means that, unless it knows about further guarantees
provided by the type of \tcode{rcvr},
the implementation of \tcode{op_state} cannot use \tcode{token}
after it executes a completion operation.
This also implies that any stop callbacks registered on token
must be destroyed before the invocation of the completion operation.
\end{note}

\pnum
\begin{codeblock}
namespace std::execution {
  template<class Rcvr, class ChildOp>
    concept @\deflibconcept{inlinable_receiver}@ = @\libconcept{receiver}@<Rcvr> &&
      requires (ChildOp* child) {
        { remove_cvref_t<Rcvr>::make_receiver_for(child) } noexcept
          -> @\libconcept{same_as}@<remove_cvref_t<Rcvr>>;
      };
}
\end{codeblock}

The \libconcept{inlinable_receiver} concept
defines the requirements for a receiver
that can be reconstructed on demand
from a pointer to the operation state object
created when the receiver was connected to a sender.
Given a receiver object \tcode{rcvr} of type \tcode{Rcvr}
which was connected to a sender producing
an operation state object \tcode{op} of type \tcode{Op},
\tcode{Rcvr} models \tcode{\libconcept{inlinable_receiver}<Op>}
only if the expression \tcode{Rcvr::make_receiver_for(addressof(op))}
evaluates to a receiver
that is equal to \tcode{rcvr}\iref{concepts.equality}.
\begin{note}
Such a receiver does not need to be stored as a data member of \tcode{op}
as it can be recreated on demand.
\end{note}
\tcode{ChildOp} may be an incomplete type.

\pnum
Given objects $O_0, \dotsc, O_n$,
$O_n$ is \defnadj{transitively}{constructed} from $O_0$ if
\begin{itemize}
\item
\tcode{remove_cvref_t<decltype($O_n$)>}
denotes the same type as
\tcode{remove_cvref_t<decltype($O_0$)>} and
\item
either
\begin{itemize}
\item
$O_1$ was initialized by decay-copying a reference to $O_0$, or
\item
$n > 1$ and $O_{n-1}$ is transitively constructed from $O_0$ and
$O_n$ was initialized from
a non-const, non-volatile rvalue reference to $O_{n-1}$.
\end{itemize}
\end{itemize}

\pnum
Let $E$ be some well-formed expression \tcode{connect(sndr, rcvr)}.
$E$ \defn{inlines the receiver} \tcode{rcvr}
if the lifetimes of all objects transitively constructed from
\tcode{rcvr} during the evaluation of $E$
end within the evaluation of $E$.
\begin{note}
This means such an expression does not store the receiver in the operation state.
\end{note}

\pnum
Let $E$ be some well-formed expression \tcode{connect(sndr, rcvr)} where
\begin{itemize}
\item
\tcode{sndr} denotes a sender type defined by this document and
\item
$E$ inlines the receiver \tcode{rcvr}.
\end{itemize}
Then, let \tcode{op} be the result of the evaluation of $E$, and
wherever the specification of the operation associated with \tcode{op}
contains a glvalue
which would denote an object transitively constructed from \tcode{rcvr},
that glvalue instead denotes the result of applying
the temporary materialization conversion to the expression
\tcode{remove_cvref_t<decltype(rcvr)>::make_receiver_for(addressof(op))}.

\pnum
Let \tcode{StdRcvr} be a receiver type defined by this document.
Given some operation state type \tcode{Op},
it is unspecified
whether \tcode{StdRcvr} models \tcode{\libconcept{inlinable_receiver}<Op>}.

\pnum
Let \tcode{StdOp} be some operation state type defined by this document,
and let \tcode{Sndr} and \tcode{Rcvr} be types such that
\tcode{is_same_v<connect_result_t<Sndr, Rcvr>, StdOp>} is \tcode{true}.
If \tcode{Rcvr} models \tcode{\libconcept{inlinable_receiver}<StdOp>}
then it is implementation-defined whether,
given an object \tcode{rcvr} of type \tcode{Rcvr},
the \tcode{connect} operation which produces an object of type \tcode{StdOp}
inlines the receiver \tcode{rcvr}.

\rSec2[exec.set.value]{\tcode{execution::set_value}}

\pnum
\tcode{set_value} is a value completion function\iref{exec.async.ops}.
Its associated completion tag is \tcode{set_value_t}.
The expression \tcode{set_value(rcvr, vs...)}
for a subexpression \tcode{rcvr} and
pack of subexpressions \tcode{vs} is ill-formed
if \tcode{rcvr} is an lvalue or an rvalue of const type.
Otherwise, it is expression-equivalent to
\tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_value(vs...))}.

\mandates
If the expression above is well-formed, its type is \tcode{void}.

\rSec2[exec.set.error]{\tcode{execution::set_error}}

\pnum
\tcode{set_error} is an error completion function\iref{exec.async.ops}.
Its associated completion tag is \tcode{set_error_t}.
The expression \tcode{set_error(rcvr, err)}
for some subexpressions \tcode{rcvr} and \tcode{err} is ill-formed
if \tcode{rcvr} is an lvalue or an rvalue of const type.
Otherwise, it is expression-equivalent to
\tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_error(err))}.

\mandates
If the expression above is well-formed, its type is \tcode{void}.

\rSec2[exec.set.stopped]{\tcode{execution::set_stopped}}

\pnum
\tcode{set_stopped} is a stopped completion function\iref{exec.async.ops}.
Its associated completion tag is \tcode{set_stopped_t}.
The expression \tcode{set_stopped(rcvr)}
for a subexpression \tcode{rcvr} is ill-formed
if \tcode{rcvr} is an lvalue or an rvalue of const type.
Otherwise, it is expression-equivalent to
\tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_stopped())}.

\mandates
If the expression above is well-formed, its type is \tcode{void}.

\rSec1[exec.opstate]{Operation states}

\rSec2[exec.opstate.general]{General}

\pnum
The \libconcept{operation_state} concept defines
the requirements of an operation state type\iref{exec.async.ops}.
\begin{codeblock}
namespace std::execution {
  template<class O>
    concept @\deflibconcept{operation_state}@ =
      @\libconcept{derived_from}@<typename O::operation_state_concept, operation_state_tag> &&
      requires (O& o) {
        start(o);
      };
}
\end{codeblock}

\pnum
If an \libconcept{operation_state} object is destroyed
during the lifetime of its asynchronous operation\iref{exec.async.ops},
the behavior is undefined.
\begin{note}
The \libconcept{operation_state} concept does not impose requirements
on any operations other than destruction and \tcode{start},
including copy and move operations.
Invoking any such operation on an object
whose type models \libconcept{operation_state} can lead to undefined behavior.
\end{note}

\pnum
The program is ill-formed
if it performs a copy or move construction or assignment operation on
an operation state object created by connecting a library-provided sender.

\rSec2[exec.opstate.start]{\tcode{execution::start}}

\pnum
The name \tcode{start} denotes a customization point object
that starts\iref{exec.async.ops}
the asynchronous operation associated with the operation state object.
For a subexpression \tcode{op},
the expression \tcode{start(op)} is ill-formed
if \tcode{op} is an rvalue.
Otherwise, it is expression-equivalent to
\tcode{\exposid{MANDATE-NOTHROW}(op.start())}.

\mandates
If the expression above is well-formed, its type is \tcode{void}.

\pnum
If \tcode{op.start()} does not start\iref{exec.async.ops}
the asynchronous operation associated with the operation state \tcode{op},
the behavior of calling \tcode{start(op)} is undefined.

\rSec1[exec.snd]{Senders}

\rSec2[exec.snd.general]{General}

\pnum
Subclauses \ref{exec.factories} and \ref{exec.adapt} define
customizable algorithms that return senders.
Each algorithm has a default implementation.
Let \tcode{sndr} be the result of an invocation of such an algorithm or
an object equal to the result\iref{concepts.equality}, and
let \tcode{Sndr} be \tcode{decltype((sndr))}.
Let \tcode{rcvr} be a receiver of type \tcode{Rcvr}
with associated environment \tcode{env} of type \tcode{Env}
such that \tcode{\exposconcept{sender-to}<Sndr, Rcvr>} is \tcode{true}.
For the default implementation of the algorithm that produced \tcode{sndr},
connecting \tcode{sndr} to \tcode{rcvr} and
starting the resulting operation state\iref{exec.async.ops}
necessarily results in the potential evaluation\iref{basic.def.odr} of
a set of completion operations
whose first argument is a subexpression equal to \tcode{rcvr}.

\pnum
Let \tcode{Sigs} be a pack of completion signatures corresponding to
this set of completion operations, and
let \tcode{CS} be
the type of the expression \tcode{get_completion_signatures<Sndr, Env>()}.
Then \tcode{CS} is
a specialization of
the class template \tcode{completion_signatures}\iref{exec.cmplsig},
the set of whose template arguments is \tcode{Sigs}.
If none of the types in \tcode{Sigs} are dependent on the type \tcode{Env}, then
the expression \tcode{get_completion_signatures<Sndr>()} is well-formed and
its type is \tcode{CS}.

\pnum
Each completion operation can potentially be evaluated
on one of several different execution agents
as determined by the semantics of the algorithm,
the environment of the receiver, and
the completions of any child senders.
For a completion tag \tcode{T},
let $\tcode{Ds}_{\tcode{T}}$ be a pack comprised of the set of domain tags
associated with the execution agents that could potentially evaluate
any of the operation's completions with tag \tcode{T}.
If there are no potentially evaluated completion operations
with tag type \tcode{T},
then \tcode{get_completion_domain<T>(get_env(sndr), env)} is ill-formed;
otherwise, it has type
\tcode{\exposid{COMMON-DOMAIN}<$\tcode{Ds}_{\tcode{T}}$...>}\iref{exec.snd.expos}.
\begin{example}
Let \tcode{sndr2} be the sender \tcode{then(sndr, fn)}.
\tcode{sndr2} has the same \tcode{set_value} completion domain tag as \tcode{sndr},
but if \tcode{fn}'s evaluation is potentially throwing,
\tcode{sndr}'s \tcode{set_error} completion domain tag would be
the \exposid{COMMON-DOMAIN} of \tcode{sndr}'s value and error completion domain tags,
in accordance with the semantics of the \tcode{then} algorithm\iref{exec.then}.
\end{example}

\pnum
If \tcode{sndr} can determine that all of its completion operations
with tag \tcode{T} happen on execution agents
associated with a particular scheduler \tcode{sch}
(as determined by the semantics of the algorithm,
the environment of the receiver, and
the completion schedulers of any child senders),
then \tcode{get_completion_scheduler<T>(get_env(sndr), env)}
is well-formed and has the type and value of \tcode{sch};
otherwise, it is ill-formed.
\begin{example}
Let \tcode{sndr2} be the sender from the example above.
The \tcode{set_value} completion scheduler of \tcode{sndr2} is
the \tcode{set_value} completion scheduler of \tcode{sndr}, if any.
But \tcode{sndr2} can only report a \tcode{set_error} completion scheduler
when invocations of \tcode{fn} are not potentially throwing or
when \tcode{sndr} has no \tcode{set_error} completions.
When \tcode{fn} can throw,
\tcode{sndr2} could complete with \tcode{set_error} either
by forwarding an error completion from \tcode{sndr} or
by completing with the exception thrown by \tcode{fn},
which would happen on an agent associated with \tcode{sndr}'s
\tcode{set_value} completion scheduler.
\end{example}

\pnum
If a user-provided implementation of the algorithm
that produced \tcode{sndr} is selected instead of the default:

\begin{itemize}
\item
Any completion signature
that is in the set of types
denoted by \tcode{completion_signatures_of_t<Sndr, Env>} and
that is not part of \tcode{Sigs} shall correspond to
error or stopped completion operations,
unless otherwise specified.

\item
If none of the types in \tcode{Sigs} are dependent on the type \tcode{Env}, then
\tcode{completion_signatures_of_t<Sndr>} and
\tcode{completion_signatures_of_t<Sndr, Env>}
shall denote the same type.
\end{itemize}

\pnum
\indexlibraryglobal{\tcode{\placeholder{unspecified-exception}}}%
Various function templates in subclause \ref{exec.snd}
can throw an exception of type \exposid{unspecified-exception}.
Each such exception object is of an unspecified type
such that a \grammarterm{handler} of type \tcode{exception}
matches\iref{except.handle} the exception object
but a \grammarterm{handler} of type \tcode{dependent_sender_error} does not.
\begin{note}
There is no requirement that two such exception objects have the same type.
\end{note}

\rSec2[exec.snd.expos]{Exposition-only entities}

\pnum
Given an expression \tcode{sndr},
whose type is any sender type defined in the standard library,
it is unspecified
whether the expression \tcode{sndr.affine()} is well-formed.
If that expression is well-formed,
then the evaluation thereof meets the semantic requirements of
the \tcode{affine}\iref{exec.affine} algorithm.

\pnum
Given an expression \tcode{sndr},
whose type is any sender type defined in the standard library,
and an expression \tcode{p},
whose type is a promise type,
it is unspecified
whether the expression \tcode{sndr.as_awaitable(p)} is well-formed.
If that expression is well-formed,
then the evaluation thereof meets the semantic requirements of
the \tcode{as_awaitable}\iref{exec.as.awaitable} algorithm.

\pnum
Subclause \ref{exec.snd} makes use of the following exposition-only entities.

\pnum
\indexlibraryglobal{\exposid{FWD-ENV}}%
For a queryable object \tcode{env},
\tcode{\exposid{FWD-ENV}(env)} is an expression
whose type satisfies \exposconcept{queryable}
such that for a query object \tcode{q} and
a pack of subexpressions \tcode{as},
the expression \tcode{\exposid{FWD-ENV}(env).query(q, as...)} is ill-formed
if \tcode{forwarding_query(q)} is \tcode{false};
otherwise, it is expression-equivalent to \tcode{env.query(q, as...)}.
\indexlibraryglobal{\exposid{FWD-ENV-T}}%
The type \tcode{\exposid{FWD-ENV-T}(Env)} is
\tcode{decltype(\exposid{FWD-ENV}(declval<Env>()))}.

\pnum
For a query object \tcode{q},
a subexpression \tcode{v}, and
a pack of subexpressions \tcode{args},
\tcode{\exposid{MAKE-ENV}(q, v)} is an expression \tcode{env}
whose type satisfies \exposconcept{queryable}
such that the result of \tcode{env.query(q, args...)} has
a value equal to \tcode{v}\iref{concepts.equality}.
Unless otherwise stated,
the object to which \tcode{env.query(q, args...)} refers remains valid
while \tcode{env} remains valid.

\pnum
For two queryable objects \tcode{env1} and \tcode{env2},
a query object \tcode{q}, and
a pack of subexpressions \tcode{as},
\tcode{\exposid{JOIN-ENV}(env1, env2)} is an expression \tcode{env3}
whose type satisfies \exposconcept{queryable}
such that \tcode{env3.query(q, as...)} is expression-equivalent to:
\begin{itemize}
\item
\tcode{env1.query(q, as...)} if that expression is well-formed,
\item
otherwise, \tcode{env2.query(q, as...)} if that expression is well-formed,
\item
otherwise, \tcode{env3.query(q, as...)} is ill-formed.
\end{itemize}

\pnum
The results of \exposid{FWD-ENV}, \exposid{MAKE-ENV}, and \exposid{JOIN-ENV}
can be context-dependent;
i.e., they can evaluate to expressions
with different types and value categories
in different contexts for the same arguments.

\pnum
For a pack of subexpressions \tcode{domains},
\tcode{\exposid{COMMON-DOMAIN}(domains...)} is expression-equivalent to
\tcode{common_type_t<decltype(auto(domains))...>()}
if that expression is well-formed, and
\tcode{indeterminate_domain<\brk{}Ds...>()} otherwise,
where \tcode{Ds} is the pack of types consisting of
\tcode{decltype(auto(domains))...} with duplicate types removed.

\pnum
For a type \tcode{Tag}, subexpression \tcode{sndr}, and pack \tcode{envs},
\tcode{\exposid{COMPL-DOMAIN}(Tag, sndr, envs)}
is expression-equivalent to \tcode{D()},
where \tcode{D} is
the type of \tcode{get_completion_domain<Tag>(get_env(sndr), envs...)}
if that expression is well-formed or \tcode{envs} is an empty pack, and
\tcode{indeterminate_domain()} otherwise.

\pnum
For a scheduler \tcode{sch},
\tcode{\exposid{SCHED-ENV}(sch)} is an expression \tcode{o}
whose type satisfies \exposconcept{queryable}
such that \tcode{o.query(\brk{}get_start_scheduler)} is a prvalue
with the same type and value as \tcode{sch}, and
such that \tcode{o.query(get_domain)} is expression-equivalent to
\tcode{sch.query(get_domain)}.

\pnum
For two subexpressions \tcode{rcvr} and \tcode{expr},
\tcode{\exposid{SET-VALUE}(rcvr, expr)} is expression-equivalent to
\tcode{(expr, set_value(std::move(rcvr)))}
if the type of \tcode{expr} is \tcode{void};
otherwise, \tcode{set_value(std::move(rcvr), expr)}.
\tcode{\exposid{TRY-EVAL}(rcvr, expr)} is equivalent to:
\begin{codeblock}
try {
  expr;
} catch(...) {
  set_error(std::move(rcvr), current_exception());
}
\end{codeblock}
if \tcode{expr} is potentially-throwing; otherwise, \tcode{expr}.
\tcode{\exposid{TRY-SET-VALUE}(rcvr, expr)} is
\begin{codeblock}
@\exposid{TRY-EVAL}@(rcvr, @\exposid{SET-VALUE}@(rcvr, expr))
\end{codeblock}
except that \tcode{rcvr} is evaluated only once.

\begin{itemdecl}
template<class Tag, class Env, class Default>
  constexpr decltype(auto) @\exposid{query-with-default}@(
    Tag, const Env& env, Default&& value) noexcept(@\seebelow@);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{e} be the expression \tcode{Tag()(env)}
if that expression is well-formed;
otherwise, it is \tcode{static_cast<Default>(std::forward<Default>(value))}.

\pnum
\returns
\tcode{e}.

\pnum
\remarks
The expression in the \tcode{noexcept} clause is \tcode{noexcept(e)}.
\end{itemdescr}

\pnum
\begin{codeblock}
template<@\exposconcept{callable}@ Fun>
  requires is_nothrow_move_constructible_v<Fun>
struct @\exposid{emplace-from}@ {
  Fun @\exposid{fun}@;                                                      // \expos
  using type = @\exposid{call-result-t}@<Fun>;

  constexpr operator type() && noexcept(@\exposconcept{nothrow-callable}@<Fun>) {
    return std::move(fun)();
  }

  constexpr type operator()() && noexcept(@\exposconcept{nothrow-callable}@<Fun>) {
    return std::move(fun)();
  }
};
\end{codeblock}
\begin{note}
\exposid{emplace-from} is used to emplace non-movable types
into \tcode{tuple}, \tcode{optional}, \tcode{variant}, and similar types.
\end{note}

\pnum
\begin{codeblock}
struct @\exposid{on-stop-request}@ {
  inplace_stop_source& @\exposid{stop-src}@;       // \expos
  void operator()() noexcept { @\exposid{stop-src}@.request_stop(); }
};
\end{codeblock}

\pnum
\begin{codeblock}
template<class T@$_0$@, class T@$_1$@, @$\dotsc$,@ class T@$_n$@>
struct @\exposid{product-type}@ {       // \expos
  T@$_0$@ t@$_0$@;                // \expos
  T@$_1$@ t@$_1$@;                // \expos
    @\vdots@
  T@$_n$@ t@$_n$@;                // \expos

  template<size_t I, class Self>
  constexpr decltype(auto) @\exposid{get}@(this Self&& self) noexcept;      // \expos

  template<class Self, class Fn>
  constexpr decltype(auto) @\exposid{apply}@(this Self&& self, Fn&& fn)     // \expos
    noexcept(@\seebelow@);
};
\end{codeblock}

\pnum
\begin{note}
\exposid{product-type} is presented here in pseudo-code form
for the sake of exposition.
It can be approximated in standard \Cpp{} with a tuple-like implementation
that takes care to keep the type an aggregate
that can be used as the initializer of a structured binding declaration.
\end{note}
\begin{note}
An expression of type \exposid{product-type} is usable as
the initializer of a structured binding declaration\iref{dcl.struct.bind}.
\end{note}

\begin{itemdecl}
template<size_t I, class Self>
constexpr decltype(auto) @\exposid{get}@(this Self&& self) noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
auto& [...ts] = self;
return std::forward_like<Self>(ts...[I]);
\end{codeblock}
\end{itemdescr}

\begin{codeblock}
template<class Self, class Fn>
constexpr decltype(auto) @\exposid{apply}@(this Self&& self, Fn&& fn) noexcept(@\seebelow@);
\end{codeblock}

\begin{itemdescr}
\pnum
\constraints
The expression in the \tcode{return} statement below is well-formed.

\pnum
\effects
Equivalent to:
\begin{codeblock}
auto& [...ts] = self;
return std::forward<Fn>(fn)(std::forward_like<Self>(ts)...);
\end{codeblock}

\pnum
\remarks
The expression in the \tcode{noexcept} clause is \tcode{true}
if the \tcode{return} statement above is not potentially throwing;
otherwise, \tcode{false}.
\end{itemdescr}

\pnum
Let \exposconcept{valid-specialization} be the following concept:
\begin{codeblock}
namespace std::execution {
  template<template<class...> class T, class... Args>
  concept @\defexposconceptnc{valid-specialization}@ =                                // \expos
    requires { typename T<Args...>; };
}
\end{codeblock}

\begin{itemdecl}
template<class Tag, class Data = @\seebelow@, class... Child>
  constexpr auto @\exposid{make-sender}@(Tag tag, Data&& data, Child&&... child);
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
The following expressions are \tcode{true}:
\begin{itemize}
\item \tcode{\libconcept{semiregular}<Tag>}
\item \tcode{\exposconcept{movable-value}<Data>}
\item \tcode{(\libconcept{sender}<Child> \&\& ...)}
\item%
\tcode{\libconcept{dependent_sender}<Sndr> || \libconcept{sender_in}<Sndr>},
where \tcode{Sndr} is
\tcode{\exposid{basic-sender}<Tag, decay_t<Data>, decay_t<Child>...>}
as defined below.

 \recommended
If evaluation of \tcode{\libconcept{sender_in}<Sndr>} results in
an uncaught exception from
the evaluation of \tcode{get_completion_signatures<Sndr>()},
the implementation should include information about that exception in
the resulting diagnostic.
\end{itemize}

\pnum
\returns
A prvalue of
type \tcode{\exposid{basic-sender}<Tag, decay_t<Data>, decay_t<Child>...>}
that has been direct-list-initialized with the forwarded arguments,
where \exposid{basic-sender} is the following exposition-only class template except as noted below.

\pnum
\remarks
The default template argument for the \tcode{Data} template parameter
denotes an unspecified empty trivially copyable class type
that models \libconcept{semiregular}.
\end{itemdescr}

\pnum
\begin{codeblock}
namespace std::execution {
  template<class Sndr, class Rcvr>                              // \expos
  using @\exposid{state-type}@ = decay_t<@\exposid{call-result-t}@<
    decltype(@\exposid{impls-for}@<tag_of_t<Sndr>>::@\exposid{get-state}@), Sndr, Rcvr&>>;

  template<class Index, class Sndr, class Rcvr>                 // \expos
  using @\exposid{env-type}@ = @\exposid{call-result-t}@<
    decltype(@\exposid{impls-for}@<tag_of_t<Sndr>>::@\exposid{get-env}@), Index,
    @\exposid{state-type}@<Sndr, Rcvr>&, const Rcvr&>;

  template<class Sndr>
  using @\exposidnc{data-type}@ = decltype(declval<Sndr>().template @\exposidnc{get}@<1>());                // \expos

  template<class Sndr, size_t I = 0>
  using @\exposidnc{child-type}@ = decltype(declval<Sndr>().template @\exposidnc{get}@<I+2>());             // \expos

  template<class Sndr>
  using @\exposidnc{indices-for}@ = remove_reference_t<Sndr>::@\exposidnc{indices-for}@;                    // \expos

  template<class Sndr, class Rcvr>
  struct @\exposidnc{basic-state}@ {                                          // \expos
    @\exposid{basic-state}@(Sndr&& sndr, Rcvr&& rcvr) noexcept(@\seebelow@)
      : @\exposid{rcvr}@(std::move(rcvr))
      , @\exposid{state}@(@\exposid{impls-for}@<tag_of_t<Sndr>>::@\exposid{get-state}@(std::forward<Sndr>(sndr), @\exposid{rcvr}@)) { }

    Rcvr @\exposidnc{rcvr}@;                                                  // \expos
    @\exposidnc{state-type}@<Sndr, Rcvr> @\exposidnc{state}@;                               // \expos
  };
}
\end{codeblock}

\pnum
The expression in the \tcode{noexcept} clause of
the constructor of \exposid{basic-state} is
\begin{codeblock}
is_nothrow_move_constructible_v<Rcvr> &&
@\exposconcept{nothrow-callable}@<decltype(@\exposid{impls-for}@<tag_of_t<Sndr>>::@\exposid{get-state}@), Sndr, Rcvr&> &&
(@\libconcept{same_as}@<@\exposid{state-type}@<Sndr, Rcvr>, @\exposid{get-state-result}@> ||
 is_nothrow_constructible_v<@\exposid{state-type}@<Sndr, Rcvr>, @\exposid{get-state-result}@>)
\end{codeblock}
where \exposid{get-state-result} is
\begin{codeblock}
@\exposid{call-result-t}@<decltype(@\exposid{impls-for}@<tag_of_t<Sndr>>::@\exposid{get-state}@), Sndr, Rcvr&>.
\end{codeblock}

\pnum
\begin{codeblock}
namespace std::execution {
  template<class Sndr, class Rcvr, class Index>
    requires @\exposconcept{valid-specialization}@<@\exposid{env-type}@, Index, Sndr, Rcvr>
  struct @\exposidnc{basic-receiver}@ {                                       // \expos
    using receiver_concept = receiver_tag;

    using @\exposidnc{tag-t}@ = tag_of_t<Sndr>;                               // \expos
    using @\exposidnc{state-t}@ = @\exposidnc{state-type}@<Sndr, Rcvr>;                     // \expos
    static constexpr const auto& @\exposidnc{complete}@ = @\exposidnc{impls-for}@<@\exposidnc{tag-t}@>::@\exposidnc{complete}@;         // \expos

    template<class... Args>
    void set_value(Args&&... args) && noexcept {
      @\exposid{complete}@(Index(), @\exposidnc{op}@->@\exposid{state}@, @\exposidnc{op}@->@\exposid{rcvr}@, set_value_t(), std::forward<Args>(args)...);
    }

    template<class Error>
    void set_error(Error&& err) && noexcept {
      @\exposid{complete}@(Index(), @\exposidnc{op}@->@\exposid{state}@, @\exposidnc{op}@->@\exposid{rcvr}@, set_error_t(), std::forward<Error>(err));
    }

    void set_stopped() && noexcept {
      @\exposid{complete}@(Index(), @\exposidnc{op}@->@\exposid{state}@, @\exposidnc{op}@->@\exposid{rcvr}@, set_stopped_t());
    }

    auto get_env() const noexcept -> @\exposid{env-type}@<Index, Sndr, Rcvr> {
      return @\exposid{impls-for}@<@\exposid{tag-t}@>::@\exposid{get-env}@(Index(), @\exposidnc{op}@->@\exposid{state}@, @\exposidnc{op}@->@\exposid{rcvr}@);
    }

    @\exposidnc{basic-state}@<Sndr, Rcvr>* @\exposidnc{op}@;                                // \expos
  };
}
\end{codeblock}

\begin{codeblock}
namespace std::execution {
  constexpr auto @\exposidnc{connect-all}@ = @\seebelownc@;                       // \expos

  template<class Sndr, class Rcvr>
  using @\exposidnc{connect-all-result}@ = @\exposidnc{call-result-t}@<                     // \expos
    decltype(@\exposid{connect-all}@), @\exposid{basic-state}@<Sndr, Rcvr>*, Sndr, @\exposid{indices-for}@<Sndr>>;
}
\end{codeblock}

\pnum
The object \exposid{connect-all} is initialized with
a callable object equivalent to the following lambda:
\begin{itemdecl}
[]<class Sndr, class Rcvr, size_t... Is>(
  @\exposid{basic-state}@<Sndr, Rcvr>* op, Sndr&& sndr, index_sequence<Is...>) noexcept(@\seebelow@)
    -> decltype(auto) {
    auto& [_, data, ...child] = sndr;
    return @\exposid{product-type}@{connect(
      std::forward_like<Sndr>(child),
      @\exposid{basic-receiver}@<Sndr, Rcvr, integral_constant<size_t, Is>>{op})...};
  }
\end{itemdecl}

\begin{itemdescr}
\pnum
\constraints
The expression in the \tcode{return} statement is well-formed.

\pnum
\remarks
The expression in the \tcode{noexcept} clause is \tcode{true}
if the \tcode{return} statement is not potentially throwing;
otherwise, \tcode{false}.
\end{itemdescr}

\pnum
\begin{codeblock}
namespace std::execution {
  template<class Sndr, class Rcvr>
    requires @\exposconcept{valid-specialization}@<@\exposid{state-type}@, Sndr, Rcvr> &&
             @\exposconcept{valid-specialization}@<@\exposid{connect-all-result}@, Sndr, Rcvr>
  struct @\exposidnc{basic-operation}@ : @\exposidnc{basic-state}@<Sndr, Rcvr> {            // \expos
    using operation_state_concept = operation_state_tag;
    using @\exposidnc{tag-t}@ = tag_of_t<Sndr>;                               // \expos

    @\exposidnc{connect-all-result}@<Sndr, Rcvr> @\exposidnc{inner-ops}@;                   // \expos

    @\exposidnc{basic-operation}@(Sndr&& sndr, Rcvr&& rcvr) noexcept(@\seebelownc@)               // \expos
      : @\exposid{basic-state}@<Sndr, Rcvr>(std::forward<Sndr>(sndr), std::move(rcvr)),
        @\exposid{inner-ops}@(@\exposid{connect-all}@(this, std::forward<Sndr>(sndr), @\exposid{indices-for}@<Sndr>()))
    {}

    void start() & noexcept {
      auto& [...ops] = @\exposid{inner-ops}@;
      @\exposid{impls-for}@<@\exposid{tag-t}@>::@\exposid{start}@(this->@\exposid{state}@, this->@\exposid{rcvr}@, ops...);
    }
  };
}
\end{codeblock}

\pnum
The expression in the \tcode{noexcept} clause of
the constructor of \exposid{basic-operation} is:
\begin{codeblock}
is_nothrow_constructible_v<@\exposid{basic-state}@<Self, Rcvr>, Self, Rcvr> &&
noexcept(@\exposid{connect-all}@(this, std::forward<Sndr>(sndr), @\exposid{indices-for}@<Sndr>()))
\end{codeblock}

\pnum
\begin{codeblock}
namespace std::execution {
  struct @\exposidnc{default-impls}@ {                                        // \expos
    static constexpr auto @\exposidnc{get-env}@ = @\seebelownc@;                  // \expos
    static constexpr auto @\exposidnc{get-state}@ = @\seebelownc@;                // \expos
    static constexpr auto @\exposidnc{start}@ = @\seebelownc@;                    // \expos
    static constexpr auto @\exposidnc{complete}@ = @\seebelownc@;                 // \expos

    template<class Sndr, class... Env>
      static consteval void @\exposidnc{check-types}@();                      // \expos
  };

  template<class Tag>
  struct @\exposidnc{impls-for}@ : @\exposidnc{default-impls}@ {};                          // \expos
}
\end{codeblock}

\pnum
The member \tcode{\exposid{default-impls}::\exposid{get-env}}
is initialized with a callable object equivalent to the following lambda:
\begin{codeblock}
[](auto, auto&, const auto& rcvr) noexcept -> decltype(auto) {
  return @\exposid{FWD-ENV}@(get_env(rcvr));
}
\end{codeblock}

\pnum
The member \tcode{\exposid{default-impls}::\exposid{get-state}}
is initialized with a callable object equivalent to the following lambda:
\begin{codeblock}
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept -> decltype(auto) {
  auto& [_, data, ...child] = sndr;
  return @\exposid{allocator-aware-forward}@(std::forward_like<Sndr>(data), rcvr);
}
\end{codeblock}

\pnum
The member \tcode{\exposid{default-impls}::\exposid{start}}
is initialized with a callable object equivalent to the following lambda:
\begin{codeblock}
[](auto&, auto&, auto&... ops) noexcept -> void {
  (execution::start(ops), ...);
}
\end{codeblock}

\pnum
The member \tcode{\exposid{default-impls}::\exposid{complete}}
is initialized with a callable object equivalent to the following lambda:
\begin{codeblock}
[]<class Index, class Rcvr, class Tag, class... Args>(
  Index, auto& state, Rcvr& rcvr, Tag, Args&&... args) noexcept
    -> void requires @\exposconcept{callable}@<Tag, Rcvr, Args...> {
  static_assert(Index::value == 0);
  Tag()(std::move(rcvr), std::forward<Args>(args)...);
}
\end{codeblock}

\indexlibrarymember{\exposid{check-types}}{\exposid{default-impls}}%
\begin{itemdecl}
template<class Sndr, class... Env>
  static consteval void @\exposid{default-impls}@::@\exposid{check-types}@();
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{Is} be the pack of integral template arguments of
the \tcode{integer_sequence} specialization denoted by
\tcode{\exposid{indices-for}<Sndr>}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
((void)get_completion_signatures<@\exposid{child-type}@<Sndr, Is>, @\exposid{FWD-ENV-T}@(Env)...>(), ...);
\end{codeblock}

\pnum
\begin{note}
For any types \tcode{T} and \tcode{S}, and pack \tcode{E},
let \tcode{e} be the expression
\tcode{\exposid{impls-for}<T>::\exposid{check-types}<S, E...>()}.
Then exactly one of the following is \tcode{true}:
\begin{itemize}
\item \tcode{e} is ill-formed, or
\item the evaluation of \tcode{e} exits with an exception, or
\item \tcode{e} is a core constant expression.
\end{itemize}
When \tcode{e} is a core constant expression,
the pack \tcode{S, E...} uniquely determines a set of completion signatures.
\end{note}
\end{itemdescr}

\pnum
\begin{codeblock}
namespace std::execution {
  template<class Tag, class Data, class... Child>
  struct @\exposidnc{basic-sender}@ : @\exposidnc{product-type}@<Tag, Data, Child...> {     // \expos
    using sender_concept = sender_tag;
    using @\exposidnc{indices-for}@ = index_sequence_for<Child...>;           // \expos

    decltype(auto) get_env() const noexcept {
      auto& [_, data, ...child] = *this;
      return @\exposid{impls-for}@<Tag>::@\exposid{get-attrs}@(data, child...);
    }

    template<@\exposconcept{decays-to}@<@\exposid{basic-sender}@> Self, @\libconcept{receiver}@ Rcvr>
    auto connect(this Self&& self, Rcvr rcvr) noexcept(@\seebelow@)
      -> @\exposid{basic-operation}@<Self, Rcvr> {
      return {std::forward<Self>(self), std::move(rcvr)};
    }

    template<@\exposconcept{decays-to}@<@\exposid{basic-sender}@> Self, class... Env>
    static constexpr auto get_completion_signatures();
  };
}
\end{codeblock}

\pnum
It is unspecified whether a specialization of \exposid{basic-sender}
is an aggregate.

\pnum
An expression of type \exposid{basic-sender} is usable as
the initializer of a structured binding declaration\iref{dcl.struct.bind}.

\pnum
The expression in the \tcode{noexcept} clause of
the \tcode{connect} member function of \exposid{basic-sender} is:
\begin{codeblock}
is_nothrow_constructible_v<@\exposid{basic-operation}@<Self, Rcvr>, Self, Rcvr>
\end{codeblock}

\indexlibrarymember{get_completion_signatures}{\exposid{basic-sender}}%
\begin{itemdecl}
template<class Tag, class Data, class... Child>
  template<@\exposconcept{decays-to}@<@\exposid{basic-sender}@> Sndr, class... Env>
    constexpr auto @\exposid{basic-sender}@<Tag, Data, Child...>::get_completion_signatures();
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{Rcvr} be the type of a receiver whose
environment has type \tcode{E}, where
\tcode{E} is the first type in the list \tcode{Env..., env<>}.
Let \tcode{\placeholder{CHECK-TYPES}()} be the expression
\tcode{\exposid{impls-for}<Tag>::template \exposid{check-types}<\linebreak{}Sndr, E>()}, and
let \tcode{CS} be a type determined as follows:

\begin{itemize}
\item%
If \tcode{\exposid{CHECK-TYPES}()} is a core constant expression,
let \tcode{op} be an lvalue subexpression
whose type is \tcode{connect_result_t<Sndr, Rcvr>}.
Then \tcode{CS} is the specialization of \tcode{completion_signatures}
the set of whose template arguments
correspond to the set of completion operations
that are potentially evaluated\iref{basic.def.odr}
as a result of evaluating \tcode{op.start()}.

\item%
Otherwise, \tcode{CS} is \tcode{completion_signatures<>}.
\end{itemize}

\pnum
\constraints
\tcode{\exposid{CHECK-TYPES}()} is a well-formed expression.

\pnum
\effects
Equivalent to:
\begin{codeblock}
@\exposid{CHECK-TYPES}@();
return CS();
\end{codeblock}
\end{itemdescr}

\pnum
\indexlibraryglobal{\exposid{overload-set}}
%%FIXME: Should this be in a namespace?
\begin{codeblock}
template<class... Fns>
struct @\exposid{overload-set}@ : Fns... {
  using Fns::operator()...;
};
\end{codeblock}

\pnum
\indexlibraryglobal{\exposid{not-a-sender}}
\indexlibrarymember{get_completion_signatures}{\exposid{not-a-sender}}
%%FIXME: Should this be in a namespace?
\begin{codeblock}
struct @\exposid{not-a-sender}@ {
  using sender_concept = sender_tag;

  template<class Sndr>
    static consteval auto get_completion_signatures() -> completion_signatures<> {
      throw @\placeholder{unspecified-exception}@();
  }
};
\end{codeblock}

\pnum
\indexlibraryglobal{\exposid{not-a-scheduler}}%
\indexlibrarymember{schedule}{\exposid{not-a-sender}}%
\begin{codeblock}
struct @\exposid{not-a-scheduler}@ {
  using scheduler_concept = scheduler_tag;

  constexpr auto schedule() const noexcept {
    return @\exposid{not-a-sender}@();
  }
};
\end{codeblock}

\pnum
\indexlibraryglobal{\exposid{decay-copyable-result-datums}}
%%FIXME: Should this be in a namespace?
\begin{codeblock}
constexpr void @\exposid{decay-copyable-result-datums}@(auto cs) {
  cs.@\exposid{for-each}@([]<class Tag, class... Ts>(Tag(*)(Ts...)) {
    if constexpr (!(is_constructible_v<decay_t<Ts>, Ts> &&...))
      throw @\placeholder{unspecified-exception}@();
  });
}
\end{codeblock}

\begin{itemdecl}
template<class T, class Context>
  decltype(auto) @\exposid{allocator-aware-forward}@(T&& obj, Context&& context);       // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\exposid{allocator-aware-forward} is an exposition-only function template
used to either
create a new object of type \tcode{remove_cvref_t<T>} from \tcode{obj}
or forward \tcode{obj} depending on whether an allocator is available.
If the environment associated with \tcode{context} provides an allocator
(i.e., the expression \tcode{get_allocator(get_env(context))} is valid),
let \exposid{alloc} be the result of this expression
and let \tcode{P} be \tcode{remove_cvref_t<T>}.

\pnum
\returns
\begin{itemize}
\item
If \exposid{alloc} is not defined, returns \tcode{std::forward<T>(obj)},
\item
otherwise if \tcode{P} is a specialization of \exposid{product-type},
returns an object of type \tcode{P} whose elements are initialized using
\begin{codeblock}
make_obj_using_allocator<decltype(e)>(@\exposid{alloc}@, std::forward_like<T>(e))
\end{codeblock}
where \tcode{e} is the corresponding element of \tcode{obj},
\item
otherwise, returns \tcode{make_obj_using_allocator<P>(\exposid{alloc}, std::forward<T>(obj))}.
\end{itemize}
\end{itemdescr}

\indexlibraryglobal{\exposid{call-with-default}}
\begin{itemdecl}
template<class Fn, class Default, class... Args>
  constexpr decltype(auto) @\exposid{call-with-default}@(
    Fn&& fn, Default&& value, Args&&... args) noexcept(@\seebelow@);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{expr} be the expression
\tcode{std::forward<Fn>(fn)(std::forward<Args>(args)...)}
if that expression is well-formed;
otherwise, it is \tcode{static_cast<Default>(std::forward<Default>(value))}.

\pnum
\returns
\tcode{expr}.

\pnum
\remarks
The expression in the \tcode{noexcept} clause is \tcode{noexcept(expr)}.
\end{itemdescr}

\pnum
\indexlibraryglobal{\exposid{inline-attrs}}%
\begin{codeblock}
template<class Tag>
struct @\exposid{inline-attrs}@ {
  @\seebelow@
};
\end{codeblock}

\pnum
For a subexpression \tcode{env},
\tcode{\exposid{inline-attrs}<Tag>\{\}.query(get_completion_scheduler<Tag>, env)}
is expres\-sion-equivalent to \tcode{get_scheduler(env)}.

\pnum
For a subexpression \tcode{env},
\tcode{\exposid{inline-attrs}<Tag>\{\}.query(get_completion_domain<Tag>, env)}
is expression-equivalent to \tcode{get_domain(env)}.

\rSec2[exec.snd.concepts]{Sender concepts}

\pnum
The \libconcept{sender} concept defines
the requirements for a sender type\iref{exec.async.ops}.
The \libconcept{sender_in} concept defines
the requirements for a sender type
that can create asynchronous operations given an associated environment type.
The exposition-only concept \exposconcept{sender-to} defines
the requirements for a sender type
that can connect with a specific receiver type.
The \tcode{get_env} customization point object is used to access
a sender's associated attributes.
The connect customization point object is used to connect\iref{exec.async.ops}
a sender and a receiver to produce an operation state.

\indexlibraryglobal{\exposid{is-dependent-sender-helper}}%
\begin{codeblock}
namespace std::execution {
  template<auto>
    concept @\defexposconcept{is-constant}@ = true;                                 // \expos

  template<class Sndr>
    concept @\defexposconcept{is-sender}@ =                                         // \expos
      @\libconcept{derived_from}@<typename Sndr::sender_concept, sender_tag>;

  template<class Sndr>
    concept @\defexposconcept{enable-sender}@ =                                     // \expos
      @\exposconcept{is-sender}@<Sndr> ||
      @\exposconcept{is-awaitable}@<Sndr, @\exposid{env-promise}@<env<>>>;                 // \ref{exec.awaitable}

  template<class Sndr>
    inline constexpr bool enable_sender = @\exposconcept{enable-sender}@<Sndr>;

  template<class Sndr>
    consteval bool @\exposidnc{is-dependent-sender-helper}@() try {           // \expos
      get_completion_signatures<Sndr>();
      return false;
    } catch (dependent_sender_error&) {
      return true;
    }

  template<class Sndr>
    concept @\deflibconcept{sender}@ =
      enable_sender<remove_cvref_t<Sndr>> &&
      requires (const remove_cvref_t<Sndr>& sndr) {
        { get_env(sndr) } -> @\exposconcept{queryable}@;
      } &&
      @\libconcept{move_constructible}@<remove_cvref_t<Sndr>> &&
      @\libconcept{constructible_from}@<remove_cvref_t<Sndr>, Sndr>;

  template<class Sndr, class... Env>
    concept @\deflibconcept{sender_in}@ =
      @\libconcept{sender}@<Sndr> &&
      (sizeof...(Env) <= 1) &&
      (@\exposconcept{queryable}@<Env> &&...) &&
      @\exposconcept{is-constant}@<get_completion_signatures<Sndr, Env...>()>;

  template<class Sndr>
    concept @\deflibconcept{dependent_sender}@ =
      @\libconcept{sender}@<Sndr> && bool_constant<@\exposid{is-dependent-sender-helper}@<Sndr>()>::value;

  template<class Sndr, class Rcvr>
    concept @\defexposconcept{sender-to}@ =                                         // \expos
      @\libconcept{sender_in}@<Sndr, env_of_t<Rcvr>> &&
      @\exposconcept{receiver-of}@<Rcvr, completion_signatures_of_t<Sndr, env_of_t<Rcvr>>> &&
      requires (Sndr&& sndr, Rcvr&& rcvr) {
        connect(std::forward<Sndr>(sndr), std::forward<Rcvr>(rcvr));
      };
}
\end{codeblock}

\pnum
For a type \tcode{Sndr}, if
\tcode{\libconcept{sender}<Sndr>} is \tcode{true} and
\tcode{\libconcept{dependent_sender}<Sndr>} is \tcode{false},
then \tcode{Sndr} is a non-dependent sender\iref{exec.async.ops}.

\pnum
Given a subexpression \tcode{sndr},
let \tcode{Sndr} be \tcode{decltype((sndr))} and
let \tcode{rcvr} be a receiver
with an associated environment whose type is \tcode{Env}.
A completion operation is a \defnadj{permissible}{completion}
for \tcode{Sndr} and \tcode{Env}
if its completion signature appears in the argument list of the specialization of \tcode{completion_signatures} denoted by
\tcode{completion_signatures_of_t<Sndr, Env>}.
\tcode{Sndr} and \tcode{Env} model \tcode{\libconcept{sender_in}<Sndr, Env>}
if all the completion operations
that are potentially evaluated by connecting \tcode{sndr} to \tcode{rcvr} and
starting the resulting operation state
are permissible completions for \tcode{Sndr} and \tcode{Env}.

\pnum
\remarks
Pursuant to \ref{namespace.std},
users may specialize \tcode{enable_sender} to
\tcode{true} for cv-unqualified program-defined types that
model \libconcept{sender}, and
\tcode{false} for types that do not.
Such specializations shall
be usable in constant expressions\iref{expr.const.init} and
have type \tcode{const bool}.

\pnum
The exposition-only concepts
\exposconcept{sender-of} and \exposconcept{sender-in-of}
define the requirements for a sender type
that completes with a given unique set of value result types.
\begin{codeblock}
namespace std::execution {
  template<class... As>
    using @\exposid{value-signature}@ = set_value_t(As...);             // \expos

  template<class Sndr, class SetValue, class... Env>
    concept @\defexposconcept{sender-in-of-impl}@ =                             // \expos
      @\libconcept{sender_in}@<Sndr, Env...> &&
      @\exposid{MATCHING-SIG}@(SetValue,                                // see \ref{exec.general}
                   @\exposid{gather-signatures}@<set_value_t,           // see \ref{exec.cmplsig}
                                     completion_signatures_of_t<Sndr, Env...>,
                                     @\exposid{value-signature}@,
                                     type_identity_t>);

  template<class Sndr, class Env, class... Values>
    concept @\defexposconcept{sender-in-of}@ =                                  // \expos
      @\exposconcept{sender-in-of-impl}@<Sndr, set_value_t(Values...), Env>;

  template<class Sndr, class... Values>
    concept @\defexposconcept{sender-of}@ =                                     // \expos
      @\exposconcept{sender-in-of-impl}@<Sndr, set_value_t(Values...)>;
}
\end{codeblock}

\pnum
Let \tcode{sndr} be an expression
such that \tcode{decltype((sndr))} is \tcode{Sndr}.
The type \tcode{tag_of_t<Sndr>} is as follows:
\begin{itemize}
\item
If the declaration
\begin{codeblock}
auto&& [tag, data, ...children] = sndr;
\end{codeblock}
would be well-formed, \tcode{tag_of_t<Sndr>} is
an alias for \tcode{decltype(auto(tag))}.
\item
Otherwise, \tcode{tag_of_t<Sndr>} is ill-formed.
\end{itemize}

\pnum
Let \exposconcept{sender-for} be an exposition-only concept defined as follows:
\begin{codeblock}
namespace std::execution {
  template<class Sndr, class Tag>
  concept @\defexposconcept{sender-for}@ =
    @\libconcept{sender}@<Sndr> &&
    @\libconcept{same_as}@<tag_of_t<Sndr>, Tag>;
}
\end{codeblock}

\pnum
For a type \tcode{T},
\tcode{\exposid{SET-VALUE-SIG}(T)} denotes the type \tcode{set_value_t()}
if \tcode{T} is \cv{} \tcode{void};
otherwise, it denotes the type \tcode{set_value_t(T)}.

\pnum
Library-provided sender types
\begin{itemize}
\item
always expose an overload of a member \tcode{connect}
that accepts an rvalue sender and
\item
only expose an overload of a member \tcode{connect}
that accepts an lvalue sender if they model \libconcept{copy_constructible}.
\end{itemize}

\rSec2[exec.awaitable]{Awaitable helpers}

\pnum
The sender concepts recognize awaitables as senders.
For \ref{exec}, an \defn{awaitable} is an expression
that would be well-formed as the operand of a \tcode{co_await} expression
within a given context.

\pnum
For a subexpression \tcode{c},
let \tcode{\exposid{GET-AWAITER}(c, p)} be expression-equivalent to
the series of transformations and conversions applied to \tcode{c}
as the operand of an \grammarterm{await-expression} in a coroutine,
resulting in lvalue \tcode{e} as described by \ref{expr.await},
where \tcode{p} is an lvalue referring to the coroutine's promise,
which has type \tcode{Promise}.
\begin{note}
This includes the invocation of
the promise type's \tcode{await_transform} member if any,
the invocation of the \tcode{operator co_await}
picked by overload resolution if any, and
any necessary implicit conversions and materializations.
\end{note}

Let \tcode{\exposid{GET-AWAITER}(c)} be
expression-equivalent to \tcode{\exposid{GET-AWAITER}(c, q)}
where \tcode{q} is an lvalue of
an unspecified empty class type \tcode{\placeholder{none-such}} that
lacks an \tcode{await_transform} member, and
where \tcode{coroutine_handle<\placeholder{none-such}>} behaves as
\tcode{coroutine_handle<void>}.

\pnum
Let \exposconcept{is-awaitable} be the following exposition-only concept:
\begin{codeblock}
namespace std {
  template<class T>
  concept @\exposconcept{await-suspend-result}@ = @\seebelow@;                     // \expos

  template<class A, class... Promise>
  concept @\defexposconcept{is-awaiter}@ =                                          // \expos
    requires (A& a, coroutine_handle<Promise...> h) {
      a.await_ready() ? 1 : 0;
      { a.await_suspend(h) } -> @\exposconcept{await-suspend-result}@;
      a.await_resume();
    };

  template<class C, class... Promise>
  concept @\defexposconcept{is-awaitable}@ =                                        // \expos
    requires (C (*fc)() noexcept, Promise&... p) {
      { @\exposid{GET-AWAITER}@(fc(), p...) } -> @\exposconcept{is-awaiter}@<Promise...>;
    };
}
\end{codeblock}

\tcode{\defexposconcept{await-suspend-result}<T>} is \tcode{true}
if and only if one of the following is \tcode{true}:
\begin{itemize}
\item \tcode{T} is \tcode{void}, or
\item \tcode{T} is \tcode{bool}, or
\item \tcode{T} is a specialization of \tcode{coroutine_handle}.
\end{itemize}

\pnum
For a subexpression \tcode{c}
such that \tcode{decltype((c))} is type \tcode{C}, and
an lvalue \tcode{p} of type \tcode{Promise},
\tcode{\exposid{await-result-\newline type}<C, Promise>} denotes
the type \tcode{decltype(\exposid{GET-AWAITER}(c, p).await_resume())} and
\tcode{\exposid{await-re\-sult-type}<C>} denotes
the type \tcode{decltype(\exposid{GET-AWAITER}(c).await_resume())}.

\pnum
Let \exposid{with-await-transform} be the exposition-only class template:
\begin{codeblock}
namespace std::execution {
  template<class T, class Promise>
    concept @\defexposconcept{has-as-awaitable}@ =                                  // \expos
      requires (T&& t, Promise& p) {
        { std::forward<T>(t).as_awaitable(p) } -> @\exposconcept{is-awaitable}@<Promise&>;
      };

  template<class Derived>
    struct @\exposid{with-await-transform}@ {                               // \expos
      template<class T>
        T&& await_transform(T&& value) noexcept {
          return std::forward<T>(value);
        }

      template<@\exposconcept{has-as-awaitable}@<Derived> T>
        auto await_transform(T&& value)
          noexcept(noexcept(std::forward<T>(value).as_awaitable(declval<Derived&>())))
          -> decltype(std::forward<T>(value).as_awaitable(declval<Derived&>())) {
          return std::forward<T>(value).as_awaitable(static_cast<Derived&>(*this));
        }
    };
}
\end{codeblock}

\pnum
Let \exposid{env-promise} be the exposition-only class template:
\begin{codeblock}
namespace std::execution {
  template<class Env>
  struct @\exposid{env-promise}@ : @\exposid{with-await-transform}@<@\exposid{env-promise}@<Env>> { // \expos
    @\unspec@ get_return_object() noexcept;
    @\unspec@ initial_suspend() noexcept;
    @\unspec@ final_suspend() noexcept;
    void unhandled_exception() noexcept;
    void return_void() noexcept;
    coroutine_handle<> unhandled_stopped() noexcept;

    const Env& get_env() const noexcept;
  };
}
\end{codeblock}
\begin{note}
Specializations of \exposid{env-promise} are used only for the purpose of type computation;
its members need not be defined.
\end{note}

\rSec2[exec.domain.indeterminate]{\tcode{execution::indeterminate_domain}}

\pnum
\indexlibraryglobal{indeterminate_domain}%
\indexlibraryctor{indeterminate_domain}%
\begin{codeblock}
namespace std::execution {
  template<class... Domains>
  struct indeterminate_domain {
    indeterminate_domain() = default;
    constexpr indeterminate_domain(auto&&) noexcept {}

    template<class Tag, @\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env>
      static constexpr decltype(auto) transform_sender(Tag, Sndr&& sndr, const Env& env)
        noexcept(@\seebelow@);
  };
}
\end{codeblock}

\indexlibrarymember{transform_sender}{indeterminate_domain}%
\begin{itemdecl}
template<class Tag, @\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env>
  static constexpr decltype(auto) transform_sender(Tag, Sndr&& sndr, const Env& env)
    noexcept(@\seebelow@);
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
For each type \tcode{D} in \tcode{Domains...},
the expression
\begin{codeblock}
D().transform_sender(Tag(), std::forward<Sndr>(sndr), env)
\end{codeblock}
is either ill-formed or has the same decayed type as
\tcode{default_domain().transform_sender(Tag(), std::forward<Sndr>(sndr), env)}.

\pnum
\returns
\tcode{default_domain().transform_sender(Tag(), std::forward<Sndr>(sndr), env)}.

\pnum
\remarks
For a pack of types \tcode{Ds},
\begin{codeblock}
common_type_t<indeterminate_domain<Domains...>, indeterminate_domain<Ds...>>
\end{codeblock}
is \tcode{indeterminate_domain<Us...>}
where \tcode{Us} is a pack that contains each type in
\tcode{Domains..., Ds...} except with duplicate types removed.
For a type \tcode{D} that is not a specialization of \tcode{indeterminate_domain},
\tcode{common_type_t<indeterminate_domain<Domains...>, D>}
is \tcode{D} if \tcode{Domains} is an empty pack, and
\tcode{common_type_t<indeterminate_domain<Domains...>, indeterminate_domain<D>>}
otherwise.
\end{itemdescr}

\rSec2[exec.domain.default]{\tcode{execution::default_domain}}

\pnum
\begin{codeblock}
namespace std::execution {
  struct @\libglobal{default_domain}@ {
    template<class Tag, @\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env>
      static constexpr decltype(auto) transform_sender(Tag, Sndr&& sndr, const Env& env)
        noexcept(@\seebelow@);

    template<class Tag, @\libconcept{sender}@ Sndr, class... Args>
      static constexpr decltype(auto) apply_sender(Tag, Sndr&& sndr, Args&&... args)
        noexcept(@\seebelow@);
  };
}
\end{codeblock}

\indexlibrarymember{transform_sender}{default_domain}%
\begin{itemdecl}
template<class Tag, @\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env>
constexpr decltype(auto) transform_sender(Tag, Sndr&& sndr, const Env& env)
  noexcept(@\seebelow@);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{e} be the expression
\begin{codeblock}
tag_of_t<Sndr>().transform_sender(Tag(), std::forward<Sndr>(sndr), env)
\end{codeblock}
if that expression is well-formed;
otherwise, \tcode{static_cast<Sndr>(std::forward<Sndr>(sndr))}.

\pnum
\returns
\tcode{e}.

\pnum
\remarks
The exception specification is equivalent to \tcode{noexcept(e)}.
\end{itemdescr}

\indexlibrarymember{apply_sender}{default_domain}%
\begin{itemdecl}
template<class Tag, @\libconcept{sender}@ Sndr, class... Args>
constexpr decltype(auto) apply_sender(Tag, Sndr&& sndr, Args&&... args)
  noexcept(@\seebelow@);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{e} be the expression
\begin{codeblock}
  Tag().apply_sender(std::forward<Sndr>(sndr), std::forward<Args>(args)...)
\end{codeblock}

\pnum
\constraints
\tcode{e} is a well-formed expression.

\pnum
\returns
\tcode{e}.

\pnum
\remarks
The exception specification is equivalent to \tcode{noexcept(e)}.
\end{itemdescr}

\rSec2[exec.snd.transform]{\tcode{execution::transform_sender}}

\indexlibraryglobal{transform_sender}%
\begin{itemdecl}
namespace std::execution {
  template<@\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env>
    constexpr decltype(auto) transform_sender(Sndr&& sndr, const Env& env)
      noexcept(@\seebelow@);
}
\end{itemdecl}

\begin{itemdescr}
\pnum
For a subexpression \tcode{s},
let \exposid{start-domain} be
\tcode{D()} where \tcode{D} is the decayed type of \tcode{get_domain(env)}
if that expression is well-formed, and
\tcode{default_domain} otherwise.

\pnum
Let \tcode{\exposid{completion-domain}(s)} be
\tcode{D()} where \tcode{D} is the decayed type of
\tcode{get_completion_domain<>(get_env(s), env)}
if that is well-formed;
otherwise, \tcode{D} is \tcode{default_domain}.

\pnum
Let \tcode{\exposid{transformed-sndr}(dom, tag, s)} be the expression
\begin{codeblock}
dom.transform_sender(tag, s, env)
\end{codeblock}
if that expression is well-formed; otherwise,
\begin{codeblock}
default_domain().transform_sender(tag, s, env)
\end{codeblock}
Let \tcode{\exposid{transform-recurse}(dom, tag, s)} be
the expression \tcode{\exposid{transformed-sndr}(dom, tag, s)}
if\newline \tcode{\exposid{transformed-sndr}(dom, tag, s)} and \exposid{s}
have the same type ignoring cv-qualifiers;
otherwise, it is
the expression \tcode{\exposid{transform-recurse}(dom2, tag, s2)}, where
\tcode{s2} is \tcode{\exposid{transformed-sender}(dom, tag, s)} and
\tcode{dom2} is \exposid{start-domain} if \tcode{tag} is \tcode{start}, and
\tcode{\exposid{completion-domain}(s2)} otherwise.

Let \exposid{tmp-sndr} be the expression
\begin{codeblock}
@\exposid{transform-recurse}@(@\exposid{completion-domain}@(sndr), set_value, sndr)
\end{codeblock}
and let \exposid{final-sndr} be the expression
\begin{codeblock}
@\exposid{transform-recurse}@(@\exposid{start-domain}@, start, @\exposid{tmp-sndr}@)
\end{codeblock}

\pnum
\returns
\exposid{final-sndr}.

\pnum
\remarks
The exception specification is equivalent to
\tcode{noexcept(\exposid{final-sndr})}.
\end{itemdescr}

\rSec2[exec.snd.apply]{\tcode{execution::apply_sender}}

\indexlibraryglobal{apply_sender}%
\begin{itemdecl}
namespace std::execution {
  template<class Domain, class Tag, @\libconcept{sender}@ Sndr, class... Args>
    constexpr decltype(auto) apply_sender(Domain dom, Tag, Sndr&& sndr, Args&&... args)
      noexcept(@\seebelow@);
}
\end{itemdecl}

\begin{itemdescr}
\pnum
Let $e$ be the expression
\begin{codeblock}
dom.apply_sender(Tag(), std::forward<Sndr>(sndr), std::forward<Args>(args)...)
\end{codeblock}
if that expression is well-formed; otherwise,
\begin{codeblock}
default_domain().apply_sender(Tag(), std::forward<Sndr>(sndr), std::forward<Args>(args)...)
\end{codeblock}

\pnum
\constraints
The expression $e$ is well-formed.

\pnum
\returns
$e$.

\pnum
\remarks
The exception specification is equivalent to \tcode{noexcept($e$)}.
\end{itemdescr}

\rSec2[exec.getcomplsigs]{\tcode{execution::get_completion_signatures}}

\indexlibraryglobal{get_completion_signatures}%
%%FIXME: Should this be in namespace std::execution?
\begin{itemdecl}
template<class Sndr, class... Env>
  consteval auto get_completion_signatures() -> @\exposconcept{valid-completion-signatures}@ auto;
\end{itemdecl}

\begin{itemdescr}
\pnum
Let $except$ be an rvalue subexpression of
an unspecified class type $Except$ such that
\tcode{\libconceptx{move_construc\-tible}{move_constructible}<$Except$> \&\& \libconcept{derived_from}<$Except$, exception>}
is \tcode{true}.
Let \tcode{\placeholder{CHECKED-COMPLSIGS}($e$)} be $e$
if $e$ is a core constant expression whose
type satisfies \exposconcept{valid-completion-signatures};
otherwise, it is the following expression:
\begin{codeblock}
(@$e$@, throw @$except$@, completion_signatures())
\end{codeblock}
Let \tcode{\placeholder{get-complsigs}<Sndr, Env...>()}
be expression-equivalent to
\tcode{remove_reference_t<Sndr>::tem\-plate get_completion_signatures<Sndr, Env...>()}.
Let \tcode{NewSndr} be \tcode{Sndr}
if \tcode{sizeof...(Env) == 0} is \tcode{true};
otherwise, \tcode{decltype($s$)}
where $s$ is the following expression:
\begin{codeblock}
transform_sender(
  declval<Sndr>(),
  declval<Env>()...)
\end{codeblock}

\pnum
\constraints
\tcode{sizeof...(Env) <= 1} is \tcode{true}.

\pnum
\effects
Equivalent to: \tcode{return $e$;}
where $e$ is expression-equivalent to the following:
\begin{itemize}
\item
\tcode{\placeholder{CHECKED-COMPLSIGS}(\placeholder{get-complsigs}<NewSndr, Env...>())}
if \tcode{\placeholder{get-complsigs}<NewSndr, Env\linebreak{}...>()}
is a well-formed expression.

\item
Otherwise,
\tcode{\placeholder{CHECKED-COMPLSIGS}(\placeholder{get-complsigs}<NewSndr>())}
if \tcode{\placeholder{get-complsigs}<NewSndr>()}
is a well-formed expression.

\item
Otherwise,
\begin{codeblock}
completion_signatures<
  @\exposid{SET-VALUE-SIG}@(@\exposid{await-result-type}@<NewSndr, @\exposid{env-promise}@<Env>...>),   // \ref{exec.snd.concepts}
  set_error_t(exception_ptr),
  set_stopped_t()>
\end{codeblock}
if \tcode{\exposconcept{is-awaitable}<NewSndr, \exposid{env-promise}<Env>...>}
is \tcode{true}.

\item
Otherwise,
\tcode{(throw \placeholder{dependent-sender-error}(), completion_signatures())}
if \tcode{sizeof...(\linebreak{}Env) == 0} is \tcode{true},
where \tcode{\placeholder{dependent-sender-error}} is
\tcode{dependent_sender_error} or
an unspecified type derived publicly and unambiguously from
\tcode{dependent_sender_error}.

\item
Otherwise,
\tcode{(throw $except$, completion_signatures())}.
\end{itemize}
\end{itemdescr}

\pnum
Given a type \tcode{Env}, if
\tcode{completion_signatures_of_t<Sndr>} and
\tcode{completion_signatures_of_t<Sndr, Env>}
are both well-formed,
the former shall be a superset of the latter,
with the difference corresponding to error or stopped completion operations.

\pnum
Let \tcode{rcvr} be an rvalue
whose type \tcode{Rcvr} models \libconcept{receiver}, and
let \tcode{Sndr} be the type of a sender
such that \tcode{\libconcept{sender_in}<Sndr, env_of_t<Rcvr>>} is \tcode{true}.
Let \tcode{Sigs...} be the template arguments of
the \tcode{completion_signatures} specialization
named by \tcode{completion_signatures_of_t<Sndr, env_of_t<Rcvr>>}.
Let \tcode{CSO} be a completion function.
If sender \tcode{Sndr} or its operation state cause
the expression \tcode{CSO(rcvr, args...)}
to be potentially evaluated\iref{basic.def.odr}
then there shall be a signature \tcode{Sig} in \tcode{Sigs...}
such that
\begin{codeblock}
@\exposid{MATCHING-SIG}@(@\exposid{decayed-typeof}@<CSO>(decltype(args)...), Sig)
\end{codeblock}
is \tcode{true}\iref{exec.general}.

\rSec2[exec.connect]{\tcode{execution::connect}}

\pnum
\tcode{connect} connects\iref{exec.async.ops} a sender with a receiver.

\pnum
The name \tcode{connect} denotes a customization point object.
For subexpressions \tcode{sndr} and \tcode{rcvr},
let \tcode{Sndr} be \tcode{decltype((sndr))} and
\tcode{Rcvr} be \tcode{decltype((rcvr))},
let \tcode{new_sndr} be the expression
\tcode{transform_sender(\newline sndr, get_env(rcvr))}
and let \tcode{DS} and \tcode{DR} be
\tcode{decay_t<decltype((new_sndr))>} and \tcode{decay_t<Rcvr>}, respectively.

\pnum
Let \exposid{connect-awaitable-promise} be the following exposition-only class:

\begin{codeblock}
namespace std::execution {
  struct @\exposid{connect-awaitable-promise}@ : @\exposid{with-await-transform}@<@\exposid{connect-awaitable-promise}@> {

    @\exposid{connect-awaitable-promise}@(DS&, DR& rcvr) noexcept : @\exposid{rcvr}@(rcvr) {}

    suspend_always initial_suspend() noexcept { return {}; }
    [[noreturn]] suspend_always final_suspend() noexcept { terminate(); }
    [[noreturn]] void unhandled_exception() noexcept { terminate(); }
    [[noreturn]] void return_void() noexcept { terminate(); }

    coroutine_handle<> unhandled_stopped() noexcept {
      set_stopped(std::move(@\exposid{rcvr}@));
      return noop_coroutine();
    }

    @\exposid{operation-state-task}@ get_return_object() noexcept {
      return @\exposid{operation-state-task}@{
        coroutine_handle<@\exposid{connect-awaitable-promise}@>::from_promise(*this)};
    }

    env_of_t<DR> get_env() const noexcept {
      return execution::get_env(@\exposid{rcvr}@);
    }

  private:
    DR& @\exposid{rcvr}@;                           // \expos
  };
}
\end{codeblock}

\pnum
Let \exposid{operation-state-task} be the following exposition-only class:
\begin{codeblock}
namespace std::execution {
  struct @\exposid{operation-state-task}@ {                              // \expos
    using operation_state_concept = operation_state_tag;
    using promise_type = @\exposid{connect-awaitable-promise}@;

    explicit @\exposid{operation-state-task}@(coroutine_handle<> h) noexcept : coro(h) {}
    @\exposid{operation-state-task}@(@\exposid{operation-state-task}@&&) = delete;
    ~@\exposid{operation-state-task}@() { @\exposid{coro}@.destroy(); }

    void start() & noexcept {
      @\exposid{coro}@.resume();
    }

  private:
    coroutine_handle<> @\exposid{coro}@;                                    // \expos
  };
}
\end{codeblock}

\pnum
Let \tcode{V} name the type
\tcode{\exposid{await-result-type}<DS, \exposid{connect-awaitable-promise}>},
let \tcode{Sigs} name the type
\begin{codeblock}
completion_signatures<
  @\exposid{SET-VALUE-SIG}@(V),         // see~\ref{exec.snd.concepts}
  set_error_t(exception_ptr),
  set_stopped_t()>
\end{codeblock}
and let \exposid{connect-awaitable} be an exposition-only coroutine
defined as follows:
\begin{codeblock}
namespace std::execution {
  template<class Fun, class... Ts>
  auto @\exposid{suspend-complete}@(Fun fun, Ts&&... as) noexcept {    // \expos
    auto fn = [&, fun]() noexcept { fun(std::forward<Ts>(as)...); };

    struct awaiter {
      decltype(fn) @\exposid{fn}@;                                     // \expos

      static constexpr bool await_ready() noexcept { return false; }
      void await_suspend(coroutine_handle<>) noexcept { @\exposid{fn}@(); }
      [[noreturn]] void await_resume() noexcept { unreachable(); }
    };
    return awaiter{fn};
  }

  @\exposid{operation-state-task}@ @\exposid{connect-awaitable}@(DS sndr, DR rcvr) requires @\exposconcept{receiver-of}@<DR, Sigs> {
    exception_ptr ep;
    try {
      if constexpr (@\libconcept{same_as}@<V, void>) {
        co_await std::move(sndr);
        co_await @\exposid{suspend-complete}@(set_value, std::move(rcvr));
      } else {
        co_await @\exposid{suspend-complete}@(set_value, std::move(rcvr), co_await std::move(sndr));
      }
    } catch(...) {
      ep = current_exception();
    }
    co_await @\exposid{suspend-complete}@(set_error, std::move(rcvr), std::move(ep));
  }
}
\end{codeblock}

\pnum
The expression \tcode{connect(sndr, rcvr)} is expression-equivalent to:
\begin{itemize}
\item
\tcode{new_sndr.connect(rcvr)} if that expression is well-formed.

\mandates
The type of the expression above satisfies \libconcept{operation_state}.

\item
Otherwise, \tcode{\exposid{connect-awaitable}(new_sndr, rcvr)}.
\end{itemize}
Except that \tcode{rcvr} is evaluated only once.
The program is ill-formed, no diagnostic required,
if there exists an rvalue expression \tcode{rcvr2} such that:
\begin{itemize}
\item \tcode{decltype(rcvr2)} models \libconcept{receiver},
\item \tcode{noexcept(rcvr2)} is \tcode{true},
\item \tcode{is_same_v<decltype(get_env(rcvr2)), decltype(get_env(rcvr))>} is \tcode{true},
\item \tcode{noexcept(execution::connect(sndr, rcvr))} is \tcode{true}, and
\item \tcode{noexcept(execution::connect(sndr, rcvr2))}
is well-formed and evaluates to \tcode{false}.
\end{itemize}
\begin{note}
This allows determination of whether \tcode{connect} throws
with only the context of the environment,
such as within \tcode{get_completion_signatures}.
\end{note}

\mandates
The following are \tcode{true}:
\begin{itemize}
\item
\tcode{\libconcept{sender_in}<Sndr, env_of_t<Rcvr>>}
\item
\tcode{\exposconcept{receiver-of}<Rcvr, completion_signatures_of_t<Sndr, env_of_t<Rcvr>>>}
\end{itemize}

\rSec2[exec.factories]{Sender factories}

\rSec3[exec.schedule]{\tcode{execution::schedule}}

\pnum
\tcode{schedule} obtains a schedule sender\iref{exec.async.ops}
from a scheduler.

\pnum
The name \tcode{schedule} denotes a customization point object.
For a subexpression \tcode{sch},
the expression \tcode{schedule(sch)} is expression-equivalent to
\tcode{sch.schedule()}.

\pnum
\mandates
The type of \tcode{sch.schedule()} satisfies \libconcept{sender}.

\rSec3[exec.just]{\tcode{execution::just}, \tcode{execution::just_error}, \tcode{execution::just_stopped}}

\pnum
\tcode{just}, \tcode{just_error}, and \tcode{just_stopped} are sender factories
whose asynchronous operations complete synchronously in their start operation
with a value completion operation,
an error completion operation, or
a stopped completion operation, respectively.

\pnum
The names \tcode{just}, \tcode{just_error}, and \tcode{just_stopped} denote
customization point objects.
Let \exposid{just-cpo} be one of
\tcode{just}, \tcode{just_error}, or \tcode{just_stopped}.
For a pack of subexpressions \tcode{ts},
let \tcode{Ts} be the pack of types \tcode{decltype((ts))}.
The expression \tcode{\exposid{just-cpo}(ts...)} is ill-formed if
\begin{itemize}
\item
\tcode{(\exposconcept{movable-value}<Ts> \&\&...)} is \tcode{false}, or
\item
\exposid{just-cpo} is \tcode{just_error} and
\tcode{sizeof...(ts) == 1} is \tcode{false}, or
\item
\exposid{just-cpo} is \tcode{just_stopped} and
\tcode{sizeof...(ts) == 0} is \tcode{false}.
\end{itemize}

Otherwise, it is expression-equivalent to
\tcode{\exposid{make-sender}(\exposid{just-cpo}, \exposid{product-type}\{ts...\})}.

For \tcode{just}, \tcode{just_error}, and \tcode{just_stopped},
let \exposid{set-cpo} be
\tcode{set_value}, \tcode{set_error}, and \tcode{set_stopped}, respectively.
The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos}
is specialized for \exposid{just-cpo} as follows:
\begin{codeblock}
namespace std::execution {
  template<>
  struct @\exposid{impls-for}@<@\exposid{decayed-typeof}@<@\exposid{just-cpo}@>> : @\exposid{default-impls}@ {
    static constexpr auto @\exposid{start}@ =
      [](auto& state, auto& rcvr) noexcept -> void {
        auto& [...ts] = state;
        @\exposid{set-cpo}@(std::move(rcvr), std::move(ts)...);
      };
  };
}
\end{codeblock}

\rSec3[exec.read.env]{\tcode{execution::read_env}}

\pnum
\tcode{read_env} is a sender factory for a sender
whose asynchronous operation completes synchronously in its start operation
with a value completion result equal to
a value read from the receiver's associated environment.

\pnum
\tcode{read_env} is a customization point object.
For some query object \tcode{q},
the expression \tcode{read_env(q)} is expression-equivalent to
\tcode{\exposid{make-sender}(read_env, q)}.

\pnum
The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos}
is specialized for \tcode{read_env} as follows:
\indexlibraryglobal{\exposid{impls-for}<\exposid{decayed-typeof}<read_env>>}
\begin{codeblock}
namespace std::execution {
  template<>
  struct @\exposid{impls-for}@<@\exposid{decayed-typeof}@<read_env>> : @\exposid{default-impls}@ {
    static constexpr auto start =
      [](auto query, auto& rcvr) noexcept -> void {
        @\exposid{TRY-SET-VALUE}@(rcvr, query(get_env(rcvr)));
      };
  };

  template<class Sndr, class Env>
    static consteval void @\exposid{check-types}@();
}
\end{codeblock}

\indexlibrarymember{\exposid{check-types}}{\exposid{impls-for}<\exposid{decayed-typeof}<read_env>>}
\begin{itemdecl}
template<class Sndr, class Env>
  static consteval void @\exposid{check-types}@();
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{Q} be \tcode{decay_t<\exposid{data-type}<Sndr>>}.

\pnum
\throws
An exception of type
\tcode{\placeholder{unspecified-exception}}\iref{exec.snd.general} if
the expression \tcode{Q()(env)} is ill-formed or has type \tcode{void}, where
\tcode{env} is an lvalue subexpression whose type is \tcode{Env}.
\end{itemdescr}

\rSec2[exec.adapt]{Sender adaptors}

\rSec3[exec.adapt.general]{General}

\pnum
Subclause \ref{exec.adapt} specifies a set of sender adaptors.

\pnum
The bitwise inclusive \logop{or} operator is overloaded
for the purpose of creating sender chains.
The adaptors also support function call syntax with equivalent semantics.

\pnum
Unless otherwise specified:
\begin{itemize}
\item
A sender adaptor is prohibited from causing observable effects,
apart from moving and copying its arguments,
before the returned sender is connected with a receiver using \tcode{connect},
and \tcode{start} is called on the resulting operation state.
\item
A parent sender\iref{exec.async.ops} with a single child sender \tcode{sndr} has
an associated attribute object equal to
\tcode{\exposid{FWD-ENV}(get_env(sndr))}\iref{exec.fwd.env}
except that the
\tcode{get_completion_scheduler<\exposid{completion-tag}>} and
\tcode{get_completion_domain<\exposid{completion-tag}>}
queries are handled as described in \ref{exec.snd.general}.
\item
A parent sender with more than one child sender has
an associated attributes object equal to \tcode{env<>\{\}}
except that the
\tcode{get_completion_scheduler<\exposid{completion-tag}>} and
\tcode{get_completion_domain<\exposid{comple\-tion-tag}>}
queries are handled as described in \ref{exec.snd.general}.
\item
When a parent sender is connected to a receiver \tcode{rcvr},
any receiver used to connect a child sender has
an associated environment equal to \tcode{\exposid{FWD-ENV}(get_env(rcvr))}.
\item
An adaptor whose child senders are all non-dependent\iref{exec.async.ops}
is itself non-dependent.
\item
These requirements apply to any function
that is selected by the implementation of the sender adaptor.
\item
 \recommended
Implementations should use
the completion signatures of the adaptors
to communicate type errors to users and
to propagate any such type errors from child senders.
\end{itemize}

\pnum
If a sender returned from a sender adaptor specified in \ref{exec.adapt}
is specified to include \tcode{set_error_t(Err)}
among its set of completion signatures
where \tcode{decay_t<Err>} denotes the type \tcode{exception_ptr},
but the implementation does not potentially evaluate
an error completion operation with an \tcode{exception_ptr} argument,
the implementation is allowed to omit
the \tcode{exception_ptr} error completion signature from the set.

\rSec3[exec.adapt.obj]{Closure objects}

\indexlibrarymisc{\idxcode{operator"|}}{pipeable sender adaptor closure objects}%
\pnum
A \defnadj{pipeable}{sender adaptor closure object} is a function object
that accepts one or more \libconcept{sender} arguments and returns a \libconcept{sender}.
For a pipeable sender adaptor closure object \tcode{c} and
an expression \tcode{sndr}
such that \tcode{decltype((sndr))} models \libconcept{sender},
the following expressions are equivalent and yield a \libconcept{sender}:
\begin{codeblock}
c(sndr)
sndr | c
\end{codeblock}
Given an additional pipeable sender adaptor closure object \tcode{d},
the expression \tcode{c | d} produces
another pipeable sender adaptor closure object \tcode{e}:

\tcode{e} is a perfect forwarding call wrapper\iref{func.require}
with the following properties:
\begin{itemize}
\item
Its target object is an object \tcode{d2} of type \tcode{decltype(auto(d))}
direct-non-list-initialized with \tcode{d}.
\item
It has one bound argument entity,
an object \tcode{c2} of type \tcode{decltype(auto(c))}
direct-non-list-initialized with \tcode{c}.
\item
Its call pattern is \tcode{d2(c2(arg))},
where \tcode{arg} is the argument used in a function call expression of \tcode{e}.
\end{itemize}
The expression \tcode{c | d} is well-formed if and only if
the initializations of the state entities\iref{func.def} of \tcode{e}
are all well-formed.

\pnum
An object \tcode{t} of type \tcode{T} is
a pipeable sender adaptor closure object
if \tcode{T} models \tcode{\libconcept{derived_from}<sender_adaptor_closure<T>>},
\tcode{T} has no other base classes
of type \tcode{sender_adaptor_closure<U>} for any other type \tcode{U}, and
\tcode{T} does not satisfy \libconcept{sender}.

\pnum
The template parameter \tcode{D} for \tcode{sender_adaptor_closure} can be
an incomplete type.
Before any expression of type \cv{} \tcode{D} appears as
an operand to the \tcode{|} operator,
\tcode{D} shall be complete and
model \tcode{\libconcept{derived_from}<sender_adaptor_closure<D>>}.
The behavior of an expression involving an object of type \cv{} \tcode{D}
as an operand to the \tcode{|} operator is undefined
if overload resolution selects a program-defined \tcode{operator|} function.

\pnum
A \defnadj{pipeable}{sender adaptor object} is a customization point object
that accepts a \libconcept{sender} as its first argument and
returns a \libconcept{sender}.
If a pipeable sender adaptor object accepts only one argument,
then it is a pipeable sender adaptor closure object.

\pnum
If a pipeable sender adaptor object adaptor accepts more than one argument,
then let \tcode{sndr} be an expression
such that \tcode{decltype((sndr))} models \libconcept{sender},
let \tcode{args...} be arguments
such that \tcode{adaptor(sndr, args...)} is a well-formed expression
as specified below, and
let \tcode{BoundArgs} be a pack that denotes \tcode{decltype(auto(args))...}.
The expression \tcode{adaptor(args...)} produces
a pipeable sender adaptor closure object \tcode{f}
that is a perfect forwarding call wrapper with the following properties:
\begin{itemize}
\item
Its target object is a copy of adaptor.
\item
Its bound argument entities \tcode{bound_args} consist of
objects of types \tcode{BoundArgs...} direct-non-list-initialized with
\tcode{std::forward<decltype((args))>(args)...}, respectively.
\item
Its call pattern is \tcode{adaptor(rcvr, bound_args...)},
where \tcode{rcvr} is
the argument used in a function call expression of \tcode{f}.
\end{itemize}
The expression \tcode{adaptor(args...)} is well-formed if and only if
the initializations of the bound argument entities of the result,
as specified above, are all well-formed.

\rSec3[exec.write.env]{\tcode{execution::write_env}}

\pnum
\tcode{write_env} is a sender adaptor
that accepts a sender and a queryable object, and
that returns a sender that,
when connected with a receiver \tcode{rcvr},
connects the adapted sender with a receiver
whose execution environment is the result of
joining the \exposconcept{queryable} object
to the result of \tcode{get_env(rcvr)}.

\pnum
\tcode{write_env} is a customization point object.
For some subexpressions \tcode{sndr} and \tcode{env},
if \tcode{decltype((sndr))} does not satisfy \libconcept{sender} or
if \tcode{decltype((env))} does not satisfy \exposconcept{queryable},
the expression \tcode{write_env(sndr, env)} is ill-formed.
Otherwise, it is expression-equivalent to
\tcode{\exposid{make-sender}(write_env, env, sndr)}.

\pnum
Let \exposid{write-env-t} denote the type \tcode{decltype(auto(write_env))}.
The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos}
is specialized for \exposid{write-env-t} as follows:
\indexlibraryglobal{\exposid{impls-for}<\exposid{write-env-t}>}
\begin{codeblock}
template<>
struct @\exposid{impls-for}@<@\exposid{write-env-t}@> : @\exposid{default-impls}@ {
  static constexpr auto @\exposid{join-env}@(const auto& state, const auto& env) noexcept {
    return @\seebelow@;
  }

  static constexpr auto @\exposid{get-env}@ =
    [](auto, const auto& state, const auto& rcvr) noexcept {
      return @\exposid{join-env}@(state, @\exposid{FWD-ENV}@(get_env(rcvr)));
    };

  template<class Sndr, class... Env>
    static consteval void @\exposid{check-types}@();
};
\end{codeblock}

\pnum
Invocation of
\tcode{\exposid{impls-for}<\exposid{write-env-t}>::\exposid{join-env}}
returns an object \tcode{e} such that
\begin{itemize}
\item
\tcode{decltype(e)} models \exposconcept{queryable} and
\item
given a query object \tcode{q},
the expression \tcode{e.query(q)} is expression-equivalent
to \tcode{state.query(q)} if that expression is valid,
otherwise, \tcode{e.query(q)} is expression-equivalent
to \tcode{env.query(q)}.
\end{itemize}

\pnum
For a type \tcode{Sndr} and a pack of types \tcode{Env},
let \tcode{State} be \tcode{\exposid{data-type}<Sndr>} and
let \tcode{JoinEnv} be the pack
\tcode{decltype(\exposid{join-env}(declval<State>(), \exposid{FWD-ENV}(declval<Env>())))}.
Then \tcode{\exposid{impls-for}<\exposid{write-env-\brk{}t}>::\exposid{check-types}<Sndr, Env...>()}
is expression-equivalent to
\tcode{get_completion_signatures<\exposid{child-\linebreak{}type}<Sndr>, JoinEnv...>()}.

\rSec3[exec.unstoppable]{\tcode{execution::unstoppable}}

\pnum
\tcode{unstoppable} is a sender adaptor
that connects its inner sender
with a receiver that has the execution environment of the outer receiver
but with an object of type \tcode{never_stop_token}
as the result of the \tcode{get_stop_token query}.

\pnum
For a subexpression \tcode{sndr},
\tcode{unstoppable(sndr)} is expression-equivalent to
\tcode{write_env(sndr, prop(get_stop_token, never_stop_token\{\}))}.

\rSec3[exec.starts.on]{\tcode{execution::starts_on}}

\pnum
\tcode{starts_on} adapts an input sender into a sender
that will start on an execution agent belonging to
a particular scheduler's associated execution resource.

\pnum
The name \tcode{starts_on} denotes a customization point object.
For subexpressions \tcode{sch} and \tcode{sndr},
if \tcode{decltype((\newline sch))} does not satisfy \libconcept{scheduler}, or
\tcode{decltype((sndr))} does not satisfy \libconcept{sender},
\tcode{starts_on(sch, sndr)} is ill-formed.

\pnum
Otherwise,
the expression \tcode{starts_on(sch, sndr)} is expression-equivalent to:
\tcode{\exposid{make-sender}(starts_on, sch, sndr)}.

\pnum
Let \tcode{out_sndr} and \tcode{env} be subexpressions
such that \tcode{OutSndr} is \tcode{decltype((out_sndr))}.
If \tcode{\exposconcept{sender-for}<Out\-Sndr, starts_on_t>} is \tcode{false},
then the expression
\tcode{starts_on.transform_sender(set_value, out_sndr, env)} is ill-formed; otherwise
\tcode{starts_on.transform_sender(set_value, out_sndr, env)} is equivalent to:
\begin{codeblock}
auto&& [_, sch, sndr] = out_sndr;
return let_value(
  continues_on(just(), sch),
  [sndr = std::forward_like<OutSndr>(sndr)]() mutable
    noexcept(is_nothrow_move_constructible_v<decay_t<OutSndr>>) {
    return std::move(sndr);
  });
\end{codeblock}

\pnum
Let \tcode{out_sndr} be a subexpression denoting
a sender returned from \tcode{starts_on(sch, sndr)} or one equal to such, and
let \tcode{OutSndr} be the type \tcode{decltype((out_sndr))}.
Let \tcode{out_rcvr} be a subexpression denoting a receiver
that has an environment of type \tcode{Env}
such that \tcode{\libconcept{sender_in}<OutSndr, Env>} is \tcode{true}.
Let \tcode{op} be an lvalue referring to the operation state
that results from connecting \tcode{out_sndr} with \tcode{out_rcvr}.
Calling \tcode{start(op)} shall start \tcode{sndr}
on an execution agent of the associated execution resource of \tcode{sch}.
If scheduling onto \tcode{sch} fails,
an error completion on \tcode{out_rcvr} shall be executed
on an unspecified execution agent.

\rSec3[exec.continues.on]{\tcode{execution::continues_on}}

\pnum
\tcode{continues_on} schedules work dependent on the completion of a sender
onto a scheduler's associated execution resource.

\pnum
The name \tcode{continues_on} denotes a customization point object.
For some subexpressions \tcode{sch} and \tcode{sndr},
let \tcode{Sch} be \tcode{decltype((sch))} and
\tcode{Sndr} be \tcode{decltype((sndr))}.
If \tcode{Sch} does not satisfy \libconcept{scheduler}, or
\tcode{Sndr} does not satisfy \libconcept{sender},
\tcode{continues_on(sndr, sch)} is ill-formed.

\pnum
Otherwise,
the expression \tcode{continues_on(sndr, sch)} is expression-equivalent to
\tcode{\exposid{make-sender}(continues_on, sch, schedule_from(sndr))}.

\pnum
The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos}
is specialized for \tcode{continues_on_t} as follows:
\indexlibraryglobal{\exposid{impls-for}<continues_on_t>}%
\begin{codeblock}
namespace std::execution {
  template<>
  struct @\exposid{impls-for}@<continues_on_t> : @\exposid{default-impls}@ {
    static constexpr auto @\exposid{get-state}@ = @\seebelow@;
    static constexpr auto @\exposid{complete}@ = @\seebelow@;

    template<class Sndr, class... Env>
      static consteval void @\exposid{check-types}@();
  };
}
\end{codeblock}

\pnum
The member \tcode{\exposid{impls-for}<continues_on_t>::\exposid{get-state}}
is initialized with a callable object equivalent to the following lambda:
\begin{codeblock}
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept(@\seebelow@)
    requires @\libconcept{sender_in}@<@\exposid{child-type}@<Sndr>, @\exposid{FWD-ENV-T}@(env_of_t<Rcvr>)> {
  auto& [_, sch, child] = sndr;

  using sched_t = decltype(auto(sch));
  using variant_t = @\seebelow@;
  using receiver_t = @\seebelow@;
  using operation_t = connect_result_t<schedule_result_t<sched_t>, receiver_t>;
  constexpr bool nothrow = noexcept(connect(schedule(sch), receiver_t{nullptr}));

  struct @\exposid{state-type}@ {
    Rcvr& @\exposid{rcvr}@;                 // \expos
    variant_t @\exposid{async-result}@;     // \expos
    operation_t @\exposid{op-state}@;       // \expos

    explicit @\exposid{state-type}@(sched_t sch, Rcvr& rcvr) noexcept(nothrow)
      : @\exposid{rcvr}@(rcvr), @\exposid{op-state}@(connect(schedule(sch), receiver_t{this})) {}
  };

  return @\exposid{state-type}@{sch, rcvr};
}
\end{codeblock}

\indexlibrarymember{\exposid{check-types}}{\exposid{impls-for}<schedule_from_t>}
\begin{itemdecl}
template<class Sndr, class... Env>
  static consteval void @\exposid{check-types}@();
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
get_completion_signatures<schedule_result_t<@\exposid{data-type}@<Sndr>>, @\exposid{FWD-ENV-T}@(Env)...>();
auto cs = get_completion_signatures<@\exposid{child-type}@<Sndr>, @\exposid{FWD-ENV-T}@(Env)...>();
@\exposid{decay-copyable-result-datums}@(cs);   // see \ref{exec.snd.expos}
\end{codeblock}
\end{itemdescr}

\pnum
Objects of the local class \exposid{state-type} can be used
to initialize a structured binding.

\pnum
Let \tcode{Sigs} be
a pack of the arguments to the \tcode{completion_signatures} specialization
named by \tcode{completion_signatures_of_t<\exposid{child-type}<Sndr>, \exposid{FWD-ENV-T}(env_of_t<Rcvr>)>}.
Let \exposid{as-tuple} be an alias template such that
\tcode{\exposid{as-tuple}<Tag(Args...)>} denotes
the type \tcode{\exposid{decayed-tuple}<Tag, Args...>}, and
let \exposid{is-no\-throw-decay-copy-sig} be a variable template such that
\tcode{auto(\exposid{is-nothrow-decay-copy-sig}<Tag(Args...\linebreak{})>)} is
a constant expression of type \tcode{bool} and
equal to \tcode{(is_nothrow_constructible_v<decay_t<Args>, Args> \&\& ...)}.
Let \exposid{error-completion} be a pack consisting of
the type \tcode{set_error_t(exception_ptr)}
if \tcode{(\exposid{is-nothrow-decay-copy-sig}<Sigs> \&\&...)} is \tcode{false},
and an empty pack otherwise.
Then \tcode{variant_t} denotes
the type \tcode{variant<monostate, \exposid{as-tuple}<Sigs>..., \exposid{error-completion}...>},
except with duplicate types removed.

\pnum
\tcode{receiver_t} is an alias for the following exposition-only class:
\begin{codeblock}
namespace std::execution {
  struct @\exposid{receiver-type}@ {
    using receiver_concept = receiver_tag;
    @\exposid{state-type}@* @\exposid{state}@;          // \expos

    void set_value() && noexcept {
      visit(
        [this]<class Tuple>(Tuple& result) noexcept -> void {
          if constexpr (!@\libconcept{same_as}@<monostate, Tuple>) {
            auto& [tag, ...args] = result;
            tag(std::move(@\exposid{state}@->@\exposid{rcvr}@), std::move(args)...);
          }
        },
        @\exposid{state}@->@\exposid{async-result}@);
    }

    template<class Error>
    void set_error(Error&& err) && noexcept {
      execution::set_error(std::move(@\exposid{state}@->@\exposid{rcvr}@), std::forward<Error>(err));
    }

    void set_stopped() && noexcept {
      execution::set_stopped(std::move(@\exposid{state}@->@\exposid{rcvr}@));
    }

    decltype(auto) get_env() const noexcept {
      return @\exposid{FWD-ENV}@(execution::get_env(@\exposid{state}@->@\exposid{rcvr}@));
    }
  };
}
\end{codeblock}

\pnum
The expression in the \tcode{noexcept} clause of the lambda is \tcode{true}
if the construction of the returned \exposid{state-type} object
is not potentially throwing;
otherwise, \tcode{false}.

\pnum
The member \tcode{\exposid{impls-for}<continues_on_t>::\exposid{complete}}
is initialized with a callable object equivalent to the following lambda:
\begin{codeblock}
[]<class Tag, class... Args>(auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept
    -> void {
  using result_t = @\exposid{decayed-tuple}@<Tag, Args...>;
  constexpr bool nothrow = (is_nothrow_constructible_v<decay_t<Args>, Args> && ...);

  try {
    state.@\exposid{async-result}@.template emplace<result_t>(Tag(), std::forward<Args>(args)...);
  } catch (...) {
    if constexpr (!nothrow)
      state.@\exposid{async-result}@.template emplace<tuple<set_error_t,
                                                exception_ptr>>(set_error, current_exception());
  }
  start(state.@\exposid{op-state}@);
};
\end{codeblock}

\pnum
Let \tcode{out_sndr} be a subexpression denoting
a sender returned from \tcode{continues_on_t(sndr, sch)} or one equal to such,
and let \tcode{OutSndr} be the type \tcode{decltype((out_sndr))}.
Let \tcode{out_rcvr} be a subexpression denoting a receiver
that has an environment of type \tcode{Env}
such that \tcode{\libconcept{sender_in}<OutSndr, Env>} is \tcode{true}.
Let \tcode{op} be an lvalue referring to the operation state
that results from connecting \tcode{out_sndr} with \tcode{out_rcvr}.
Calling \tcode{start(op)} shall
start \tcode{sndr} on the current execution agent and
execute completion operations on \tcode{out_rcvr}
on an execution agent of the execution resource associated with \tcode{sch}.
If scheduling onto \tcode{sch} fails,
an error completion on \tcode{out_rcvr} shall be executed
on an unspecified execution agent.

\rSec3[exec.schedule.from]{\tcode{execution::schedule_from}}

\pnum
The name \tcode{schedule_from} denotes a customization point object.
For some subexpression \tcode{sndr},
if \tcode{decltype((\brk{}sndr))} does not satisfy \libconcept{sender},
\tcode{schedule_from(sndr)} is ill-formed.
Otherwise,
the expression \tcode{schedule_from(sndr)} is expression-equivalent to
\tcode{\exposid{make-sender}(schedule_from, \{\}, sndr)}.
\begin{note}
\tcode{schedule_from} is used by schedulers to control
how to transition off of their schedulers' associated execution contexts.
\end{note}

\rSec3[exec.on]{\tcode{execution::on}}

\pnum
The \tcode{on} sender adaptor has two forms:
\begin{itemize}
\item
\tcode{on(sch, sndr)},
which starts a sender \tcode{sndr} on an execution agent
belonging to a scheduler \tcode{sch}'s associated execution resource and
that, upon \tcode{sndr}'s completion,
transfers execution back to the execution resource
on which the \tcode{on} sender was started.
\item
\tcode{on(sndr, sch, closure)},
which upon completion of a sender \tcode{sndr},
transfers execution to an execution agent
belonging to a scheduler \tcode{sch}'s associated execution resource,
then executes a sender adaptor closure \tcode{closure}
with the async results of the sender, and
that then transfers execution back to the execution resource
on which \tcode{sndr} completed.
\end{itemize}

\pnum
The name \tcode{on} denotes a pipeable sender adaptor object.
For subexpressions \tcode{sch} and \tcode{sndr},
\tcode{on(sch, sndr)} is ill-formed if any of the following is \tcode{true}:
\begin{itemize}
\item
\tcode{decltype((sch))} does not satisfy \libconcept{scheduler}, or
\item
\tcode{decltype((sndr))} does not satisfy \libconcept{sender} and
\tcode{sndr} is not
a pipeable sender adaptor closure object\iref{exec.adapt.obj}, or
\item
\tcode{decltype((sndr))} satisfies \libconcept{sender} and
\tcode{sndr }is also a pipeable sender adaptor closure object.
\end{itemize}

\pnum
Otherwise, if \tcode{decltype((sndr))} satisfies \libconcept{sender},
the expression \tcode{on(sch, sndr)} is expression-equivalent to
\tcode{\exposid{make-sender}(on, sch, sndr)}.

\pnum
For subexpressions \tcode{sndr}, \tcode{sch}, and \tcode{closure}, if
\begin{itemize}
\item
\tcode{decltype((sch))} does not satisfy \libconcept{scheduler}, or
\item
\tcode{decltype((sndr))} does not satisfy \libconcept{sender}, or
\item
\tcode{closure} is not a pipeable sender adaptor closure object\iref{exec.adapt.obj},
\end{itemize}
the expression \tcode{on(sndr, sch, closure)} is ill-formed;
otherwise, it is expression-equivalent to
\tcode{\exposid{make-sender}(\brk{}on, \exposid{product-type}\{sch, closure\}, sndr)}.

\pnum
Let \tcode{out_sndr} and \tcode{env} be subexpressions,
let \tcode{OutSndr} be \tcode{decltype((out_sndr))}, and
let \tcode{Env} be \tcode{decltype((\linebreak env))}.
If \tcode{\exposconcept{sender-for}<OutSndr, on_t>} is \tcode{false},
then the expression \tcode{on.transform_sender(set_value, out_sndr, env)} is ill-formed.

\pnum
Otherwise, the expression \tcode{on.transform_sender(set_value, out_sndr, env)}
has effects equivalent to:
\begin{codeblock}
auto&& [_, data, child] = out_sndr;
if constexpr (@\libconcept{scheduler}@<decltype(data)>) {
  auto orig_sch = @\exposid{call-with-default}@(get_start_scheduler, @\exposid{not-a-scheduler}@(), env);
  return continues_on(
    starts_on(std::forward_like<OutSndr>(data), std::forward_like<OutSndr>(child)),
    std::move(orig_sch));
} else {
  auto& [sch, closure] = data;
  auto orig_sch = @\exposid{call-with-default}@(
    get_completion_scheduler<set_value_t>, @\exposid{not-a-scheduler}@(), get_env(child), env);
  return continues_on(
    std::forward_like<OutSndr>(closure)(continues_on(std::forward_like<OutSndr>(child), sch)),
    orig_sch);
}
\end{codeblock}

\pnum
Let \tcode{out_sndr} be a subexpression denoting
a sender returned from \tcode{on(sch, sndr)} or one equal to such, and
let \tcode{OutSndr} be the type \tcode{decltype((out_sndr))}.
Let \tcode{out_rcvr} be a subexpression denoting a receiver
that has an environment of type \tcode{Env}
such that \tcode{\libconcept{sender_in}<OutSndr, Env>} is \tcode{true}.
Let \tcode{op} be an lvalue referring to the operation state
that results from connecting \tcode{out_sndr} with \tcode{out_rcvr}.
Calling \tcode{start(op)} shall
\begin{itemize}
\item
remember the current scheduler,
which is obtained by \tcode{get_start_scheduler(get_env(rcvr))};
\item
start \tcode{sndr} on an execution agent belonging to
\tcode{sch}'s associated execution resource;
\item
upon \tcode{sndr}'s completion,
transfer execution back to the execution resource
associated with the scheduler remembered in step 1; and
\item
forward \tcode{sndr}'s async result to \tcode{out_rcvr}.
\end{itemize}
If any scheduling operation fails,
an error completion on \tcode{out_rcvr} shall be executed
on an unspecified execution agent.

\pnum
Let \tcode{out_sndr} be a subexpression denoting
a sender returned from \tcode{on(sndr, sch, closure)} or one equal to such, and
let \tcode{OutSndr} be the type \tcode{decltype((out_sndr))}.
Let \tcode{out_rcvr} be a subexpression denoting a receiver
that has an environment of type \tcode{Env}
such that \tcode{\libconcept{sender_in}<OutSndr, Env>} is \tcode{true}.
Let \tcode{op} be an lvalue referring to the operation state
that results from connecting \tcode{out_sndr} with \tcode{out_rcvr}.
Calling \tcode{start(op)} shall
\begin{itemize}
\item
remember the current scheduler,
which is
\tcode{get_completion_scheduler<set_value_t>(get_env(\newline sndr), get_env(out_rcvr))};
\item
start \tcode{sndr} on the current execution agent;
\item
upon \tcode{sndr}'s completion,
transfer execution to an agent
owned by \tcode{sch}'s associated execution resource;
\item
forward \tcode{sndr}'s async result as if by
connecting and starting a sender \tcode{closure(S)},
where \tcode{S} is a sender
that completes synchronously with \tcode{sndr}'s async result; and
\item
upon completion of the operation started in the previous step,
transfer execution back to the execution resource
associated with the scheduler remembered in step 1 and
forward the operation's async result to \tcode{out_rcvr}.
\end{itemize}
If any scheduling operation fails,
an error completion on \tcode{out_rcvr} shall be executed on
an unspecified execution agent.

\rSec3[exec.then]{\tcode{execution::then}, \tcode{execution::upon_error}, \tcode{execution::upon_stopped}}

\pnum
\tcode{then} attaches an invocable as a continuation
for an input sender's value completion operation.
\tcode{upon_error} and \tcode{upon_stopped} do the same
for the error and stopped completion operations, respectively,
sending the result of the invocable as a value completion.

\pnum
The names \tcode{then}, \tcode{upon_error}, and \tcode{upon_stopped}
denote pipeable sender adaptor objects.
Let the expression \exposid{then-cpo} be one of
\tcode{then}, \tcode{upon_error}, or \tcode{upon_stopped}.
For subexpressions \tcode{sndr} and \tcode{f},
if \tcode{decltype((sndr))} does not satisfy \libconcept{sender}, or
\tcode{decltype((f))} does not satisfy \exposconcept{movable-value},
\tcode{\exposid{then-cpo}(\linebreak sndr, f) }is ill-formed.

\pnum
Otherwise,
the expression \tcode{\exposid{then-cpo}(sndr, f)} is expression-equivalent to
\tcode{\exposid{make-sender}(\exposid{then-cpo}, f, sndr)}.

\pnum
For \tcode{then}, \tcode{upon_error}, and \tcode{upon_stopped},
let \exposid{set-cpo} be
\tcode{set_value}, \tcode{set_error}, and \tcode{set_stopped}, respectively.
The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos}
is specialized for \exposid{then-cpo} as follows:
\indexlibraryglobal{\exposid{impls-for}<\exposid{decayed-typeof}<\exposid{then-cpo}>>}
\begin{codeblock}
namespace std::execution {
  template<>
  struct @\exposid{impls-for}@<@\exposid{decayed-typeof}@<@\exposid{then-cpo}@>> : @\exposid{default-impls}@ {
    static constexpr auto @\exposid{complete}@ =
      []<class Tag, class... Args>
        (auto, auto& fn, auto& rcvr, Tag, Args&&... args) noexcept -> void {
          if constexpr (@\libconcept{same_as}@<Tag, @\exposid{decayed-typeof}@<@\exposid{set-cpo}@>>) {
            @\exposid{TRY-SET-VALUE}@(rcvr,
                          invoke(std::move(fn), std::forward<Args>(args)...));
          } else {
            Tag()(std::move(rcvr), std::forward<Args>(args)...);
          }
        };

    template<class Sndr, class... Env>
      static consteval void @\exposid{check-types}@();
  };
}
\end{codeblock}

\indexlibrarymember{\exposid{check-types}}{\exposid{impls-for}<\exposid{decayed-typeof}<\exposid{then-cpo}>>}
\begin{itemdecl}
template<class Sndr, class... Env>
  static consteval void @\exposid{check-types}@();
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
auto cs = get_completion_signatures<@\exposid{child-type}@<Sndr>, @\exposid{FWD-ENV-T}@(Env)...>();
auto fn = []<class... Ts>(@\exposid{decayed-typeof}@<@\exposid{set-cpo}@>(*)(Ts...)) {
  if constexpr (!@\libconcept{invocable}@<remove_cvref_t<@\exposid{data-type}@<Sndr>>, Ts...>)
    throw @\placeholder{unspecified-exception}@();
};
cs.@\exposid{for-each}@(@\exposid{overload-set}@{fn, [](auto){}});
\end{codeblock}
\end{itemdescr}

\pnum
The expression \tcode{\exposid{then-cpo}(sndr, f)} has undefined behavior
unless it returns a sender \tcode{out_sndr} that
\begin{itemize}
\item
invokes \tcode{f} or a copy of such
with the value, error, or stopped result datums of \tcode{sndr}
for \tcode{then}, \tcode{upon_error}, and \tcode{upon_stopped}, respectively,
using the result value of \tcode{f} as \tcode{out_sndr}'s value completion, and
\item
forwards all other completion operations unchanged.
\end{itemize}

\rSec3[exec.let]{\tcode{execution::let_value}, \tcode{execution::let_error}, \tcode{execution::let_stopped}}

\pnum
\tcode{let_value}, \tcode{let_error}, and \tcode{let_stopped} transform
a sender's value, error, and stopped completions, respectively,
into a new child asynchronous operation
by passing the sender's result datums to a user-specified callable,
which returns a new sender that is connected and started.

\pnum
For \tcode{let_value}, \tcode{let_error}, and \tcode{let_stopped},
let \exposid{set-cpo} be
\tcode{set_value}, \tcode{set_error}, and \tcode{set_stopped}, respectively.
Let the expression \exposid{let-cpo} be one of
\tcode{let_value}, \tcode{let_error}, or \tcode{let_stopped}.
Let \exposid{let-tag} denote a unique, empty class type for each of
\tcode{let_value}, \tcode{let_error}, and \tcode{let_stopped}.
For subexpressions \tcode{sndr} and \tcode{env},
let \tcode{\exposid{let-env}(sndr, env)} be expression-equivalent to
the first well-formed expression below:
\begin{itemize}
\item
\tcode{\exposid{SCHED-ENV}(get_completion_scheduler<\exposid{decayed-typeof}<\exposid{set-cpo}>>(get_env(sndr),\newline \exposid{FWD-ENV}(env)))}
\item
\tcode{\exposid{MAKE-ENV}(get_domain, get_completion_domain<\exposid{decayed-typeof}<\exposid{set-cpo}>>(get_env(sndr),\newline \exposid{FWD-ENV}(env)))}
\item
\tcode{(void(sndr), env<>\{\})}
\end{itemize}

\pnum
The names \tcode{let_value}, \tcode{let_error}, and \tcode{let_stopped} denote
pipeable sender adaptor objects.
For subexpressions \tcode{sndr} and \tcode{f},
let \tcode{F} be the decayed type of \tcode{f}.
If \tcode{decltype((sndr))} does not satisfy \libconcept{sender} or
if \tcode{decltype((f))} does not satisfy \exposconcept{movable-value},
the expression \tcode{\exposid{let-cpo}(sndr, f)} is ill-formed.
If \tcode{F} does not satisfy \libconcept{invocable},
the expression \tcode{let_stopped(sndr, f)} is ill-formed.

\pnum
Otherwise,
the expression \tcode{\exposid{let-cpo}(sndr, f)} is expression-equivalent to
\tcode{\exposid{make-sender}(\exposid{let-cpo}, f, sndr)}.

\pnum
Let \exposid{let-data} denote the following exposition-only class template:
\begin{codeblock}
template<class Sndr, class Fn>
struct @\exposid{let-data}@ {
  Sndr @\exposid{sndr}@;    // \expos
  Fn @\exposid{fn}@;        // \expos
};
\end{codeblock}

\pnum
Then let the expression \tcode{\exposid{let-cpo}.transform_sender(s, es...)}
be expression-equivalent to:
\begin{codeblock}
@\exposid{make-sender}@(@\exposid{let-tag}@{}, @\exposid{let-data}@{s.template @\exposid{get}@<2>(), s.template @\exposid{get}@<1>()})
\end{codeblock}
except that \tcode{s} is evaluated only once.

\pnum
The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos}
is specialized for \exposid{let-tag} as follows:
\indexlibraryglobal{\exposid{impls-for}<\exposid{decayed-typeof}<\exposid{let-cpo}>>}
\begin{codeblock}
namespace std::execution {
  template<>
  struct @\exposid{impls-for}@<@\exposid{let-tag}@> : @\exposid{default-impls}@ {
    static constexpr auto @\exposid{get-state}@ = @\seebelow@;
    static constexpr auto @\exposid{start}@ = @\seebelow@;

    template<class Sndr, class... Env>
      static consteval void @\exposid{check-types}@();
  };
}
\end{codeblock}

\pnum
Let \exposid{receiver2} denote the following exposition-only class template:
\begin{codeblock}
namespace std::execution {
  template<class Rcvr, class Env>
  struct @\exposid{receiver2}@ {
    using receiver_concept = receiver_tag;

    template<class... Args>
    void set_value(Args&&... args) && noexcept {
      execution::set_value(std::move(@\exposid{rcvr}@), std::forward<Args>(args)...);
    }

    template<class Error>
    void set_error(Error&& err) && noexcept {
      execution::set_error(std::move(@\exposid{rcvr}@), std::forward<Error>(err));
    }

    void set_stopped() && noexcept {
      execution::set_stopped(std::move(@\exposid{rcvr}@));
    }

    decltype(auto) get_env() const noexcept {
      return @\seebelow@;
    }

    Rcvr& @\exposid{rcvr}@;                 // \expos
    Env @\exposid{env}@;                    // \expos
  };
}
\end{codeblock}
Invocation of the function \tcode{\exposid{receiver2}::get_env}
returns an object \tcode{e} such that
\begin{itemize}
\item
\tcode{decltype(e)} models \exposconcept{queryable} and
\item
given a query object \tcode{q} and a pack of subexpressions \tcode{args},
the expression \tcode{e.query(q, args...)} is expression-equivalent
to \tcode{\exposid{env}.query(q, args...)} if that expression is valid;
otherwise,
if the type of \tcode{q} satisfies \exposconcept{forwarding-query},
\tcode{e.query(q, args...)} is expression-equivalent
to \tcode{get_env(\exposid{rcvr}).query\newline (q, args...)};
otherwise,
\tcode{e.query(q, args...)} is ill-formed.
\end{itemize}

\indexlibrarymember{\exposid{check-types}}{\exposid{impls-for}<\exposid{decayed-typeof}<\exposid{let-cpo}>>}
\begin{itemdecl}
template<class Sndr, class... Env>
  static consteval void @\exposid{check-types}@();
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
using LetFn = remove_cvref_t<@\exposid{data-type}@<Sndr>>;
auto cs = get_completion_signatures<@\exposid{child-type}@<Sndr>, @\exposid{FWD-ENV-T}@(Env)...>();
auto fn = []<class... Ts>(@\exposid{decayed-typeof}@<@\exposid{set-cpo}@>(*)(Ts...)) {
  if constexpr (!@\placeholder{is-valid-let-sender}@)   // \seebelow
    throw @\placeholder{unspecified-exception}@();
};
cs.@\exposid{for-each}@(@\exposid{overload-set}@(fn, [](auto){}));
\end{codeblock}
where \tcode{\placeholder{is-valid-let-sender}} is \tcode{true} if and only if
all of the following are \tcode{true}:
\begin{itemize}
\item \tcode{(\libconcept{constructible_from}<decay_t<Ts>, Ts> \&\&...)}
\item \tcode{\libconcept{invocable}<LetFn, decay_t<Ts>\&...>}
\item \tcode{\libconcept{sender}<invoke_result_t<LetFn, decay_t<Ts>\&...>>}
\item%
\tcode{sizeof...(Env) == 0 || \libconcept{sender_in}<invoke_result_t<LetFn, decay_t<Ts>\&...>, \placeholder{env-t}\linebreak{}...>}
\end{itemize}
where \tcode{\placeholder{env-t}} is the pack
\tcode{decltype(\exposid{JOIN-ENV}(\exposid{let-env}(declval<\exposid{child-type}<Sndr>>(), declval<\brk{}Env>()), \exposid{FWD-ENV}(declval<Env>())))}.
\end{itemdescr}

\pnum
Let \exposid{let-state} denote the following exposition-only class template:
\begin{codeblock}
template<class Cpo, class Sndr, class Fn, class Rcvr, class ArgsVariant, class OpsVariant>
struct @\exposid{let-state}@ {
  using @\exposidnc{env_t}@ = decltype(@\exposidnc{let-env}@(declval<Sndr>()), get_env(declval<Rcvr&>()));  // \expos
  Fn @\exposidnc{fn}@;                                                                        // \expos
  env_t @\exposidnc{env}@;                                                                    // \expos
  ArgsVariant @\exposidnc{args}@;                                                             // \expos
  OpsVariant @\exposidnc{ops}@;                                                               // \expos

  template<class Tag, class... Ts>
  constexpr void @\exposid{impl}@(Rcvr& rcvr, Tag tag, Ts&&... ts) noexcept {               // \expos
    using args_t = @\exposid{decayed-tuple}@<Ts...>;
    using receiver_type = @\exposid{receiver2}@<Rcvr, env_t>;
    using sender_type = apply_result_t<Fn, args_t&>;
    if constexpr (is_same_v<Tag, Cpo>) {
      try {
        auto& tuple = @\exposid{args}@.template emplace<args_t>(std::forward<Ts>(ts)...);
        @\exposid{ops}@.template emplace<monostate>();
        auto&& sndr = apply(std::move(@\exposid{fn}@), tuple);
        using op_t = connect_result_t<sender_type, receiver_type>;
        auto mkop2 = [&] {
          return connect(std::forward<sender_type>(sndr),
          receiver_type{@\exposid{rcvr}@, @\exposid{env}@});
        };
        auto& op = @\exposid{ops}@.template emplace<op_t>(@\exposid{emplace-from}@{mkop2});
        start(op);
      } catch (...) {
        constexpr bool nothrow =
          is_nothrow_constructible_v<args_t, Ts...> &&
          is_nothrow_applicable_v<Fn, args_t&> &&
          noexcept(connect(declval<sender_type>(), receiver_type{@\exposid{rcvr}@, @\exposid{env}@}));
        if constexpr (!nothrow) {
          set_error(std::move(@\exposid{rcvr}@), current_exception());
        }
      }
    } else {
      tag(std::move(@\exposid{rcvr}@), std::forward<Ts>(ts)...);
    }
  }

  struct @\exposid{receiver}@ {     // \expos
    @\exposid{let-state}@& state;   // \expos
    Rcvr& @\exposid{rcvr}@;         // \expos

    using receiver_concept = receiver_tag;

    template<class... Args>
    constexpr void set_value(Args&&... args) noexcept {
      @\exposid{state}@.@\exposid{impl}@(@\exposid{rcvr}@, execution::set_value, std::forward<Args>(args)...);
    }
    template<class... Args>
    constexpr void set_error(Args&&... args) noexcept {
      @\exposid{state}@.@\exposid{impl}@(@\exposid{rcvr}@, execution::set_error, std::forward<Args>(args)...);
    }
    template<class... Args>
    constexpr void set_stopped(Args&&... args) noexcept {
      @\exposid{state}@.@\exposid{impl}@(@\exposid{rcvr}@, execution::set_stopped, std::forward<Args>(args)...);
    }

    constexpr env_of_t<const Rcvr&> get_env() const noexcept {
      return execution::get_env(@\exposid{rcvr}@);
    }
  };

  using @\exposidnc{op_t}@ = connect_result_t<Sndr, @\exposidnc{receiver}@>;                                // \expos

  constexpr @\exposidnc{let-state}@(Sndr&& sndr, Fn fn, Rcvr& rcvr)                           // \expos
    : @\exposid{fn}@(std::move(fn)), @\exposid{env}@(@\exposid{let-env}@(sndr), get_env(rcvr)),
      @\exposid{ops}@(in_place_type<@\exposid{op_t}@>, std::forward<Sndr>(sndr), @\exposid{receiver}@{*this, rcvr}) {}
};
\end{codeblock}

\pnum
\tcode{\exposid{impls-for}<\exposid{let-tag}>::\exposid{get-state}}
is initialized with a callable object equivalent to the following:
\begin{codeblock}
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) requires @\seebelow@ {
  auto& [_, data] = sndr;
  auto& [child, fn] = data;
  using child_t = decltype(std::forward_like<Sndr>(child));
  using fn_t = decay_t<decltype(fn)>;
  using args_variant_t = @\seebelow@;
  using ops_variant_t = @\seebelow@;
  using state_t = @\exposid{let-state}@<@\exposid{decayed-typeof}@<@\exposid{set-cpo}@>, child_t, fn_t, Rcvr,
                            args_variant_t, ops_variant_t>;
  return state_t(std::forward_like<Sndr>(child), std::forward_like<Sndr>(fn), @\exposid{rcvr}@);
}
\end{codeblock}

\pnum
Let \tcode{Sigs} be a pack of the arguments
to the \tcode{completion_signatures} specialization named by
\tcode{completion_signatures_of_t<\exposid{child-type}<Sndr>, \exposid{FWD-ENV-T}(env_of_t<Rcvr>)>}.
Let \tcode{LetSigs} be a pack of those types in \tcode{Sigs}
with a return type of \tcode{\exposid{decayed-typeof}<\exposid{set-cpo}>}.
Let \exposid{as-tuple} be an alias template
such that \tcode{\exposid{as-tuple}<Tag(Args...)>} denotes
the type \tcode{\exposid{decayed-tuple}<Args...>}.
Then \tcode{args_variant_t} denotes
the type \tcode{variant<monostate, \exposid{as-tuple}<LetSigs>...>}
except with duplicate types removed.

\pnum
Given a type \tcode{Tag} and a pack \tcode{Args},
let \exposid{as-sndr2} be an alias template
such that \tcode{\exposid{as-sndr2}<Tag(Args...)>} denotes
the type \tcode{\exposid{call-result-t}<F, decay_t<Args>\&...>}.
Then \tcode{ops_variant_t} denotes
the type
\begin{codeblock}
variant<monostate,
        connect_result_t<child_t, @\exposid{let-state}@::@\exposid{receiver}@>,
        connect_result_t<@\exposid{as-sndr2}@<LetSigs>, @\exposid{receiver2}@<Rcvr, env_t>>...>
\end{codeblock}
except with duplicate types removed.

\pnum
The \grammarterm{requires-clause} constraining the above lambda is satisfied
if and only if
the types \tcode{args_variant_t} and \tcode{ops2_variant_t} are well-formed.

\pnum
\tcode{\exposid{impls-for}<\exposid{let-tag}>::\exposid{start}}
is initialized with a callable object equivalent to the following:
\begin{codeblock}
[]<class State, class Rcvr>(State& state, Rcvr&) noexcept {
  start(get<typename State::@\exposid{op_t}@>(state.@\exposid{ops}@));
}
\end{codeblock}

\pnum
Let the subexpression \tcode{out_sndr} denote
the result of the invocation \tcode{\exposid{let-cpo}(sndr, f)} or
an object equal to such, and
let the subexpression \tcode{rcvr} denote a receiver
such that the expression \tcode{connect(out_sndr, rcvr)} is well-formed.
The expression \tcode{connect(out_sndr, rcvr)} has undefined behavior
unless it creates an asynchronous operation\iref{exec.async.ops} that,
when started:
\begin{itemize}
\item
invokes \tcode{f} when \exposid{set-cpo} is called
with \tcode{sndr}'s result datums,
\item
makes its completion dependent on
the completion of a sender returned by \tcode{f}, and
\item
propagates the other completion operations sent by \tcode{sndr}.
\end{itemize}

\rSec3[exec.bulk]{\tcode{execution::bulk}, \tcode{execution::bulk_chunked}, and \tcode{execution::bulk_unchunked}}

\pnum
\tcode{bulk}, \tcode{bulk_chunked}, and \tcode{bulk_unchunked}
run a task repeatedly for every index in an index space.

\pnum
The names \tcode{bulk}, \tcode{bulk_chunked}, and \tcode{bulk_unchunked}
denote pipeable sender adaptor objects.
Let \tcode{\placeholder{bulk-algo}} be either
\tcode{bulk}, \tcode{bulk_chunked}, or \tcode{bulk_unchunked}.
For subexpressions \tcode{sndr}, \tcode{policy}, \tcode{shape}, and \tcode{f},
let
\tcode{Policy} be \tcode{remove_cvref_t<decltype(policy)>},
\tcode{Shape} be \tcode{decltype(auto(shape))}, and
\tcode{Func} be \tcode{decay_t<decltype((f))>}.
If
\begin{itemize}
\item
\tcode{decltype((sndr))} does not satisfy \libconcept{sender}, or
\item
\tcode{is_execution_policy_v<Policy>} is \tcode{false}, or
\item
\tcode{Shape} does not satisfy \libconcept{integral}, or
\item
\tcode{Func} does not model \libconcept{copy_constructible},
\end{itemize}
\tcode{\placeholder{bulk-algo}(sndr, policy, shape, f)} is ill-formed.

\pnum
Otherwise,
the expression \tcode{\placeholder{bulk-algo}(sndr, policy, shape, f)}
is expression-equivalent to:
\begin{codeblock}
@\exposid{make-sender}@(@\placeholder{bulk-algo}@, @\exposid{product-type}@<@\seebelow@, Shape, Func>{policy, shape, f}, sndr)
\end{codeblock}
The first template argument of \exposid{product-type} is \tcode{Policy}
if \tcode{Policy} models \libconcept{copy_constructible}, and
\tcode{const Policy\&} otherwise.

\pnum
Let \tcode{sndr} and \tcode{env} be subexpressions such that
\tcode{Sndr} is \tcode{decltype((sndr))}.
If \tcode{\exposconcept{sender-for}<Sndr, bulk_t>} is \tcode{false}, then
the expression \tcode{bulk.transform_sender(set_value, sndr, env)} is ill-formed;
otherwise, it is equivalent to:
\begin{codeblock}
auto [_, data, child] = sndr;
auto& [policy, shape, f] = data;
auto new_f = [func = std::move(f)](Shape begin, Shape end, auto&&... vs)
    noexcept(noexcept(f(begin, vs...))) {
  while (begin != end) func(begin++, vs...);
}
return bulk_chunked(std::move(child), policy, shape, std::move(new_f));
\end{codeblock}
\begin{note}
This causes the \tcode{bulk(sndr, policy, shape, f)} sender to be
expressed in terms of \tcode{bulk_chunked(sndr, policy, shape, f)} when
it is connected to a receiver whose
execution domain does not customize \tcode{bulk}.
\end{note}

\pnum
The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos}
is specialized for \tcode{bulk_chunked_t} as follows:
\indexlibraryglobal{\exposid{impls-for}<bulk_chunked_t>}
\begin{codeblock}
namespace std::execution {
  template<>
  struct @\exposid{impls-for}@<bulk_chunked_t> : @\exposid{default-impls}@ {
    static constexpr auto @\exposid{complete}@ = @\seebelow@;

    template<class Sndr, class... Env>
      static consteval void @\exposid{check-types}@();
  };
}
\end{codeblock}
The member \tcode{\exposid{impls-for}<bulk_chunked_t>::\exposid{complete}}
is initialized with a callable object equivalent to the following lambda:
\begin{codeblock}
[]<class Index, class State, class Rcvr, class Tag, class... Args>
  (Index, State& state, Rcvr& rcvr, Tag, Args&&... args) noexcept
  -> void requires @\seebelow@ {
    if constexpr (@\libconcept{same_as}@<Tag, set_value_t>) {
      auto& [policy, shape, f] = state;
      constexpr bool nothrow = noexcept(f(auto(shape), auto(shape), args...));
      @\exposid{TRY-EVAL}@(rcvr, [&]() noexcept(nothrow) {
        f(static_cast<decltype(auto(shape))>(0), auto(shape), args...);
        Tag()(std::move(rcvr), std::forward<Args>(args)...);
      }());
    } else {
      Tag()(std::move(rcvr), std::forward<Args>(args)...);
    }
  }
\end{codeblock}
The expression in the \grammarterm{requires-clause} of the lambda above is
\tcode{true} if and only
if \tcode{Tag} denotes a type other than \tcode{set_value_t} or
if the expression \tcode{f(auto(shape), auto(shape), args...)} is well-formed.

\begin{itemdecl}
template<class Sndr, class... Env>
  static consteval void @\exposid{check-types}@();
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
auto cs = get_completion_signatures<@\exposid{child-type}@<Sndr>, @\exposid{FWD-ENV-T}@(Env)...>();
auto fn = []<class... Ts>(set_value_t(*)(Ts...)) {
  using data_type = @\exposid{data-type}@<Sndr>;
  if constexpr (!@\libconcept{invocable}@<remove_cvref_t<@\exposid{child-type}@<data_type>&,
                           remove_cvref_t<@\exposid{data-type}@<data_type>>, Ts&...>)
    throw @\placeholder{unspecified-exception}@();
};
cs.@\exposid{for-each}@(@\exposid{overload-set}@(fn, [](auto){}));
\end{codeblock}
\end{itemdescr}

\pnum
The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos}
is specialized for \tcode{bulk_unchunked_t} as follows:
\begin{codeblock}
namespace std::execution {
  template<>
  struct @\exposid{impls-for}@<bulk_unchunked_t> : @\exposid{default-impls}@ {
    static constexpr auto @\exposid{complete}@ = @\seebelow@;

    template<class Sndr, class... Env>
      static consteval void @\exposid{check-types}@();
  };
}
\end{codeblock}
The member \tcode{\exposid{impls-for}<bulk_unchunked_t>::\exposid{complete}}
is initialized with a callable object equivalent to the following lambda:
\begin{codeblock}
[]<class Index, class State, class Rcvr, class Tag, class... Args>
  (Index, State& state, Rcvr& rcvr, Tag, Args&&... args) noexcept
  -> void requires @\seebelow@ {
    if constexpr (@\libconcept{same_as}@<Tag, set_value_t>) {
      auto& [policy, shape, f] = state;
      constexpr bool nothrow = noexcept(f(auto(shape), args...));
      @\exposid{TRY-EVAL}@(rcvr, [&]() noexcept(nothrow) {
        for (decltype(auto(shape)) i = 0; i < shape; ++i) {
          f(auto(i), args...);
        }
        Tag()(std::move(rcvr), std::forward<Args>(args)...);
      }());
    } else {
      Tag()(std::move(rcvr), std::forward<Args>(args)...);
    }
  }
\end{codeblock}
The expression in the \grammarterm{requires-clause} of the lambda above
is \tcode{true} if and only
if \tcode{Tag} denotes a type other than \tcode{set_value_t} or
if the expression \tcode{f(auto(shape), args...)} is well-formed.

\indexlibrarymember{\exposid{check-types}}{\exposid{impls-for}<bulk_t>}
\begin{itemdecl}
template<class Sndr, class... Env>
  static consteval void @\exposid{check-types}@();
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
auto cs = get_completion_signatures<@\exposid{child-type}@<Sndr>, @\exposid{FWD-ENV-T}@(Env)...>();
auto fn = []<class... Ts>(set_value_t(*)(Ts...)) {
  using data_type = @\exposid{data-type}@<Sndr>;
  if constexpr (!@\libconcept{invocable}@<remove_cvref_t<@\exposid{child-type}@<data_type>&,
                           remove_cvref_t<@\exposid{data-type}@<data_type>>, Ts&...>)
    throw @\placeholder{unspecified-exception}@();
};
cs.@\exposid{for-each}@(@\exposid{overload-set}@(fn, [](auto){}));
\end{codeblock}
\end{itemdescr}

\pnum
Let the subexpression \tcode{out_sndr} denote
the result of the invocation
\tcode{\placeholder{bulk-algo}(sndr, policy, shape, f)} or
an object equal to such, and
let the subexpression \tcode{rcvr} denote a receiver
such that the expression \tcode{connect(out_sndr, rcvr)} is well-formed.
The expression \tcode{connect(out_sndr, rcvr)} has undefined behavior
unless it creates an asynchronous operation\iref{exec.async.ops} that,
when started:

\begin{itemize}
\item
If \tcode{sndr} has a successful completion, where
\tcode{args} is a pack of lvalue subexpressions
referring to the value completion result datums of \tcode{sndr}, or
decayed copies of those values if they model \libconcept{copy_constructible},
then:

  \begin{itemize}
  \item
  If \tcode{out_sndr} also completes successfully, then:

    \begin{itemize}
    \item
    for \tcode{bulk},
    invokes \tcode{f($i$, args...)} for every $i$ of type \tcode{Shape}
    from \tcode{0} to \tcode{shape};

    \item
    for \tcode{bulk_unchunked},
    invokes \tcode{f($i$, args...)} for every $i$ of type \tcode{Shape}
    from \tcode{0} to \tcode{shape};

    \recommended
    The underlying scheduler should execute each iteration
    on a distinct execution agent.

    \item
    for \tcode{bulk_chunked},
    invokes \tcode{f($b$, $e$, args...)} zero or more times
    with pairs of $b$ and $e$ of type \tcode{Shape}
    in range \crange{\tcode{0}}{\tcode{shape}},
    such that $b < e$ and
    for every $i$ of type \tcode{Shape} from \tcode{0} to \tcode{shape},
    there is exactly one invocation with a pair $b$ and $e$,
    such that $i$ is in the range \range{$b$}{$e$}.
    \end{itemize}

  \item
  If \tcode{out_sndr} completes with \tcode{set_error(rcvr, eptr)}, then
  the asynchronous operation may invoke a subset of
  the invocations of \tcode{f}
  before the error completion handler is called, and
  \tcode{eptr} is an \tcode{exception_ptr} containing either:
    \begin{itemize}
    \item
    an exception thrown by an invocation of \tcode{f}, or
    \item
    a \tcode{bad_alloc} exception if
    the implementation fails to allocate required resources, or
    \item
    an exception derived from \tcode{runtime_error}.
    \end{itemize}

  \item
  If \tcode{out_sndr} completes with \tcode{set_stopped(rcvr)}, then
  the asynchronous operation may invoke a subset of
  the invocations of \tcode{f}
  before the stopped completion handler.
  \end{itemize}

\item
If \tcode{sndr} does not complete with \tcode{set_value}, then
the completion is forwarded to \tcode{recv}.

\item
For \tcode{\placeholder{bulk-algo}},
the parameter \tcode{policy} describes
the manner in which
the execution of the asynchronous operations corresponding to these algorithms
may be parallelized and
the manner in which
%%FIXME: Should this be "apply to f"?
they apply \tcode{f}.
Permissions and requirements
on parallel algorithm element access functions\iref{algorithms.parallel.exec}
apply to \tcode{f}.
\end{itemize}

\pnum
\begin{note}
The asynchronous operation corresponding to
\tcode{\placeholder{bulk-algo}(sndr, policy, shape, f)}
can complete with \tcode{set_stopped} if cancellation is requested or
ignore cancellation requests.
\end{note}

\rSec3[exec.when.all]{\tcode{execution::when_all}}

\pnum
\tcode{when_all} and \tcode{when_all_with_variant}
both adapt multiple input senders into a sender
that completes when all input senders have completed.
\tcode{when_all} only accepts senders
with a single value completion signature and
on success concatenates all the input senders' value result datums
into its own value completion operation.
\tcode{when_all_with_variant(sndrs...)} is semantically equivalent to
w\tcode{hen_all(into_variant(sndrs)...)},
where \tcode{sndrs} is a pack of subexpressions
whose types model \libconcept{sender}.

\pnum
The names \tcode{when_all} and \tcode{when_all_with_variant} denote
customization point objects.
Let \tcode{sndrs} be a pack of subexpressions and
let \tcode{Sndrs} be a pack of the types \tcode{decltype((sndrs))...}.
The expressions \tcode{when_all(sndrs...)} and
\tcode{when_all_with_variant(sndrs...)} are ill-formed
if any of the following is \tcode{true}:
\begin{itemize}
\item
\tcode{sizeof...(sndrs)} is \tcode{0}, or
\item
\tcode{(\libconcept{sender}<Sndrs> \&\& ...)} is \tcode{false}.
\end{itemize}

\pnum
The expression \tcode{when_all(sndrs...)} is expression-equivalent to
\tcode{\exposid{make-sender}(when_all, \{\}, sndrs...)}.

\pnum
The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos}
is specialized for \tcode{when_all_t} as follows:
\indexlibraryglobal{\exposid{impls-for}<when_all_t>}
\begin{codeblock}
namespace std::execution {
  template<>
  struct @\exposid{impls-for}@<when_all_t> : @\exposid{default-impls}@ {
    static constexpr auto @\exposid{get-env}@ = @\seebelow@;
    static constexpr auto @\exposid{get-state}@ = @\seebelow@;
    static constexpr auto @\exposid{start}@ = @\seebelow@;
    static constexpr auto @\exposid{complete}@ = @\seebelow@;

    template<class Sndr, class... Env>
      static consteval void @\exposid{check-types}@();
  };
}
\end{codeblock}

\pnum
Let \exposid{make-when-all-env} be
the following exposition-only function template:
\indexlibraryglobal{\exposid{make-when-all-env}}
%%FIXME: Should this be in namespace std::execution?
\begin{codeblock}
template<class Env>
  constexpr auto @\exposid{make-when-all-env}@(inplace_stop_source& stop_src,               // \expos
                                   Env&& env) noexcept;
\end{codeblock}

\pnum
\returns
An object \tcode{e} such that
\begin{itemize}
\item
\tcode{decltype(e)} models \exposconcept{queryable}, and
\item
\tcode{e.query(get_stop_token)} is expression-equivalent to
\tcode{stop_src.get_token()}, and
\item
given a query object \tcode{q}
with type other than \cv{} \tcode{get_stop_token_t},
\tcode{e.query(q)} is expression-equivalent to \tcode{env.query(q)}
if the type of \tcode{q} satisfies \exposconcept{forwarding-query}, and
ill-formed otherwise.
\end{itemize}

\pnum
Let \tcode{\placeholder{when-all-env}} be an alias template such that
\tcode{\placeholder{when-all-env}<Env>} denotes the type
\tcode{decltype(\exposid{make-\linebreak{}when-all-env}(declval<inplace_stop_source\&>(), declval<Env>()))}.

\indexlibrarymember{\exposid{check-types}}{\exposid{impls-for}<when_all_t>}
\begin{itemdecl}
template<class Sndr, class... Env>
  static consteval void @\exposid{check-types}@();
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{Is} be the pack of integral template arguments of
the \tcode{integer_sequence} specialization denoted by
\tcode{\exposid{indices-for}<Sndr>}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
auto fn = []<class Child>() {
  auto cs = get_completion_signatures<Child, @\placeholder{when-all-env}@<Env>...>();
  if constexpr (cs.@\exposid{count-of}@(set_value) >= 2)
    throw @\placeholder{unspecified-exception}@();
  @\exposid{decay-copyable-result-datums}@(cs); // see \ref{exec.snd.expos}
};
(fn.template operator()<@\exposid{child-type}@<Sndr, Is>>(), ...);
\end{codeblock}
\end{itemdescr}

\pnum
The member \tcode{\exposid{impls-for}<when_all_t>::\exposid{get-env}}
is initialized with a callable object
equivalent to the following lambda expression:
\begin{codeblock}
[]<class State, class Rcvr>(auto&&, State& state, const Receiver& rcvr) noexcept {
  return @\exposid{make-when-all-env}@(state.@\exposid{stop-src}@, get_env(rcvr));
}
\end{codeblock}

\pnum
The member \tcode{\exposid{impls-for}<when_all_t>::\exposid{get-state}}
is initialized with a callable object
equivalent to the following lambda expression:
\begin{codeblock}
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept(noexcept(@$e$@)) -> decltype(@$e$@) {
  return @$e$@;
}
\end{codeblock}
where $e$ is the expression
\begin{codeblock}
std::forward<Sndr>(sndr).@\exposid{apply}@(@\exposid{make-state}@<Rcvr>())
\end{codeblock}
and where \exposid{make-state} is the following exposition-only class template:
\begin{codeblock}
enum class @\exposid{disposition}@ { @\exposid{started}@, @\exposid{error}@, @\exposid{stopped}@ };             // \expos

template<class Rcvr>
struct @\exposid{make-state}@ {
  template<class... Sndrs>
  auto operator()(auto, auto, Sndrs&&... sndrs) const {
    using values_tuple = @\seebelow@;
    using errors_variant = @\seebelow@;
    using stop_callback = stop_callback_for_t<stop_token_of_t<env_of_t<Rcvr>>, @\exposid{on-stop-request}@>;

    struct @\exposid{state-type}@ {
      void @\exposid{arrive}@(Rcvr& rcvr) noexcept {                        // \expos
        if (0 == --count) {
          @\exposid{complete}@(rcvr);
        }
      }

      void @\exposid{complete}@(Rcvr& rcvr) noexcept;                       // \expos

      atomic<size_t> @\exposid{count}@{sizeof...(sndrs)};                   // \expos
      inplace_stop_source @\exposid{stop_src}@{};                           // \expos
      atomic<@\exposid{disposition}@> disp{@\exposidnc{disposition}@::@\exposidnc{started}@};           // \expos
      errors_variant @\exposid{errors}@{};                                  // \expos
      values_tuple @\exposid{values}@{};                                    // \expos
      optional<stop_callback> @\exposid{on_stop}@{nullopt};                 // \expos
    };

    return @\exposid{state-type}@{};
  }
};
\end{codeblock}

\pnum
Let \exposid{copy-fail} be \tcode{exception_ptr}
if decay-copying any of the child senders' result datums can potentially throw;
otherwise, \tcode{\placeholder{none-such}},
where \tcode{\placeholder{none-such}} is an unspecified empty class type.

\pnum
The alias \tcode{values_tuple} denotes the type
\begin{codeblock}
tuple<value_types_of_t<Sndrs, @\exposid{FWD-ENV-T}@(env_of_t<Rcvr>), @\exposid{decayed-tuple}@, optional>...>
\end{codeblock}
if that type is well-formed; otherwise, \tcode{tuple<>}.

\pnum
The alias \tcode{errors_variant} denotes
the type \tcode{variant<\placeholder{none-such}, \exposid{copy-fail}, Es...>}
with duplicate types removed,
where \tcode{Es} is the pack of the decayed types
of all the child senders' possible error result datums.

\pnum
The member
\tcode{void \exposid{state-type}::\exposid{complete}(Rcvr\& rcvr) noexcept}
behaves as follows:
\begin{itemize}
\item
If \tcode{disp} is equal to \tcode{\exposid{disposition}::\exposid{started}},
evaluates:
\begin{codeblock}
auto tie = []<class... T>(tuple<T...>& t) noexcept { return tuple<T&...>(t); };
auto set = [&](auto&... t) noexcept { set_value(std::move(rcvr), std::move(t)...); };

@\exposid{on_stop}@.reset();
apply(
  [&](auto&... opts) noexcept {
    apply(set, tuple_cat(tie(*opts)...));
  },
  values);
\end{codeblock}
\item
Otherwise,
if \tcode{disp} is equal to \tcode{\exposid{disposition}::\exposid{error}},
evaluates:
\begin{codeblock}
@\exposid{on_stop}@.reset();
visit(
  [&]<class Error>(Error& error) noexcept {
    if constexpr (!@\libconcept{same_as}@<Error, @\placeholder{none-such}@>) {
      set_error(std::move(rcvr), std::move(error));
    }
  },
  errors);
\end{codeblock}
\item
Otherwise, evaluates:
\begin{codeblock}
if constexpr (@\placeholder{sends-stopped}@) {
  @\exposid{on_stop}@.reset();
  set_stopped(std::move(rcvr));
}
\end{codeblock}
where \tcode{\placeholder{sends-stopped}} equals \tcode{true}
if and only if there exists an element \tcode{S} of \tcode{Sndrs} such that
\tcode{completion_signatures_of_t<S, \exposid{when-all-env}<Env>>}
contains \tcode{set_stopped_t()}.
\end{itemize}

\pnum
The member \tcode{\exposid{impls-for}<when_all_t>::\exposid{start}}
is initialized with a callable object
equivalent to the following lambda expression:
\begin{codeblock}
[]<class State, class Rcvr, class... Ops>(
    State& state, Rcvr& rcvr, Ops&... ops) noexcept -> void {
  state.@\exposid{on_stop}@.emplace(
    get_stop_token(get_env(rcvr)),
    @\exposid{on-stop-request}@{state.@\exposid{stop_src}@});
  (start(ops), ...);
}
\end{codeblock}

\pnum
The member \tcode{\exposid{impls-for}<when_all_t>::\exposid{complete}}
is initialized with a callable object
equivalent to the following lambda expression:
\begin{codeblock}
[]<class Index, class State, class Rcvr, class Set, class... Args>(
    this auto& complete, Index, State& state, Rcvr& rcvr, Set, Args&&... args) noexcept -> void {
  if constexpr (@\libconcept{same_as}@<Set, set_error_t>) {
    if (@\exposid{disposition}@::@\exposid{error}@ != state.disp.exchange(@\exposid{disposition}@::@\exposid{error}@)) {
      state.@\exposid{stop_src}@.request_stop();
      @\exposid{TRY-EMPLACE-ERROR}@(state.errors, std::forward<Args>(args)...);
    }
  } else if constexpr (@\libconcept{same_as}@<Set, set_stopped_t>) {
    auto expected = @\exposid{disposition}@::@\exposid{started}@;
    if (state.disp.compare_exchange_strong(expected, @\exposid{disposition}@::@\exposid{stopped}@)) {
      state.@\exposid{stop_src}@.request_stop();
    }
  } else if constexpr (!@\libconcept{same_as}@<decltype(State::values), tuple<>>) {
    if (state.disp == @\exposid{disposition}@::@\exposid{started}@) {
      auto& opt = get<Index::value>(state.values);
      @\exposid{TRY-EMPLACE-VALUE}@(complete, opt, std::forward<Args>(args)...);
    }
  }
  state.@\exposid{arrive}@(rcvr);
}
\end{codeblock}
where \tcode{\exposid{TRY-EMPLACE-ERROR}(v, e)},
for subexpressions \tcode{v} and \tcode{e}, is equivalent to:
\begin{codeblock}
try {
  v.template emplace<decltype(auto(e))>(e);
} catch (...) {
  v.template emplace<exception_ptr>(current_exception());
}
\end{codeblock}
if the expression \tcode{decltype(auto(e))(e)} is potentially throwing;
otherwise, \tcode{v.template emplace<decl\-type(auto(e))>(e)};
and where \tcode{\exposid{TRY-EMPLACE-VALUE}(c, o, as...)},
for subexpressions \tcode{c}, \tcode{o}, and pack of subexpressions \tcode{as},
is equivalent to:
\begin{codeblock}
try {
  o.emplace(as...);
} catch (...) {
  c(Index(), state, rcvr, set_error, current_exception());
  return;
}
\end{codeblock}
if the expression \tcode{\exposid{decayed-tuple}<decltype(as)...>\{as...\}}
is potentially throwing;
otherwise, \tcode{o.emplace(\linebreak as...)}.

\pnum
The expression \tcode{when_all_with_variant(sndrs...)}
is expression-equivalent to
\tcode{\exposid{make-sender}(when_all_with_variant, \{\}, sndrs...)}.

\pnum
Given subexpressions \tcode{sndr} and \tcode{env},
if
\tcode{\exposconcept{sender-for}<decltype((sndr)), when_all_with_variant_t>}
is \tcode{false},
then the expression \tcode{when_all_with_variant.transform_sender(set_value, sndr, env)}
is ill-formed;
otherwise, it is equivalent to:
\begin{codeblock}
auto&& [_, _, ...child] = sndr;
return when_all(into_variant(std::forward_like<decltype((sndr))>(child))...);
\end{codeblock}
\begin{note}
This causes the \tcode{when_all_with_variant(sndrs...)} sender
to become \tcode{when_all(into_variant(sndrs)...)}
when it is connected with a receiver
whose execution domain does not customize \tcode{when_all_with_variant}.
\end{note}

\rSec3[exec.into.variant]{\tcode{execution::into_variant}}

\pnum
\tcode{into_variant} adapts a sender with multiple value completion signatures
into a sender with just one value completion signature
consisting of a \tcode{variant} of \tcode{tuple}s.

\pnum
The name \tcode{into_variant} denotes a pipeable sender adaptor object.
For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}.
If \tcode{Sndr} does not satisfy \libconcept{sender},
\tcode{into_variant(sndr)} is ill-formed.

\pnum
Otherwise, the expression \tcode{into_variant(sndr)}
is expression-equivalent to
\tcode{\exposid{make-sender}(into_variant, \{\}, sndr)}.

\pnum
The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos}
is specialized for \tcode{into_variant} as follows:
\indexlibraryglobal{\exposid{impls-for}<into_variant_t>}
\indexlibrarymember{\exposid{check-types}}{\exposid{impls-for}<into_variant_t>}
\begin{codeblock}
namespace std::execution {
  template<>
  struct @\exposid{impls-for}@<into_variant_t> : @\exposid{default-impls}@ {
    static constexpr auto @\exposid{get-state}@ = @\seebelow@;
    static constexpr auto @\exposid{complete}@ = @\seebelow@;

    template<class Sndr, class... Env>
      static consteval void @\exposid{check-types}@() {
        auto cs = get_completion_signatures<@\exposid{child-type}@<Sndr>, @\exposid{FWD-ENV-T}@(Env)...>();
        @\exposid{decay-copyable-result-datums}@(cs);   // see \ref{exec.snd.expos}
      }
  };
}
\end{codeblock}

\pnum
The member \tcode{\exposid{impls-for}<into_variant_t>::\exposid{get-state}}
is initialized with a callable object equivalent to the following lambda:
\begin{codeblock}
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept
  -> type_identity<value_types_of_t<@\exposid{child-type}@<Sndr>, @\exposid{FWD-ENV-T}@(env_of_t<Rcvr>)>> {
  return {};
}
\end{codeblock}

\pnum
The member \tcode{\exposid{impls-for}<into_variant_t>::\exposid{complete}}
is initialized with a callable object equivalent to the following lambda:
\begin{codeblock}
[]<class State, class Rcvr, class Tag, class... Args>(
    auto, State, Rcvr& rcvr, Tag, Args&&... args) noexcept -> void {
  if constexpr (@\libconcept{same_as}@<Tag, set_value_t>) {
    using variant_type = State::type;
    @\exposid{TRY-SET-VALUE}@(rcvr, variant_type(@\exposid{decayed-tuple}@<Args...>{std::forward<Args>(args)...}));
  } else {
    Tag()(std::move(rcvr), std::forward<Args>(args)...);
  }
}
\end{codeblock}

\rSec3[exec.stopped.opt]{\tcode{execution::stopped_as_optional}}

\pnum
\tcode{stopped_as_optional} maps a sender's stopped completion operation
into a value completion operation as a disengaged \tcode{optional}.
The sender's value completion operation
is also converted into an \tcode{optional}.
The result is a sender that never completes with stopped,
reporting cancellation by completing with a disengaged \tcode{optional}.

\pnum
The name \tcode{stopped_as_optional} denotes a pipeable sender adaptor object.
For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}.
The expression \tcode{stopped_as_optional(sndr)} is expression-equivalent to
\tcode{\exposid{make-sender}(stopped_as_optional, \{\}, sndr)}.

\pnum
The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos}
is specialized for \tcode{stopped_as_optional_t} as follows:
\indexlibraryglobal{\exposid{impls-for}<stopped_as_optional_t>}
\indexlibrarymember{\exposid{check-types}}{\exposid{impls-for}<stopped_as_optional_t>}
\begin{codeblock}
namespace std::execution {
  template<>
  struct @\exposid{impls-for}@<stopped_as_optional_t> : @\exposid{default-impls}@ {
    template<class Sndr, class... Env>
      static consteval void @\exposid{check-types}@() {
        @\exposid{default-impls}@::@\exposid{check-types}@<Sndr, Env...>();
        if constexpr (!requires {
          requires (!@\libconcept{same_as}@<void, @\exposid{single-sender-value-type}@<@\exposid{child-type}@<Sndr>,
                                                            @\exposid{FWD-ENV-T}@(Env)...>>); })
          throw @\placeholder{unspecified-exception}@();
      }
  };
}
\end{codeblock}

\pnum
Let \tcode{sndr} and \tcode{env} be subexpressions
such that \tcode{Sndr} is \tcode{decltype((sndr))} and
\tcode{Env} is \tcode{decltype((env))}.
If \tcode{\exposconcept{sender-for}<Sndr, stopped_as_optional_t>}
is \tcode{false}
then the expression \tcode{stopped_as_optional.trans\-form_sender(set_value, sndr, env)}
is ill-formed;
otherwise,
if \tcode{\libconcept{sender_in}<\exposid{child-type}<Sndr>, \exposid{FWD-\brk{}ENV-\brk{}T}(Env)>}
is \tcode{false},
the expression \tcode{stopped_as_optional.transform_sender(sndr, env)}
is equivalent to \tcode{\exposid{not-a-sen\-der}()};
otherwise, it is equivalent to:
\begin{codeblock}
auto&& [_, _, child] = sndr;
using V = @\exposid{single-sender-value-type}@<@\exposid{child-type}@<Sndr>, @\exposid{FWD-ENV-T}@(Env)>;
return let_stopped(
  then(std::forward_like<Sndr>(child),
       []<class... Ts>(Ts&&... ts) noexcept(is_nothrow_constructible_v<V, Ts...>) {
         return optional<V>(in_place, std::forward<Ts>(ts)...);
       }),
  []() noexcept { return just(optional<V>()); });
\end{codeblock}

\rSec3[exec.stopped.err]{\tcode{execution::stopped_as_error}}

\pnum
\tcode{stopped_as_error} maps an input sender's stopped completion operation
into an error completion operation as a custom error type.
The result is a sender that never completes with stopped,
reporting cancellation by completing with an error.

\pnum
The name \tcode{stopped_as_error} denotes a pipeable sender adaptor object.
For some subexpressions \tcode{sndr} and \tcode{err},
let \tcode{Sndr} be \tcode{decltype((sndr))} and
let \tcode{Err} be \tcode{decltype((err))}.
If the type \tcode{Sndr} does not satisfy \libconcept{sender} or
if the type \tcode{Err} does not satisfy \exposconcept{movable-value},
\tcode{stopped_as_error(sndr, err)} is ill-formed.
Otherwise, the expression \tcode{stopped_as_error(sndr, err)}
is expression-equivalent to
\tcode{\exposid{make-sender}(stopped_as_error, err, sndr)}.

\pnum
Let \tcode{sndr} and \tcode{env} be subexpressions
such that \tcode{Sndr} is \tcode{decltype((sndr))} and
\tcode{Env} is \tcode{decltype((env))}.
If \tcode{\exposconcept{sender-for}<Sndr, stopped_as_error_t>} is \tcode{false},
then the expression \tcode{stopped_as_error.transform_sender(set_value, sndr, env)}
is ill-formed;
otherwise, it is equivalent to:
\begin{codeblock}
auto&& [_, err, child] = sndr;
using E = decltype(auto(err));
return let_stopped(
  std::forward_like<Sndr>(child),
  [err = std::forward_like<Sndr>(err)]() mutable noexcept(is_nothrow_move_constructible_v<E>) {
    return just_error(std::move(err));
  });
\end{codeblock}

\rSec3[exec.associate]{\tcode{execution::associate}}

\pnum
\tcode{associate} tries to associate
a sender with an async scope such that
the scope can track the lifetime of any asynchronous operations
created with the sender.

\pnum
Let \exposid{associate-data} be the following exposition-only class template:

\indexlibraryglobal{execution::\exposid{associate-data}}%
\begin{codeblock}
namespace std::execution {
  template<@\libconcept{scope_token}@ Token, @\libconcept{sender}@ Sender>
  struct @\exposidnc{associate-data}@ {                                               // \expos
    using @\exposidnc{wrap-sender}@ =                                                 // \expos
      remove_cvref_t<decltype(declval<Token&>().wrap(declval<Sender>()))>;
    using @\exposidnc{assoc-t}@ = decltype(declval<Token&>().try_associate());        // \expos
    using @\exposidnc{sender-ref}@ =                                                  // \expos
      unique_ptr<@\exposidnc{wrap-sender}@, decltype([](auto* p) noexcept { destroy_at(p); })>;

    explicit @\exposid{associate-data}@(Token t, Sender&& s)
      : @\exposid{sndr}@(t.wrap(std::forward<Sender>(s))),
        @\exposid{assoc}@([&] {
          @\exposid{sender-ref}@ guard{addressof(@\exposid{sndr}@)};
          auto assoc = t.try_associate();
          if (assoc) {
            guard.release();
          }
          return assoc;
        }()) {}

    @\exposid{associate-data}@(const @\exposid{associate-data}@& other)
      noexcept(is_nothrow_copy_constructible_v<@\exposid{wrap-sender}@> &&
               noexcept(other.@\exposid{assoc}@.try_associate()));

    @\exposid{associate-data}@(@\exposid{associate-data}@&& other)
      noexcept(is_nothrow_move_constructible_v<@\exposid{wrap-sender}@>)
      : @\exposid{associate-data}@(std::move(other).release()) {}

    ~@\exposid{associate-data}@();

    pair<@\exposid{assoc-t}@, @\exposid{sender-ref}@> release() && noexcept;

  private:
    @\exposidnc{associate-data}@(pair<@\exposidnc{assoc-t}@, @\exposidnc{sender-ref}@> parts);                    // \expos
    union {
      @\exposidnc{wrap-sender}@ @\exposidnc{sndr}@;                                                 // \expos
    };
    @\exposidnc{assoc-t}@ @\exposidnc{assoc}@;                                                      // \expos
  };

  template<@\libconcept{scope_token}@ Token, @\libconcept{sender}@ Sender>
    @\exposid{associate-data}@(Token, Sender&&) -> @\exposid{associate-data}@<Token, Sender>;
}
\end{codeblock}

\pnum
For an \exposid{associate-data} object \tcode{a},
\tcode{bool(a.\exposid{assoc})} is \tcode{true}
if and only if
an association was successfully made and is owned by \tcode{a}.

\indexlibraryctor{execution::\exposid{associate-data}}%
\begin{itemdecl}
@\exposid{associate-data}@(const @\exposid{associate-data}@& other)
  noexcept(is_nothrow_copy_constructible_v<@\exposid{wrap-sender}@> &&
           noexcept(other.@\exposid{assoc}@.try_associate()));
\end{itemdecl}

\begin{itemdescr}
\pnum
\constraints
\exposid{wrap-sender} models \libconcept{copy_constructible}.

\pnum
\effects
Initializes \exposid{assoc} with \tcode{other.\exposid{assoc}.try_associate()}.
If \tcode{bool(\exposid{assoc})} is \tcode{true},
initializes \exposid{sndr} with \tcode{other.\exposid{sndr}}.
\end{itemdescr}

\indexlibraryctor{execution::\exposid{associate-data}}%
\begin{itemdecl}
@\exposid{associate-data}@(pair<@\exposid{assoc-t}@, @\exposid{sender-ref}@> parts);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Initializes \exposid{assoc} with \tcode{std::move(parts.first)}.
If \tcode{bool(\exposid{assoc})} is \tcode{true},
initializes \exposid{sndr} with \tcode{std::move(*parts.second)}.
\end{itemdescr}

\indexlibrarydtor{execution::\exposid{associate-data}}%
\begin{itemdecl}
~@\exposid{associate-data}@();
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
If \tcode{bool(\exposid{assoc})} is \tcode{true}, destroys \exposid{sndr}.
\end{itemdescr}

\indexlibrarymember{release}{execution::\exposid{associate-data}}%
\begin{itemdecl}
pair<@\exposid{assoc-t}@, @\exposid{sender-ref}@> release() && noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Constructs an object \tcode{u} of type \exposid{sender-ref}
that is initialized with \tcode{addressof(\exposid{sndr})}
if \tcode{bool(\exposid{assoc})} is \tcode{true} and
with \tcode{nullptr} otherwise,
then returns \tcode{pair\{std::move(\exposid{assoc}), std::\brk move(u)\}}.
\end{itemdescr}

\pnum
The name \tcode{associate} denotes a pipeable sender adaptor object.
For subexpressions \tcode{sndr} and \tcode{token}:
\begin{itemize}
\item
If \tcode{decltype((sndr))} does not satisfy \libconcept{sender}, or
\tcode{remove_cvref_t<decltype((token))>}
does not satisfy \libconcept{scope_token}, then
\tcode{associate(sndr, token)} is ill-formed.
\item
Otherwise,
the expression \tcode{associate(sndr, token)}
is expression-equivalent to
\tcode{\exposid{make-sender}(asso\-ci\-ate, \exposid{associate-data}(token, sndr))}.
\end{itemize}

\pnum
The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos}
is specialized for \tcode{associate_t} as follows:
\indexlibraryglobal{execution::\exposid{impls-for}<associate_t>}%
\begin{codeblock}
namespace std::execution {
  template<>
  struct @\exposid{impls-for}@<associate_t> : @\exposid{default-impls}@ {
    static constexpr auto @\exposid{get-state}@ = @\seebelow@;                // \expos
    static constexpr auto @\exposid{start}@ = @\seebelow@;                    // \expos

    template<class Sndr, class... Env>
      static consteval void @\exposid{check-types}@() {                     // \expos
        using associate_data_t = remove_cvref_t<@\exposid{data-type}@<Sndr>>;
        using child_type_t = associate_data_t::@\exposid{wrap-sender}@;
        (void)get_completion_signatures<child_type_t, @\exposid{FWD-ENV-T}@(Env)...>();
    }
  };
}
\end{codeblock}

\pnum
The member \tcode{\exposid{impls-for}<associate_t>::\exposid{get-state}}
is initialized with a callable object equivalent to the following lambda:

\begin{codeblock}
[]<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept(@\seebelow@) {
  auto&& [_, data] = std::forward<Sndr>(sndr);

  using associate_data_t = remove_cvref_t<decltype(data)>;
  using assoc_t = associate_data_t::@\exposid{assoc-t}@;
  using sender_ref_t = associate_data_t::@\exposid{sender-ref}@;

  using op_t = connect_result_t<typename sender_ref_t::element_type, Rcvr>;

  struct op_state {
    assoc_t @\exposid{assoc}@;              // \expos
    union {
      Rcvr* @\exposid{rcvr}@;               // \expos
      op_t @\exposid{op}@;                  // \expos
    };

    explicit op_state(pair<assoc_t, sender_ref_t> parts, Rcvr& r)
      : @\exposid{assoc}@(std::move(parts.first)) {
      if (@\exposid{assoc}@) {
        ::new (@\placeholdernc{voidify}@(@\exposid{op}@)) op_t(connect(std::move(*parts.second), std::move(r)));
      } else {
        @\exposid{rcvr}@ = addressof(r);
      }
    }

    explicit op_state(associate_data_t&& ad, Rcvr& r)
      : op_state(std::move(ad).release(), r) {}

    explicit op_state(const associate_data_t& ad, Rcvr& r)
      requires @\libconcept{copy_constructible}@<associate_data_t>
      : op_state(associate_data_t(ad).release(), r) {}

    op_state(op_state&&) = delete;

    ~op_state() {
      if (@\exposid{assoc}@) {
        @\exposid{op}@.~op_t();
      }
    }

    void @\exposid{run}@() noexcept {       // \expos
      if (@\exposid{assoc}@) {
        start(@\exposid{op}@);
      } else {
        set_stopped(std::move(*@\exposid{rcvr}@));
      }
    }
  };

  return op_state{std::forward_like<Sndr>(data), @\exposid{rcvr}@};
}
\end{codeblock}

\pnum
The expression in the \tcode{noexcept} clause of
\tcode{\exposid{impls-for}<associate_t>::\exposid{get-state}} is
\begin{codeblock}
(is_same_v<Sndr, remove_cvref_t<Sndr>> ||
 is_nothrow_constructible_v<remove_cvref_t<Sndr>, Sndr>) &&
@\exposconcept{nothrow-callable}@<connect_t, @\exposid{wrap-sender}@, Rcvr>
\end{codeblock}
where \exposid{wrap-sender} is the type
\tcode{remove_cvref_t<\exposid{data-type}<Sndr>>::\exposid{wrap-sender}}.

\pnum
The member \tcode{\exposid{impls-for}<associate_t>::\exposid{start}}
is initialized with a callable object equivalent to the following lambda:
\begin{codeblock}
[](auto& state, auto&) noexcept -> void {
  state.@\exposid{run}@();
}
\end{codeblock}

\pnum
%%FIXME: What are "sndr" and "token" referring to here?
The evaluation of \tcode{associate(sndr, token)}
may cause side effects observable
via \tcode{token}{'s} associated async scope object.

\rSec3[exec.stop.when]{Exposition-only \tcode{execution::\exposid{stop-when}}}

\pnum
%%FIXME: Should stop-when be declared somewhere as \expos?
\exposid{stop-when} fuses an additional stop token \tcode{t}
into a sender so that, upon connecting to a receiver \tcode{r},
the resulting operation state receives stop requests from both
\tcode{t} and the token returned from \tcode{get_stop_token(get_env(r))}.

\pnum
The name \exposid{stop-when} denotes an exposition-only sender adaptor.
For subexpressions \tcode{sndr} and \tcode{token}:
\begin{itemize}
\item
If \tcode{decltype((sndr))} does not satisfy \libconcept{sender}, or
\tcode{remove_cvref_t<decltype((token))>}
does not satisfy \libconcept{stoppable_token},
then \tcode{\exposid{stop-when}(sndr, token)} is ill-formed.

\item
Otherwise,
if \tcode{remove_cvref_t<decltype((token))>} models
\libconcept{unstoppable_token} then
\tcode{\exposid{stop-when}(\brk{}sndr, token)} is expression-equivalent to
\tcode{(void)token, sndr},
except that \tcode{token} and \tcode{sndr} are indeterminately sequenced.

\item
Otherwise,
\tcode{\exposid{stop-when}(sndr, token)} returns a sender \tcode{osndr}.
%%FIXME: What is rtoken if osndr is not connected to a receiver?
If \tcode{osndr} is connected to a receiver \tcode{r},
let \tcode{rtoken} be the result of \tcode{get_stop_token(get_env(r))}.

\begin{itemize}
\item
If the type of \tcode{rtoken} models \libconcept{unstoppable_token} then
the effects of connecting \tcode{osndr} to \tcode{r}
are equivalent to
\tcode{connect(write_env(sndr, prop(get_stop_token, token)), r)}.

\item
Otherwise,
the effects of connecting \tcode{osndr} to \tcode{r}
are equivalent to
\tcode{connect(write_env(sndr, prop(get_stop_token, stoken)), r)}
where \tcode{stoken} is an object of
an exposition-only type \exposid{stoken-t} such that:
  \begin{itemize}
  \item
  \exposid{stoken-t} models \libconcept{stoppable_token};
  \item
  \tcode{stoken.stop_requested()} returns
  \tcode{token.stop_requested() || rtoken.stop_reques-\linebreak{}ted()};
  \item
  \tcode{stoken.stop_possible()} returns
  \tcode{token.stop_possible() || rtoken.stop_possible()}; and
  \item
  for types \tcode{Fn} and \tcode{Init} such that both
  \tcode{\libconcept{invocable}<Fn>} and
  \tcode{\libconcept{constructible_from}<Fn, Init>}
  are modeled,
  \tcode{\exposid{stoken-t}::callback_type<Fn>} models
  \tcode{\exposconcept{stoppable-callback-for}<Fn, \exposid{sto\-ken-t}, Init>}.
  \begin{tailnote}
  For an object \tcode{fn} of type \tcode{Fn}
  constructed from a value, \tcode{init}, of type \tcode{Init},
  registering \tcode{fn} using
  \tcode{\exposid{stoken-t}::callback_type<Fn>(stoken, init)}
  results in an invocation of \tcode{fn} when
  a callback registered with \tcode{token} or \tcode{rtoken} would be invoked.
  \tcode{fn} is invoked at most once.
  \end{tailnote}
  \end{itemize}
\end{itemize}
\end{itemize}

\rSec3[exec.spawn.future]{\tcode{execution::spawn_future}}

\pnum
\tcode{spawn_future} attempts to associate the given input sender
with the given token's async scope and, on success,
eagerly starts the input sender;
the return value is a sender that, when connected and started,
completes with either
the result of the eagerly-started input sender or with
\tcode{set_stopped} if the input sender was not started.

\pnum
The name \tcode{spawn_future} denotes a customization point object.
For subexpressions \tcode{sndr}, \tcode{token}, and \tcode{env},
\begin{itemize}
\item let \tcode{Sndr} be \tcode{decltype((sndr))},
\item let \tcode{Token} be \tcode{remove_cvref_t<decltype((token))>}, and
\item let \tcode{Env} be \tcode{remove_cvref_t<decltype((env))>}.
\end{itemize}
If any of
\tcode{\libconcept{sender}<Sndr>},
\tcode{\libconcept{scope_token}<Token>}, or
\tcode{\exposconcept{queryable}<Env>}
are not satisfied,
the expression \tcode{spawn_future(sndr, token, env)} is ill-formed.

\pnum
Let \exposid{try-cancelable} be the exposition-only class:

\indexlibraryglobal{execution::\exposid{try-cancelable}}%
\begin{codeblock}
namespace std::execution {
  struct @\exposid{try-cancelable}@ {                                           // \expos
    virtual void @\exposid{try-cancel}@() noexcept = 0;                         // \expos
  };
}
\end{codeblock}

\pnum
Let \exposid{spawn-future-state-base} be the exposition-only class template:

\indexlibraryglobal{execution::\exposid{spawn-future-state-base}}%
\begin{codeblock}
namespace std::execution {
  template<class Completions>
  struct @\exposid{spawn-future-state-base}@;                                   // \expos

  template<class... Sigs>
  struct @\exposid{spawn-future-state-base}@<completion_signatures<Sigs...>>    // \expos
    : @\exposid{try-cancelable}@ {
    using @\exposid{variant-t}@ = @\seebelow@;                                    // \expos
    @\exposid{variant-t}@ @\exposid{result}@;                                               // \expos
    virtual void @\exposid{complete}@() noexcept = 0;                           // \expos
  };
}
\end{codeblock}

\pnum
Let \tcode{Sigs} be the pack of arguments to
the \tcode{completion_signatures} specialization provided as
a parameter to the \exposid{spawn-future-state-base} class template.
Let \exposid{as-tuple} be an alias template that
transforms a completion signature \tcode{Tag(Args...)}
into the tuple specialization \tcode{\exposid{decayed-tuple}<Tag, Args...>}.

\begin{itemize}
\item
If \tcode{is_nothrow_constructible_v<decay_t<Arg>, Arg>} is \tcode{true}
for every type \tcode{Arg}
in every parameter pack \tcode{Args}
in every completion signature \tcode{Tag(Args...)}
in \tcode{Sigs} then
\exposid{variant-t} denotes the type
\tcode{variant<monostate, tuple<set_stopped_t>, \placeholder{as-tuple}<Sigs>...>},
except with duplicate types removed.

\item
Otherwise
\exposid{variant-t} denotes the type
\tcode{variant<monostate, tuple<set_stopped_t>, tuple<set_error_t, exception_ptr>, \placeholder{as-tuple}<Sigs>...>},
except with duplicate types removed.
\end{itemize}

\pnum
Let \exposid{spawn-future-receiver} be the exposition-only class template:

\indexlibraryglobal{execution::\exposid{spawn-future-receiver}}%
\begin{codeblock}
namespace std::execution {
  template<class Completions>
  struct @\exposid{spawn-future-receiver}@ {                                // \expos
    using receiver_concept = receiver_tag;

    @\exposid{spawn-future-state-base}@<Completions>* @\exposid{state}@;                // \expos

    template<class... T>
      void set_value(T&&... t) && noexcept {
        @\exposid{set-complete}@<set_value_t>(std::forward<T>(t)...);
      }

    template<class E>
      void set_error(E&& e) && noexcept {
        @\exposid{set-complete}@<set_error_t>(std::forward<E>(e));
      }

    void set_stopped() && noexcept {
      @\exposid{set-complete}@<set_stopped_t>();
    }

  private:
    template<class CPO, class... T>
      void @\exposid{set-complete}@(T&&... t) noexcept {                    // \expos
        constexpr bool nothrow = (is_nothrow_constructible_v<decay_t<T>, T> && ...);
        try {
          @\exposid{state}@->@\exposid{result}@.template emplace<@\exposid{decayed-tuple}@<CPO, T...>>(CPO{},
                                                                   std::forward<T>(t)...);
        }
        catch (...) {
          if constexpr (!nothrow) {
            using tuple_t = @\exposid{decayed-tuple}@<set_error_t, exception_ptr>;
            @\exposid{state}@->@\exposid{result}@.template emplace<tuple_t>(set_error_t{}, current_exception());
          }
        }
        @\exposid{state}@->@\exposid{complete}@();
      }
  };
}
\end{codeblock}

\pnum
Let \tcode{\placeholder{ssource-t}} be an unspecified type
that models \exposconcept{stoppable-source} and \libconcept{default_initializable},
such that a default-initialized object of type \tcode{\placeholder{ssource-t}}
has an associated stop state.
Let \tcode{ssource} be an lvalue of type \tcode{\placeholder{ssource-t}}.
Let \tcode{\placeholder{stoken-t}} be \tcode{decltype(ssource.get_token())}.
Let \exposid{future-spawned-sender} be the alias template:

\begin{codeblock}
template<@\libconcept{sender}@ Sender, class Env>
using @\exposid{future-spawned-sender}@ =                                   // \expos
  decltype(write_env(@\exposid{stop-when}@(declval<Sender>(), declval<@\placeholder{stoken-t}@>()), declval<Env>()));
\end{codeblock}

\pnum
Let \exposid{spawn-future-state} be the exposition-only class template:

\indexlibraryglobal{execution::\exposid{spawn-future-state}}%
\begin{codeblock}
namespace std::execution {
  template<class Alloc, @\libconcept{scope_token}@ Token, @\libconcept{sender}@ Sender, class Env>
  struct @\exposidnc{spawn-future-state}@                                                 // \expos
    : @\exposid{spawn-future-state-base}@<completion_signatures_of_t<@\exposid{future-spawned-sender}@<Sender, Env>>> {
    using @\exposidnc{sigs-t}@ =                                                          // \expos
      completion_signatures_of_t<@\exposid{future-spawned-sender}@<Sender, Env>>;
    using @\exposidnc{receiver-t}@ =                                                      // \expos
      @\exposid{spawn-future-receiver}@<@\exposid{sigs-t}@>;
    using @\exposidnc{op-t}@ =                                                            // \expos
      connect_result_t<@\exposid{future-spawned-sender}@<Sender, Env>, @\exposid{receiver-t}@>;

    @\exposidnc{spawn-future-state}@(Alloc alloc, Sender&& sndr, Token token, Env env)    // \expos
      : @\exposid{alloc}@(std::move(alloc)),
        @\exposid{op}@(connect(
          write_env(@\exposid{stop-when}@(std::forward<Sender>(sndr), @\exposid{ssource}@.get_token()), std::move(env)),
          @\exposid{receiver-t}@(this))),
        @\exposid{assoc}@(token.try_associate()) {
          if (@\exposid{assoc}@)
            start(@\exposid{op}@);
          else
            set_stopped(@\exposid{receiver-t}@(this));
        }

    void @\exposidnc{complete}@() noexcept override;                                      // \expos
    void @\exposidnc{consume}@(@\libconcept{receiver}@ auto& rcvr) noexcept;                             // \expos
    void @\exposidnc{abandon}@() noexcept;                                                // \expos
    void @\exposidnc{try-cancel}@() noexcept override {                                   // \expos
      @\exposid{ssource}@.request_stop();
      @\exposid{try-set-stopped}@();
    }
    void @\exposidnc{try-set-stopped}@() noexcept;                                        // \expos

  private:
    using @\exposidnc{assoc-t}@ =                                                         // \expos
      remove_cvref_t<decltype(declval<Token&>().try_associate())>;

    Alloc @\exposidnc{alloc}@;                                                            // \expos
    @\exposidnc{ssource-t}@ @\exposidnc{ssource}@;                                                      // \expos
    @\exposidnc{op-t}@ @\exposidnc{op}@;                                                                // \expos
    @\exposidnc{assoc-t}@ @\exposidnc{assoc}@;                                                          // \expos

    void @\exposidnc{destroy}@() noexcept;                                                // \expos
  };

  template<class Alloc, @\libconcept{scope_token}@ Token, @\libconcept{sender}@ Sender, class Env>        // \expos
    @\exposid{spawn-future-state}@(Alloc alloc, Sender&& sndr, Token token, Env env)
      -> @\exposid{spawn-future-state}@<Alloc, Token, Sender, Env>;
}
\end{codeblock}

\pnum
For purposes of determining the existence of a data race,
\exposid{complete}, \exposid{consume}, \exposid{try-set-stopped}, and \exposid{abandon}
behave as atomic operations\iref{intro.multithread}.
These operations on a single object of a type
that is a specialization of \exposid{spawn-future-state}
appear to occur in a single total order.

\indexlibrarymember{\exposid{complete}}{execution::\exposid{spawn-future-state}}%
\begin{itemdecl}
void @\exposid{complete}@() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
\begin{itemize}
\item
No effects if this invocation of \exposid{complete} happens before
an invocation of
\exposid{consume}, \exposid{try-set-\linebreak{}stopped}, or \exposid{abandon}
on \tcode{*this};
\item
otherwise,
if an invocation of \exposid{consume} on \tcode{*this} happens before
this invocation of \exposid{complete} and
no invocation of \exposid{try-set-stopped} on \tcode{*this} happened before
this invocation of \tcode{complete} then
there is a receiver, \tcode{rcvr}, registered and
that receiver is deregistered and completed
as if by \tcode{\exposid{consume}(rcvr)};
\item
otherwise,
\exposid{destroy} is invoked.
\end{itemize}
\end{itemdescr}

\indexlibrarymember{\exposid{consume}}{execution::\exposid{spawn-future-state}}%
\begin{itemdecl}
void @\exposid{consume}@(@\libconcept{receiver}@ auto& rcvr) noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
\begin{itemize}
\item
If this invocation of \exposid{consume} happens before
an invocation of \exposid{complete} on \tcode{*this} and
no invocation of \exposid{try-set-stopped} on \tcode{*this} happened before
this invocation of \exposid{consume} then
\tcode{rcvr} is registered to be completed when
\exposid{complete} is subsequently invoked on \tcode{*this};

\item
otherwise,
if this invocation of \exposid{consume} happens after
an invocation of \exposid{try-set-stopped} on \tcode{*this} and
no invocation of \exposid{complete} on \tcode{*this} happened before
this invocation of \exposid{consume} then
\tcode{rcvr} is completed as if by \tcode{set_stopped(std::move(rcvr))};

\item
otherwise,
\tcode{rcvr} is completed as if by:
\begin{codeblock}
std::move(this->@\exposid{result}@).visit(
  [&rcvr](auto&& tuple) noexcept {
    if constexpr (!@\libconcept{same_as}@<remove_reference_t<decltype(tuple)>, monostate>) {
      apply([&rcvr](auto cpo, auto&&... vals) {
        cpo(std::move(rcvr), std::move(vals)...);
      }, std::move(tuple));
    }
  });
@\exposid{destroy}@();
\end{codeblock}
\end{itemize}
\end{itemdescr}

\indexlibrarymember{\exposid{try-set-stopped}}{execution::\exposid{spawn-future-state}}%
\begin{itemdecl}
void @\exposid{try-set-stopped}@() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
\begin{itemize}
\item
If an invocation of \exposid{consume} on \tcode{*this} happens before
this invocation of \exposid{try-set-stopped} and
no invocation of \exposid{complete} on \tcode{*this} happened before
this invocation of \exposid{try-set-stopped} then
there is a receiver, \tcode{rcvr}, registered and
that receiver is deregistered and completed as if by
\tcode{set_stopped(std::move(rcvr)), \exposid{destroy}()};

\item
otherwise, no effects.
\end{itemize}
\end{itemdescr}

\indexlibrarymember{\exposid{abandon}}{execution::\exposid{spawn-future-state}}%
\begin{itemdecl}
void @\exposid{abandon}@() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
\begin{itemize}
\item
If this invocation of \exposid{abandon} happens before
an invocation of \exposid{complete} on \tcode{*this} then
equivalent to:
\begin{codeblock}
@\exposid{ssource}@.request_stop();
\end{codeblock}
\item
otherwise,
\exposid{destroy} is invoked.
\end{itemize}
\end{itemdescr}

\indexlibrarymember{\exposid{destroy}}{execution::\exposid{spawn-future-state}}%
\begin{itemdecl}
void @\exposid{destroy}@() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
auto associated = std::move(this->@\exposid{associated}@);
{
  using traits = allocator_traits<Alloc>::template rebind_traits<@\exposid{spawn-future-state}@>;
  typename traits::allocator_type alloc(std::move(this->@\exposid{alloc}@));
  traits::destroy(alloc, this);
  traits::deallocate(alloc, this, 1);
}
\end{codeblock}
\end{itemdescr}

\pnum
Let \exposid{future-operation} be the exposition-only class template:

\begin{codeblock}
namespace std::execution {
  template<class StatePtr, class Rcvr>
  struct @\exposid{future-operation}@ {                                     // \expos
    struct @\exposid{callback}@ {                                           // \expos
      @\exposid{try-cancelable}@* @\exposid{state}@;                                    // \expos

      void operator()() noexcept {
        @\exposid{state}@->@\exposid{try-cancel}@();
      };
    };

    using @\exposid{stop-token-t}@ =                                        // \expos
      stop_token_of_t<env_of_t<Rcvr>>;

    using @\exposid{stop-callback-t}@ =                                     // \expos
      stop_callback_for_t<@\exposid{stop-token-t}@, @\exposid{callback}@>;

    struct @\exposid{rcvr-t}@ {                                             // \expos
      using receiver_concept = receiver_tag;
      @\exposid{future-operation}@* @\exposid{op}@;                                     // \expos

      template<class... T>
      void set_value(T&&... ts) && noexcept {
        @\exposid{op}@->@\exposid{set-complete}@<set_value_t>(std::forward<T>(ts)...);
      }

      template<class E>
      void set_error(E&& e) && noexcept {
        @\exposid{op}@->@\exposid{set-complete}@<set_error_t>(std::forward<E>(e));
      }

      void set_stopped() && noexcept {
        @\exposid{op}@->@\exposid{set-complete}@<set_stopped_t>();
      }

      env_of_t<Rcvr> get_env() const noexcept {
        return execution::get_env(@\exposid{op}@->@\exposid{rcvr}@);
      }
    };

    Rcvr @\exposid{rcvr}@;                                                  // \expos
    StatePtr @\exposid{state}@;                                             // \expos
    @\exposid{rcvr-t}@ @\exposid{inner}@;                                               // \expos
    optional<@\exposid{stop-callback-t}@> @\exposid{stopCallback}@;                     // \expos


    @\exposid{future-operation}@(StatePtr state, Rcvr rcvr) noexcept        // \expos
      : @\exposid{rcvr}@(std::move(rcvr)), @\exposid{state}@(std::move(state)), @\exposid{inner}@(this)
    {}

    @\exposid{future-operation}@(@\exposid{future-operation}@&&) = delete;

    void @\exposid{run}@() & noexcept {                                     // \expos
      constexpr bool nothrow =
        is_nothrow_constructible_v<@\exposid{stop-callback-t}@, @\exposid{stop-token-t}@, @\exposid{callback}@>;
      try {
        @\exposid{stopCallback}@.emplace(get_stop_token(@\exposid{rcvr}@), @\exposid{callback}@(@\exposid{state}@.get()));
      }
      catch (...) {
        if constexpr (!nothrow) {
          set_error(std::move(@\exposid{rcvr}@), current_exception());
          return;
        }
      }

      @\exposid{state}@.release()->@\exposid{consume}@(@\exposid{inner}@);
    }

    template<class CPO, class... T>
    void @\exposid{set-complete}@(T&&... ts) noexcept {                     // \expos
      @\exposid{stopCallback}@.reset();
      CPO{}(std::move(@\exposid{rcvr}@), std::forward<T>(ts)...);
    }
  };
}
\end{codeblock}

\pnum
The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos}
is specialized for \tcode{spawn_future_t} as follows:

\indexlibraryglobal{execution::\exposid{impls-for}<spawn_future_t>}%
\begin{codeblock}
namespace std::execution {
  template<>
  struct @\exposid{impls-for}@<spawn_future_t> : @\exposid{default-impls}@ {
    static constexpr auto @\exposid{start}@ = @\seebelow@;                    // \expos
    static constexpr auto @\exposid{get-state}@ = @\seebelow@;                // \expos
  };
}
\end{codeblock}

\pnum
The member \tcode{\exposid{impls-for}<spawn_future_t>::\exposid{start}}
is initialized with a callable object equivalent to the following lambda:
\begin{codeblock}
[](auto& state, auto&) noexcept -> void {
  state.@\exposid{run}@();
}
\end{codeblock}

\pnum
The member \tcode{\exposid{impls-for}<spawn_future_t>::\exposid{get-state}}
is initialized with a callable object equivalent to the following lambda:
\begin{codeblock}
[]<class Sndr, class Rcvr>(Sndr sndr, Rcvr& rcvr) noexcept {
  auto& [_, data] = sndr;
  using state_ptr = remove_cvref_t<decltype(data)>;
  return @\exposid{future-operation}@<state_ptr, Rcvr>(std::move(data), std::move(rcvr));
}
\end{codeblock}

\pnum
For the expression \tcode{spawn_future(sndr, token, env)}
let \tcode{new_sender} be the expression \tcode{token.wrap(sndr)} and
let \tcode{alloc} and \tcode{senv} be defined as follows:
\begin{itemize}
\item
if the expression \tcode{get_allocator(env)} is well-formed, then
\tcode{alloc} is the result of \tcode{get_allocator(env)} and
\tcode{senv} is the expression \tcode{env};
\item
otherwise,
if the expression \tcode{get_allocator(get_env(new_sender))} is well-formed, then
\tcode{alloc} is the result of \tcode{get_allocator(get_env(new_sender))} and
\tcode{senv} is the expression
\tcode{\exposid{JOIN-ENV}(prop(get_allocator, alloc), env)};
\item
otherwise,
\tcode{alloc} is \tcode{allocator<void>()} and
\tcode{senv} is the expression \tcode{env}.
\end{itemize}

\pnum
The expression \tcode{spawn_future(sndr, token, env)}
has the following effects:

\begin{itemize}
\item
Uses \tcode{alloc} to allocate and construct an object \tcode{s} of type
\tcode{decltype(\exposid{spawn-future-state}(alloc, token.wrap(sndr), token, senv))}
from \tcode{alloc}, \tcode{token.wrap(sndr)}, \tcode{token}, and \tcode{senv}.
If an exception is thrown then
any constructed objects are destroyed and
any allocated memory is deallocated.

\item
Constructs an object \tcode{u} of
a type that is a specialization of \tcode{unique_ptr} such that:
  \begin{itemize}
  \item
  \tcode{u.get()} is equal to the address of \tcode{s}, and
  \item
  \tcode{u.get_deleter()(u.release())} is equivalent to
  \tcode{u.release()->\exposid{abandon}()}.
  \end{itemize}

\item
Returns \tcode{\exposid{make-sender}(spawn_future, std::move(u))}.
\end{itemize}

\pnum
The expression \tcode{spawn_future(sndr, token)} is expression-equivalent to
\tcode{spawn_future(sndr, token, ex\-ecution::env<>())}.

\rSec2[exec.consumers]{Sender consumers}

\rSec3[exec.sync.wait]{\tcode{this_thread::sync_wait}}

\pnum
\tcode{this_thread::sync_wait} and \tcode{this_thread::sync_wait_with_variant}
are used
to block the current thread of execution
until the specified sender completes and
to return its async result.
\tcode{sync_wait} mandates
that the input sender has exactly one value completion signature.

\pnum
Let \exposid{sync-wait-env} be the following exposition-only class type:
\begin{codeblock}
namespace std::this_thread {
  struct @\exposid{sync-wait-env}@ {
    execution::run_loop* @\exposid{loop}@;                                  // \expos

    auto query(execution::get_scheduler_t) const noexcept {
      return @\exposid{loop}@->get_scheduler();
    }

    auto query(execution::get_start_scheduler_t) const noexcept {
      return @\exposid{loop}@->get_scheduler();
    }

    auto query(execution::get_delegation_scheduler_t) const noexcept {
      return @\exposid{loop}@->get_scheduler();
    }
  };
}
\end{codeblock}

\pnum
Let \exposid{sync-wait-result-type} and
\exposid{sync-wait-with-variant-result-type}
be exposition-only alias templates defined as follows:
\begin{codeblock}
namespace std::this_thread {
  template<execution::@\libconcept{sender_in}@<@\exposid{sync-wait-env}@> Sndr>
    using @\exposid{sync-wait-result-type}@ =
      optional<execution::value_types_of_t<Sndr, @\exposid{sync-wait-env}@, @\exposid{decayed-tuple}@,
               type_identity_t>>;

  template<execution::@\libconcept{sender_in}@<@\exposid{sync-wait-env}@> Sndr>
    using @\exposid{sync-wait-with-variant-result-type}@ =
      optional<execution::value_types_of_t<Sndr, @\exposid{sync-wait-env}@>>;
}
\end{codeblock}

\pnum
The name \tcode{this_thread::sync_wait} denotes a customization point object.
For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}.
The expression \tcode{this_thread::sync_wait(sndr)}
is equivalent to \tcode{apply_sender(Domain(), sync_wait, sndr)},
where \tcode{Domain} is the type of
\tcode{get_completion_domain<set_value_t>(get_env(sndr), \exposid{sync-wait-env}\{\})}.

\pnum
\mandates
\begin{itemize}
\item
\tcode{\libconcept{sender_in}<Sndr, \exposid{sync-wait-env}>} is \tcode{true}.
\item
The type \tcode{\exposid{sync-wait-result-type}<Sndr>} is well-formed.
\item
\tcode{\libconcept{same_as}<decltype($e$), \exposid{sync-wait-result-type}<Sndr>>}
is \tcode{true}, where $e$ is the \tcode{apply_sender} expression above.
\end{itemize}

\pnum
Let \exposid{sync-wait-state} and \exposid{sync-wait-receiver}
be the following exposition-only class templates:
\begin{codeblock}
namespace std::this_thread {
  template<class Sndr>
  struct @\exposid{sync-wait-state}@ {                                      // \expos
    execution::run_loop @\exposid{loop}@;                                   // \expos
    exception_ptr @\exposid{error}@;                                        // \expos
    @\exposid{sync-wait-result-type}@<Sndr> @\exposidnc{result}@;                         // \expos
  };

  template<class Sndr>
  struct @\exposid{sync-wait-receiver}@ {                                   // \expos
    using receiver_concept = execution::receiver_tag;
    @\exposidnc{sync-wait-state}@<Sndr>* @\exposid{state}@;                               // \expos

    template<class... Args>
    void set_value(Args&&... args) && noexcept;

    template<class Error>
    void set_error(Error&& err) && noexcept;

    void set_stopped() && noexcept;

    @\exposid{sync-wait-env}@ get_env() const noexcept { return {&@\exposid{state}@->@\exposid{loop}@}; }
  };
}
\end{codeblock}

\begin{itemdecl}
template<class... Args>
void set_value(Args&&... args) && noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
try {
  @\exposid{state}@->@\exposid{result}@.emplace(std::forward<Args>(args)...);
} catch (...) {
  @\exposid{state}@->@\exposid{error}@ = current_exception();
}
@\exposid{state}@->@\exposid{loop}@.finish();
\end{codeblock}
\end{itemdescr}

\begin{itemdecl}
template<class Error>
void set_error(Error&& err) && noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
@\exposid{state}@->@\exposid{error}@ = @\exposid{AS-EXCEPT-PTR}@(std::forward<Error>(err));    // see \ref{exec.general}
@\exposid{state}@->@\exposid{loop}@.finish();
\end{codeblock}
\end{itemdescr}

\begin{itemdecl}
void set_stopped() && noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to \tcode{\exposid{state}->\exposid{loop}.finish()}.
\end{itemdescr}

\pnum
For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}.
If \tcode{\exposconcept{sender-to}<Sndr, \exposid{sync-wait-receiver}<\linebreak Sndr>>}
is \tcode{false},
the expression \tcode{sync_wait.apply_sender(sndr)} is ill-formed;
otherwise, it is equivalent to:
\begin{codeblock}
@\exposid{sync-wait-state}@<Sndr> state;
auto op = connect(sndr, @\exposid{sync-wait-receiver}@<Sndr>{&state});
start(op);

state.@\exposid{loop}@.run();
if (state.@\exposid{error}@) {
  rethrow_exception(std::move(state.@\exposid{error}@));
}
return std::move(state.@\exposid{result}@);
\end{codeblock}

\pnum
The behavior of \tcode{this_thread::sync_wait(sndr)} is undefined unless:
\begin{itemize}
\item
It blocks the current thread of execution\iref{defns.block}
with forward progress guarantee delegation\iref{intro.progress}
until the specified sender completes.
\begin{note}
The default implementation of \tcode{sync_wait} achieves
forward progress guarantee delegation by providing a \tcode{run_loop} scheduler
via the \tcode{get_delegation_scheduler} query
on the \exposid{sync-wait-receiver}'s environment.
The \tcode{run_loop} is driven by the current thread of execution.
\end{note}
\item
It returns the specified sender's async results as follows:
\begin{itemize}
\item
For a value completion,
the result datums are returned in
a \tcode{tuple} in an engaged \tcode{optional} object.
\item
For an error completion, an exception is thrown.
\item
For a stopped completion, a disengaged \tcode{optional} object is returned.
\end{itemize}
\end{itemize}

\rSec3[exec.sync.wait.var]{\tcode{this_thread::sync_wait_with_variant}}

\pnum
The name \tcode{this_thread::sync_wait_with_variant} denotes
a customization point object.
For a subexpression \tcode{sndr},
let \tcode{Sndr} be \tcode{decltype(into_variant(sndr))}.
The expression \tcode{this_thread::sync_wait_with_variant(sndr)}
is equivalent to \tcode{apply_sender(Domain(), sync_wait_with_variant, sndr)},
where \tcode{Domain} is the type of
\tcode{get_completion_domain<set_value_t>(get_env(sndr), \exposid{sync-wait-env}\{\})}.

\pnum
\mandates
\begin{itemize}
\item
\tcode{\libconcept{sender_in}<Sndr, \exposid{sync-wait-env}>} is \tcode{true}.
\item
The type \tcode{\exposid{sync-wait-with-variant-result-type}<Sndr>}
is well-formed.
\item
\tcode{\libconcept{same_as}<decltype($e$), \exposid{sync-wait-with-variant-result-type}<Sndr>>}
is \tcode{true}, where $e$ is the \tcode{ap\-ply_sender} expression above.
\end{itemize}

\pnum
The expression \tcode{sync_wait_with_variant.apply_sender(sndr)} is equivalent to:
\begin{codeblock}
using result_type = @\exposid{sync-wait-with-variant-result-type}@<Sndr>;
if (auto opt_value = sync_wait(into_variant(sndr))) {
  return result_type(std::move(get<0>(*opt_value)));
}
return result_type(nullopt);
\end{codeblock}

\pnum
The behavior of \tcode{this_thread::sync_wait_with_variant(sndr)}
is undefined unless:
\begin{itemize}
\item
It blocks the current thread of execution\iref{defns.block}
with forward progress guarantee delegation\iref{intro.progress}
until the specified sender completes.
\begin{note}
The default implementation of \tcode{sync_wait_with_variant} achieves
forward progress guarantee delegation by relying on
the forward progress guarantee delegation provided by \tcode{sync_wait}.
\end{note}
\item
It returns the specified sender's async results as follows:
\begin{itemize}
\item
For a value completion,
the result datums are returned in an engaged \tcode{optional} object
that contains a \tcode{variant} of \tcode{tuple}s.
\item
For an error completion, an exception is thrown.
\item
For a stopped completion, a disengaged \tcode{optional} object is returned.
\end{itemize}
\end{itemize}

\rSec3[exec.spawn]{\tcode{execution::spawn}}

\pnum
\tcode{spawn} attempts to associate the given input sender with
the given token's async scope and, on success,
eagerly starts the input sender.

\pnum
The name \tcode{spawn} denotes a customization point object.
For subexpressions \tcode{sndr}, \tcode{token}, and \tcode{env},
\begin{itemize}
\item let \tcode{Sndr} be \tcode{decltype((sndr))},
\item let \tcode{Token} be \tcode{remove_cvref_t<decltype((token))>}, and
\item let \tcode{Env} be \tcode{remove_cvref_t<decltype((env))>}.
\end{itemize}
If any of
\tcode{\libconcept{sender}<Sndr>},
\tcode{\libconcept{scope_token}<Token>}, or
\tcode{\exposconcept{queryable}<Env>}
are not satisfied,
the expression \tcode{spawn(\brk{}sndr, token, env)} is ill-formed.

\pnum
Let \exposid{spawn-state-base} be the exposition-only class:

\indexlibraryglobal{execution::\exposid{spawn-state-base}}%
\begin{codeblock}
namespace std::execution {
  struct @\exposid{spawn-state-base}@ {                                 // \expos
    virtual void @\exposid{complete}@() noexcept = 0;                   // \expos
  };
}
\end{codeblock}

\pnum
Let \exposid{spawn-receiver} be the exposition-only class:

\indexlibraryglobal{execution::\exposid{spawn-receiver}}%
\begin{codeblock}
namespace std::execution {
  struct @\exposid{spawn-receiver}@ {                                   // \expos
    using receiver_concept = receiver_tag;

    @\exposid{spawn-state-base}@* @\exposid{state}@;                                // \expos
    void set_value() && noexcept { @\exposid{state}@->@\exposid{complete}@(); }
    void set_stopped() && noexcept { @\exposid{state}@->@\exposid{complete}@(); }
  };
}
\end{codeblock}

\pnum
Let \exposid{spawn-state} be the exposition-only class template:

\indexlibraryglobal{execution::\exposid{spawn-state}}%
\begin{codeblock}
namespace std::execution {
  template<class Alloc, @\libconcept{scope_token}@ Token, @\libconcept{sender}@ Sender>
  struct @\exposid{spawn-state}@ : @\exposid{spawn-state-base}@ {                   // \expos
    using @\exposid{op-t}@ = connect_result_t<Sender, @\exposid{spawn-receiver}@>;  // \expos

    @\exposid{spawn-state}@(Alloc alloc, Sender&& sndr, Token token);   // \expos
    void @\exposid{complete}@() noexcept override;                      // \expos
    void @\exposid{run}@() noexcept;                                    // \expos

  private:
    using @\exposid{assoc-t}@ =                                         // \expos
      remove_cvref_t<decltype(declval<Token&>().try_associate())>;

    Alloc @\exposid{alloc}@;                                            // \expos
    @\exposid{op-t}@ @\exposid{op}@;                                                // \expos
    @\exposid{assoc-t}@ @\exposid{assoc}@;                                          // \expos
  };
}
\end{codeblock}

\indexlibraryctor{execution::\exposid{spawn-state}}%
\begin{itemdecl}
@\exposid{spawn-state}@(Alloc alloc, Sender&& sndr, Token token);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Initializes
\exposid{alloc} with \tcode{std::move(alloc)},
\exposid{op} with \tcode{connect(std::move(sndr), \exposid{spawn-re\-ceiv\-er}(this))}, and
\exposid{assoc} with \tcode{token.try_associate()}.
\end{itemdescr}

\indexlibrarymember{\exposid{run}}{execution::\exposid{spawn-state}}%
\begin{itemdecl}
void @\exposid{run}@() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if (@\exposid{assoc}@)
  start(@\exposid{op}@);
else
  @\exposid{complete}@();
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{\exposid{complete}}{execution::\exposid{spawn-state}}%
\begin{itemdecl}
void @\exposid{complete}@() noexcept override;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
auto assoc = std::move(this->@\exposid{assoc}@);
{
  using traits = allocator_traits<Alloc>::template rebind_traits<@\exposid{spawn-state}@>;
  typename traits::allocator_type alloc(this->@\exposid{alloc}@);
  traits::destroy(alloc, this);
  traits::deallocate(alloc, this, 1);
}
\end{codeblock}
\end{itemdescr}

\pnum
For the expression \tcode{spawn(sndr, token, env)}
let \tcode{new_sender} be the expression \tcode{token.wrap(sndr)} and
let \tcode{alloc} and \tcode{senv} be defined as follows:
\begin{itemize}
\item
if the expression \tcode{get_allocator(env)} is well-formed, then
\tcode{alloc} is the result of \tcode{get_allocator(env)} and
\tcode{senv} is the expression \tcode{env},
\item
otherwise
if the expression \tcode{get_allocator(get_env(new_sender))} is well-formed, then
\tcode{alloc} is the result of \tcode{get_allocator(get_env(new_sender))} and
\tcode{senv} is the expression \tcode{\exposid{JOIN-ENV}(prop(get_allocator, alloc), env)},
\item
otherwise
\tcode{alloc} is \tcode{allocator<void>()} and
\tcode{senv} is the expression \tcode{env}.
\end{itemize}

\pnum
The expression \tcode{spawn(sndr, token, env)} is of type \tcode{void} and
has the following effects:
%%FIXME: Was this supposed to be more than a single bullet?
\begin{itemize}
\item
Uses \tcode{alloc} to allocate and construct an object \tcode{o} of type
\tcode{decltype(\exposid{spawn-state}(alloc, write_env(token.wrap(sndr), senv), token))}
from \tcode{alloc}, \tcode{write_env(token.wrap(sndr), senv)}, and \tcode{token}
and then
invokes \tcode{o.\exposid{run}()}.
If an exception is thrown then
any constructed objects are destroyed and any allocated memory is deallocated.
\end{itemize}

\pnum
The expression \tcode{spawn(sndr, token)} is expression-equivalent to
\tcode{spawn(sndr, token, execution::env<>(\brk{}))}.

\rSec1[exec.cmplsig]{Completion signatures}

\pnum
\tcode{completion_signatures} is a type
that encodes a set of completion signatures\iref{exec.async.ops}.

\pnum
\begin{example}
\begin{codeblock}
struct my_sender {
  using sender_concept = sender_tag;
  using completion_signatures =
    execution::completion_signatures<
      set_value_t(),
      set_value_t(int, float),
      set_error_t(exception_ptr),
      set_error_t(error_code),
      set_stopped_t()>;
};
\end{codeblock}
Declares \tcode{my_sender} to be a sender
that can complete by calling one of the following
for a receiver expression \tcode{rcvr}:
\begin{itemize}
\item \tcode{set_value(rcvr)}
\item \tcode{set_value(rcvr, int\{...\}, float\{...\})}
\item \tcode{set_error(rcvr, exception_ptr\{...\})}
\item \tcode{set_error(rcvr, error_code\{...\})}
\item \tcode{set_stopped(rcvr)}
\end{itemize}
\end{example}

\pnum
This subclause makes use of the following exposition-only entities:
\begin{codeblock}
template<class Fn>
  concept @\defexposconcept{completion-signature}@ = @\seebelow@;
\end{codeblock}

\pnum
A type \tcode{Fn} satisfies \exposconcept{completion-signature}
if and only if it is a function type with one of the following forms:
\begin{itemize}
\item
\tcode{set_value_t(Vs...)},
where \tcode{Vs} is a pack of object or reference types.
\item
\tcode{set_error_t(Err)},
where \tcode{Err} is an object or reference type.
\item
\tcode{set_stopped_t()}
\end{itemize}

\pnum
\begin{codeblock}
template<bool>
  struct @\exposid{indirect-meta-apply}@ {
    template<template<class...> class T, class... As>
      using @\exposid{meta-apply}@ = T<As...>;                              // \expos
  };

template<class...>
  concept @\defexposconcept{always-true}@ = true;                                   // \expos

template<class Tag,
         @\exposconcept{valid-completion-signatures}@ Completions,
         template<class...> class Tuple,
         template<class...> class Variant>
  using @\exposid{gather-signatures}@ = @\seebelow@;
\end{codeblock}

\pnum
Let \tcode{Fns} be a pack of the arguments of
the \tcode{completion_signatures} specialization named by \tcode{Completions},
let \tcode{TagFns} be a pack of the function types in \tcode{Fns}
whose return types are \tcode{Tag}, and
let $\tcode{Ts}_n$ be a pack of the function argument types
in the $n$-th type in \tcode{TagFns}.
Then, given two variadic templates \tcode{Tuple} and \tcode{Variant},
the type \tcode{\exposid{gather-signatures}<Tag, Completions, Tuple, Variant>}
names the type
\begin{codeblock}
@\exposid{META-APPLY}@(Variant, @\exposid{META-APPLY}@(Tuple, Ts@$_0$@...),
                    @\itcorr[1]\exposid{META-APPLY}@(Tuple, Ts@$_1$@...),
                    @\itcorr[1]\ldots@,
                    @\itcorr[1]\exposid{META-APPLY}@(Tuple, Ts@$_{m-1}$@...))
\end{codeblock}
where $m$ is the size of the pack \tcode{TagFns} and
\tcode{\exposid{META-APPLY}(T, As...)} is equivalent to:
\begin{codeblock}
typename @\exposid{indirect-meta-apply}@<@\exposid{always-true}@<As...>>::template @\exposid{meta-apply}@<T, As...>
\end{codeblock}

\pnum
\begin{note}
The purpose of \exposid{META-APPLY} is to make it valid
to use non-variadic templates as \tcode{Variant} and \tcode{Tuple} arguments
to \exposid{gather-signatures}.
\end{note}

\pnum
\indexlibraryglobal{execution::completion_signatures}%
\indexlibrarymember{\exposid{for-each}}{execution::completion_signatures}%
\indexlibrarymember{\exposid{count-of}}{execution::completion_signatures}%
\begin{codeblock}
namespace std::execution {
  template<@\exposconcept{completion-signature}@... Fns>
    struct completion_signatures {
      template<class Tag>
        static constexpr size_t @\exposid{count-of}@(Tag) { return @\seebelow@; }

      template<class Fn>
        static constexpr void @\exposid{for-each}@(Fn&& fn) {               // \expos
          (fn(static_cast<Fns*>(nullptr)), ...);
        }
    };

  template<class Sndr, class Env = env<>,
           template<class...> class Tuple = @\exposid{decayed-tuple}@,
           template<class...> class Variant = @\exposid{variant-or-empty}@>
      requires @\libconcept{sender_in}@<Sndr, Env>
    using @\libglobal{value_types_of_t}@ =
      @\exposid{gather-signatures}@<set_value_t, completion_signatures_of_t<Sndr, Env>, Tuple, Variant>;

  template<class Sndr, class Env = env<>,
           template<class...> class Variant = @\exposid{variant-or-empty}@>
      requires @\libconcept{sender_in}@<Sndr, Env>
    using error_types_of_t =
      @\exposid{gather-signatures}@<set_error_t, completion_signatures_of_t<Sndr, Env>,
                        type_identity_t, Variant>;

  template<class Sndr, class Env = env<>>
      requires @\libconcept{sender_in}@<Sndr, Env>
    constexpr bool sends_stopped =
      !@\libconcept{same_as}@<@\exposid{type-list}@<>,
               @\exposid{gather-signatures}@<set_stopped_t, completion_signatures_of_t<Sndr, Env>,
                                 @\exposid{type-list}@, @\exposid{type-list}@>>;
}
\end{codeblock}

\pnum
For a subexpression \tcode{tag},
let \tcode{Tag} be the decayed type of \tcode{tag}.
\tcode{completion_signatures<Fns...>::\exposid{count-of}(\linebreak{}tag)}
returns the count of function types in \tcode{Fns...} that
are of the form \tcode{Tag(Ts...)} where \tcode{Ts} is a pack of types.

\rSec1[exec.envs]{Queryable utilities}

\rSec2[exec.prop]{Class template \tcode{prop}}

\begin{codeblock}
namespace std::execution {
  template<class QueryTag, class ValueType>
  struct @\libglobal{prop}@ {
    QueryTag @\exposid{query_}@;            // \expos
    ValueType @\exposid{value_}@;           // \expos

    constexpr const ValueType& query(QueryTag, auto&&...) const noexcept {
      return @\exposid{value_}@;
    }
  };

  template<class QueryTag, class ValueType>
    prop(QueryTag, ValueType) -> prop<QueryTag, unwrap_reference_t<ValueType>>;
}
\end{codeblock}

\pnum
Class template \tcode{prop} is for building a queryable object
from a query object and a value.

\pnum
\mandates
\tcode{\exposconcept{callable}<QueryTag, \exposid{prop-like}<ValueType>>}
is modeled,
where \exposid{prop-like} is the following exposition-only class template:
\begin{codeblock}
template<class ValueType>
struct @\exposid{prop-like}@ {              // \expos
  const ValueType& query(auto) const noexcept;
};
\end{codeblock}

\pnum
\begin{example}
\begin{codeblock}
template<@\libconcept{sender}@ Sndr>
@\libconcept{sender}@ auto parameterize_work(Sndr sndr) {
  // Make an environment such that \tcode{get_allocator(env)} returns a reference to a copy of \tcode{my_alloc\{\}}.
  auto e = prop(get_allocator, my_alloc{});

  // Parameterize the input sender so that it will use our custom execution environment.
  return write_env(sndr, e);
}
\end{codeblock}
\end{example}

\pnum
Specializations of \tcode{prop} are not assignable.

\rSec2[exec.env]{Class template \tcode{env}}

\begin{codeblock}
namespace std::execution {
  template<@\exposconcept{queryable}@... Envs>
  struct @\libglobal{env}@ {
    Envs@$_0$@ @$\exposid{envs}_0$@;               // \expos
    Envs@$_1$@ @$\exposid{envs}_1$@;               // \expos
      @\vdots@
    Envs@$_{n-1}$@ @$\exposid{envs}_{n-1}$@;           // \expos

    template<class QueryTag, class... Args>
      constexpr decltype(auto) query(QueryTag q, Args&&... args) const noexcept(@\seebelow@);
  };

  template<class... Envs>
    env(Envs...) -> env<unwrap_reference_t<Envs>...>;
}
\end{codeblock}

\pnum
The class template \tcode{env} is used to construct a queryable object
from several queryable objects.
Query invocations on the resulting object are resolved
by attempting to query each subobject in lexical order.

\pnum
Specializations of \tcode{env} are not assignable.

\pnum
It is unspecified
whether \tcode{env} supports initialization
using a parenthesized \grammarterm{expression-list}\iref{dcl.init},
unless the \grammarterm{expression-list} consist of
a single element of type (possibly const) \tcode{env}.

\pnum
\begin{example}
\begin{codeblock}
template<@\libconcept{sender}@ Sndr>
sender auto parameterize_work(Sndr sndr) {
  // Make an environment such that:
  //   \tcode{get_allocator(env)} returns a reference to a copy of \tcode{my_alloc\{\}}
  //   \tcode{get_scheduler(env)} returns a reference to a copy of \tcode{my_sched\{\}}
  auto e = env{prop(get_allocator, my_alloc{}),
               prop(get_scheduler, my_sched{})};

  // Parameterize the input sender so that it will use our custom execution environment.
  return write_env(sndr, e);
}
\end{codeblock}
\end{example}

\indexlibrarymember{query}{env}%
\begin{itemdecl}
template<class QueryTag, class... Args>
constexpr decltype(auto) query(QueryTag q, Args&&... args) const noexcept(@\seebelow@);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \exposconcept{has-query} be the following exposition-only concept:
\begin{codeblock}
template<class Env, class QueryTag, class... Args>
  concept @\defexposconcept{has-query}@ =                   // \expos
    requires (const Env& env, Args&&... args) {
      env.query(QueryTag(), std::forward<Args>(args)...);
    };
\end{codeblock}

\pnum
Let \exposid{fe} be the first element of
$\exposid{envs}_0$, $\exposid{envs}_1$, $\dotsc$, $\exposid{envs}_{n-1}$
such that the expression
\tcode{\exposid{fe}.query(q, std::forward<Args>(args)...)}
is well-formed.

\pnum
\constraints
\tcode{(\exposconcept{has-query}<Envs, QueryTag, Args...> || ...)} is \tcode{true}.

\pnum
\effects
Equivalent to: \tcode{return \exposid{fe}.query(q, std::forward<Args>(args)...);}

\pnum
\remarks
The expression in the \tcode{noexcept} clause is equivalent
to \tcode{noexcept(\exposid{fe}.query(q, std::for\-ward<Args>(args)...))}.
\end{itemdescr}

\rSec1[exec.ctx]{Execution contexts}

\rSec2[exec.run.loop]{\tcode{execution::run_loop}}

\rSec3[exec.run.loop.general]{General}

\pnum
A \tcode{run_loop} is an execution resource on which work can be scheduled.
It maintains a thread-safe first-in-first-out queue of work.
Its \tcode{run} member function removes elements from the queue and
executes them in a loop on the thread of execution that calls \tcode{run}.

\pnum
A \tcode{run_loop} instance has an associated \defn{count}
that corresponds to the number of work items that are in its queue.
Additionally, a \tcode{run_loop} instance has an associated state
that can be one of
\defn{starting}, \defn{running}, \defn{finishing}, or \defn{finished}.

\pnum
Concurrent invocations of the member functions of \tcode{run_loop}
other than \tcode{run} and its destructor do not introduce data races.
The member functions
\exposid{pop-front}, \exposid{push-back}, and \tcode{finish}
execute atomically.

\pnum
\recommended
Implementations should use an intrusive queue of operation states
to hold the work units to make scheduling allocation-free.

\begin{codeblock}
namespace std::execution {
  class @\libglobal{run_loop}@ {
    // \ref{exec.run.loop.types}, associated types
    class @\exposid{run-loop-scheduler}@;                                   // \expos
    class @\exposid{run-loop-sender}@;                                      // \expos
    struct @\exposid{run-loop-opstate-base}@ {                              // \expos
      virtual void @\exposid{execute}@() noexcept = 0;                      // \expos
      run_loop* @\exposid{loop}@;                                           // \expos
      @\exposid{run-loop-opstate-base}@* @\exposid{next}@;                              // \expos
    };
    template<class Rcvr>
      using @\exposid{run-loop-opstate}@ = @\unspec@;                     // \expos

    // \ref{exec.run.loop.members}, member functions
    @\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@() noexcept;                // \expos
    void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@*) noexcept;            // \expos

  public:
    // \ref{exec.run.loop.ctor}, constructor and destructor
    run_loop() noexcept;
    run_loop(run_loop&&) = delete;
    ~run_loop();

    // \ref{exec.run.loop.members}, member functions
    @\exposid{run-loop-scheduler}@ get_scheduler() noexcept;
    void run() noexcept;
    void finish() noexcept;
  };
}
\end{codeblock}

\rSec3[exec.run.loop.types]{Associated types}

\begin{itemdecl}
class @\exposid{run-loop-scheduler}@;
\end{itemdecl}

\pnum
\exposid{run-loop-scheduler} is an unspecified type
that models \libconcept{scheduler}.

\pnum
Instances of \exposid{run-loop-scheduler} remain valid
until the end of the lifetime of the \tcode{run_loop} instance
from which they were obtained.

\pnum
Two instances of \exposid{run-loop-scheduler} compare equal
if and only if they were obtained from the same \tcode{run_loop} instance.

\pnum
Let \exposid{sch} be an expression of type \exposid{run-loop-scheduler}.
The expression \tcode{schedule(\exposid{sch})}
has type \exposid{run-loop-\newline sender} and
is not potentially-throwing if \exposid{sch} is not potentially-throwing.

\pnum
For type \exposid{set-tag} other than \tcode{set_error_t},
the expression
\tcode{get_completion_scheduler<\exposid{set-tag}>(get_env(schedule(\exposid{sch}))) == \exposid{sch}}
evaluates to \tcode{true}.

\begin{itemdecl}
class @\exposid{run-loop-sender}@;
\end{itemdecl}

\pnum
\exposid{run-loop-sender} is an exposition-only type
that satisfies \libconcept{sender}.
Let \tcode{E} be the type of an environment.
If \tcode{unstoppable_token<stop_token_of_t<E>>} is \tcode{true}, then
\tcode{completion_signatures_of_t<\exposid{run-loop-sen\-der}, E>} is
\tcode{completion_signatures<set_value_t()>}.
Otherwise, it is \tcode{completion_signatures<set_value_t(), set_stopped_t()>}.

\pnum
An instance of \exposid{run-loop-sender} remains valid
until the end of the lifetime of its associated \tcode{run_loop} instance.

\pnum
Let \exposid{sndr} be an expression of type \exposid{run-loop-sender},
let \exposid{rcvr} be an expression
such that \tcode{\exposconcept{receiver-of}<decl\-type((\exposid{rcvr})), CS>} is \tcode{true}
where \tcode{CS} is the \tcode{completion_signatures} specialization above.
Let \tcode{C} be either \tcode{set_value_t} or \tcode{set_stopped_t}.
Then:
\begin{itemize}
\item
The expression \tcode{connect(\exposid{sndr}, \exposid{rcvr})}
has type \tcode{\exposid{run-loop-opstate}<decay_t<decltype((\exposid{rcvr}))>>}
and is potentially-throwing if and only if
\tcode{(void(\exposid{sndr}), auto(\exposid{rcvr}))} is potentially-throwing.
\item
The expression \tcode{get_completion_scheduler<C>(get_env(\exposid{sndr}))}
is potentially-throwing if and only if \exposid{sndr} is potentially-throwing,
has type \exposid{run-loop-scheduler}, and
compares equal to the \exposid{run-loop-\newline scheduler} instance
from which \exposid{sndr} was obtained.
\end{itemize}

\begin{itemdecl}
template<class Rcvr>
  struct @\exposid{run-loop-opstate}@;
\end{itemdecl}

\pnum
\tcode{\exposid{run-loop-opstate}<Rcvr>}
inherits privately and unambiguously from \exposid{run-loop-opstate-base}.

\pnum
Let $o$ be a non-const lvalue of type \tcode{\exposid{run-loop-opstate}<Rcvr>},
and let \tcode{REC($o$)} be a non-const lvalue reference to an instance of type \tcode{Rcvr}
that was initialized with the expression \exposid{rcvr}
passed to the invocation of connect that returned $o$.
Then:
\begin{itemize}
\item
The object to which \tcode{\exposid{REC}($o$)} refers
remains valid for the lifetime of the object to which $o$ refers.
\item
The type \tcode{\exposid{run-loop-opstate}<Rcvr>} overrides
\tcode{\exposid{run-loop-opstate-base}::\exposid{execute}()}
such that \tcode{$o$.\exposid{exe\-cute}()} is equivalent to:
\begin{codeblock}
if (get_stop_token(@\exposid{REC}@(@$o$@)).stop_requested()) {
  set_stopped(std::move(@\exposid{REC}@(@$o$@)));
} else {
  set_value(std::move(@\exposid{REC}@(@$o$@)));
}
\end{codeblock}
\item
The expression \tcode{start($o$)} is equivalent to:
\begin{codeblock}
@$o$@.@\exposid{loop}@->@\exposid{push-back}@(addressof(@$o$@));
\end{codeblock}
\end{itemize}

\rSec3[exec.run.loop.ctor]{Constructor and destructor}

\indexlibraryctor{run_loop}%
\begin{itemdecl}
run_loop() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\ensures
The \tcode{run_loop} instance's count is 0 and
its state is starting.
\end{itemdescr}

\indexlibrarydtor{run_loop}%
\begin{itemdecl}
~run_loop();
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
If the \tcode{run_loop} instance's count is not 0 or
if its state is running,
invokes \tcode{terminate}\iref{except.terminate}.
Otherwise, has no effects.
\end{itemdescr}

\rSec3[exec.run.loop.members]{Member functions}

\begin{itemdecl}
@\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Blocks\iref{defns.block} until one of the following conditions is \tcode{true}:
\begin{itemize}
\item
The \tcode{run_loop} instance's count is 0 and its state is finishing,
in which case \exposid{pop-front} sets the state to finished
and returns \tcode{nullptr}; or
\item
the \tcode{run_loop} instance's count is greater than 0,
in which case an item is removed from the front of the queue,
the count is decremented by \tcode{1}, and
the removed item is returned.
\end{itemize}
\end{itemdescr}

\begin{itemdecl}
void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@* item) noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Adds \tcode{item} to the back of the queue and
increments the \tcode{run_loop} instance's count by 1.

\pnum
\sync
This operation synchronizes with
the \exposid{pop-front} operation that obtains \tcode{item}.
\end{itemdescr}

\indexlibrarymember{get_scheduler}{run_loop}%
\begin{itemdecl}
@\exposid{run-loop-scheduler}@ get_scheduler() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
An instance of \exposid{run-loop-scheduler}
that can be used to schedule work onto this \tcode{run_loop} instance.
\end{itemdescr}

\indexlibrarymember{run}{run_loop}%
\begin{itemdecl}
void run() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\expects
The \tcode{run_loop} instance's state is either starting or finishing.

\pnum
\effects
If the \tcode{run_loop} instance's state is starting,
sets the state to running,
otherwise leaves the state unchanged.
Then, equivalent to:
\begin{codeblock}
while (auto* op = @\exposid{pop-front}@()) {
  op->@\exposid{execute}@();
}
\end{codeblock}

\pnum
\remarks
When the \tcode{run_loop} instance's state changes,
it does so without introducing data races.
\end{itemdescr}

\indexlibrarymember{finish}{run_loop}%
\begin{itemdecl}
void finish() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\expects
The \tcode{run_loop} instance's state is either starting or running.

\pnum
\effects
Changes the \tcode{run_loop} instance's state to finishing.

\pnum
\sync
\tcode{finish} synchronizes with the \exposid{pop-front} operation
that returns \tcode{nullptr}.
\end{itemdescr}

\rSec1[exec.coro.util]{Coroutine utilities}

\rSec2[exec.as.awaitable]{\tcode{execution::as_awaitable}}

\pnum
\tcode{as_awaitable} transforms an object into one
that is awaitable within a particular coroutine.
Subclause \ref{exec.coro.util} makes use of
the following exposition-only entities:
\begin{codeblock}
namespace std::execution {
  template<class Sndr, class Promise>
    concept @\defexposconcept{awaitable-sender}@ =
      @\exposconcept{single-sender}@<Sndr, env_of_t<Promise>> &&
      @\exposconcept{sender-to}@<Sndr,
                typename @\exposid{sender-awaitable}@<Sndr, Promise>::@\exposid{awaitable-receiver}@> &&    // \seebelow
      requires (Promise& p) {
        { p.unhandled_stopped() } -> @\libconcept{convertible_to}@<coroutine_handle<>>;
      };

  template<class Sndr>
    concept @\defexposconcept{has-queryable-await-completion-adaptor}@ =            // \expos
      @\libconcept{sender}@<Sndr> &&
      requires(Sndr&& sender) {
        get_await_completion_adaptor(get_env(sender));
      };

  template<class Sndr, class Promise>
    class @\exposidnc{sender-awaitable}@;                                     // \expos
}
\end{codeblock}

\pnum
The type \tcode{\exposid{sender-awaitable}<Sndr, Promise>} is equivalent to:

\begin{codeblock}
namespace std::execution {
  template<class Sndr, class Promise>
  class @\exposidnc{sender-awaitable}@ {
    struct @\exposidnc{unit}@ {};                                             // \expos
    using @\exposidnc{value-type}@ =                                          // \expos
      @\exposidnc{single-sender-value-type}@<Sndr, env_of_t<Promise>>;
    using @\exposidnc{result-type }@=                                         // \expos
      conditional_t<is_void_v<@\exposid{value-type}@>, unit, @\exposid{value-type}@>;
    struct @\exposidnc{awaitable-receiver}@;                                  // \expos

    variant<monostate, @\exposidnc{result-type}@, exception_ptr> @\exposidnc{result}@{};    // \expos
    connect_result_t<Sndr, @\exposidnc{awaitable-receiver}@> @\exposidnc{state}@;           // \expos

  public:
    @\exposid{sender-awaitable}@(Sndr&& sndr, Promise& p);
    static constexpr bool await_ready() noexcept { return false; }
    void await_suspend(coroutine_handle<Promise>) noexcept { start(@\exposid{state}@); }
    @\exposid{value-type}@ await_resume();
  };
}
\end{codeblock}

\pnum
\exposid{awaitable-receiver} is equivalent to:
\begin{codeblock}
struct @\exposid{awaitable-receiver}@ {
  using receiver_concept = receiver_tag;
  variant<monostate, @\exposidnc{result-type}@, exception_ptr>* @\exposidnc{result-ptr}@;   // \expos
  coroutine_handle<Promise> @\exposidnc{continuation}@;                       // \expos
  // \seebelow
};
\end{codeblock}

\pnum
Let \tcode{rcvr} be an rvalue expression of type \exposid{awaitable-receiver},
let \tcode{crcvr} be a const lvalue that refers to \tcode{rcvr},
let \tcode{vs} be a pack of subexpressions, and
let \tcode{err} be an expression of type \tcode{Err}.
Let \tcode{\placeholder{MAKE-NOEXCEPT}(expr)}
for some subexpression \tcode{expr} be expression-equivalent to
\tcode{[\&] noexcept -> decltype(auto) \{ return (expr); \}()}.
Then:
\begin{itemize}
\item
The expression \tcode{set_value(rcvr, vs...)} is equivalent to:
\begin{codeblock}
try {
  rcvr.@\exposid{result-ptr}@->template emplace<1>(vs...);
} catch(...) {
  rcvr.@\exposid{result-ptr}@->template emplace<2>(current_exception());
}
@\placeholder{MAKE-NOEXCEPT}@(rcvr.@\exposid{continuation}@.resume());
\end{codeblock}

\mandates
\tcode{\libconcept{constructible_from}<\exposid{result-type}, decltype((vs))...>}
is satisfied.
\item
The expression \tcode{set_error(rcvr, err)} is equivalent to:
\begin{codeblock}
try {
  rcvr.@\exposid{result-ptr}@->template emplace<2>(@\exposid{AS-EXCEPT-PTR}@(err));  // see \ref{exec.general}
} catch(...) {
  rcvr.@\exposid{result-ptr}@->template emplace<2>(current_exception());
}
@\placeholder{MAKE-NOEXCEPT}@(rcvr.@\exposid{continuation}@.resume());
\end{codeblock}
\item
The expression \tcode{set_stopped(rcvr)} is equivalent to:
\begin{codeblock}
@\placeholder{MAKE-NOEXCEPT}@(
  static_cast<coroutine_handle<>>(
    rcvr.@\exposid{continuation}@.promise().unhandled_stopped()).resume());
\end{codeblock}
\item
For any expression \tcode{tag}
whose type satisfies \exposconcept{forwarding-query} and
for any pack of subexpressions \tcode{as},
\tcode{get_env(crcvr).query(tag, as...)} is expression-equivalent to:
\begin{codeblock}
tag(get_env(as_const(@\placeholder{MAKE-NOEXCEPT}@(crcvr.@\exposid{continuation}@.promise()))),
    as...)
\end{codeblock}
\end{itemize}

\begin{itemdecl}
@\exposid{sender-awaitable}@(Sndr&& sndr, Promise& p);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Initializes \exposid{state} with
\begin{codeblock}
connect(std::forward<Sndr>(sndr),
        @\exposid{awaitable-receiver}@{addressof(@\exposid{result}@), coroutine_handle<Promise>::from_promise(p)})
\end{codeblock}
\end{itemdescr}

\begin{itemdecl}
@\exposid{value-type}@ await_resume();
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if (@\exposid{result}@.index() == 2)
  rethrow_exception(get<2>(@\exposid{result}@));
if constexpr (!is_void_v<@\exposid{value-type}@>)
  return std::forward<@\exposid{value-type}@>(get<1>(@\exposid{result}@));
\end{codeblock}
\end{itemdescr}

\pnum
\tcode{as_awaitable} is a customization point object.
For subexpressions \tcode{expr} and \tcode{p}
where \tcode{p} is an lvalue,
\tcode{Expr} names the type \tcode{decltype((expr))} and
\tcode{Promise} names the type \tcode{decay_t<decltype((p))>},
\tcode{as_awaitable(expr, p)} is expression-equivalent to,
except that the evaluations of \tcode{expr} and \tcode{p}
are indeterminately sequenced:
\begin{itemize}
\item
\tcode{expr.as_awaitable(p)} if that expression is well-formed.

\mandates
\tcode{\exposconcept{is-awaitable}<A, Promise>} is \tcode{true},
where \tcode{A} is the type of the expression above.
\item
Otherwise,
\begin{codeblock}
@\exposid{adapt-for-await-completion}@(transform_sender(expr, get_env(p))).as_awaitable(p)
\end{codeblock}
if this expression is well-formed,
\tcode{\libconcept{sender_in}<Expr, env_of_t<Promise>>} is \tcode{true}, and
\tcode{\exposid{single-sen\-der-value-type}<Expr, env_of_t<Promise>>}
is well-formed,
except that \tcode{p} is only evaluated once.
\item
Otherwise, \tcode{(void(p), expr)}
if \tcode{decltype(\exposid{GET-AWAITER}(expr))}
satisfies \tcode{\exposconcept{is-awaiter}<Promise>}.
\item
Otherwise,
\begin{codeblock}
@\exposid{sender-awaitable}@{@\exposid{adapt-for-await-completion}@(transform_sender(expr, get_env(p))), p}
\end{codeblock}
if \tcode{sender_in<Expr, env_of_t<Promise>>} is \tcode{true} and
\tcode{\exposid{single-sender-value-type}<Expr, env_of_t<Promise>>}
is well-formed,
except that \tcode{p} is only evaluated once.
\item
Otherwise, \tcode{(void(p), expr)}.
\end{itemize}

\pnum
\tcode{\exposid{adapt-for-await-completion}(s)} is expression-equivalent to
\begin{itemize}
\item
\tcode{get_await_completion_adaptor(get_env(s))(s)} if that is well-formed,
except that \tcode{s} is evaluated only once,
\item
otherwise, \tcode{s}.
\end{itemize}

\rSec2[exec.with.awaitable.senders]{\tcode{execution::with_awaitable_senders}}

\pnum
\tcode{with_awaitable_senders},
when used as the base class of a coroutine promise type,
makes senders awaitable in that coroutine type.

In addition, it provides a default implementation of \tcode{unhandled_stopped}
such that if a sender completes by calling \tcode{set_stopped},
it is treated as if an uncatchable "stopped" exception were thrown
from the \grammarterm{await-expression}.
\begin{note}
The coroutine is never resumed, and
the \tcode{unhandled_stopped} of the coroutine caller's promise type is called.
\end{note}

\begin{codeblock}
namespace std::execution {
  template<@\exposconcept{class-type}@ Promise>
    struct @\libglobal{with_awaitable_senders}@ {
      template<class OtherPromise>
        requires (!@\libconcept{same_as}@<OtherPromise, void>)
      void set_continuation(coroutine_handle<OtherPromise> h) noexcept;

      coroutine_handle<> @\libmember{continuation}{with_awaitable_senders}@() const noexcept { return @\exposid{continuation}@; }

      coroutine_handle<> @\libmember{unhandled_stopped}{with_awaitable_senders}@() noexcept {
        return @\exposid{stopped-handler}@(@\exposid{continuation}@.address());
      }

      template<class Value>
      @\seebelow@ await_transform(Value&& value);

    private:
      [[noreturn]] static coroutine_handle<>
        @\exposid{default-unhandled-stopped}@(void*) noexcept {             // \expos
        terminate();
      }
      coroutine_handle<> @\exposid{continuation}@{};                        // \expos
      coroutine_handle<> (*@\exposid{stopped-handler}@)(void*) noexcept =   // \expos
        &@\exposid{default-unhandled-stopped}@;
    };
}
\end{codeblock}

\indexlibrarymember{set_continuation}{with_awaitable_senders}%
\begin{itemdecl}
template<class OtherPromise>
  requires (!@\libconcept{same_as}@<OtherPromise, void>)
void set_continuation(coroutine_handle<OtherPromise> h) noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
@\exposid{continuation}@ = h;
if constexpr ( requires(OtherPromise& other) { other.unhandled_stopped(); } ) {
  @\exposid{stopped-handler}@ = [](void* p) noexcept -> coroutine_handle<> {
    return coroutine_handle<OtherPromise>::from_address(p)
      .promise().unhandled_stopped();
  };
} else {
  @\exposid{stopped-handler}@ = &@\exposid{default-unhandled-stopped}@;
}
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{await_transform}{with_awaitable_senders}%
\begin{itemdecl}
template<class Value>
@\exposid{call-result-t}@<as_awaitable_t, Value, Promise&> await_transform(Value&& value);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return as_awaitable(std::forward<Value>(value), static_cast<Promise&>(*this));
\end{codeblock}
\end{itemdescr}

\rSec2[exec.affine]{\tcode{execution::affine}}

\pnum
\tcode{affine} adapts a sender into one that completes on
the receiver's scheduler.
If the algorithm determines that the adapted sender already completes
on the correct scheduler it can avoid any scheduling operation.

\pnum
The name \tcode{affine} denotes a pipeable sender adaptor
object.
For a subexpression \tcode{sndr}, if \tcode{decltype((\brk{}sndr))}
does not satisfy \libconcept{sender}, \tcode{affine(sndr)}
is ill-formed.

\pnum
Otherwise, the expression \tcode{affine(sndr)} is
expression-equivalent to \tcode{\exposid{make-sender}(affine, env<>(), sndr)}.

\pnum
For a subexpression \tcode{sch} whose type models \libconcept{scheduler},
let \tcode{\exposid{UNSTOPPABLE-SCHEDULER}(sch)} be an expression \tcode{e}
whose type models \libconcept{scheduler} such that:
\begin{itemize}
\item
\tcode{schedule(e)} is expression-equivalent to \tcode{unstoppable(schedule(sch))}.
\item
For any query object \tcode{q} and pack of subexpressions \tcode{args...},
\tcode{e.query(q, args...)} is expression-equivalent to
\tcode{sch.query(q, args...)}.
\item
The expression \tcode{e == \exposid{UNSTOPPABLE-SCHEDULER}(other)}
is expression-equivalent to \tcode{sch == other}.
\end{itemize}

\pnum
Let \tcode{sndr} and \tcode{ev} be subexpressions
such that \tcode{Sndr} is \tcode{decltype((sndr))}.
If \tcode{\exposconcept{sender-for}<Sndr, affine_t>} is \tcode{false},
then the expression \tcode{affine.transform_sender(sndr, ev)} is ill-formed;
otherwise, it is equal to:
\begin{codeblock}
auto& [_, _, child] = sndr;
if constexpr (requires { std::forward_like<Sndr>(child).affine(); }) {
  return std::forward_like<Sndr>(child).affine();
} else {
  return continues_on(std::forward_like<Sndr>(child),
                      @\exposidnc{UNSTOPPABLE-SCHEDULER}@(get_start_scheduler(ev)));
}
\end{codeblock}

\pnum
\recommended
Implementations should provide \tcode{affine} member functions
for senders that are known to resume on the scheduler where they were started.
Example senders for which that is the case are
\tcode{just},
\tcode{just_error},
\tcode{just_stopped},
\tcode{read_env}, and
\tcode{write_env}.

\pnum
Let \tcode{\placeholder{out_sndr}} be a subexpression denoting a sender
returned from \tcode{affine(sndr)} or one equal to such,
and let \tcode{\placeholder{OutSndr}} be the type \tcode{decltype((\placeholder{out_sndr}))}.
Let \tcode{\placeholder{out_rcvr}} be a subexpression denoting a receiver that
has an environment of type \tcode{Env}.
If \tcode{get_start_scheduler(get_env(\placeholder{out_rcvr}))} is ill-formed or
does not satisfy \tcode{\exposconcept{infallible-scheduler}<Env>},
then evaluation of
the expression \tcode{get_completion_signatures<\placeholder{OutSndr}, Env>()}
exits with an exception.
Let \tcode{\placeholder{op}} be an lvalue referring to the operation state that
results from connecting \tcode{\placeholder{out_sndr}} to \tcode{\placeholder{out_rcvr}}.
Calling \tcode{start(\placeholder{op})} will start \tcode{sndr} on the current
execution agent and execute completion operations on \tcode{\placeholder{out_rcvr}}
on an execution agent of the execution resource associated with
\tcode{\placeholder{sch}}.
If the current execution resource is the same as the execution
resource associated with \tcode{\placeholder{sch}}, the completion operation on
\tcode{\placeholder{out_rcvr}} may be called before \tcode{start(\placeholder{op})} completes.

\rSec2[exec.inline.scheduler]{\tcode{execution::inline_scheduler}}

\begin{codeblock}
namespace std::execution {
  class @\libglobal{inline_scheduler}@ {
    class @\exposidnc{inline-sender}@;                // \expos

    template<@\libconcept{receiver}@ R>
      class @\exposidnc{inline-state}@;               // \expos

  public:
    using scheduler_concept = scheduler_tag;

    constexpr @\exposid{inline-sender}@ schedule() noexcept { return {}; }
    constexpr bool operator==(const inline_scheduler&) const noexcept = default;
  };
}
\end{codeblock}

\pnum
\tcode{inline_scheduler} is a class that models
\libconcept{scheduler}\iref{exec.sched}.
All objects of type \tcode{inline_scheduler} are equal.
For a subexpression \tcode{sch} of type \tcode{inline_scheduler},
a query object \tcode{q}, and
a pack of subexpressions \tcode{args},
the expression \tcode{sch.query(q, args...)} is expression-equivalent to
\tcode{\exposid{inline-attrs}<set_value_t>().query(q, args...)}.

\pnum
\exposid{inline-sender} is an exposition-only type that satisfies
\libconcept{sender}.
The type \tcode{completion_signatures_of_t<\exposid{inline-sender}>}
is \tcode{completion_signatures<set_value_t()>}.

\pnum
Let \tcode{sndr} be an expression of type \exposid{inline-sender},
let \tcode{rcvr} be an expression such that
\tcode{\exposconcept{receiver-of}<decl\-type((rcvr)), CS>} is \tcode{true}
where \tcode{CS} is \tcode{completion_signatures<set_value_t()>},
then the expression \tcode{connect(sndr, rcvr)} has
type \tcode{\exposid{inline-state}<remove_cvref_t<decltype((rcvr))>>}
and is potentially-throwing if and only if
\tcode{((void)sndr, auto(rcvr))} is potentially-throwing.

\pnum
Let \tcode{\placeholder{o}} be a non-\tcode{const} lvalue of type
\tcode{\exposid{inline-state}<Rcvr>}, and let \tcode{REC(\placeholder{o})} be
a non-\tcode{const} lvalue reference to an object of type \tcode{Rcvr} that
was initialized with the expression \tcode{rcvr} passed to an
invocation of \tcode{connect} that returned \tcode{\placeholder{o}}, then:
\begin{itemize}
\item the object to which \tcode{REC(\placeholder{o})} refers remains valid for
the lifetime of the object to which \tcode{\placeholder{o}} refers, and
\item the expression \tcode{start(\placeholder{o})} is equivalent to
\tcode{set_value(std::move(REC(\placeholder{o})))}.
\end{itemize}

\rSec2[exec.task.scheduler]{\tcode{execution::task_scheduler}}

\begin{codeblock}
namespace std::execution {
  class @\libglobal{task_scheduler}@ {
    class @\exposid{ts-domain}@;                      // \expos

    template<@\libconcept{scheduler}@ Sch>
      class @\exposid{backend-for}@;                  // \expos

  public:
    using scheduler_concept = scheduler_tag;

    template<class Sch, class Allocator = allocator<void>>
      requires (!@\libconcept{same_as}@<task_scheduler, remove_cvref_t<Sch>>) && @\libconcept{scheduler}@<Sch>
    explicit task_scheduler(Sch&& sch, Allocator alloc = {});

    task_scheduler(const task_scheduler&) = default;
    task_scheduler& operator=(const task_scheduler&) = default;

    @\seebelow@ schedule();

    friend bool operator==(const task_scheduler& lhs, const task_scheduler& rhs) noexcept;
    template<class Sch>
      requires (!@\libconcept{same_as}@<task_scheduler, Sch>) && @\libconcept{scheduler}@<Sch>
    friend bool operator==(const task_scheduler& lhs, const Sch& rhs) noexcept;

  private:
    // see \ref{exec.parschedrepl.psb}
    shared_ptr<parallel_scheduler_replacement::parallel_scheduler_backend> @\exposidnc{sch_}@;  // \expos
  };
}
\end{codeblock}

\pnum
\tcode{task_scheduler} is a class that models
\libconcept{scheduler}\iref{exec.sched}.
Given an object \tcode{s} of type \tcode{task_scheduler}, let
\tcode{\exposid{SCHED}(s)} be the object
pointed to by the pointer owned by \tcode{s.\exposid{sch_}}.
The expression \tcode{get_forward_progress_guarantee(s)} is equivalent to
\tcode{get_forward_progress_guarantee(\exposid{SCHED}(s))}.
The expression \tcode{get_completion_domain<set_value_t>(s)} is equivalent to
\tcode{task_scheduler::\exposid{ts-domain}()}.

\indexlibraryctor{task_scheduler}
\begin{itemdecl}
template<class Sch, class Allocator = allocator<void>>
  requires(!@\libconcept{same_as}@<task_scheduler, remove_cvref_t<Sch>>) && @\libconcept{scheduler}@<Sch>
explicit task_scheduler(Sch&& sch, Allocator alloc = {});
\end{itemdecl}
\begin{itemdescr}
\pnum
\mandates
\tcode{Sch} satisfies \tcode{\exposconcept{infallible-scheduler}<env<>>}.

\pnum
\effects
Initializes \exposid{sch_} with:
\begin{codeblock}
allocate_shared<@\exposid{backend-for}@<remove_cvref_t<Sch>>>(alloc, std::forward<Sch>(sch))
\end{codeblock}

\pnum
\recommended
Implementations should avoid the use of dynamically
allocated memory for small scheduler objects.

\pnum
\remarks
Any allocations performed by calls on \tcode{*this} are
performed using a copy of \tcode{alloc}.
\end{itemdescr}

\indexlibrarymember{operator==}{task_scheduler}%
\begin{itemdecl}
bool operator==(const task_scheduler& lhs, const task_scheduler& rhs) noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to: \tcode{return lhs == \exposid{SCHED}(rhs);}
\end{itemdescr}

\indexlibrarymember{operator==}{task_scheduler}%
\begin{itemdecl}
template<class Sch>
  requires (!@\libconcept{same_as}@<task_scheduler, Sch>)
        && @\libconcept{scheduler}@<Sch>
bool operator==(const task_scheduler& lhs, const Sch& rhs) noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{false} if the type of \tcode{\exposid{SCHED}(lhs)} is not \tcode{Sch},
otherwise \tcode{\exposid{SCHED}(lhs) == rhs}.
\end{itemdescr}

\pnum
For an lvalue \tcode{r} of a type derived from \tcode{receiver_proxy},
let \tcode{\exposid{WRAP-RCVR}(r)} be an object of a type
that models \libconcept{receiver} and
whose completion handlers result in
invoking the corresponding completion handlers of \tcode{r}.
\begin{codeblock}
namespace std::execution {
  template<@\libconcept{scheduler}@ Sch>
  class task_scheduler::@\exposid{backend-for}@
    : public parallel_scheduler_replacement::parallel_scheduler_backend {       // \expos
  public:
    explicit @\exposid{backend-for}@(Sch sch) : @\exposid{sched_}@(std::move(sch)) {}

    void schedule(receiver_proxy& r, span<byte> s) noexcept override;
    void schedule_bulk_chunked(size_t shape, bulk_item_receiver_proxy& r,
                               span<byte> s) noexcept override;
    void schedule_bulk_unchunked(size_t shape, bulk_item_receiver_proxy& r,
                                 span<byte> s) noexcept override;

  private:
    Sch @\exposid{sched_}@;
  };
}
\end{codeblock}

\pnum
Let \tcode{env} be a pack of subexpressions, and
let \exposid{just-sndr-like} be a sender
whose only value completion signature is \tcode{set_value_t()} and
for which the expression
\tcode{get_completion_scheduler<set_value_t>(get_env(\exposid{just-sndr-like)}, env...)}
is expression-equivalent to
\tcode{get_completion_scheduler<set_value_t>(\exposid{sched_}, env...)}.

\begin{itemdecl}
void schedule(receiver_proxy& r, span<byte> s) noexcept override;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Constructs an operation state \tcode{os}
with \tcode{connect(schedule(\exposid{sched_}), \exposid{WRAP-RCVR}(r))} and
calls \tcode{start(os)}.
\end{itemdescr}

\begin{itemdecl}
void schedule_bulk_chunked(size_t shape, bulk_item_receiver_proxy& r,
                           span<byte> s) noexcept override;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Let \tcode{chunk_size} be an integer less than or equal to \tcode{shape},
let \tcode{num_chunks} be \tcode{(shape + chunk_size - 1) / chunk_size}, and
let \tcode{fn} be a function object such that
for an integer \tcode{i},
\tcode{fn(i)} calls \tcode{r.execute(i * chunk_size, m)},
where \tcode{m} is the lesser of \tcode{(i + 1) * chunk_size} and \tcode{shape}.
Constructs an operation state \tcode{os} as if with
\begin{codeblock}
connect(bulk(@\exposid{just-sndr-like}@, par, num_chunks, fn), @\exposid{WRAP-RCVR}@(r))
\end{codeblock}
and calls \tcode{start(os)}.
\end{itemdescr}

\begin{itemdecl}
void schedule_bulk_unchunked(size_t shape, bulk_item_receiver_proxy& r,
                             span<byte> s) noexcept override;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Let \tcode{fn} be a function object such that
for an integer \tcode{i},
\tcode{fn(i)} is equivalent to \tcode{r.execute(i, i + 1)}.
Constructs an operation state \tcode{os} as if with
\begin{codeblock}
connect(bulk(@\exposid{just-sndr-like}@, par, shape, fn), @\exposid{WRAP-RCVR}@(r))
\end{codeblock}
and calls \tcode{start(os)}.
\end{itemdescr}

\begin{itemdecl}
@\seebelow@ schedule();
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
A prvalue \exposid{ts-sndr} whose type models \libconcept{sender} such that:
\begin{itemize}
\item
\tcode{get_completion_scheduler<set_value_t>(get_env(\exposid{ts-sndr}))}
is equal to \tcode{*this}.
\item
\tcode{get_completion_domain<set_value_t>(get_env(\exposid{ts-sndr}))}
is expression-equivalent to \tcode{\exposid{ts-do\-main}()}.
\item
If a receiver \tcode{rcvr} is connected to \exposid{ts-sndr} and
the resulting operation state is started,
calls \tcode{\exposid{sch_}->schedule(r, s)}, where
\begin{itemize}
\item
\tcode{r} is a proxy for \tcode{rcvr} with base
\tcode{parallel_scheduler_replacement::receiver_proxy}\iref{exec.par.scheduler}
and
\item
\tcode{s} is a preallocated backend storage for \tcode{r}.
\end{itemize}
\item
For any type \tcode{E},
\tcode{completion_signatures_of_t<decltype(\exposid{ts-sndr}), E>} denotes
\tcode{completion_signatures<set_value_t()>} if
\tcode{\libconcept{unstoppable_token}<stop_token_of_t<E>>} is \tcode{true}, and
otherwise \tcode{completion_signatures<set_value_t(), set_stopped_t()>}.
\end{itemize}
\end{itemdescr}

\begin{codeblock}
namespace std::execution {
  class task_scheduler::@\exposid{ts-domain}@ : public default_domain {     // \expos
  public:
    template<class BulkSndr, class Env>
      static constexpr auto transform_sender(set_value_t, BulkSndr&& bulk_sndr, const Env& env)
        noexcept(@\seebelow@);
  };
}
\end{codeblock}

\begin{itemdecl}
template<class BulkSndr, class Env>
  static constexpr auto transform_sender(BulkSndr&& bulk_sndr, const Env& env)
    noexcept(is_nothrow_constructible_v<decay_t<BulkSndr>, BulkSndr>);
\end{itemdecl}

\begin{itemdescr}
\pnum
\constraints
\begin{itemize}
\item
\tcode{\libconcept{sender_in}<BulkSndr, Env>} is \tcode{true},
\item
\tcode{auto(std::forward<BulkSndr>(bulk_sndr))} is well-formed, and
\item
either
\begin{itemize}
\item
\tcode{\exposconcept{sender-for}<BulkSndr, bulk_chunked_t>} or
\item
\tcode{\exposconcept{sender-for}<BulkSndr, bulk_un\-chunked_t>}
\end{itemize}
is \tcode{true}.
\end{itemize}

\pnum
\effects
Equivalent to:
\begin{codeblock}
auto& [_, data, child] = bulk_sndr;
auto& [_, shape, fn] = data;
auto sch = @\exposidnc{call-with-default}@(get_completion_scheduler<set_value_t>,
                             @\exposidnc{not-a-scheduler}@(), get_env(child), @\exposidnc{FWD-ENV}@(env));
return @$e$@;
\end{codeblock}
where $e$ is \tcode{\exposid{not-a-sender}()}
if the type of \tcode{sch} is not \tcode{task_scheduler};
otherwise, it is a prvalue whose type models \libconcept{sender} such that,
if it is connected to a receiver \tcode{rcvr} and
the resulting operation state is started,
\tcode{child} is connected to an unspecified receiver \tcode{R} and started.
The expression \tcode{get_env(R)}
is expression-equivalent to \tcode{\exposid{FWD-ENV}(get_env(\exposid{rcvr-copy}))},
where \exposid{rcvr-copy} is an lvalue subexpression
designating an object decay-copied from \tcode{rcvr}.

If \tcode{child} completes with an error or a stopped completion,
the completion operation is forwarded unchanged to \tcode{rcvr}.
Otherwise, let \tcode{args} be a pack of lvalue subexpressions
designating objects decay-copied from the value result datums.
Then:
\begin{itemize}
\item
If \tcode{bulk_sndr} was the result of the evaluation of
an expression equivalent to \tcode{bulk_chunked(child, policy, shape, fn)} or
a copy of such,
then \tcode{\exposid{sch_}->schedule_bulk_chunked(shape, r, s)} is called
where \tcode{r} is a bulk chunked proxy\iref{exec.par.scheduler}
for \tcode{rcvr} with callable \tcode{fn} and arguments \tcode{args}, and
\tcode{s} is a preallocated backend storage for \tcode{r}.
\item
Otherwise, calls \tcode{\exposid{sch_}->schedule_bulk_unchunked(shape, r, s)}
where \tcode{r} is a bulk unchunked proxy for \tcode{rcvr}
with callable \tcode{fn} and arguments \tcode{args}, and
\tcode{s} is a preallocated backend storage for \tcode{r}.
\end{itemize}
\end{itemdescr}

\rSec2[exec.task]{\tcode{execution::task}}

\rSec3[task.overview]{\tcode{task} overview}

\pnum
The \tcode{task} class template represents a sender that can
be used as the return type of coroutines.
The first template parameter \tcode{T} defines the type of the value
completion datum\iref{exec.async.ops} if \tcode{T} is not \tcode{void}.
Otherwise, there are no value completion datums.
Inside coroutines returning \tcode{task<T, E>} the operand of
\tcode{co_return} (if any) becomes the argument of \tcode{set_value}.
The second template parameter \tcode{Environment} is used to customize
the behavior of \tcode{task}.

\rSec3[task.class]{Class template \tcode{task}}

\begin{codeblock}
namespace std::execution {
  template<class T = void, class Environment = env<>>
  class @\libglobal{task}@ {
    // \ref{task.state}
    template<@\libconcept{receiver}@ Rcvr>
      class @\exposidnc{state}@;                              // \expos

  public:
    using sender_concept = sender_tag;
    using allocator_type = @\seebelow@;
    using start_scheduler_type = @\seebelow@;
    using stop_source_type = @\seebelow@;
    using stop_token_type = decltype(declval<stop_source_type>().get_token());
    using error_types = @\seebelow@;

    // \ref{task.promise}
    class promise_type;

    task(task&&) noexcept;
    ~task();

    template<class Self, class... Env>
      static consteval auto get_completion_signatures();

    template<@\libconcept{receiver}@ Rcvr>
      @\exposid{state}@<Rcvr> connect(Rcvr&& rcvr) &&;

  private:
    coroutine_handle<promise_type> @\exposidnc{handle}@;      // \expos
  };
}
\end{codeblock}

\pnum
\tcode{task<T, E>} models \libconcept{sender}\iref{exec.snd}
if \tcode{T} is \tcode{void}, a reference type, or a \cv{}-unqualified
non-array object type and \tcode{E} is a class type.
Otherwise a program that instantiates the definition of \tcode{task<T, E>}
is ill-formed.

\pnum
The nested types of \tcode{task} template specializations
are determined based on the \tcode{Environment} parameter:
\begin{itemize}
\item \tcode{allocator_type} is \tcode{Environment::allocator_type}
if that \grammarterm{qualified-id} is valid and denotes a type,
\tcode{allocator<byte>} otherwise.
\item \tcode{start_scheduler_type} is \tcode{Environment::start_scheduler_type}
if that \grammarterm{qualified-id} is valid and denotes a type,
\tcode{task_scheduler} otherwise.
\item \tcode{stop_source_type} is \tcode{Environment::stop_source_type}
if that \grammarterm{qualified-id} is valid and denotes a type,
\tcode{inplace_stop_source} otherwise.
\item \tcode{error_types} is \tcode{Environment::error_types} if
that \grammarterm{qualified-id} is valid and denotes a type,
\tcode{com\-pletion_sign\-atures<set_error_t(exception_ptr)>} otherwise.
\end{itemize}

\pnum
 A program is ill-formed if \tcode{error_types} is not a
specialization of \tcode{execution::completion_signatures}
or if the template arguments of that specialization
contain an element which is not of the form
\tcode{set_error_t(E)} for some type \tcode{E}.

\pnum
\tcode{allocator_type} shall meet the \oldconcept{Allocator} requirements,
\tcode{scheduler_type} shall model \libconcept{scheduler}, and
\tcode{stop_source_type} shall model \exposconcept{stoppable-source}.

\rSec3[task.members]{\tcode{task} members}

\indexlibraryctor{task}%
\begin{itemdecl}
task(task&& other) noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Initializes \exposid{handle} with \tcode{exchange(other.\exposid{handle},
\{\})}.
\end{itemdescr}

\indexlibrarydtor{task}%
\begin{itemdecl}
~task();
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if (@\exposid{handle}@)
  @\exposid{handle}@.destroy();
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{get_completion_signatures}{task}%
\begin{itemdecl}
template<class Self, class... Env>
  static consteval auto get_completion_signatures();
\end{itemdecl}
\begin{itemdescr}
\pnum
Let the type \tcode{C} be a specialization
of \tcode{execution::completion_signatures}
with the template arguments (in unspecified order):
\begin{itemize}
\item
\tcode{set_value_t()} if \tcode{T} is \tcode{void},
and \tcode{set_value_t(T)} otherwise;
\item
template arguments of the specialization of
\tcode{execution::completion_signatures} denoted by \tcode{error_types};
and
\item \tcode{set_stopped_t()}.
\end{itemize}

\pnum
\returns
\tcode{C()}.
\end{itemdescr}

\indexlibrarymember{connect}{task}%
\begin{itemdecl}
template<@\libconcept{receiver}@ Rcvr>
  @\exposid{state}@<Rcvr> connect(Rcvr&& recv) &&;
\end{itemdecl}
\begin{itemdescr}
\pnum
\mandates
At least one of the expressions
\tcode{allocator_type(get_allocator(get_env(rcvr)))} and
\tcode{allocator_type()}
is well-formed.

\pnum
\expects
\tcode{bool(\exposid{handle})} is \tcode{true}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
return @\exposid{state}@<Rcvr>(exchange(@\exposid{handle}@, {}), std::forward<Rcvr>(recv));
\end{codeblock}
\end{itemdescr}

\rSec3[task.state]{Class template \tcode{task::\exposid{state}}}

\begin{codeblock}
namespace std::execution {
  template<class T, class Environment>
  template<@\libconcept{receiver}@ Rcvr>
  class task<T, Environment>::@\exposidnc{state}@ {           // \expos
  public:
    using operation_state_concept = operation_state_tag;

    template<class R>
      @\exposid{state}@(coroutine_handle<promise_type> h, R&& rr);

    ~@\exposid{state}@();

    void start() & noexcept;

    stop_token_type @\exposidnc{get-stop-token}@();           // \expos

  private:
    using @\exposidnc{own-env-t}@ = @\seebelownc@;                // \expos
    coroutine_handle<promise_type> @\exposidnc{handle}@;      // \expos
    remove_cvref_t<Rcvr>           @\exposidnc{rcvr}@;        // \expos
    optional<stop_source_type>     @\exposidnc{source}@;      // \expos
    @\exposidnc{own-env-t}@                      @\exposidnc{own-env}@;     // \expos
    Environment                    @\exposidnc{environment}@; // \expos
    optional<T>                    @\exposidnc{result}@;      // \expos; present only if \tcode{is_void_v<T>} is \tcode{false}
    exception_ptr                  @\exposidnc{error}@;       // \expos
  };
}
\end{codeblock}

\pnum
The type \exposid{own-env-t} is \tcode{Environment::template
env_type<decltype(get_env(\brk{}declval\brk{}<Rcvr>(\brk{})))\brk{}>} if that
\grammarterm{qualified-id} is valid and denotes a type, \tcode{env<>} otherwise.

\indexlibraryctor{task::\exposid{state}}%
\begin{itemdecl}
template<class R>
  @\exposid{state}@(coroutine_handle<promise_type> h, R&& rr);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Initializes
\begin{itemize}
\item \exposid{handle} with \tcode{std::move(h)};
\item \exposid{rcvr} with \tcode{std::forward<R>(rr)};
\item \exposid{own-env}
with \tcode{\exposid{own-env-t}(get_env(\exposid{rcvr}))} if that expression
is valid and \tcode{\exposid{own-env-t}()} otherwise.
If neither of these expressions is valid, the program is ill-formed.
\item \exposid{environment} with
\tcode{Environment(\exposid{own-env})} if that expression is
valid, otherwise \tcode{Environment(\brk{}get_env(\exposid{rcvr}))}
if this expression is valid, otherwise \tcode{Environment()}.
If neither of these expressions is valid, the program is ill-formed.
\end{itemize}
\end{itemdescr}

\indexlibrarydtor{task::\exposid{state}}%
\begin{itemdecl}
~@\exposid{state}@();
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if (@\exposid{handle}@)
  @\exposid{handle}@.destroy();
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{start}{task::\exposid{state}}%
\begin{itemdecl}
void start() & noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Let \tcode{\placeholder{prom}} be the object \tcode{\exposid{handle}.promise()}.
Associates \tcode{\exposid{STATE}(\placeholder{prom})}, \tcode{\exposid{RCVR}(\placeholder{prom})}, and \tcode{\exposid{SCHED}(\placeholder{prom})}
with \tcode{*this} as follows:
\begin{itemize}
\item \tcode{\exposid{STATE}(\placeholder{prom})} is \tcode{*this}.
\item \tcode{\exposid{RCVR}(\placeholder{prom})} is \exposid{rcvr}.
\item \tcode{\exposid{SCHED}(\placeholder{prom})} is the object initialized
with \tcode{start_scheduler_type(get_start_scheduler(get_env(\exposid{rcvr})))}
if that expression is valid and \tcode{start_scheduler_type()} otherwise.
If neither of these expressions is valid, the program is ill-formed.
\end{itemize}
Finally, invokes \tcode{\exposid{handle}.resume()}.
\end{itemdescr}

\indexlibrarymember{\exposid{get-stop-token}}{task::\exposid{state}}%
\begin{itemdecl}
stop_token_type @\exposidnc{get-stop-token}@();           // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
If
\tcode{\libconcept{same_as}<decltype(declval<stop_source_type>().get_token()), decltype(get_\linebreak{}stop_token(get_env(\exposid{rcvr})))>}
is \tcode{true},
returns \tcode{get_stop_token(get_env(\exposid{rcvr}))}.
Otherwise, if \tcode{\exposid{source}.has_value()} is \tcode{false},
initializes the contained value of \exposid{source} such that
\begin{itemize}
\item
\tcode{\exposid{source}->stop_requested()} returns
\tcode{get_stop_token(get_env(\exposid{rcvr}))->stop_requested()};\linebreak
and
\item
\tcode{\exposid{source}->stop_possible()} returns
\tcode{get_stop_token(get_env(\exposid{rcvr}))->stop_possible()}.
\end{itemize}
Finally, returns \tcode{\exposid{source}->get_token()}.
\end{itemdescr}

\rSec3[task.promise]{Class \tcode{task::promise_type}}

\begin{codeblock}
namespace std::execution {
  template<class T, class Environment>
  class task<T, Environment>::promise_type {
  public:
    task get_return_object() noexcept;

    static constexpr suspend_always @\libmember{initial_suspend}{task::promise_type}@() noexcept { return {}; }
    auto final_suspend() noexcept;

    void unhandled_exception();
    coroutine_handle<> unhandled_stopped() noexcept;

    void return_void();                 // present only if \tcode{is_void_v<T>} is \tcode{true}
    template<class V = T>
      void return_value(V&& value);     // present only if \tcode{is_void_v<T>} is \tcode{false}

    template<class E>
      @\unspec@ yield_value(with_error<E> error);

    template<@\libconcept{sender}@ Sender>
      auto await_transform(Sender&& sndr);

    @\unspec@ get_env() const noexcept;

    void* operator new(size_t size);
    template<class Alloc, class... Args>
      void* operator new(size_t size, allocator_arg_t, Alloc alloc, Args&&...);
    template<class This, class Alloc, class... Args>
      void* operator new(size_t size, const This&, allocator_arg_t, Alloc alloc, Args&&...);

    void operator delete(void* pointer, size_t size) noexcept;
  };
}
\end{codeblock}

\pnum
Let \tcode{\placeholder{prom}} be an object of \tcode{promise_type}
and let \tcode{\placeholder{tsk}} be the \tcode{task} object
created by \tcode{\placeholder{prom}.get_return_object()}.
The description below
refers to objects \tcode{\exposid{STATE}(\placeholder{prom})},
\tcode{\exposid{RCVR}(\placeholder{prom})},
and \tcode{\exposid{SCHED}(\placeholder{prom})}
associated with \tcode{\placeholder{tsk}}
during evaluation of \tcode{task::\exposid{state}<Rcvr>::start}
for some receiver \tcode{Rcvr}.

\indexlibrarymember{get_return_object}{task::promise_type}%
\begin{itemdecl}
task get_return_object() noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
A \tcode{task} object whose member \exposid{handle} is
\tcode{coroutine_handle<promise_type>::\brk{}from_promise\brk{}(*this)}.
\end{itemdescr}

\indexlibrarymember{final_suspend}{task::promise_type}%
\begin{itemdecl}
auto final_suspend() noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
An awaitable object of unspecified type\iref{expr.await} whose
member functions arrange for the completion of the asynchronous
operation associated with \tcode{\exposid{STATE}(*this)}.
Let \tcode{st} be a reference to \tcode{\exposid{STATE}(*this)}.
The asynchronous completion first destroys the coroutine frame
using \tcode{st.\exposid{handle}.destroy()} and then invokes:
\begin{itemize}
\item
\tcode{set_error(std::move(st.\exposid{rcvr}), std::move(st.\exposid{error}))}
if \tcode{bool(st.\exposid{error})} is \tcode{true}, otherwise
\item
\tcode{set_value(std::move(st.\exposid{rcvr}))} if \tcode{is_void_v<T>} is \tcode{true},
and otherwise
\item
 \tcode{set_value(std::move(st.\exposid{rcvr}), *std::move(st.\exposid{result}))}.
\end{itemize}
\end{itemdescr}

\indexlibrarymember{yield_value}{task::promise_type}%
\begin{itemdecl}
template<class Err>
  auto yield_value(with_error<Err> err);
\end{itemdecl}
\begin{itemdescr}
\pnum
\mandates
\tcode{std::move(err.error)} is convertible to exactly one of the
\tcode{set_error_t} argument types of \tcode{error_types}.
Let \tcode{\placeholder{Cerr}} be that type.

\pnum
\returns
An awaitable object of unspecified type\iref{expr.await} whose
member functions arrange for the calling coroutine to be suspended
and then completes the asynchronous operation associated with
\tcode{\exposid{STATE}(*this)}.
Let \tcode{st} be a reference to \tcode{\exposid{STATE}(*this)}.
Then the asynchronous operation completes by first
destroying the coroutine frame using \tcode{st.\exposid{handle}.destroy()}
and then invoking
\tcode{set_error(std::move(st.\exposid{rcvr}),
\placeholder{Cerr}(std::move(err.error)))}.
\end{itemdescr}

\indexlibrarymember{await_transform}{task::promise_type}%
\begin{itemdecl}
template<@\libconcept{sender}@ Sender>
  auto await_transform(Sender&& sndr);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
If \tcode{\libconcept{same_as}<inline_scheduler, start_scheduler_type>}
is \tcode{true},
returns \tcode{as_awaitable(\brk{}std::forward<Sender>(sndr), *this)};
otherwise returns \tcode{as_awaitable(affine(std::forward<\brk{}Sender>(sndr)), *this)}.
\end{itemdescr}

\indexlibrarymember{unhandled_exception}{task::promise_type}%
\begin{itemdecl}
void unhandled_exception();
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
If the signature \tcode{set_error_t(exception_ptr)} is not an element
of \tcode{error_types}, calls \tcode{terminate()}\iref{except.terminate}.
Otherwise, stores \tcode{current_exception()} into
\tcode{\exposid{STATE}(*this).\exposid{error}}.
\end{itemdescr}

\indexlibrarymember{unhandled_stopped}{task::promise_type}%
\begin{itemdecl}
coroutine_handle<> unhandled_stopped() noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Completes the asynchronous operation associated with \tcode{\exposid{STATE}(*this)}.
Let \tcode{st} be a reference to \tcode{\exposid{STATE}(*this)}.
The asynchronous operation is completed by first
destroying the coroutine frame
using \tcode{st.\exposid{handle}.destroy()} and then
invoking \tcode{set_stopped(std::move(st.\exposid{rcvr}))}.
\end{itemdescr}
\begin{itemdescr}
\pnum
\returns
\tcode{noop_coroutine()}.
\end{itemdescr}

\indexlibrarymember{return_void}{task::promise_type}%
\begin{itemdecl}
void return_void();
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Does nothing.
\end{itemdescr}

\indexlibrarymember{return_value}{task::promise_type}%
\begin{itemdecl}
template<class V>
  void return_value(V&& v);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to \tcode{\exposid{result}.emplace(std::forward<V>(v))}.
\end{itemdescr}

\indexlibrarymember{get_env}{task::promise_type}%
\begin{itemdecl}
@\unspec@ get_env() const noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
An object \tcode{env} such that queries are forwarded as follows:
\begin{itemize}
\item \tcode{env.query(get_start_scheduler)} returns
\tcode{start_scheduler_type(\exposid{SCHED}(*this))}.
\item \tcode{env.query(get_allocator)} returns
\tcode{allocator_type(get_allocator(get_env(\exposid{RCVR}(*this))\brk{}))}
if this expression is well-formed and
\tcode{allocator_type()} otherwise.
\item \tcode{env.query(get_stop_token)} returns
\tcode{\exposid{STATE}(*this).\exposid{get-stop-token}()}.
\item For any other query \tcode{q} and arguments \tcode{a...} a
call to \tcode{env.query(q, a...)} returns
\tcode{\exposid{STATE}(*this)}. \tcode{\exposid{environment}.query(q, a...)} if this expression
is well-formed and \tcode{forwarding_query(q)} is well-formed and is \tcode{true}.
Otherwise \tcode{env.query(q, a...)} is ill-formed.
\end{itemize}
\end{itemdescr}

\indexlibrarymember{operator new}{task::promise_type}%
\begin{itemdecl}
void* operator new(size_t size);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return operator new(size, allocator_arg, allocator_type());}
\end{itemdescr}

\indexlibrarymember{operator new}{task::promise_type}%
\begin{itemdecl}
template<class Alloc, class... Args>
  void* operator new(size_t size, allocator_arg_t, Alloc alloc, Args&&...);
template<class This, class Alloc, class... Args>
  void* operator new(size_t size, const This&, allocator_arg_t, Alloc alloc, Args&&...);
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \tcode{PAlloc} be
\tcode{allocator_traits<Alloc>::template rebind_alloc<U>},
where \tcode{U} is an unspecified type
whose size and alignment are both \mname{STDCPP_DEFAULT_NEW_ALIGNMENT}.

\pnum
\mandates
\tcode{allocator_traits<PAlloc>::pointer} is a pointer type.

\pnum
\effects
Initializes an allocator \tcode{palloc} of type \tcode{PAlloc} with
\tcode{alloc}.
Uses \tcode{palloc} to allocate storage for the
smallest array of \tcode{U} sufficient to provide storage for a
coroutine state of size \tcode{size}, and unspecified additional
state necessary to ensure that \tcode{operator delete} can later
deallocate this memory block with an allocator equal to \tcode{palloc}.

\pnum
\returns
A pointer to the allocated storage.
\end{itemdescr}

\indexlibrarymember{operator delete}{task::promise_type}%
\begin{itemdecl}
void operator delete(void* pointer, size_t size) noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\expects
\tcode{pointer} was returned from an invocation of the above overload
of \tcode{operator new} with a size argument equal to \tcode{size}.

\pnum
\effects
Deallocates the storage pointed to by \tcode{pointer} using an
allocator equal to that used to allocate it.
\end{itemdescr}

\rSec1[exec.scope]{Execution scope utilities}

\rSec2[exec.scope.concepts]{Execution scope concepts}

\pnum
The \libconcept{scope_association} concept defines
the requirements on a type \tcode{Assoc}.
An object of type \tcode{Assoc} is \defn{engaged}
if and only if it owns an association with an async scope,
referred to as its \defnadj{associated}{scope}.

\begin{codeblock}
namespace std::execution {
  template<class Assoc>
    concept @\deflibconcept{scope_association}@ =
      @\libconcept{movable}@<Assoc> &&
      is_nothrow_move_constructible_v<Assoc> &&
      is_nothrow_move_assignable_v<Assoc> &&
      @\libconcept{default_initializable}@<Assoc> &&
      requires(const Assoc assoc) {
        { static_cast<bool>(assoc) } noexcept;
        { assoc.try_associate() } -> @\libconcept{same_as}@<Assoc>;
      };
}
\end{codeblock}

\pnum
A type \tcode{Assoc} models \libconcept{scope_association} only if:
\begin{itemize}
\item
a default constructed object of type \tcode{Assoc} is not engaged;
\item
for an object \exposid{assoc} of type \tcode{Assoc},
\tcode{static_cast<bool>(assoc)} is \tcode{true}
if and only if \tcode{assoc} is engaged;
\item
no two distinct objects of type \tcode{Assoc} own the same association;
\item
for an object \tcode{assoc} of type \tcode{Assoc},
destroying \tcode{assoc} releases the association owned by \tcode{assoc}, if any;
\item
for an object \tcode{assoc} of type \tcode{Assoc},
after it is used as the source operand of a move constructor,
the \tcode{assoc} is not engaged;
\item
for distinct objects \tcode{assoc1} and \tcode{assoc2} of type \tcode{Assoc},
after evaluating \tcode{assoc1 = std::move(assoc2)},
the association owned by \tcode{assoc1}, if any, is released and
\tcode{assoc2} is not engaged;
\item
for an object \tcode{assoc} of type \tcode{Assoc} that is engaged,
\tcode{assoc.try_associate()} either
returns an object that is not engaged or
acquires a new association with \tcode{assoc}'s associated scope and
returns an engaged object that owns that association;
\item
for an object \tcode{assoc} of type \tcode{Assoc} that is not engaged,
\tcode{assoc.try_associate()} returns an object that is not engaged.
\end{itemize}

\pnum
The \libconcept{scope_token} concept defines the requirements on
a type \tcode{Token} that can be used to create associations
between senders and an async scope.
Every object of type \tcode{Token} is associated with an async scope
that is referred to as its \term{associated scope}.

\pnum
Let \placeholder{test-sender} and \placeholder{test-env}
be unspecified types such that
\tcode{\libconcept{sender_in}<\placeholder{test-sender}, \placeholder{test-env}>}
is modeled.

\begin{codeblock}
namespace std::execution {
  template<class Token>
    concept @\deflibconcept{scope_token}@ =
      @\libconcept{copyable}@<Token> &&
      requires(const Token token) {
        { token.try_associate() } -> @\libconcept{scope_association}@;
        { token.wrap(declval<@\placeholder{test-sender}@>()) } -> @\libconcept{sender_in}@<@\placeholder{test-env}@>;
      };
}
\end{codeblock}

\pnum
A type \tcode{Token} models \libconcept{scope_token} only if:

\begin{itemize}
\item
no exceptions are thrown from
copy construction,
move construction,
copy assignment, or
move assignment
of objects of type \tcode{Token};

\item
for an object \tcode{token} of type \tcode{Token},
\tcode{token.try_associate()} either
returns an object that is not engaged or
acquires a new association with \tcode{token}'s associated scope and
returns an engaged object that owns that association; and

\item
given an lvalue \tcode{token} of type (possibly const) \tcode{Token},
for all expressions \tcode{sndr} such that
\tcode{decltype((\linebreak{}sndr))} models \libconcept{sender}:
  \begin{itemize}
  \item
  \tcode{token.wrap(sndr)} is a valid expression,
  \item
  \tcode{decltype(token.wrap(sndr))} models \libconcept{sender}, and
  \item
  \tcode{completion_signatures_of_t<decltype(token.wrap(sndr)), E>}
  contains the same completion signatures as
  \tcode{completion_signatures_of_t<decltype((sndr)), E>}
  for all types \tcode{E} such that
  \tcode{\libconcept{sender_in}<decltype((sndr)), E>} is modeled.
  \end{itemize}
\end{itemize}

\rSec2[exec.counting.scopes]{Counting Scopes}

\rSec3[exec.counting.scopes.general]{General}

\pnum
Scopes of type \tcode{simple_counting_scope} and \tcode{counting_scope}
maintain counts of associations.
Let:
\begin{itemize}
\item
\tcode{Scope} be either \tcode{simple_counting_scope} or \tcode{counting_scope},
\item
\tcode{scope} be an object of type \tcode{Scope},
\item
\tcode{tkn} be an object of type \tcode{Scope::token}
obtained from \tcode{scope.get_token()},
\item
\tcode{jsndr} be a sender obtained from \tcode{scope.join()}, and
\item
\tcode{op} be an operation state obtained from
connecting \tcode{jsndr} to a receiver.
\end{itemize}
During its lifetime \tcode{scope} goes through different states
which govern what operations are allowed and the result of these operations:

\begin{itemize}
\item
\exposid{unused}:
a newly constructed object starts in the \exposid{unused} state.

\item
\exposid{open}:
when \tcode{tkn.try_associate()} is called
while \tcode{scope} is in the \exposid{unused} state,
\tcode{scope} moves to the \exposid{open} state.

\item
\exposid{open-and-joining}:
when the operation state \tcode{op} is started
while \tcode{scope} is in the \exposid{unused} or \exposid{open} state,
\tcode{scope} moves to the \exposid{open-and-joining} state.

\item
\exposid{closed}:
when \tcode{scope.close()} is called
while \tcode{scope} is in the \exposid{open} state,
\tcode{scope} moves to the \exposid{closed} state.

\item
\exposid{unused-and-closed}:
when \tcode{scope.close()} is called
while \tcode{scope} is in the \exposid{unused} state,
\tcode{scope} moves to the \exposid{unused-and-closed} state.

\item
\exposid{closed-and-joining}:
when \tcode{scope.close()} is called
while \tcode{scope} is in the \exposid{open-and-joining} state or
the operation state \tcode{op} is started
while \tcode{scope} is in
the \exposid{closed} or \exposid{unused-and-closed} state,
\tcode{scope} moves to the \exposid{closed-and-joining} state.

\item
\exposid{joined}:
when the count of associations drops to zero
while \tcode{scope} is in
the \exposid{open-and-joining} or \exposid{closed-and-joining} state,
\tcode{scope} moves to the \exposid{joined} state.
\end{itemize}

\pnum
\recommended
For \tcode{simple_counting_scope} and \tcode{counting_scope},
implementations should store the state and the count of associations
in a single member of type \tcode{size_t}.

\pnum
Subclause \ref{exec.counting.scopes} makes use of
the following exposition-only entities:

\begin{codeblock}
struct @\exposid{scope-join-t}@ {};     // \expos

enum @\exposid{scope-state-type}@ {     // \expos
  @\exposid{unused}@,                   // \expos
  @\exposid{open}@,                     // \expos
  @\exposid{closed}@,                   // \expos
  @\exposid{open-and-joining}@,         // \expos
  @\exposid{closed-and-joining}@,       // \expos
  @\exposid{unused-and-closed}@,        // \expos
  @\exposid{joined}@,                   // \expos
};

template<class Scope>
  struct @\exposid{association-t}@;     // \expos
\end{codeblock}

\pnum
The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos}
is specialized for \exposid{scope-join-t} as follows:

\indexlibraryglobal{execution::\exposid{impls-for}<\exposid{scope-join-t}>}%
%%FIXME: The declarations of "receiver" below hide the \libconcept of the same name
\begin{codeblock}
namespace std::execution {
  template<>
  struct @\exposid{impls-for}@<@\exposid{scope-join-t}@> : @\exposid{default-impls}@ {
    template<class Scope, class Rcvr>
    struct @\exposid{state}@ {                          // \expos
      struct @\exposid{rcvr-t}@ {                       // \expos
        using receiver_concept = receiver_tag;

        Rcvr& @\exposid{rcvr}@;                         // \expos

        void set_value() && noexcept {
          execution::set_value(std::move(@\exposid{rcvr}@));
        }

        template<class E>
          void set_error(E&& e) && noexcept {
            execution::set_error(std::move(@\exposid{rcvr}@), std::forward<E>(e));
          }

        void set_stopped() && noexcept {
          execution::set_stopped(std::move(@\exposid{rcvr}@));
        }

        decltype(auto) get_env() const noexcept {
          return execution::get_env(@\exposid{rcvr}@);
        }
      };

      using @\exposid{sched-sender}@ =                  // \expos
        decltype(schedule(get_start_scheduler(get_env(declval<Rcvr&>()))));
      using @\exposid{op-t}@ =                          // \expos
        connect_result_t<@\exposid{sched-sender}@, @\exposid{rcvr-t}@>;

      Scope* @\exposid{scope}@;                         // \expos
      Rcvr& @\exposid{receiver}@;                       // \expos
      @\exposid{op-t}@ @\exposid{op}@;                              // \expos

      @\exposid{state}@(Scope* scope, Rcvr& rcvr)       // \expos
        noexcept(@\exposconcept{nothrow-callable}@<connect_t, @\exposid{sched-sender}@, @\exposid{rcvr-t}@>)
        : @\exposid{scope}@(scope),
          @\exposid{receiver}@(rcvr),
          @\exposid{op}@(connect(schedule(get_start_scheduler(get_env(rcvr))), @\exposid{rcvr-t}@(rcvr))) {}

      void @\exposid{complete}@() noexcept {            // \expos
        start(@\exposid{op}@);
      }

      void @\exposid{complete-inline}@() noexcept {     // \expos
        set_value(std::move(@\exposid{receiver}@));
      }
    };

    static constexpr auto @\exposid{get-state}@ =       // \expos
      []<class Rcvr>(auto&& sender, Rcvr& receiver)
        noexcept(is_nothrow_constructible_v<@\exposid{state}@<Rcvr>, @\exposid{data-type}@<decltype(sender)>, Rcvr&>) {
        auto[_, self] = sender;
        return @\exposid{state}@(self, receiver);
      };

    static constexpr auto @\exposid{start}@ =           // \expos
      [](auto& s, auto&) noexcept {
        if (s.@\exposid{scope}@->@\exposid{start-join-sender}@(s))
          s.@\exposid{complete-inline}@();
      };
  };
}
\end{codeblock}

\pnum
\exposid{association-t} is a class template,
specializations of which model \libconcept{scope_association} and
contain an exposition-only member \exposid{scope} of type \tcode{Scope*}.
For a class type \tcode{Scope} and
an object \tcode{assoc} of type \tcode{\exposid{association-t}<Scope>}:
\begin{itemize}
\item
\tcode{assoc.\exposid{scope}} points to its associated scope,
\item
\tcode{assoc} is engaged when \tcode{assoc.\exposid{scope} != nullptr} is \tcode{true},
\item
if \tcode{assoc} is engaged,
then \tcode{assoc.try_associate()} is equivalent to
\tcode{assoc.\exposid{scope}->\exposid{try-associate}()}, and
\item
the association owned by \tcode{assoc}
is released by invoking \tcode{assoc.\exposid{scope}->\exposid{disassociate}()}.
\end{itemize}

\rSec3[exec.scope.simple.counting]{Simple Counting Scope}

\rSec4[exec.scope.simple.counting.general]{General}

\indexlibraryglobal{execution::simple_counting_scope}%
\begin{codeblock}
namespace std::execution {
  class simple_counting_scope {
  public:
    // \ref{exec.simple.counting.token}, token
    struct token;

    using @\exposid{assoc-t}@ = @\exposid{association-t}@<simple_counting_scope>;     // \expos

    static constexpr size_t max_associations = @\UNSP{\impldef{value of \tcode{std::execution::simple_counting_scope::max_associations}}}@;

    // \ref{exec.simple.counting.ctor}, constructor and destructor
    simple_counting_scope() noexcept;
    simple_counting_scope(simple_counting_scope&&) = delete;
    ~simple_counting_scope();

    // \ref{exec.simple.counting.mem}, members
    token get_token() noexcept;
    void close() noexcept;
    @\libconcept{sender}@ auto join() noexcept;

  private:
    size_t @\exposid{count}@;                                       // \expos
    @\exposid{scope-state-type}@ @\exposid{state}@;                             // \expos

    @\exposid{assoc-t}@ @\exposid{try-associate}@() noexcept;                   // \expos
    void @\exposid{disassociate}@() noexcept;                       // \expos
    template<class State>
      bool @\exposid{start-join-sender}@(State& state) noexcept;    // \expos
  };
}
\end{codeblock}

\pnum
For purposes of determining the existence of a data race,
\tcode{get_token},
\tcode{close},
\tcode{join},
\exposid{try-associate},
\exposid{disassociate}, and
\exposid{start-join-sender}
behave as atomic operations\iref{intro.multithread}.
These operations on a single object of
type \tcode{simple_counting_scope} appear to occur in a single total order.

\rSec4[exec.simple.counting.ctor]{Constructor and Destructor}

\indexlibraryctor{execution::simple_counting_scope}%
\begin{itemdecl}
simple_counting_scope() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\ensures
\exposid{count} is \tcode{0} and \exposid{state} is \exposid{unused}.
\end{itemdescr}

\indexlibrarydtor{execution::simple_counting_scope}%
\begin{itemdecl}
~simple_counting_scope();
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
If \exposid{state} is not one of
\exposid{joined}, \exposid{unused}, or \exposid{unused-and-closed},
invokes \tcode{terminate}\iref{except.terminate}.
Otherwise, has no effects.
\end{itemdescr}

\rSec4[exec.simple.counting.mem]{Members}

\indexlibrarymember{get_token}{execution::simple_counting_scope}%
\begin{itemdecl}
token get_token() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
An object \tcode{t} of type \tcode{simple_counting_scope::token} such that
\tcode{t.\exposid{scope} == this} is \tcode{true}.
\end{itemdescr}

\indexlibrarymember{close}{execution::simple_counting_scope}%
\begin{itemdecl}
void close() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
If \exposid{state} is
\begin{itemize}
\item
\exposid{unused}, then changes \exposid{state} to \exposid{unused-and-closed};
\item
\exposid{open}, then changes \exposid{state} to \exposid{closed};
\item
\exposid{open-and-joining},
then changes \exposid{state} to \exposid{closed-and-joining};
\item
otherwise, no effects.
\end{itemize}

\pnum
\ensures
Any subsequent call to \tcode{\exposid{try-associate}()} on \tcode{*this}
returns \tcode{false}.
\end{itemdescr}

\indexlibrarymember{join}{execution::simple_counting_scope}%
\begin{itemdecl}
@\libconcept{sender}@ auto join() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{\exposid{make-sender}(\exposid{scope-join-t}(), this)}.
\end{itemdescr}

\indexlibrarymember{\exposid{try-associate}}{execution::simple_counting_scope}%
\begin{itemdecl}
@\exposid{assoc-t}@ @\exposid{try-associate}@() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
If \exposid{count} is equal to \tcode{max_associations}, then no effects.
Otherwise, if \exposid{state} is
\begin{itemize}
\item
\exposid{unused},
then increments \exposid{count} and changes \exposid{state} to \exposid{open};
\item
\exposid{open} or \exposid{open-and-joining},
then increments \exposid{count};
\item
otherwise, no effects.
\end{itemize}

\pnum
\returns
If \exposid{count} was incremented,
an object of type \exposid{assoc-t}
that is engaged and associated with \tcode{*this}, and
\tcode{\exposid{assoc-t}()} otherwise.
\end{itemdescr}

\indexlibrarymember{\exposid{disassociate}}{execution::simple_counting_scope}%
\begin{itemdecl}
void @\exposid{disassociate}@() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\expects
\exposid{count} is greater than zero.

\pnum
\effects
Decrements \exposid{count}.
If \exposid{count} is zero after decrementing and
\exposid{state} is \exposid{open-and-joining} or \exposid{closed-and-joining},
changes \exposid{state} to \exposid{joined} and
calls \tcode{\exposid{complete}()} on all objects registered with \tcode{*this}.
\begin{note}
Calling \tcode{\exposid{complete}()} on any registered object
can cause \tcode{*this} to be destroyed.
\end{note}
\end{itemdescr}

\indexlibrarymember{\exposid{start-join-sender}}{execution::simple_counting_scope}%
\begin{itemdecl}
template<class State>
  bool @\exposid{start-join-sender}@(State& st) noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
If \tcode{count} is zero, then
changes \exposid{state} to \exposid{joined} and returns \tcode{true}.
Otherwise, if \exposid{state} is
\begin{itemize}
\item
\exposid{open} or \exposid{open-and-joining}, then
changes \exposid{state} to \exposid{open-and-joining},
registers \tcode{st} with \tcode{*this} and returns \tcode{false};
\item
\exposid{closed} or \exposid{closed-and-joining}, then
changes \exposid{state} to \exposid{closed-and-joining},
registers \tcode{st} with \tcode{*this} and returns \tcode{false}.
\end{itemize}
\end{itemdescr}

\rSec4[exec.simple.counting.token]{Token}

\indexlibraryglobal{execution::simple_counting_scope::token}%
\begin{codeblock}
namespace std::execution {
  struct simple_counting_scope::token {
    template<@\libconcept{sender}@ Sender>
      Sender&& wrap(Sender&& snd) const noexcept;
    @\exposid{assoc-t}@ try_associate() const noexcept;

  private:
    simple_counting_scope* @\exposid{scope}@;   // \expos
  };
}
\end{codeblock}

\indexlibrarymember{wrap}{execution::simple_counting_scope::token}%
\begin{itemdecl}
template<@\libconcept{sender}@ Sender>
  Sender&& wrap(Sender&& snd) const noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{std::forward<Sender>(snd)}.
\end{itemdescr}

\indexlibrarymember{try_associate}{execution::simple_counting_scope::token}%
\begin{itemdecl}
@\exposid{assoc-t}@ try_associate() const noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to: \tcode{return \exposid{scope}->\exposid{try-associate}();}
\end{itemdescr}

\rSec3[exec.scope.counting]{Counting Scope}

\indexlibraryglobal{execution::counting_scope}%
\indexlibrarymember{token}{execution::counting_scope}%
\begin{codeblock}
namespace std::execution {
  class counting_scope {
  public:
    using @\exposid{assoc-t}@ = @\exposid{association-t}@<counting_scope>;      // \expos

    struct token {
      template<@\libconcept{sender}@ Sender>
        @\libconcept{sender}@ auto wrap(Sender&& snd) const noexcept(@\seebelow@);
      @\exposid{assoc-t}@ try_associate() const noexcept;

    private:
      counting_scope* @\exposid{scope}@;                            // \expos
    };

    static constexpr size_t max_associations = @\UNSP{\impldef{value of \tcode{std::execution::counting_scope::max_associations}}}@;

    counting_scope() noexcept;
    counting_scope(counting_scope&&) = delete;
    ~counting_scope();

    token get_token() noexcept;
    void close() noexcept;
    @\libconcept{sender}@ auto join() noexcept;
    void request_stop() noexcept;

  private:
    size_t @\exposid{count}@;                                       // \expos
    @\exposid{scope-state-type}@ @\exposid{state}@;                             // \expos
    inplace_stop_source @\exposid{s_source}@;                       // \expos

    @\exposid{assoc-t}@ @\exposid{try-associate}@() noexcept;                   // \expos
    void @\exposid{disassociate}@() noexcept;                       // \expos

    template<class State>
      bool @\exposid{start-join-sender}@(State& state) noexcept;    // \expos
  };
}
\end{codeblock}

\pnum
\tcode{counting_scope} differs from \tcode{simple_counting_scope} by
adding support for cancellation.
Unless specified below, the semantics of members of \tcode{counting_scope}
are the same as the corresponding members of \tcode{simple_counting_scope}.

\indexlibrarymember{get_token}{execution::counting_scope}%
\begin{itemdecl}
token get_token() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
An object \tcode{t} of type \tcode{counting_scope::token} such that
\tcode{t.\exposid{scope} == this} is \tcode{true}.
\end{itemdescr}

\indexlibrarymember{request_stop}{execution::counting_scope}%
\begin{itemdecl}
void request_stop() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to \tcode{\exposid{s_source}.request_stop()}.

\pnum
\remarks
Calls to \tcode{request_stop} do not introduce data races.
\end{itemdescr}

\indexlibrarymember{\exposid{try-associate}}{execution::counting_scope}%
\begin{itemdecl}
@\exposid{assoc-t}@ @\exposid{try-associate}@() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
If \exposid{count} is equal to \tcode{max_associations},
then no effects.
Otherwise, if \exposid{state} is
\begin{itemize}
\item
\exposid{unused}, then increments \exposid{count} and
changes \exposid{state} to \exposid{open};
\item
\exposid{open} or \exposid{open-and-joining}, then increments \exposid{count};
\item
otherwise, no effects.
\end{itemize}

\pnum
\returns
If \exposid{count} was incremented,
an object of type \exposid{assoc-t}
that is engaged and associated with \tcode{*this}, and
\tcode{\exposid{assoc-t}()} otherwise.
\end{itemdescr}

\indexlibrarymember{wrap}{execution::counting_scope::token}%
\begin{itemdecl}
template<@\libconcept{sender}@ Sender>
  @\libconcept{sender}@ auto counting_scope::token::wrap(Sender&& snd) const
    noexcept(is_nothrow_constructible_v<remove_cvref_t<Sender>, Sender>);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return @\exposid{stop-when}@(std::forward<Sender>(snd), @\exposid{scope}@->@\exposid{s_source}@.get_token());
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{wrap}{execution::counting_scope::token}%
\begin{itemdecl}
@\exposid{assoc-t}@ counting_scope::token::try_associate() const noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to: \tcode{return \exposid{scope}->\exposid{try-associate}();}
\end{itemdescr}

\rSec1[exec.par.scheduler]{Parallel scheduler}

\begin{codeblock}
namespace std::execution {
  class @\libglobal{parallel_scheduler}@ {
    @\unspec@
  };
}
\end{codeblock}

\pnum
\tcode{parallel_scheduler} models \libconcept{scheduler}.

\pnum
Let \tcode{sch} be an object of type \tcode{parallel_scheduler}, and
let \tcode{\exposid{BACKEND-OF}(sch)} be \tcode{*ptr},
where \tcode{sch} is associated with \tcode{ptr}.

\pnum
The expression \tcode{get_forward_progress_guarantee(sch)} has the value
\tcode{forward_progress_guarantee::\brk{}parallel}.

\pnum
Let \tcode{sch2} be an object of type \tcode{parallel_scheduler}.
Two objects \tcode{sch} and \tcode{sch2} compare equal if and only if
\tcode{\exposid{BACKEND-OF}(sch)} and
\tcode{\exposid{BACKEND-OF}(sch2)} refer to the same object.

\pnum
Let \tcode{rcvr} be a receiver.
A \defnx{proxy for \tcode{rcvr} with base \tcode{B}}{proxy} is
an lvalue \tcode{r} of type \tcode{B} such that:
\begin{itemize}
\item
\tcode{r.set_value()} has effects equivalent to
\tcode{set_value(std::move(rcvr))}.
\item
\tcode{r.set_error(e)}, where \tcode{e} is an \tcode{exception_ptr} object,
has effects equivalent to \tcode{set_error(std::move(\brk{}rcvr), std::move(e))}.
\item
\tcode{r.set_stopped()} has effects equivalent to
\tcode{set_stopped(std::move(rcvr))}.
\end{itemize}

\pnum
A \defn{preallocated backend storage for a proxy} \tcode{r} is
an object \tcode{s} of type \tcode{span<byte>}
such that the range \tcode{s} remains valid and may be overwritten
until one of \tcode{set_value}, \tcode{set_error}, or \tcode{set_stopped}
is called on \tcode{r}.
\begin{note}
The storage referenced by \tcode{s} can be used as temporary storage
for operations launched via calls to \tcode{parallel_scheduler_backend}.
\end{note}

\pnum
Let \tcode{b} be \tcode{\exposid{BACKEND-OF}(sch)},
let \tcode{sndr} be the object returned by \tcode{schedule(sch)}, and
let \tcode{rcvr} be a receiver.
If \tcode{rcvr} is connected to \tcode{sndr} and
the resulting operation state is started, then:
\begin{itemize}
\item
If \tcode{sndr} completes successfully,
then \tcode{b.schedule(r, s)} is called, where
\begin{itemize}
\item
\tcode{r} is a proxy for \tcode{rcvr}
with base \tcode{parallel_scheduler_replacement::receiver_proxy} and
\item
\tcode{s} is a preallocated backend storage for \tcode{r}.
\end{itemize}
\item
All other completion operations are forwarded unchanged.
\end{itemize}

\pnum
The expression \tcode{get_domain(sch)}
returns an expression of exposition-only type
\exposid{parallel-scheduler-do\-main}, that is equivalent with:

\begin{codeblock}
struct @\exposid{parallel-scheduler-domain}@ {
  template<@\exposconcept{sender-for}@<bulk_chunked_t> Sndr, @\exposconcept{queryable}@ Env>
  static constexpr decltype(auto)
    transform_sender(set_value_t, Sndr&& sndr, const Env& env) const noexcept {
      return @\seebelow@;
    }
  template<@\exposconcept{sender-for}@<bulk_unchunked_t> Sndr, @\exposconcept{queryable}@ Env>
  static constexpr decltype(auto)
    transform_sender(set_value_t, Sndr&& sndr, const Env& env) const noexcept {
      return @\seebelow@;
    }
};
\end{codeblock}

\pnum
For argument \tcode{sndr} of the above \tcode{transform_sender},
let \tcode{child}, \tcode{pol}, \tcode{shape} and \tcode{f}
be defined by the following declarations:
\begin{codeblock}
auto& [_, data, child] = sndr;
auto& [pol, shape, f] = data;
\end{codeblock}

\pnum
Let \tcode{p} be
\begin{itemize}
\item
\tcode{true}, if the type of the expression \tcode{pol} is
\cv{}~\tcode{parallel_policy} or \cv{}~\tcode{parallel_unsequenced_policy};
\item
\impldef{parallelism flag for an implementation-defined execution policy},
if \tcode{pol} is an implementation-defined execution policy;
\item
\tcode{false}, otherwise.
\end{itemize}

\pnum
The \tcode{transform_sender} overload
that accepts senders with tag \tcode{bulk_chunked_t}
returns a sender such that if it is connected to a receiver \tcode{rcvr} and
the resulting operation state is started, then:
\begin{itemize}
\item
If \tcode{child} completes with values \tcode{vals},
let \tcode{args} be a pack of lvalue subexpressions designating \tcode{vals},
then \tcode{b.schedule_bulk_chunked(p ? shape : 1, r, s)} is called, where
\begin{itemize}
\item
\tcode{r} is a proxy for \tcode{rcvr}
with base \tcode{parallel_scheduler_replacement::bulk_item_receiver_proxy}
such that \tcode{r.execute(i, j)} for indices \tcode{i} and \tcode{j}
has effects equivalent to
\tcode{f(i, j, args...)} if \tcode{p} is true and
\tcode{f(0, shape, args...)} otherwise; and
\item
\tcode{s} is a preallocated backend storage for \tcode{r}.
\end{itemize}
\item
All other completion operations are forwarded unchanged.
\end{itemize}

\pnum
The \tcode{transform_sender} overload
that accepts senders with tag \tcode{bulk_unchunked_t}
returns a sender such that if it is connected to a receiver \tcode{rcvr} and
the resulting operation state is started, then:
\begin{itemize}
\item
If \tcode{child} completes with values \tcode{vals},
let \tcode{args} be a pack of lvalue subexpressions designating \tcode{vals},
then \tcode{b.schedule_bulk_unchunked(p ? shape : 1, r, s)} is called, where
\begin{itemize}
\item
\tcode{r} is a proxy for \tcode{rcvr}
with base \tcode{parallel_scheduler_replacement::bulk_item_receiver_proxy}
such that \tcode{r.execute(i, i + 1)} for index \tcode{i}
has effects equivalent to
\tcode{f(i, args...)} if \tcode{p} is true and
\begin{codeblock}
for (decltype(shape) i = 0; i < shape; i++) { f(i, args...); }
\end{codeblock}
otherwise; and
\item
\tcode{s} is a preallocated backend storage for \tcode{r}.
\end{itemize}
\item
All other completion operations are forwarded unchanged.
\end{itemize}

\indexlibraryglobal{get_parallel_scheduler}%
\begin{itemdecl}
parallel_scheduler get_parallel_scheduler();
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Let \tcode{eb} be the result of \tcode{parallel_scheduler_replacement::query_parallel_scheduler_backend()}.
If \tcode{eb == nullptr} is \tcode{true},
calls \tcode{terminate}\iref{except.terminate}.
Otherwise, returns a \tcode{parallel_scheduler} object
associated with \tcode{eb}.
\end{itemdescr}

\rSec1[exec.parschedrepl]{Namespace \tcode{parallel_scheduler_replacement}}

\rSec2[exec.parschedrepl.general]{General}

\pnum
Facilities in the \tcode{parallel_scheduler_replacement} namespace
allow users to replace the default implementation of \tcode{parallel_scheduler}.

\rSec2[exec.parschedrepl.recvproxy]{Receiver proxies}

\begin{codeblock}
namespace std::execution::parallel_scheduler_replacement {
  struct @\libglobal{receiver_proxy}@ {
  protected:
    virtual bool @\exposidnc{query-env}@(@\unspecnc@) noexcept = 0;   // \expos

  public:
    virtual void set_value() noexcept = 0;
    virtual void set_error(exception_ptr) noexcept = 0;
    virtual void set_stopped() noexcept = 0;

    template<class P, @\exposconcept{class-type}@ Query>
      optional<P> try_query(Query q) const noexcept;
  };

  struct @\libglobal{bulk_item_receiver_proxy}@ : receiver_proxy {
    virtual void execute(size_t, size_t) noexcept = 0;
  };
}
\end{codeblock}

\pnum
\tcode{receiver_proxy} represents a receiver
that will be notified
by the implementations of \tcode{parallel_scheduler_backend}
to trigger the completion operations.
\tcode{bulk_item_receiver_proxy} is derived from \tcode{receiver_proxy} and
is used for \tcode{bulk_chunked} and \tcode{bulk_unchunked} customizations
that will also receive notifications
from implementations of \tcode{parallel_scheduler_backend}
corresponding to different iterations.

\begin{itemdecl}
template<class P, @\exposconcept{class-type}@ Query>
  optional<P> @\libglobal{try_query}@(Query q) const noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
\tcode{P} is a cv-unqualified non-array object type.

\pnum
\returns
Let \tcode{env} be the environment of the receiver represented by \tcode{*this}.
If
\begin{itemize}
\item
\tcode{Query} is not a member of an implementation-defined set
of supported queries; or
\item
\tcode{P} is not a member of an implementation-defined set
of supported result types for \tcode{Query}; or
\item
the expression \tcode{q(env)} is not well-formed,
\end{itemize}
then returns \tcode{nullopt}.
Otherwise, if \tcode{q(env)} has type \cv{}~\tcode{P},
then returns \tcode{q(env)}.
Otherwise, returns an
\impldef{return value of \tcode{receiver_proxy::try_query}} value
of type \tcode{optional<P>}.

\pnum
\remarks
\tcode{get_stop_token_t} is
in the implementation-defined set of supported queries, and
\tcode{inplace_stop_token} is a member
of the implementation-defined set of supported result types
for \tcode{get_stop_token_t}.

\pnum
\recommended
If \tcode{P} is \tcode{inplace_stop_token} and
\tcode{T} is a type other than \tcode{inplace_stop_token}
that models \libconcept{stoppable_token},
\tcode{try_query} should return an object of type \tcode{inplace_stop_token}
such that until one of
\tcode{set_value},
\tcode{set_error} or
\tcode{set_stopped}
is called on \tcode{*this},
all calls to \tcode{try_query} return equivalent \tcode{inplace_stop_token} objects.
\end{itemdescr}

\rSec2[exec.parschedrepl.query]{\tcode{query_parallel_scheduler_backend}}

\indexlibraryglobal{query_parallel_scheduler_backend}%
\begin{itemdecl}
shared_ptr<parallel_scheduler_backend> query_parallel_scheduler_backend();
\end{itemdecl}

\begin{itemdescr}
\pnum
\tcode{query_parallel_scheduler_backend()} returns
the implementation object for a parallel scheduler.

\pnum
\returns
An object \tcode{p},
such that \tcode{p.get()} points to a \tcode{parallel_scheduler_backend} object
that is a base-class subobject
of some most derived object \tcode{o} within its lifetime.
The lifetime of \tcode{o} does not end
as long as there exists a \tcode{shared_ptr} object \tcode{q} within its lifetime
such that \tcode{q.owner_equal(p)} is \tcode{true}.

\pnum
\remarks
This function is replaceable\iref{term.replaceable.function}.
\end{itemdescr}

\rSec2[exec.parschedrepl.psb]{Class \tcode{parallel_scheduler_backend}}

\begin{codeblock}
namespace std::execution::parallel_scheduler_replacement {
  struct @\libglobal{parallel_scheduler_backend}@ {
    virtual ~parallel_scheduler_backend() = default;

    virtual void schedule(receiver_proxy&, span<byte>) noexcept = 0;
    virtual void schedule_bulk_chunked(size_t, bulk_item_receiver_proxy&,
                                       span<byte>) noexcept = 0;
    virtual void schedule_bulk_unchunked(size_t, bulk_item_receiver_proxy&,
                                         span<byte>) noexcept = 0;
  };
}
\end{codeblock}

\indexlibrarymember{schedule}{parallel_scheduler_backend}%
\begin{itemdecl}
virtual void schedule(receiver_proxy& r, span<byte> s) noexcept = 0;
\end{itemdecl}

\begin{itemdescr}
\pnum
\expects
The ends
of the lifetime of \tcode{*this},
of the lifetime of the object referred to by \tcode{r}, and
of the duration of any storage referenced by \tcode{s}
all happen after
the beginning of the evaluation of
the call to \tcode{set_value}, \tcode{set_error}, or \tcode{set_stopped}
on \tcode{r} (see below).

\pnum
\effects
A derived class shall implement this function such that:
\begin{itemize}
\item
One of the following expressions is evaluated:
\begin{itemize}
\item
\tcode{r.set_value()}, if no error occurs, and the work is successful;
\item
\tcode{r.set_error(eptr)}, if an error occurs,
where \tcode{eptr} is an object of type \tcode{exception_ptr};
\item
\tcode{r.set_stopped()}, if the work is canceled.
\end{itemize}
\item
Any call to \tcode{r.set_value()} happens on
an execution agent of the execution context represented by \tcode{*this}.
\end{itemize}

\pnum
\remarks
The storage referenced by \tcode{s}
may be used by \tcode{*this} as temporary storage
for the duration of the operation launched by this call.
\end{itemdescr}

\indexlibrarymember{schedule_bulk_chunked}{parallel_scheduler_backend}%
\begin{itemdecl}
virtual void schedule_bulk_chunked(size_t n, bulk_item_receiver_proxy& r,
                                   span<byte> s) noexcept = 0;
\end{itemdecl}

\begin{itemdescr}
\pnum
\expects
The ends
of the lifetime of \tcode{*this},
of the lifetime of the object referred to by \tcode{r}, and
of the duration of any storage referenced by \tcode{s}
all happen after
the beginning of the evaluation of the call to
\tcode{set_value}, \tcode{set_error}, or \tcode{set_stopped}
on \tcode{r} (see below).

\pnum
\effects
A derived class shall implement this function such that:
\begin{itemize}
\item
Eventually, one of the following expressions is evaluated:
\begin{itemize}
\item
\tcode{r.set_value()}, if no error occurs, and the work is successful;
\item
\tcode{r.set_error(eptr)}, if an error occurs,
where \tcode{eptr} is an object of type \tcode{exception_ptr};
\item
\tcode{r.set_stopped()}, if the work is canceled.
\end{itemize}
\item
If \tcode{r.execute(b, e)} is called,
then \tcode{b} and \tcode{e} are in the range \crange{0}{n} and
$\tcode{b} < \tcode{e}$.
\item
For each $i$ in \range{0}{n},
there is at most one call to \tcode{r.execute(b, e)}
such that $i$ is in the range \range{b}{e}.
\item
If \tcode{r.set_value()} is called,
then for each $i$ in \range{0}{n},
there is exactly one call to \tcode{r.execute(b, e)}
such that $i$ is in the range \range{b}{e}.
\item
All calls to \tcode{execute} on \tcode{r} happen before
the call to either \tcode{set_value}, \tcode{set_error}, or \tcode{set_stopped}
on \tcode{r}.
\item
All calls to \tcode{execute} and \tcode{set_value} on \tcode{r} are made
on execution agents of the execution context represented by \tcode{*this}.
\end{itemize}

\pnum
\remarks
The storage referenced by \tcode{s} may be used by \tcode{*this}
as temporary storage for the duration of the operation launched by this call.
\end{itemdescr}

\indexlibrarymember{schedule_bulk_unchunked}{parallel_scheduler_backend}%
\begin{itemdecl}
virtual void schedule_bulk_unchunked(size_t n, bulk_item_receiver_proxy& r,
                                     span<byte> s) noexcept = 0;
\end{itemdecl}

\begin{itemdescr}
\pnum
\expects
The ends
of the lifetime of \tcode{*this},
of the lifetime of the object referred to by \tcode{r}, and
of the duration of any storage referenced by \tcode{s}
all happen after
the beginning of the evaluation of the call to
\tcode{set_value}, \tcode{set_error}, or \tcode{set_stopped}
on \tcode{r} (see below).

\pnum
\effects
A derived class shall implement this function such that:
\begin{itemize}
\item
Eventually, one of the following expressions is evaluated:
\begin{itemize}
\item
\tcode{r.set_value()}, if no error occurs, and the work is successful;
\item
\tcode{r.set_error(eptr)}, if an error occurs,
where \tcode{eptr} is an object of type \tcode{exception_ptr};
\item
\tcode{r.set_stopped()}, if the work is canceled.
\end{itemize}
\item
If \tcode{r.execute(b, e)} is called,
then \tcode{b} is in the range \range{0}{n} and
\tcode{e} is equal to \tcode{b + 1}.
For each $i$ in \range{0}{n},
there is at most one call to \tcode{r.execute($i$, $i$ + 1)}.
\item
If \tcode{r.set_value()} is called,
then for each $i$ in \range{0}{n},
there is exactly one call to \tcode{r.execute($i$, $i$ + 1)}.
\item
All calls to \tcode{execute} on \tcode{r} happen before
the call to either \tcode{set_value}, \tcode{set_error}, or \tcode{set_stopped}
on \tcode{r}.
\item
All calls to \tcode{execute} and \tcode{set_value} on \tcode{r} are made
on execution agents of the execution context represented by \tcode{*this}.
\end{itemize}

\pnum
\remarks
The storage referenced by \tcode{s} may be used by \tcode{*this}
as temporary storage for the duration of the operation launched by this call.
\end{itemdescr}
