Title
Constraints on `get-state` functions are incorrect
Status
new
Section
[exec.schedule.from]
Submitter
Eric Niebler

Created on 2025-02-03.00:00:00 last changed 2 days ago

Messages

Date: 2025-02-07.22:17:52

Proposed resolution:

This wording is relative to N5001.

  1. Change [exec.snd.expos] as indicated:
    -2- For a queryable object `env`, FWD-ENV(env) is an expression whose type satisfies `queryable` such that for a query object `q` and a pack of subexpressions `as`, the expression FWD-ENV(env).query(q, as...) is ill-formed if `forwarding_query(q)` is `false`; otherwise, it is expression-equivalent to `env.query(q, as...)`. The type FWD-ENV-T(Env) is decltype(FWD-ENV(declval<Env>())).
  2. Change [exec.schedule.from] as indicated:
    -6- The member impls-for<schedule_from_t>::get-state is initialized with a callable object equivalent to the following lambda:
      []<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept(see below)
       requires sender_in<child-type<Sndr>, FWD-ENV-T(env_of_t<Rcvr>)> {
    

    -8- Let `Sigs` be a pack of the arguments to the `completion_signatures` specialization named by completion_signatures_of_t<child-type<Sndr>, FWD-ENV-T(env_of_t<Rcvr>)>. Let as-tuple be an alias template that transforms a completion signature Tag(Args...) into the tuple specialization decayed-tuple<Tag, Args...>. Then variant_t denotes the type variant<monostate, as-tuple<Sigs>...>, except with duplicate types removed.

  3. Change [exec.let] as indicated:

    -6- Let `receiver2` denote the following exposition-only class template:

      namespace std::execution {
        …
      }
    
    Invocation of the function receiver2::get_env returns an object `e` such that
    1. (6.1) — `decltype(e)` models `queryable` and
    2. (6.2) — given a query object `q`, the expression `e.query(q)` is expression-equivalent to env.query(q) if that expression is valid,; otherwise, if the type of `q` satisfies `forwarding-query`, `e.query(q)` is expression-equivalent to get_env(rcvr).query(q) ; otherwise, `e.query(q)` is ill-formed.

    -7- impls-for<decayed-typeof<let-cpo>>::get-state is initialized with a callable object […]

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

  4. Change [exec.when.all] as indicated:

    -6- The member impls-for<when_all_t>::get-env is initialized with a callable object equivalent to the following lambda expression:

      []<class State, class Rcvr>(auto&&, State& state, const Receiver& rcvr) noexcept {
        return see below;
      }
    
    Returns an object `e` such that
    1. (6.1) — `decltype(e)` models `queryable`, and
    2. (6.2) — `e.query(get_stop_token)` is expression-equivalent to state.stop-src.get_token(), and
    3. (6.3) — given a query object `q` with type other than cv `stop_token_t` and whose type satisfies `forwarding-query`, `e.query(q)` is expression-equivalent to `get_env(rcvr).query(q)`.

    -7- The member impls-for<when_all_t>::get-state is initialized with a callable object equivalent to the following lambda expression:

      []<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept(e) -> decltype(e) {
        return e;
      }
    
    where e is the expression
      std::forward<Sndr>(sndr).apply(make-state<Rcvr>())
    
    and `make-state` is the following exposition-only class template:
      template<class Sndr, class Env>
      concept max-1-sender-in = sender_in<Sndr, Env> && // exposition only
        (tuple_size_v<value_types_of_t<Sndr, Env, tuple, tuple>> <= 1);
    
      enum class disposition { started, error, stopped }; // exposition only
    
      template<class Rcvr>
      struct make-state {
       template<max-1-sender-in<FWD-ENV-T(env_of_t<Rcvr>)>... Sndrs>
    

    -8- Let `copy_fail` be `exception_ptr` if […]

    -9- The alias `values_tuple` denotes the type

      tuple<value_types_of_t<Sndrs, FWD-ENV-T(env_of_t<Rcvr>), decayed-tuple, optional>...>
    
    if that type is well-formed; otherwise, tuple<>.

  5. Change [exec.into.variant] as indicated:
    -5- The member impls-for<into_variant_t>::get-state is initialized with a callable object equivalent to the following lambda:
      []<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept
        -> type_identity<value_types_of_t<child-type<Sndr>, FWD-ENV-T(env_of_t<Rcvr>)>> {
        return {};
      }
    
  6. Change [exec.stopped.opt] as indicated:
    -3- Let `sndr` and `env` be subexpressions such that `Sndr` is `decltype((sndr))` and `Env` is `decltype((env))`. If sender-for<Sndr, stopped_as_optional_t> is `false`, or if the type single-sender-value-type<child-type<Sndr>, FWD-ENV-T(Env)> is ill-formed or `void`, then the expression `stopped_as_optional.transform_sender(sndr, env)` is ill-formed; otherwise, it is equivalent to:
      auto&& [_, _, child] = sndr;
      using V = single-sender-value-type<child-type<Sndr>, FWD-ENV-T(Env)>;
    
Date: 2025-02-15.00:00:00

[ 2025-02-07; Reflector poll ]

Set priority to 1 after reflector poll.

Date: 2025-02-03.20:20:12

[ The resolution touches some of the same text as LWG 4198, but without conflicting. ]

Imported from: cplusplus/sender-receiver #315.

[exec.when.all] p6 reads:

The member impls-for<when_all_t>::get-env is initialized with a callable object equivalent to the following lambda expression:
  []<class State, class Rcvr>(auto&&, State& state, const Receiver& rcvr) noexcept {
    return see below;
  }
Returns an object `e` such that
  1. (6.1) — `decltype(e)` models `queryable`, and
  2. (6.2) — `e.query(get_stop_token)` is expression-equivalent to state.stop-src.get_token(), and
  3. (6.3) — given a query object `q` with type other than cv `stop_token_t`, `e.query(q)` is expression-equivalent to `get_env(rcvr).query(q)`.
The problem is in (6.3). It should be forwarding on `forwarding-query`'s to `get_env(rcvr)` but is is instead forwarding all queries.

Imported from: cplusplus/sender-receiver #316.

The child senders should only see the parent's queries if they are forwarding queries.

Imported from: cplusplus/sender-receiver #311.

[exec.stopped.opt]/para 3 reads:

Let `sndr` and `env` be subexpressions such that `Sndr` is `decltype((sndr))` and `Env` is `decltype((env))`. If sender-for<Sndr, stopped_as_optional_t> is `false`, or if the type single-sender-value-type<Sndr, Env> is ill-formed or `void`, then the expression `stopped_as_optional.transform_sender(sndr, env)` is ill-formed; otherwise, it is equivalent to:
the test for single-sender-value-type<Sndr, Env> is incorrect. It should be testing its child for single-sender-ness.

In addition, it should be applying `FWD-ENV-T` to `Env` so that only forwarding queries are forwarded.

Date: 2025-02-03.20:20:12

Imported from: cplusplus/sender-receiver #313 and cplusplus/sender-receiver #314.

[exec.schedule.from] p6 reads:

The member impls-for<schedule_from_t>::get-state is initialized with a callable object equivalent to the following lambda:
  []<class Sndr, class Rcvr>(Sndr&& sndr, Rcvr& rcvr) noexcept(see below)
     requires sender_in<child-type<Sndr>, env_of_t<Rcvr>> {
The constraint should account for the fact that the child sender will be connected with FWD-ENV(get_env(rcvr)).

History
Date User Action Args
2025-02-07 22:17:52adminsetmessages: + msg14612
2025-02-03 16:56:11adminsetmessages: + msg14566
2025-02-03 16:56:11adminsetmessages: + msg14565
2025-02-03 00:00:00admincreate