Skip to content

Commit 79a1f4d

Browse files
authored
add resolution for LWG4339: task's coroutine frame may be released late
1 parent 0d60c16 commit 79a1f4d

File tree

1 file changed

+72
-0
lines changed

1 file changed

+72
-0
lines changed

xml/issue4339.xml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,78 @@ Thus, the <code>variant</code> can be replaced with an
4444

4545
<resolution>
4646
<p>
47+
In <sref ref="[task.state]"/>, add
48+
exposition-only data members <code><i>result</i></code> and
49+
<code><i>error</i></code> to the exposition-only class
50+
<code><i>state</i></code>:
51+
<blockquote>
52+
<pre>
53+
namespace std::execution {
54+
template&lt;class T, class Environment&gt;
55+
template&lt;receiver Rcvr&gt;
56+
class task&lt;T, Environment&gt;::<i>state</i> { // <i>exposition only</i>
57+
...
58+
Environment <i>environment</i>; // <i>exposition only</i>
59+
<ins>optional&lt;T&gt; <i>result</i>; // <i>exposition only; present only if</i> is_void_v&lt;T&gt; <i>is</i> false</ins>
60+
<ins>exception_ptr <i>error</i>; // <i>exposition-only</i></ins>
61+
};
62+
}
63+
</pre>
64+
</blockquote>
65+
</p>
66+
<p>
67+
Remove the exposition-only data members
68+
<code><i>result</i></code> and <code><i>errors</i></code> from
69+
the class <code>promise_type</code> in
70+
<sref ref="[task.promise]"/>:
71+
<blockquote>
72+
<pre>
73+
namespace std::execution {
74+
template&lt;class T, class Environment&gt;
75+
class task&lt;T, Environment&gt;::promise_type {
76+
...
77+
stop_token_type <i>token</i>; // <i>exposition only</i>
78+
<del>optional&lt;T&gt; <i>result</i>; // <i>exposition only; present only if</i> is_void_v&lt;T&gt; <i>is</i> false</del>
79+
<del><i>error-variant</i> <i>errors</i>; // <i>exposition only</i></del>
80+
};
81+
}
82+
</pre>
83+
</blockquote>
84+
</p>
85+
<p>
86+
The definition of <code><i>error-variant</i></code> isn't needed, i.e., remove <sref ref="[task.promise]"/> paragraph 2:
87+
<blockquote>
88+
<p><del>
89+
-2- <code><i>error-variant</i></code> is a <code>variant&lt;monostate, remove_cvref_t&lt;E&gt;...&gt;</code>, with duplicate types removed, where <code>E...</code> are template arguments of the specialization of <code>execution::completion_signatures</code> denoted by <code>error_types</code>.
90+
</del></p>
91+
</blockquote>
92+
</p>
93+
<p>
94+
In <sref ref="[task.promise]"/> change paragraph 7 to use the members added to <code><i>state</i></code>:
95+
<blockquote>
96+
<pre>auto final_suspend() noexcept</pre>
97+
<p>-7- <i>Returns</i>: An awaitable object of unspecified type (<sref ref="[expr.await]"/>) whose member functions arrange for the completion of the asynchronous operation associated with <code><i>STATE</i>(*this)</code><del> by invoking</del><ins>. Let <code>st</code> be a reference to <code><i>STATE</i>(*this)</code>. The asynchronous completion first destroys the coroutine frame using <code>st.<i>handle</i>.destroy()</code> and then invokes</ins>:</p>
98+
99+
<ul>
100+
<li>-7.1- <code>set_error(std::move(<del><i>RCVR</i>(*this)</del><ins>st.<i>rcvr</i></ins>), std::move(<del>e</del><ins>st.<i>error</i></ins>))</code> if <del><code><i>errors</i>.index()</code> is greater than zero and <code>e</code> is the value held by <code><i>errors</i></code></del><ins><code>bool(st.<i>error</i>)</code> is <code>true</code></ins>, otherwise</li>
101+
<li>-7.2- <code>set_value(std::move(<del><i>RCVR</i>(*this)</del><ins>st.<i>rcvr</i></ins>))</code> if <code>is_void&lt;T&gt;</code> is <code>true</code>, and otherwise</li>
102+
<li>-7.3- <code>set_value(std::move(<del><i>RCVR</i>(*this)</del><ins>st.<i>rcvr</i></ins>), *<ins>st.</ins><i>result</i>)</code>.</li>
103+
</ul>
104+
</blockquote>
105+
</p>
106+
<p>
107+
Change the specification of <code>yield_value</code> to destroy the coroutine frame before invoking the <code>set_error</code> completion, i.e., change <sref ref="[task.promise]"/> paragraph 9:
108+
<blockquote>
109+
<p>-9- <i>Returns</i>: An awaitable object of unspecified type ([expr.await]) whose member functions arrange for the calling coroutine to be suspended and then completes the asynchronous operation associated with <code><i>STATE</i>(*this)</code><del> by</del><ins>. Let <code>st</code> be a reference to <code><i>STATE</i>(*this)</code>. Then the asynchronous operation completes by first destroying the coroutine frame using <code>st.<i>handle</i>.destroy()</code> and then</ins> invoking <code>set_error(std::move(<del><i>RCVR</i>(*this)</del><ins>st.<i>rcvr</i></ins>), Cerr(std::move(err.error)))</code>.
110+
</p>
111+
</blockquote>
112+
</p>
113+
<p>
114+
Change the specification of <code>unhandled_stopped</code> to destroy the coroutine frame before invoking the <code>set_stopped</code> completion, i.e., change <sref ref="[task.promise]"/> paragraph 13:
115+
<blockquote>
116+
<pre>coroutine_handle&lt;&gt; unhandled_stopped();</pre>
117+
<p>-13- <i>Effects</i>: Completes the asynchronous operation associated with <code><i>STATE</i>(*this)</code><del> by</del><ins>. Let <code>st</code> be a reference to <code><i>STATE</i>(*this)</code>. The asynchronous operation is completed by first destroying the coroutine frame using <code>st.<i>handle</i>.destroy()</code> and then</ins> invoking <code>set_stopped(std::move(<del><i>RCVR</i>(*this)</del><ins>st.<i>rcvr</i></ins>))</code>.</p>
118+
</blockquote>
47119
</p>
48120
</resolution>
49121

0 commit comments

Comments
 (0)