@@ -8258,15 +8258,23 @@ but do not pass them to the underlying coroutine or pass them by value.
82588258def CoroAwaitElidableDoc : Documentation {
82598259 let Category = DocCatDecl;
82608260 let Content = [{
8261- The ``[[clang::coro_await_elidable]]`` is a class attribute which can be applied
8262- to a coroutine return type.
8261+ The ``[[clang::coro_await_elidable]]`` is a class attribute which can be
8262+ applied to a coroutine return type. It provides a hint to the compiler to apply
8263+ Heap Allocation Elision more aggressively.
82638264
8264- When a coroutine function that returns such a type calls another coroutine function,
8265- the compiler performs heap allocation elision when the call to the coroutine function
8266- is immediately co_awaited as a prvalue. In this case, the coroutine frame for the
8267- callee will be a local variable within the enclosing braces in the caller's stack
8268- frame. And the local variable, like other variables in coroutines, may be collected
8269- into the coroutine frame, which may be allocated on the heap.
8265+ When a coroutine function returns such a type, a direct call expression therein
8266+ that returns a prvalue of a type attributed ``[[clang::coro_await_elidable]]``
8267+ is said to be under a safe elide context if one of the following is true:
8268+ - it is the immediate right-hand side operand to a co_await expression.
8269+ - it is an argument to a ``[[clang::coro_await_elidable_argument]]`` parameter
8270+ or parameter pack of another direct call expression under a safe elide context.
8271+
8272+ Do note that the safe elide context applies only to the call expression itself,
8273+ and the context does not transitively include any of its subexpressions unless
8274+ exceptional rules of ``[[clang::coro_await_elidable_argument]]`` apply.
8275+
8276+ The compiler performs heap allocation elision on call expressions under a safe
8277+ elide context, if the callee is a coroutine.
82708278
82718279Example:
82728280
@@ -8281,8 +8289,63 @@ Example:
82818289 co_await t;
82828290 }
82838291
8284- The behavior is undefined if the caller coroutine is destroyed earlier than the
8285- callee coroutine.
8292+ Such elision replaces the heap allocated activation frame of the callee coroutine
8293+ with a local variable within the enclosing braces in the caller's stack frame.
8294+ The local variable, like other variables in coroutines, may be collected into the
8295+ coroutine frame, which may be allocated on the heap. The behavior is undefined
8296+ if the caller coroutine is destroyed earlier than the callee coroutine.
8297+
8298+ }];
8299+ }
8300+
8301+ def CoroAwaitElidableArgumentDoc : Documentation {
8302+ let Category = DocCatDecl;
8303+ let Content = [{
8304+
8305+ The ``[[clang::coro_await_elidable_argument]]`` is a function parameter attribute.
8306+ It works in conjunction with ``[[clang::coro_await_elidable]]`` to propagate a
8307+ safe elide context to a parameter or parameter pack if the function is called
8308+ under a safe elide context.
8309+
8310+ This is sometimes necessary on utility functions used to compose or modify the
8311+ behavior of a callee coroutine.
8312+
8313+ Example:
8314+
8315+ .. code-block:: c++
8316+
8317+ template <typename T>
8318+ class [[clang::coro_await_elidable]] Task { ... };
8319+
8320+ template <typename... T>
8321+ class [[clang::coro_await_elidable]] WhenAll { ... };
8322+
8323+ // `when_all` is a utility function that composes coroutines. It does not
8324+ // need to be a coroutine to propagate.
8325+ template <typename... T>
8326+ WhenAll<T...> when_all([[clang::coro_await_elidable_argument]] Task<T> tasks...);
8327+
8328+ Task<int> foo();
8329+ Task<int> bar();
8330+ Task<void> example1() {
8331+ // `when_all``, `foo``, and `bar` are all elide safe because `when_all` is
8332+ // under a safe elide context and, thanks to the [[clang::coro_await_elidable_argument]]
8333+ // attribute, such context is propagated to foo and bar.
8334+ co_await when_all(foo(), bar());
8335+ }
8336+
8337+ Task<void> example2() {
8338+ // `when_all` and `bar` are elide safe. `foo` is not elide safe.
8339+ auto f = foo();
8340+ co_await when_all(f, bar());
8341+ }
8342+
8343+
8344+ Task<void> example3() {
8345+ // None of the calls are elide safe.
8346+ auto t = when_all(foo(), bar());
8347+ co_await t;
8348+ }
82868349
82878350}];
82888351}
0 commit comments