Title
`schedule_from` isn't starting the schedule sender if decay-copying results throws
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-03.16:56:11

[ This touches the same text as LWG 4203. ]

Date: 2025-02-03.00:00:00

Imported from cplusplus/sender-receiver #304.

[exec.schedule.from]/p11 specifies `shedule_from`'s completion operation as follows:


[]<class Tag, class... Args>(auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept
    -> void {
  using result_t = decayed-tuple<Tag, Args...>;
  constexpr bool nothrow = is_nothrow_constructible_v<result_t, Tag, Args...>;

  try {
    state.async-result.template emplace<result_t>(Tag(), std::forward<Args>(args)...);
  } catch (...) {
    if constexpr (!nothrow) {
      set_error(std::move(rcvr), current_exception());
      return;
    }
  }
  start(state.op-state);
};
so if emplacing the result tuple throws, `set_error` is immediately called on the downstream receiver. no attempt is made to post the completion to the specified scheduler. this is probably not the right behavior.

Suggested resolution

The right thing, i think, is to catch the exception, emplace the `exception_ptr` into the `async-result` variant, and then start the schedule operation, as shown below:


[]<class Tag, class... Args>(auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept
    -> void {
  using result_t = decayed-tuple<Tag, Args...>;
  constexpr bool nothrow = is_nothrow_constructible_v<result_t, Tag, Args...>;

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

  start(state.op-state);
}
we also need to change how we specify the variant type of `state.async-result`:
Let `Sigs` be a pack of the arguments to the `completion_signatures` specialization named by completion_signatures_of_t<child-type<Sndr>, 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...>. such that as-tuple<Tag(Args...)> denotes the tuple specialization decayed-tuple<Tag, Args...>, and let is-nothrow-decay-copy-sig be a variable template such that is-nothrow-decay-copy-sig<Tag(Args...)> is a core constant expression of type `bool const` and whose value is `true` if the types `Args...` are all nothrow decay-copyable, and `false` otherwise. Let error-completion be a pack consisting of the type `set_error_t(exception_ptr)` if (is-nothrow-decay-copy-sig<Sigs> &&...) is `false`, and an empty pack otherwise. Then `variant_t` denotes the type variant<monostate, as-tuple<Sigs>..., error-completion...>, except with duplicate types removed.

History
Date User Action Args
2025-02-03 16:56:11adminsetmessages: + msg14563
2025-02-03 00:00:00admincreate