Skip to content

schedule_from isn't starting the schedule sender if decay-copying results throws #304

Open
@ericniebler

Description

@ericniebler

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.

Proposed 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...>. Then variant_t denotes the type
-variant<monostate, as-tuple<Sigs>...>, except with duplicate types
-removed.
+env_of_t<Rcvr>>. Let as-tuple be an alias template 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1bugSomething isn't workingpending-wg21A paper or an LWG issue exits

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions