aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
authorYuxuan Chen <ych@meta.com>2023-11-28 19:04:29 -0800
committerGitHub <noreply@github.com>2023-11-28 19:04:29 -0800
commit4a294b5806417aa88c91aa05735b2d557ea5dfe5 (patch)
tree158bbe34e08c69306dbe8a91e0f4da5f95d36c87 /clang/lib/CodeGen
parent593358937025e8635f75ba8931130b1ca5212ea1 (diff)
downloadllvm-4a294b5806417aa88c91aa05735b2d557ea5dfe5.zip
llvm-4a294b5806417aa88c91aa05735b2d557ea5dfe5.tar.gz
llvm-4a294b5806417aa88c91aa05735b2d557ea5dfe5.tar.bz2
[Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (#73160)
Previously we were not properly skipping the generation of the `try { }` block around the `init_suspend.await_resume()` if the `await_resume` is not returning void. The reason being that the resume expression was wrapped in a `CXXBindTemporaryExpr` and the first dyn_cast failed, silently ignoring the noexcept. This only mattered for `init_suspend` because it had its own try block. This patch changes to first extract the sub expression when we see a `CXXBindTemporaryExpr`. Then perform the same logic to check for `noexcept`. Another version of this patch also wanted to assert the second step by `cast<CXXMemberCallExpr>` and as far as I understand it should be a valid assumption. I can change to that if upstream prefers.
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGCoroutine.cpp52
1 files changed, 43 insertions, 9 deletions
diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp
index aaf122c..888d30b 100644
--- a/clang/lib/CodeGen/CGCoroutine.cpp
+++ b/clang/lib/CodeGen/CGCoroutine.cpp
@@ -129,14 +129,48 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData &Coro, AwaitKind Kind) {
return Prefix;
}
-static bool memberCallExpressionCanThrow(const Expr *E) {
- if (const auto *CE = dyn_cast<CXXMemberCallExpr>(E))
- if (const auto *Proto =
- CE->getMethodDecl()->getType()->getAs<FunctionProtoType>())
- if (isNoexceptExceptionSpec(Proto->getExceptionSpecType()) &&
- Proto->canThrow() == CT_Cannot)
- return false;
- return true;
+// Check if function can throw based on prototype noexcept, also works for
+// destructors which are implicitly noexcept but can be marked noexcept(false).
+static bool FunctionCanThrow(const FunctionDecl *D) {
+ const auto *Proto = D->getType()->getAs<FunctionProtoType>();
+ if (!Proto) {
+ // Function proto is not found, we conservatively assume throwing.
+ return true;
+ }
+ return !isNoexceptExceptionSpec(Proto->getExceptionSpecType()) ||
+ Proto->canThrow() != CT_Cannot;
+}
+
+static bool ResumeStmtCanThrow(const Stmt *S) {
+ if (const auto *CE = dyn_cast<CallExpr>(S)) {
+ const auto *Callee = CE->getDirectCallee();
+ if (!Callee)
+ // We don't have direct callee. Conservatively assume throwing.
+ return true;
+
+ if (FunctionCanThrow(Callee))
+ return true;
+
+ // Fall through to visit the children.
+ }
+
+ if (const auto *TE = dyn_cast<CXXBindTemporaryExpr>(S)) {
+ // Special handling of CXXBindTemporaryExpr here as calling of Dtor of the
+ // temporary is not part of `children()` as covered in the fall through.
+ // We need to mark entire statement as throwing if the destructor of the
+ // temporary throws.
+ const auto *Dtor = TE->getTemporary()->getDestructor();
+ if (FunctionCanThrow(Dtor))
+ return true;
+
+ // Fall through to visit the children.
+ }
+
+ for (const auto *child : S->children())
+ if (ResumeStmtCanThrow(child))
+ return true;
+
+ return false;
}
// Emit suspend expression which roughly looks like:
@@ -233,7 +267,7 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Co
// is marked as 'noexcept', we avoid generating this additional IR.
CXXTryStmt *TryStmt = nullptr;
if (Coro.ExceptionHandler && Kind == AwaitKind::Init &&
- memberCallExpressionCanThrow(S.getResumeExpr())) {
+ ResumeStmtCanThrow(S.getResumeExpr())) {
Coro.ResumeEHVar =
CGF.CreateTempAlloca(Builder.getInt1Ty(), Prefix + Twine("resume.eh"));
Builder.CreateFlagStore(true, Coro.ResumeEHVar);