[clang] [Clang] Coroutines code gen check for member call noexcept nested in a temp expr (PR #73160)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Nov 22 11:27:57 PST 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
Author: Yuxuan Chen (yuxuanchen1997)
<details>
<summary>Changes</summary>
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 that to extract the sub expression when we see a `CXXBindTemporaryExpr`. Another version of this patch also wanted to assert by `cast<CXXMemberCallExpr>` and as far as I understand it should be a valid assumption. I can change to that if upstream prefers.
---
Full diff: https://github.com/llvm/llvm-project/pull/73160.diff
2 Files Affected:
- (modified) clang/lib/CodeGen/CGCoroutine.cpp (+11-3)
- (modified) clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp (+47-3)
``````````diff
diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp
index aaf122c0f83bc47..724d471cc9d78b6 100644
--- a/clang/lib/CodeGen/CGCoroutine.cpp
+++ b/clang/lib/CodeGen/CGCoroutine.cpp
@@ -12,9 +12,10 @@
#include "CGCleanup.h"
#include "CodeGenFunction.h"
-#include "llvm/ADT/ScopeExit.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/ScopeExit.h"
using namespace clang;
using namespace CodeGen;
@@ -129,7 +130,14 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData &Coro, AwaitKind Kind) {
return Prefix;
}
-static bool memberCallExpressionCanThrow(const Expr *E) {
+static bool ResumeExprCanThrow(const CoroutineSuspendExpr &S) {
+ const Expr *E = S.getResumeExpr();
+
+ // If the return type of await_resume is not void, get the CXXMemberCallExpr
+ // from its subexpr.
+ if (const auto *BindTempExpr = dyn_cast<CXXBindTemporaryExpr>(E)) {
+ E = BindTempExpr->getSubExpr();
+ }
if (const auto *CE = dyn_cast<CXXMemberCallExpr>(E))
if (const auto *Proto =
CE->getMethodDecl()->getType()->getAs<FunctionProtoType>())
@@ -233,7 +241,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())) {
+ ResumeExprCanThrow(S)) {
Coro.ResumeEHVar =
CGF.CreateTempAlloca(Builder.getInt1Ty(), Prefix + Twine("resume.eh"));
Builder.CreateFlagStore(true, Coro.ResumeEHVar);
diff --git a/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp b/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp
index c4b8da327f5c140..0e50a616d6ef7c2 100644
--- a/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp
+++ b/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp
@@ -3,6 +3,7 @@
#include "Inputs/coroutine.h"
+namespace can_throw {
struct NontrivialType {
~NontrivialType() {}
};
@@ -38,9 +39,52 @@ Task coro_create() {
co_return;
}
-// CHECK-LABEL: define{{.*}} ptr @_Z11coro_createv(
+// CHECK-LABEL: define{{.*}} ptr @_ZN9can_throw11coro_createEv(
// CHECK: init.ready:
// CHECK-NEXT: store i1 true, ptr {{.*}}
-// CHECK-NEXT: call void @_ZN4Task23initial_suspend_awaiter12await_resumeEv(
-// CHECK-NEXT: call void @_ZN14NontrivialTypeD1Ev(
+// CHECK-NEXT: call void @_ZN9can_throw4Task23initial_suspend_awaiter12await_resumeEv(
+// CHECK-NEXT: call void @_ZN9can_throw14NontrivialTypeD1Ev(
// CHECK-NEXT: store i1 false, ptr {{.*}}
+}
+
+namespace no_throw {
+struct NontrivialType {
+ ~NontrivialType() {}
+};
+
+struct Task {
+ struct promise_type;
+ using handle_type = std::coroutine_handle<promise_type>;
+
+ struct initial_suspend_awaiter {
+ bool await_ready() {
+ return false;
+ }
+
+ void await_suspend(handle_type h) {}
+
+ NontrivialType await_resume() noexcept { return {}; }
+ };
+
+ struct promise_type {
+ void return_void() {}
+ void unhandled_exception() {}
+ initial_suspend_awaiter initial_suspend() { return {}; }
+ std::suspend_never final_suspend() noexcept { return {}; }
+ Task get_return_object() {
+ return Task{handle_type::from_promise(*this)};
+ }
+ };
+
+ handle_type handler;
+};
+
+Task coro_create() {
+ co_return;
+}
+
+// CHECK-LABEL: define{{.*}} ptr @_ZN8no_throw11coro_createEv(
+// CHECK: init.ready:
+// CHECK-NEXT: call void @_ZN8no_throw4Task23initial_suspend_awaiter12await_resumeEv(
+// CHECK-NEXT: call void @_ZN8no_throw14NontrivialTypeD1Ev(
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/73160
More information about the cfe-commits
mailing list