[libcxx-commits] [clang] [libcxx] Elide suspension points via [[clang::coro_await_suspend_destroy]] (PR #152623)
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Aug 19 23:05:07 PDT 2025
================
@@ -401,36 +432,85 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
return Calls;
}
Expr *CoroHandle = CoroHandleRes.get();
+ Calls.UseAwaitSuspendDestroy = false;
CallExpr *AwaitSuspend = cast_or_null<CallExpr>(
BuildSubExpr(ACT::ACT_Suspend, "await_suspend", CoroHandle));
if (!AwaitSuspend)
return Calls;
+
+ // When this `await_suspend()` overload is annotated with
+ // `[[clang::coro_await_suspend_destroy]]`, do NOT call `await_suspend()` --
+ // instead call `await_suspend_destroy(Promise&)`. This assumes that the
+ // `await_suspend()` is just a compatibility stub consisting of:
+ // await_suspend_destroy(handle.promise());
+ // handle.destroy();
+ // Users of the attribute must follow this contract. Then, diagnostics from
+ // both `await_suspend` and `await_suspend_destroy` will get exposed.
+ CallExpr *PlainAwaitSuspend = nullptr;
+ if (FunctionDecl *AwaitSuspendCallee = AwaitSuspend->getDirectCallee()) {
+ if (AwaitSuspendCallee->hasAttr<CoroAwaitSuspendDestroyAttr>()) {
+ Calls.UseAwaitSuspendDestroy = true;
+ ExprResult PromiseRefRes =
+ buildPromiseRef(S, CoroPromise->getType(), Loc);
+ if (PromiseRefRes.isInvalid()) {
+ Calls.IsInvalid = true;
+ return Calls;
+ }
+ Expr *PromiseRef = PromiseRefRes.get();
+ PlainAwaitSuspend = AwaitSuspend;
+ AwaitSuspend = cast_or_null<CallExpr>(
+ BuildSubExpr(ACT::ACT_Suspend, "await_suspend_destroy", PromiseRef));
+ if (!AwaitSuspend)
+ return Calls;
+ }
+ }
----------------
snarkmaster wrote:
Do you have a pointer for the best way to do overload resolution so I can test for whether the attribute is present, without constructing the AST for the handle or for the call?
https://github.com/llvm/llvm-project/pull/152623
More information about the libcxx-commits
mailing list