7 Expressions [expr]

7.6 Compound expressions [expr.compound]

7.6.2 Unary expressions [expr.unary]

7.6.2.3 Await [expr.await]

The co_­await expression is used to suspend evaluation of a coroutine ([dcl.fct.def.coroutine]) while awaiting completion of the computation represented by the operand expression.
await-expression:
	co_await cast-expression
An await-expression shall appear only in a potentially-evaluated expression within the compound-statement of a function-body outside of a handler.
In a declaration-statement or in the simple-declaration (if any) of a for-init-statement, an await-expression shall appear only in an initializer of that declaration-statement or simple-declaration.
An await-expression shall not appear in a default argument ([dcl.fct.default]).
An await-expression shall not appear in the initializer of a block-scope variable with static or thread storage duration.
A context within a function where an await-expression can appear is called a suspension context of the function.
Evaluation of an await-expression involves the following auxiliary types, expressions, and objects:
The await-expression has the same type and value category as the await-resume expression.
The await-expression evaluates the (possibly-converted) o expression and the await-ready expression, then:
  • If the result of await-ready is false, the coroutine is considered suspended. Then:
    • If the type of await-suspend is std​::​coroutine_­handle<Z>, await-suspend.resume() is evaluated.
      Note
      : This resumes the coroutine referred to by the result of await-suspend. Any number of coroutines may be successively resumed in this fashion, eventually returning control flow to the current coroutine caller or resumer ([dcl.fct.def.coroutine]). — end note
       ]
    • Otherwise, if the type of await-suspend is bool, await-suspend is evaluated, and the coroutine is resumed if the result is false.
    • Otherwise, await-suspend is evaluated.
    If the evaluation of await-suspend exits via an exception, the exception is caught, the coroutine is resumed, and the exception is immediately re-thrown ([except.throw]). Otherwise, control flow returns to the current coroutine caller or resumer ([dcl.fct.def.coroutine]) without exiting any scopes ([stmt.jump]).
  • If the result of await-ready is true, or when the coroutine is resumed, the await-resume expression is evaluated, and its result is the result of the await-expression.
Example
:
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 go to sleep...\n";
  co_await 10ms;
  std::cout << "resumed\n";
  co_await h();
}

auto f(int x = co_await h());   // error: await-expression outside of function suspension context
int a[] = { co_await h() };     // error: await-expression outside of function suspension context
— end example
 ]