|
| 1 | +<?xml version='1.0' encoding='utf-8' standalone='no'?> |
| 2 | +<!DOCTYPE issue SYSTEM "lwg-issue.dtd"> |
| 3 | + |
| 4 | +<issue num="4198" status="New"> |
| 5 | +<title>`schedule_from` isn't starting the schedule sender if decay-copying results throws</title> |
| 6 | +<section><sref ref="[exec.schedule.from]"/></section> |
| 7 | +<submitter>Eric Niebler</submitter> |
| 8 | +<date>03 Feb 2025</date> |
| 9 | +<priority>99</priority> |
| 10 | + |
| 11 | +<discussion> |
| 12 | +<p> |
| 13 | +Imported from <a href="https://github.com/cplusplus/sender-receiver/issues/304">cplusplus/sender-receiver #304</a>. |
| 14 | +</p> |
| 15 | +<p> |
| 16 | +<sref ref="[exec.schedule.from]"/>/p11 specifies `shedule_from`'s completion operation as follows: |
| 17 | + |
| 18 | +<pre><code> |
| 19 | +[]<class Tag, class... Args>(auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept |
| 20 | + -> void { |
| 21 | + using result_t = decayed-tuple<Tag, Args...>; |
| 22 | + constexpr bool nothrow = is_nothrow_constructible_v<result_t, Tag, Args...>; |
| 23 | + |
| 24 | + try { |
| 25 | + state.async-result.template emplace<result_t>(Tag(), std::forward<Args>(args)...); |
| 26 | + } catch (...) { |
| 27 | + if constexpr (!nothrow) { |
| 28 | + set_error(std::move(rcvr), current_exception()); |
| 29 | + return; |
| 30 | + } |
| 31 | + } |
| 32 | + start(state.op-state); |
| 33 | +}; |
| 34 | +</code></pre> |
| 35 | + |
| 36 | +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. |
| 37 | +</p> |
| 38 | +<p><b>Suggested resolution</b></p> |
| 39 | +<p> |
| 40 | +The right thing, i think, is to catch the exception, emplace the `exception_ptr` into the <i>`async-result`</i> variant, and then start the schedule operation, as shown below: |
| 41 | + |
| 42 | +<pre><code> |
| 43 | +[]<class Tag, class... Args>(auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept |
| 44 | + -> void { |
| 45 | + using result_t = decayed-tuple<Tag, Args...>; |
| 46 | + constexpr bool nothrow = is_nothrow_constructible_v<result_t, Tag, Args...>; |
| 47 | + |
| 48 | + try { |
| 49 | + state.async-result.template emplace<result_t>(Tag(), std::forward<Args>(args)...); |
| 50 | + } catch(...) { |
| 51 | + if constexpr (nothrow) |
| 52 | + state.async-result.template emplace<tuple<set_error_t, exception_ptr>>(set_error, current_exception()); |
| 53 | + } |
| 54 | + } |
| 55 | + |
| 56 | + start(state.op-state); |
| 57 | +} |
| 58 | +</code></pre> |
| 59 | + |
| 60 | +we also need to change how we specify the variant type of `state.async-result`: |
| 61 | + |
| 62 | +<blockquote> |
| 63 | +Let `Sigs` be a pack of the arguments to the `completion_signatures` |
| 64 | +specialization named by |
| 65 | +`completion_signatures_of_t<child-type<Sndr>, env_of_t<Rcvr>>`. |
| 66 | +Let <i><code>as-tuple</code></i> be an alias template |
| 67 | +<del> |
| 68 | +that transforms a completion signature `Tag(Args...)` into |
| 69 | +the tuple specialization `decayed-tuple<Tag, Args...>`. |
| 70 | +</del> |
| 71 | +<ins> |
| 72 | +such that `as-tuple<Tag(Args...)>` denotes |
| 73 | +the tuple specialization `decayed-tuple<Tag, Args...>`, |
| 74 | +and let is-nothrow-decay-copy-sig be |
| 75 | +a variable template such that |
| 76 | +<code>is-nothrow-decay-copy-sig<Tag(Args...)></code> |
| 77 | +is a core constant expression of type `bool const` and whose value |
| 78 | +is `true` if the types `Args...` are all nothrow decay-copyable, and `false` |
| 79 | +otherwise. |
| 80 | +Let <i><code>error-completion</code></i> be a pack consisting of the type |
| 81 | +`set_error_t(exception_ptr)` if |
| 82 | +<code>(is-nothrow-decay-copy-sig<Sigs> &&...)</code> |
| 83 | +is `false`, and an empty pack otherwise. |
| 84 | +</ins> |
| 85 | +Then `variant_t` denotes the type |
| 86 | +<code>variant<monostate, as-tuple<Sigs>...<ins>, <i>error-completion</i>...</ins>></code>, |
| 87 | +except with duplicate types removed. |
| 88 | +</blockquote> |
| 89 | + |
| 90 | +</p> |
| 91 | +</discussion> |
| 92 | + |
| 93 | +<resolution> |
| 94 | +<p> |
| 95 | +</p> |
| 96 | +</resolution> |
| 97 | + |
| 98 | +</issue> |
0 commit comments