From Jason Turner

[expr.await]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpeeqz164x/{from.md → to.md} +122 -0
tmp/tmpeeqz164x/{from.md → to.md} RENAMED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #### Await <a id="expr.await">[[expr.await]]</a>
2
+
3
+ The `co_await` expression is used to suspend evaluation of a coroutine
4
+ [[dcl.fct.def.coroutine]] while awaiting completion of the computation
5
+ represented by the operand expression.
6
+
7
+ ``` bnf
8
+ await-expression:
9
+ 'co_await' cast-expression
10
+ ```
11
+
12
+ An *await-expression* shall appear only in a potentially-evaluated
13
+ expression within the *compound-statement* of a *function-body* outside
14
+ of a *handler* [[except.pre]]. In a *declaration-statement* or in the
15
+ *simple-declaration* (if any) of a *for-init-statement*, an
16
+ *await-expression* shall appear only in an *initializer* of that
17
+ *declaration-statement* or *simple-declaration*. An *await-expression*
18
+ shall not appear in a default argument [[dcl.fct.default]]. An
19
+ *await-expression* shall not appear in the initializer of a block-scope
20
+ variable with static or thread storage duration. A context within a
21
+ function where an *await-expression* can appear is called a *suspension
22
+ context* of the function.
23
+
24
+ Evaluation of an *await-expression* involves the following auxiliary
25
+ types, expressions, and objects:
26
+
27
+ - *p* is an lvalue naming the promise object [[dcl.fct.def.coroutine]]
28
+ of the enclosing coroutine and `P` is the type of that object.
29
+ - *a* is the *cast-expression* if the *await-expression* was implicitly
30
+ produced by a *yield-expression* [[expr.yield]], an initial suspend
31
+ point, or a final suspend point [[dcl.fct.def.coroutine]]. Otherwise,
32
+ the *unqualified-id* `await_transform` is looked up within the scope
33
+ of `P` by class member access lookup [[basic.lookup.classref]], and if
34
+ this lookup finds at least one declaration, then *a* is
35
+ *p*`.await_transform(`*cast-expression*`)`; otherwise, *a* is the
36
+ *cast-expression*.
37
+ - *o* is determined by enumerating the applicable `operator co_await`
38
+ functions for an argument *a* [[over.match.oper]], and choosing the
39
+ best one through overload resolution [[over.match]]. If overload
40
+ resolution is ambiguous, the program is ill-formed. If no viable
41
+ functions are found, *o* is *a*. Otherwise, *o* is a call to the
42
+ selected function with the argument *a*. If *o* would be a prvalue,
43
+ the temporary materialization conversion [[conv.rval]] is applied.
44
+ - *e* is an lvalue referring to the result of evaluating the
45
+ (possibly-converted) *o*.
46
+ - *h* is an object of type `std::coroutine_handle<P>` referring to the
47
+ enclosing coroutine.
48
+ - *await-ready* is the expression *e*`.await_ready()`, contextually
49
+ converted to `bool`.
50
+ - *await-suspend* is the expression *e*`.await_suspend(`*h*`)`, which
51
+ shall be a prvalue of type `void`, `bool`, or
52
+ `std::coroutine_handle<Z>` for some type `Z`.
53
+ - *await-resume* is the expression *e*`.await_resume()`.
54
+
55
+ The *await-expression* has the same type and value category as the
56
+ *await-resume* expression.
57
+
58
+ The *await-expression* evaluates the (possibly-converted) *o* expression
59
+ and the *await-ready* expression, then:
60
+
61
+ - If the result of *await-ready* is `false`, the coroutine is considered
62
+ suspended. Then:
63
+ - If the type of *await-suspend* is `std::coroutine_handle<Z>`,
64
+ *await-suspend*`.resume()` is evaluated. \[*Note 1*: This resumes
65
+ the coroutine referred to by the result of *await-suspend*. Any
66
+ number of coroutines may be successively resumed in this fashion,
67
+ eventually returning control flow to the current coroutine caller or
68
+ resumer [[dcl.fct.def.coroutine]]. — *end note*]
69
+ - Otherwise, if the type of *await-suspend* is `bool`, *await-suspend*
70
+ is evaluated, and the coroutine is resumed if the result is `false`.
71
+ - Otherwise, *await-suspend* is evaluated.
72
+
73
+ If the evaluation of *await-suspend* exits via an exception, the
74
+ exception is caught, the coroutine is resumed, and the exception is
75
+ immediately re-thrown [[except.throw]]. Otherwise, control flow
76
+ returns to the current coroutine caller or resumer
77
+ [[dcl.fct.def.coroutine]] without exiting any scopes [[stmt.jump]].
78
+ - If the result of *await-ready* is `true`, or when the coroutine is
79
+ resumed, the *await-resume* expression is evaluated, and its result is
80
+ the result of the *await-expression*.
81
+
82
+ [*Example 1*:
83
+
84
+ ``` cpp
85
+ template <typename T>
86
+ struct my_future {
87
+ ...
88
+ bool await_ready();
89
+ void await_suspend(std::coroutine_handle<>);
90
+ T await_resume();
91
+ };
92
+
93
+ template <class Rep, class Period>
94
+ auto operator co_await(std::chrono::duration<Rep, Period> d) {
95
+ struct awaiter {
96
+ std::chrono::system_clock::duration duration;
97
+ ...
98
+ awaiter(std::chrono::system_clock::duration d) : duration(d) {}
99
+ bool await_ready() const { return duration.count() <= 0; }
100
+ void await_resume() {}
101
+ void await_suspend(std::coroutine_handle<> h) { ... }
102
+ };
103
+ return awaiter{d};
104
+ }
105
+
106
+ using namespace std::chrono;
107
+
108
+ my_future<int> h();
109
+
110
+ my_future<void> g() {
111
+ std::cout << "just about go to sleep...\n";
112
+ co_await 10ms;
113
+ std::cout << "resumed\n";
114
+ co_await h();
115
+ }
116
+
117
+ auto f(int x = co_await h()); // error: await-expression outside of function suspension context
118
+ int a[] = { co_await h() }; // error: await-expression outside of function suspension context
119
+ ```
120
+
121
+ — *end example*]
122
+