================ @@ -9270,6 +9270,93 @@ Example: }]; } +def CoroAwaitSuspendDestroyDoc : Documentation { + let Category = DocCatDecl; + let Content = [{ + +The ``[[clang::coro_await_suspend_destroy]]`` attribute may be applied to a C++ +coroutine awaiter type. When this attribute is present, the awaiter must +implement ``void await_suspend_destroy(Promise&)``. If ``await_ready()`` +returns ``false`` at a suspension point, ``await_suspend_destroy`` will be +called directly, bypassing the ``await_suspend(std::coroutine_handle<...>)`` +method. The coroutine being suspended will then be immediately destroyed. + +Logically, the new behavior is equivalent to this standard code: + +.. code-block:: c++ + + void await_suspend_destroy(YourPromise&) { ... } + void await_suspend(auto handle) { + await_suspend_destroy(handle.promise()); + handle.destroy(); + } + +This enables `await_suspend_destroy()` usage in portable awaiters — just add a +stub ``await_suspend()`` as above. Without ``coro_await_suspend_destroy`` +support, the awaiter will behave nearly identically, with the only difference +being heap allocation instead of stack allocation for the coroutine frame. + +This attribute exists to optimize short-circuiting coroutines—coroutines whose +suspend points are either (i) trivial (like ``std::suspend_never``), or (ii) +short-circuiting (like a ``co_await`` that can be expressed in regular control +flow as): + +.. code-block:: c++ + + T val; + if (awaiter.await_ready()) { + val = awaiter.await_resume(); + } else { + awaiter.await_suspend(); + return /* value representing the "execution short-circuited" outcome */; + } + +The benefits of this attribute are: + - **Avoid heap allocations for coro frames**: Allocating short-circuiting ---------------- snarkmaster wrote:
I understand the mechanism to be this: - If all `co_await` / `co_yield` awaiters use `await_suspend_destroy()`, that leaves the coro with just 2 suspend points: initial & final. - If those suspend points have `await_ready() { return true; }` like `suspend_never`, the remaining two suspends get cut out somewhere in the middle end. - At that point, there are no suspend intrinsics left for the escape analysis, and heap elision kicks in. If we were able to elide `suspend_never` earlier, I suspect that short-circuiting coros could optimize even more like plain functions. Can you please clarify how you'd like me to edit this portion of the **docs**? My reasoning seems a bit too low-level to be user-relevant. I feel like if a user cares about allocs, they would just look at the generated code for their application... https://github.com/llvm/llvm-project/pull/152623 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits