From Jason Turner

[dcl.fct.def.coroutine]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpre5msqlo/{from.md → to.md} +230 -0
tmp/tmpre5msqlo/{from.md → to.md} RENAMED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### Coroutine definitions <a id="dcl.fct.def.coroutine">[[dcl.fct.def.coroutine]]</a>
2
+
3
+ A function is a *coroutine* if its *function-body* encloses a
4
+ *coroutine-return-statement* [[stmt.return.coroutine]], an
5
+ *await-expression* [[expr.await]], or a *yield-expression*
6
+ [[expr.yield]]. The *parameter-declaration-clause* of the coroutine
7
+ shall not terminate with an ellipsis that is not part of a
8
+ *parameter-declaration*.
9
+
10
+ [*Example 1*:
11
+
12
+ ``` cpp
13
+ task<int> f();
14
+
15
+ task<void> g1() {
16
+ int i = co_await f();
17
+ std::cout << "f() => " << i << std::endl;
18
+ }
19
+
20
+ template <typename... Args>
21
+ task<void> g2(Args&&...) { // OK, ellipsis is a pack expansion
22
+ int i = co_await f();
23
+ std::cout << "f() => " << i << std::endl;
24
+ }
25
+
26
+ task<void> g3(int a, ...) { // error: variable parameter list not allowed
27
+ int i = co_await f();
28
+ std::cout << "f() => " << i << std::endl;
29
+ }
30
+ ```
31
+
32
+ — *end example*]
33
+
34
+ The *promise type* of a coroutine is
35
+ `std::coroutine_traits<R, P₁, …, Pₙ>::promise_type`, where `R` is the
36
+ return type of the function, and `P₁` … `Pₙ` are the sequence of types
37
+ of the function parameters, preceded by the type of the implicit object
38
+ parameter [[over.match.funcs]] if the coroutine is a non-static member
39
+ function. The promise type shall be a class type.
40
+
41
+ In the following, `pᵢ` is an lvalue of type `Pᵢ`, where `p₁` denotes
42
+ `*this` and `p_i+1` denotes the $i^\textrm{th}$ function parameter for a
43
+ non-static member function, and `pᵢ` denotes the $i^\textrm{th}$
44
+ function parameter otherwise.
45
+
46
+ A coroutine behaves as if its *function-body* were replaced by:
47
+
48
+ ``` bnf
49
+ '{'
50
+ *promise-type* promise *promise-constructor-arguments* ';'
51
+ % FIXME: promise'.get_return_object()' ';'
52
+ % ... except that it's not a discarded-value expression
53
+ 'try' '{'
54
+ 'co_await' 'promise.initial_suspend()' ';'
55
+ function-body
56
+ '} catch ( ... ) {'
57
+ 'if (!initial-await-resume-called)'
58
+ 'throw' ';'
59
+ 'promise.unhandled_exception()' ';'
60
+ '}'
61
+ final-suspend ':'
62
+ 'co_await' 'promise.final_suspend()' ';'
63
+ '}'
64
+ ```
65
+
66
+ where
67
+
68
+ - the *await-expression* containing the call to `initial_suspend` is the
69
+ *initial suspend point*, and
70
+ - the *await-expression* containing the call to `final_suspend` is the
71
+ *final suspend point*, and
72
+ - *initial-await-resume-called* is initially `false` and is set to
73
+ `true` immediately before the evaluation of the *await-resume*
74
+ expression [[expr.await]] of the initial suspend point, and
75
+ - *promise-type* denotes the promise type, and
76
+ - the object denoted by the exposition-only name *`promise`* is the
77
+ *promise object* of the coroutine, and
78
+ - the label denoted by the name *`final-suspend`* is defined for
79
+ exposition only [[stmt.return.coroutine]], and
80
+ - *promise-constructor-arguments* is determined as follows: overload
81
+ resolution is performed on a promise constructor call created by
82
+ assembling an argument list with lvalues `p₁` … `pₙ`. If a viable
83
+ constructor is found [[over.match.viable]], then
84
+ *promise-constructor-arguments* is `(p₁, …, pₙ)`, otherwise
85
+ *promise-constructor-arguments* is empty.
86
+
87
+ The *unqualified-id*s `return_void` and `return_value` are looked up in
88
+ the scope of the promise type. If both are found, the program is
89
+ ill-formed.
90
+
91
+ [*Note 1*: If the *unqualified-id* `return_void` is found, flowing off
92
+ the end of a coroutine is equivalent to a `co_return` with no operand.
93
+ Otherwise, flowing off the end of a coroutine results in undefined
94
+ behavior [[stmt.return.coroutine]]. — *end note*]
95
+
96
+ The expression `promise.get_return_object()` is used to initialize the
97
+ glvalue result or prvalue result object of a call to a coroutine. The
98
+ call to `get_return_object` is sequenced before the call to
99
+ `initial_suspend` and is invoked at most once.
100
+
101
+ A suspended coroutine can be resumed to continue execution by invoking a
102
+ resumption member function [[coroutine.handle.resumption]] of a
103
+ coroutine handle [[coroutine.handle]] that refers to the coroutine. The
104
+ function that invoked a resumption member function is called the
105
+ *resumer*. Invoking a resumption member function for a coroutine that is
106
+ not suspended results in undefined behavior.
107
+
108
+ An implementation may need to allocate additional storage for a
109
+ coroutine. This storage is known as the *coroutine state* and is
110
+ obtained by calling a non-array allocation function
111
+ [[basic.stc.dynamic.allocation]]. The allocation function’s name is
112
+ looked up in the scope of the promise type. If this lookup fails, the
113
+ allocation function’s name is looked up in the global scope. If the
114
+ lookup finds an allocation function in the scope of the promise type,
115
+ overload resolution is performed on a function call created by
116
+ assembling an argument list. The first argument is the amount of space
117
+ requested, and has type `std::size_t`. The lvalues `p₁` … `pₙ` are the
118
+ succeeding arguments. If no viable function is found
119
+ [[over.match.viable]], overload resolution is performed again on a
120
+ function call created by passing just the amount of space required as an
121
+ argument of type `std::size_t`.
122
+
123
+ The *unqualified-id* `get_return_object_on_allocation_failure` is looked
124
+ up in the scope of the promise type by class member access lookup
125
+ [[basic.lookup.classref]]. If any declarations are found, then the
126
+ result of a call to an allocation function used to obtain storage for
127
+ the coroutine state is assumed to return `nullptr` if it fails to obtain
128
+ storage, and if a global allocation function is selected, the
129
+ `::operator new(size_t, nothrow_t)` form is used. The allocation
130
+ function used in this case shall have a non-throwing
131
+ *noexcept-specification*. If the allocation function returns `nullptr`,
132
+ the coroutine returns control to the caller of the coroutine and the
133
+ return value is obtained by a call to
134
+ `T::get_return_object_on_allocation_failure()`, where `T` is the promise
135
+ type.
136
+
137
+ [*Example 2*:
138
+
139
+ ``` cpp
140
+ #include <iostream>
141
+ #include <coroutine>
142
+
143
+ // ::operator new(size_t, nothrow_t) will be used if allocation is needed
144
+ struct generator {
145
+ struct promise_type;
146
+ using handle = std::coroutine_handle<promise_type>;
147
+ struct promise_type {
148
+ int current_value;
149
+ static auto get_return_object_on_allocation_failure() { return generator{nullptr}; }
150
+ auto get_return_object() { return generator{handle::from_promise(*this)}; }
151
+ auto initial_suspend() { return std::suspend_always{}; }
152
+ auto final_suspend() { return std::suspend_always{}; }
153
+ void unhandled_exception() { std::terminate(); }
154
+ void return_void() {}
155
+ auto yield_value(int value) {
156
+ current_value = value;
157
+ return std::suspend_always{};
158
+ }
159
+ };
160
+ bool move_next() { return coro ? (coro.resume(), !coro.done()) : false; }
161
+ int current_value() { return coro.promise().current_value; }
162
+ generator(generator const&) = delete;
163
+ generator(generator && rhs) : coro(rhs.coro) { rhs.coro = nullptr; }
164
+ ~generator() { if (coro) coro.destroy(); }
165
+ private:
166
+ generator(handle h) : coro(h) {}
167
+ handle coro;
168
+ };
169
+ generator f() { co_yield 1; co_yield 2; }
170
+ int main() {
171
+ auto g = f();
172
+ while (g.move_next()) std::cout << g.current_value() << std::endl;
173
+ }
174
+ ```
175
+
176
+ — *end example*]
177
+
178
+ The coroutine state is destroyed when control flows off the end of the
179
+ coroutine or the `destroy` member function
180
+ [[coroutine.handle.resumption]] of a coroutine handle
181
+ [[coroutine.handle]] that refers to the coroutine is invoked. In the
182
+ latter case objects with automatic storage duration that are in scope at
183
+ the suspend point are destroyed in the reverse order of the
184
+ construction. The storage for the coroutine state is released by calling
185
+ a non-array deallocation function [[basic.stc.dynamic.deallocation]]. If
186
+ `destroy` is called for a coroutine that is not suspended, the program
187
+ has undefined behavior.
188
+
189
+ The deallocation function’s name is looked up in the scope of the
190
+ promise type. If this lookup fails, the deallocation function’s name is
191
+ looked up in the global scope. If deallocation function lookup finds
192
+ both a usual deallocation function with only a pointer parameter and a
193
+ usual deallocation function with both a pointer parameter and a size
194
+ parameter, then the selected deallocation function shall be the one with
195
+ two parameters. Otherwise, the selected deallocation function shall be
196
+ the function with one parameter. If no usual deallocation function is
197
+ found, the program is ill-formed. The selected deallocation function
198
+ shall be called with the address of the block of storage to be reclaimed
199
+ as its first argument. If a deallocation function with a parameter of
200
+ type `std::size_t` is used, the size of the block is passed as the
201
+ corresponding argument.
202
+
203
+ When a coroutine is invoked, after initializing its parameters
204
+ [[expr.call]], a copy is created for each coroutine parameter. For a
205
+ parameter of type cv `T`, the copy is a variable of type cv `T` with
206
+ automatic storage duration that is direct-initialized from an xvalue of
207
+ type `T` referring to the parameter.
208
+
209
+ [*Note 2*: An original parameter object is never a const or volatile
210
+ object [[basic.type.qualifier]]. — *end note*]
211
+
212
+ The initialization and destruction of each parameter copy occurs in the
213
+ context of the called coroutine. Initializations of parameter copies are
214
+ sequenced before the call to the coroutine promise constructor and
215
+ indeterminately sequenced with respect to each other. The lifetime of
216
+ parameter copies ends immediately after the lifetime of the coroutine
217
+ promise object ends.
218
+
219
+ [*Note 3*: If a coroutine has a parameter passed by reference, resuming
220
+ the coroutine after the lifetime of the entity referred to by that
221
+ parameter has ended is likely to result in undefined
222
+ behavior. — *end note*]
223
+
224
+ If the evaluation of the expression `promise.unhandled_exception()`
225
+ exits via an exception, the coroutine is considered suspended at the
226
+ final suspend point.
227
+
228
+ The expression `co_await` `promise.final_suspend()` shall not be
229
+ potentially-throwing [[except.spec]].
230
+