189 lines
9.9 KiB
Markdown
189 lines
9.9 KiB
Markdown
[expr.await]
|
||
|
||
# 7 Expressions [[expr]](./#expr)
|
||
|
||
## 7.6 Compound expressions [[expr.compound]](expr.compound#expr.await)
|
||
|
||
### 7.6.2 Unary expressions [[expr.unary]](expr.unary#expr.await)
|
||
|
||
#### 7.6.2.4 Await [expr.await]
|
||
|
||
[1](#1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5411)
|
||
|
||
The co_await expression is used to suspend evaluation of a
|
||
coroutine ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions")) while awaiting completion of
|
||
the computation represented by the operand expression[.](#1.sentence-1)
|
||
|
||
Suspending the evaluation of a coroutine
|
||
transfers control to its caller or resumer[.](#1.sentence-2)
|
||
|
||
[await-expression:](#nt:await-expression "7.6.2.4 Await [expr.await]")
|
||
co_await [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]")
|
||
|
||
[2](#2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5423)
|
||
|
||
An [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") shall appear only as a potentially-evaluated
|
||
expression within the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of a[*function-body*](dcl.fct.def.general#nt:function-body "9.6.1 General [dcl.fct.def.general]") or [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]"),
|
||
in either case
|
||
outside of a [*handler*](except.pre#nt:handler "14.1 Preamble [except.pre]") ([[except.pre]](except.pre "14.1 Preamble"))[.](#2.sentence-1)
|
||
|
||
In a [*declaration-statement*](stmt.dcl#nt:declaration-statement "8.10 Declaration statement [stmt.dcl]") or in the[*simple-declaration*](dcl.pre#nt:simple-declaration "9.1 Preamble [dcl.pre]") (if any)
|
||
of an [*init-statement*](stmt.pre#nt:init-statement "8.1 Preamble [stmt.pre]"), an [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") shall appear only in an [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") of that[*declaration-statement*](stmt.dcl#nt:declaration-statement "8.10 Declaration statement [stmt.dcl]") or [*simple-declaration*](dcl.pre#nt:simple-declaration "9.1 Preamble [dcl.pre]")[.](#2.sentence-2)
|
||
|
||
An [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") shall not appear in a
|
||
default argument ([[dcl.fct.default]](dcl.fct.default "9.3.4.7 Default arguments"))[.](#2.sentence-3)
|
||
|
||
An [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") shall not appear in the initializer of
|
||
a block variable with static or thread storage duration[.](#2.sentence-4)
|
||
|
||
An [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") shall not be
|
||
a potentially-evaluated subexpression
|
||
of the predicate of a contract assertion ([[basic.contract]](basic.contract "6.11 Contract assertions"))[.](#2.sentence-5)
|
||
|
||
A context within a function where an [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") can appear
|
||
is called a [*suspension context*](#def:suspension_context) of the function[.](#2.sentence-6)
|
||
|
||
[3](#3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5444)
|
||
|
||
Evaluation of an [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") involves the following
|
||
auxiliary types, expressions, and objects:
|
||
|
||
- [(3.1)](#3.1)
|
||
|
||
*p* is an lvalue naming the promise
|
||
object ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions"))
|
||
of the enclosing coroutine and P is the type of that object[.](#3.1.sentence-1)
|
||
|
||
- [(3.2)](#3.2)
|
||
|
||
Unless
|
||
the [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") was implicitly produced by
|
||
a [*yield-expression*](expr.yield#nt:yield-expression "7.6.17 Yielding a value [expr.yield]") ([[expr.yield]](expr.yield "7.6.17 Yielding a value")),
|
||
an initial await expression,
|
||
or a final await expression ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions")),
|
||
a search is performed for the name await_transform in the scope of P ([[class.member.lookup]](class.member.lookup "6.5.2 Member name lookup"))[.](#3.2.sentence-1)
|
||
If this search is performed and finds at least one declaration,
|
||
then *a* is*p*.await_transform([*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]"));
|
||
otherwise, *a* is the [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]")[.](#3.2.sentence-2)
|
||
|
||
- [(3.3)](#3.3)
|
||
|
||
*o* is determined by enumerating the applicableoperator co_await functions for an argument*a* ([[over.match.oper]](over.match.oper "12.2.2.3 Operators in expressions")), and choosing the best one through
|
||
overload resolution ([[over.match]](over.match "12.2 Overload resolution"))[.](#3.3.sentence-1)
|
||
If overload resolution is ambiguous,
|
||
the program is ill-formed[.](#3.3.sentence-2)
|
||
If no viable functions are found, *o* is *a*[.](#3.3.sentence-3)
|
||
Otherwise, *o* is a call to the selected function
|
||
with the argument *a*[.](#3.3.sentence-4)
|
||
If *o* would be a prvalue,
|
||
the temporary materialization conversion ([[conv.rval]](conv.rval "7.3.5 Temporary materialization conversion")) is applied[.](#3.3.sentence-5)
|
||
|
||
- [(3.4)](#3.4)
|
||
|
||
*e* is an lvalue
|
||
referring to the result of evaluating
|
||
the (possibly-converted) *o*[.](#3.4.sentence-1)
|
||
|
||
- [(3.5)](#3.5)
|
||
|
||
*h* is an object of typestd::coroutine_handle<P> referring to the enclosing coroutine[.](#3.5.sentence-1)
|
||
|
||
- [(3.6)](#3.6)
|
||
|
||
*await-ready* is the expression*e*.await_ready(),
|
||
contextually converted to bool[.](#3.6.sentence-1)
|
||
|
||
- [(3.7)](#3.7)
|
||
|
||
*await-suspend* is the expression*e*.await_suspend(*h*),
|
||
which shall be a prvalue of type void, bool, orstd::coroutine_handle<Z> for some type Z[.](#3.7.sentence-1)
|
||
|
||
- [(3.8)](#3.8)
|
||
|
||
*await-resume* is the expression*e*.await_resume()[.](#3.8.sentence-1)
|
||
|
||
[4](#4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5507)
|
||
|
||
The [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") has the same type and value category
|
||
as the *await-resume* expression[.](#4.sentence-1)
|
||
|
||
[5](#5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5511)
|
||
|
||
The [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") evaluates
|
||
the (possibly-converted) *o* expression and
|
||
the *await-ready* expression, then:
|
||
|
||
- [(5.1)](#5.1)
|
||
|
||
If the result of *await-ready* is false,
|
||
the coroutine is considered suspended[.](#5.1.sentence-1)
|
||
Then:
|
||
* [(5.1.1)](#5.1.1)
|
||
|
||
If the type of *await-suspend* is std::coroutine_handle<Z>,*await-suspend*.resume() is evaluated[.](#5.1.1.sentence-1)
|
||
[*Note [1](#note-1)*:
|
||
This resumes the coroutine referred to
|
||
by the result of *await-suspend*[.](#5.1.1.sentence-2)
|
||
Any number of coroutines can be successively resumed in this fashion,
|
||
eventually returning control flow to the current coroutine caller or
|
||
resumer ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions"))[.](#5.1.1.sentence-3)
|
||
â *end note*]
|
||
|
||
* [(5.1.2)](#5.1.2)
|
||
|
||
Otherwise, if the type of *await-suspend* is bool,*await-suspend* is evaluated,
|
||
and the coroutine is resumed if the result is false[.](#5.1.2.sentence-1)
|
||
|
||
* [(5.1.3)](#5.1.3)
|
||
|
||
Otherwise, *await-suspend* is evaluated[.](#5.1.3.sentence-1)
|
||
|
||
If the evaluation of *await-suspend* exits via an exception, the exception is caught,
|
||
the coroutine is resumed, and the exception is immediately
|
||
rethrown ([[except.throw]](except.throw "14.2 Throwing an exception"))[.](#5.1.sentence-3)
|
||
Otherwise, control flow returns
|
||
to the current coroutine caller or resumer ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions"))
|
||
without exiting any scopes ([[stmt.jump]](stmt.jump "8.8 Jump statements"))[.](#5.1.sentence-4)
|
||
The point in the coroutine
|
||
immediately prior to control returning to its caller or resumer
|
||
is a coroutine [*suspend point*](#def:suspend_point "7.6.2.4 Await [expr.await]")[.](#5.1.sentence-5)
|
||
|
||
- [(5.2)](#5.2)
|
||
|
||
If the result of *await-ready* is true,
|
||
or when the coroutine is resumed
|
||
other than by rethrowing an exception from *await-suspend*,
|
||
the *await-resume* expression is evaluated, and
|
||
its result is the result of the [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]")[.](#5.2.sentence-1)
|
||
|
||
[*Note [2](#note-2)*:
|
||
|
||
With respect to sequencing,
|
||
an [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") is indivisible ([[intro.execution]](intro.execution "6.10.1 Sequential execution"))[.](#5.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[6](#6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L5565)
|
||
|
||
[*Example [1](#example-1)*: template <typename T>struct my_future {/* ... */bool await_ready(); void await_suspend(std::coroutine_handle<>);
|
||
T await_resume();};
|
||
|
||
template <class Rep, class Period>auto operator co_await(std::chrono::duration<Rep, Period> d) {struct awaiter { std::chrono::system_clock::duration duration; /* ... */ awaiter(std::chrono::system_clock::duration d) : duration(d) {}bool await_ready() const { return duration.count() <= 0; }void await_resume() {}void await_suspend(std::coroutine_handle<> h) { /* ... */ }}; return awaiter{d};}using namespace std::chrono;
|
||
|
||
my_future<int> h();
|
||
|
||
my_future<void> g() { std::cout << "just about to go to sleep...\n"; co_await 10ms;
|
||
std::cout << "resumed\n"; co_await h();}auto f(int x = co_await h()); // error: [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") outside of function suspension contextint a[] = { co_await h() }; // error: [*await-expression*](#nt:await-expression "7.6.2.4 Await [expr.await]") outside of function suspension context â *end example*]
|