aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorChuanqi Xu <yedeng.yd@linux.alibaba.com>2023-08-29 14:19:11 +0800
committerChuanqi Xu <yedeng.yd@linux.alibaba.com>2023-08-29 14:35:27 +0800
commit20e6515d5c5ff155a54e10f64caef1c76d8d5976 (patch)
tree0a1fade486f37efb5b5c24f3ba686e936e78b01b /clang/lib
parentbbf0733030ae16a1ef19c2a031f805a971e941d2 (diff)
downloadllvm-20e6515d5c5ff155a54e10f64caef1c76d8d5976.zip
llvm-20e6515d5c5ff155a54e10f64caef1c76d8d5976.tar.gz
llvm-20e6515d5c5ff155a54e10f64caef1c76d8d5976.tar.bz2
[Coroutines] Mark 'coroutine_handle<>::address' as always-inline
Close https://github.com/llvm/llvm-project/issues/65054 The direct issue is still the call to coroutine_handle<>::address() after await_suspend(). Without optimizations, the current logic will put the temporary result of await_suspend() to the coroutine frame since the middle end feel the temporary is escaped from coroutine_handle<>::address. To fix this fundamentally, we should wrap the whole logic about await-suspend into a standalone function. See https://github.com/llvm/llvm-project/issues/64945 And as a short-term workaround, we probably can mark coroutine_handle<>::address() as always-inline so that the temporary result may not be thought to be escaped then it won't be put on the coroutine frame. Although it looks dirty, it is probably do-able since the compiler are allowed to do special tricks to standard library components.
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/SemaCoroutine.cpp22
1 files changed, 22 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index 0b29873..42e4283 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -344,6 +344,28 @@ static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E,
Expr *JustAddress = AddressExpr.get();
+ // FIXME: Without optimizations, the temporary result from `await_suspend()`
+ // may be put on the coroutine frame since the coroutine frame constructor
+ // will think the temporary variable will escape from the
+ // `coroutine_handle<>::address()` call. This is problematic since the
+ // coroutine should be considered to be suspended after it enters
+ // `await_suspend` so it shouldn't access/update the coroutine frame after
+ // that.
+ //
+ // See https://github.com/llvm/llvm-project/issues/65054 for the report.
+ //
+ // The long term solution may wrap the whole logic about `await-suspend`
+ // into a standalone function. This is similar to the proposed solution
+ // in tryMarkAwaitSuspendNoInline. See the comments there for details.
+ //
+ // The short term solution here is to mark `coroutine_handle<>::address()`
+ // function as always-inline so that the coroutine frame constructor won't
+ // think the temporary result is escaped incorrectly.
+ if (auto *FD = cast<CallExpr>(JustAddress)->getDirectCallee())
+ if (!FD->hasAttr<AlwaysInlineAttr>() && !FD->hasAttr<NoInlineAttr>())
+ FD->addAttr(AlwaysInlineAttr::CreateImplicit(S.getASTContext(),
+ FD->getLocation()));
+
// Check that the type of AddressExpr is void*
if (!JustAddress->getType().getTypePtr()->isVoidPointerType())
S.Diag(cast<CallExpr>(JustAddress)->getCalleeDecl()->getLocation(),