Open
Description
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.