Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
ericniebler opened this issue Nov 21, 2024 · 0 comments

Comments

@ericniebler
Copy link
Collaborator

ericniebler commented Nov 21, 2024

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-EVAL(rcvr, [&]() noexcept(nothrow) {
    state.async-result.template emplace<result_t>(Tag(), std::forward<Args>(args)...);
  }());

  if (state.async-result.valueless_by_exception())
    return;
  if (state.async-result.index() == 0)
    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. 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant