[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-28 Thread Chuanqi Xu via cfe-commits


@@ -129,14 +129,48 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData 
, AwaitKind Kind) {
   return Prefix;
 }
 
-static bool memberCallExpressionCanThrow(const Expr *E) {
-  if (const auto *CE = dyn_cast(E))
-if (const auto *Proto =
-CE->getMethodDecl()->getType()->getAs())
-  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();
+  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(S)) {
+const auto *Callee = CE->getDirectCallee();
+if (!Callee)
+  // We don't have direct callee. Conservatively assume throwing.
+  return true;
+
+if (FunctionCanThrow(Callee))
+  return true;

ChuanqiXu9 wrote:

Please don't land it when you have different opinions.

It should be safe to return false directly if we know the function is nothrow. 
Then it may be slightly more efficient.

https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-28 Thread Yuxuan Chen via cfe-commits

https://github.com/yuxuanchen1997 closed 
https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-28 Thread Yuxuan Chen via cfe-commits


@@ -129,14 +129,48 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData 
, AwaitKind Kind) {
   return Prefix;
 }
 
-static bool memberCallExpressionCanThrow(const Expr *E) {
-  if (const auto *CE = dyn_cast(E))
-if (const auto *Proto =
-CE->getMethodDecl()->getType()->getAs())
-  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();
+  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(S)) {
+const auto *Callee = CE->getDirectCallee();
+if (!Callee)
+  // We don't have direct callee. Conservatively assume throwing.
+  return true;
+
+if (FunctionCanThrow(Callee))
+  return true;

yuxuanchen1997 wrote:

The logic doesn't go this way. 

If a function can throw, the task of this (conservative) analysis is to return 
true and nothing else needs to be done. Otherwise, fall through and recursively 
visit all children, which may include Stmts that throw. 

https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-28 Thread Chuanqi Xu via cfe-commits


@@ -129,14 +129,48 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData 
, AwaitKind Kind) {
   return Prefix;
 }
 
-static bool memberCallExpressionCanThrow(const Expr *E) {
-  if (const auto *CE = dyn_cast(E))
-if (const auto *Proto =
-CE->getMethodDecl()->getType()->getAs())
-  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();
+  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(S)) {
+const auto *Callee = CE->getDirectCallee();
+if (!Callee)
+  // We don't have direct callee. Conservatively assume throwing.
+  return true;
+
+if (FunctionCanThrow(Callee))
+  return true;

ChuanqiXu9 wrote:

```suggestion
if (!FunctionCanThrow(Callee))
  return false;
```

nit: This reads better. In case we know the called function is nothrow, we 
don't need to check it further recursively especially await_resume doesn't have 
arguments except `this`.

https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-28 Thread Chuanqi Xu via cfe-commits

https://github.com/ChuanqiXu9 approved this pull request.

LGTM with nit.

https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-28 Thread Chuanqi Xu via cfe-commits

https://github.com/ChuanqiXu9 edited 
https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-28 Thread Yuxuan Chen via cfe-commits

https://github.com/yuxuanchen1997 updated 
https://github.com/llvm/llvm-project/pull/73160

>From dbd06bc001c0e00436fcacac231d9d80b443edf4 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen 
Date: Tue, 21 Nov 2023 21:38:12 -0800
Subject: [PATCH 1/3] add checks for nested noexcept in cxxtempexpr

---
 clang/lib/CodeGen/CGCoroutine.cpp | 28 ++--
 .../coro-init-await-nontrivial-return.cpp | 66 ++-
 2 files changed, 88 insertions(+), 6 deletions(-)

diff --git a/clang/lib/CodeGen/CGCoroutine.cpp 
b/clang/lib/CodeGen/CGCoroutine.cpp
index aaf122c0f83bc47..37ac5bca38c7049 100644
--- a/clang/lib/CodeGen/CGCoroutine.cpp
+++ b/clang/lib/CodeGen/CGCoroutine.cpp
@@ -129,12 +129,32 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData 
, AwaitKind Kind) {
   return Prefix;
 }
 
-static bool memberCallExpressionCanThrow(const Expr *E) {
+static bool FunctionProtoNoexcept(const FunctionProtoType *Proto) {
+  return isNoexceptExceptionSpec(Proto->getExceptionSpecType()) &&
+ Proto->canThrow() == CT_Cannot;
+}
+
+static bool ResumeExprCanThrow(const CoroutineSuspendExpr ) {
+  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(E)) {
+auto *Temporary = BindTempExpr->getTemporary();
+const auto *DtorProto = Temporary->getDestructor()
+->getCanonicalDecl()
+->getType()
+->getAs();
+bool DtorCanThrow = !FunctionProtoNoexcept(DtorProto);
+if (DtorCanThrow) {
+  return true;
+}
+E = BindTempExpr->getSubExpr();
+  }
   if (const auto *CE = dyn_cast(E))
 if (const auto *Proto =
 CE->getMethodDecl()->getType()->getAs())
-  if (isNoexceptExceptionSpec(Proto->getExceptionSpecType()) &&
-  Proto->canThrow() == CT_Cannot)
+  if (FunctionProtoNoexcept(Proto))
 return false;
   return true;
 }
@@ -233,7 +253,7 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction 
, CGCoroData 
   // 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..052b4e235e739fe 100644
--- a/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp
+++ b/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp
@@ -7,6 +7,11 @@ struct NontrivialType {
   ~NontrivialType() {}
 };
 
+struct NontrivialTypeWithThrowingDtor {
+  ~NontrivialTypeWithThrowingDtor() noexcept(false) {}
+};
+
+namespace can_throw {
 struct Task {
 struct promise_type;
 using handle_type = std::coroutine_handle;
@@ -38,9 +43,66 @@ 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 
@_ZN9can_throw4Task23initial_suspend_awaiter12await_resumeEv(
 // CHECK-NEXT: call void @_ZN14NontrivialTypeD1Ev(
 // CHECK-NEXT: store i1 false, ptr {{.*}}
+}
+
+template 
+struct NoexceptResumeTask {
+struct promise_type;
+using handle_type = std::coroutine_handle;
+
+struct initial_suspend_awaiter {
+bool await_ready() {
+return false;
+}
+
+void await_suspend(handle_type h) {}
+
+R 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 {}; }
+NoexceptResumeTask get_return_object() {
+return NoexceptResumeTask{handle_type::from_promise(*this)};
+}
+};
+
+handle_type handler;
+};
+
+namespace no_throw {
+using InitNoThrowTask = NoexceptResumeTask;
+
+InitNoThrowTask coro_create() {
+co_return;
+}
+
+// CHECK-LABEL: define{{.*}} ptr @_ZN8no_throw11coro_createEv(
+// CHECK: init.ready:
+// CHECK-NEXT: call void 
@_ZN18NoexceptResumeTaskI14NontrivialTypeE23initial_suspend_awaiter12await_resumeEv(
+// CHECK-NEXT: call void @_ZN14NontrivialTypeD1Ev(
+}
+
+namespace throwing_dtor {
+using InitTaskWithThrowingDtor = 
NoexceptResumeTask;
+
+InitTaskWithThrowingDtor coro_create() {
+co_return;
+}
+
+// CHECK-LABEL: define{{.*}} ptr 

[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-28 Thread Yuxuan Chen via cfe-commits

yuxuanchen1997 wrote:

@ChuanqiXu9, I updated the check like you suggested, and it should look much 
nicer now. The only caveat is that the `children()` call isn't going to cover 
the implicit destructor call in a `CXXBindTemporaryExpr`. That pattern matching 
case is here to stay and likely there are many other types implicit calls that 
make this analysis unsound (See https://eel.is/c++draft/except.spec#6). In 
reality none of them can reach here though.

https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-28 Thread Yuxuan Chen via cfe-commits

https://github.com/yuxuanchen1997 updated 
https://github.com/llvm/llvm-project/pull/73160

>From dbd06bc001c0e00436fcacac231d9d80b443edf4 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen 
Date: Tue, 21 Nov 2023 21:38:12 -0800
Subject: [PATCH 1/2] add checks for nested noexcept in cxxtempexpr

---
 clang/lib/CodeGen/CGCoroutine.cpp | 28 ++--
 .../coro-init-await-nontrivial-return.cpp | 66 ++-
 2 files changed, 88 insertions(+), 6 deletions(-)

diff --git a/clang/lib/CodeGen/CGCoroutine.cpp 
b/clang/lib/CodeGen/CGCoroutine.cpp
index aaf122c0f83bc47..37ac5bca38c7049 100644
--- a/clang/lib/CodeGen/CGCoroutine.cpp
+++ b/clang/lib/CodeGen/CGCoroutine.cpp
@@ -129,12 +129,32 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData 
, AwaitKind Kind) {
   return Prefix;
 }
 
-static bool memberCallExpressionCanThrow(const Expr *E) {
+static bool FunctionProtoNoexcept(const FunctionProtoType *Proto) {
+  return isNoexceptExceptionSpec(Proto->getExceptionSpecType()) &&
+ Proto->canThrow() == CT_Cannot;
+}
+
+static bool ResumeExprCanThrow(const CoroutineSuspendExpr ) {
+  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(E)) {
+auto *Temporary = BindTempExpr->getTemporary();
+const auto *DtorProto = Temporary->getDestructor()
+->getCanonicalDecl()
+->getType()
+->getAs();
+bool DtorCanThrow = !FunctionProtoNoexcept(DtorProto);
+if (DtorCanThrow) {
+  return true;
+}
+E = BindTempExpr->getSubExpr();
+  }
   if (const auto *CE = dyn_cast(E))
 if (const auto *Proto =
 CE->getMethodDecl()->getType()->getAs())
-  if (isNoexceptExceptionSpec(Proto->getExceptionSpecType()) &&
-  Proto->canThrow() == CT_Cannot)
+  if (FunctionProtoNoexcept(Proto))
 return false;
   return true;
 }
@@ -233,7 +253,7 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction 
, CGCoroData 
   // 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..052b4e235e739fe 100644
--- a/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp
+++ b/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp
@@ -7,6 +7,11 @@ struct NontrivialType {
   ~NontrivialType() {}
 };
 
+struct NontrivialTypeWithThrowingDtor {
+  ~NontrivialTypeWithThrowingDtor() noexcept(false) {}
+};
+
+namespace can_throw {
 struct Task {
 struct promise_type;
 using handle_type = std::coroutine_handle;
@@ -38,9 +43,66 @@ 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 
@_ZN9can_throw4Task23initial_suspend_awaiter12await_resumeEv(
 // CHECK-NEXT: call void @_ZN14NontrivialTypeD1Ev(
 // CHECK-NEXT: store i1 false, ptr {{.*}}
+}
+
+template 
+struct NoexceptResumeTask {
+struct promise_type;
+using handle_type = std::coroutine_handle;
+
+struct initial_suspend_awaiter {
+bool await_ready() {
+return false;
+}
+
+void await_suspend(handle_type h) {}
+
+R 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 {}; }
+NoexceptResumeTask get_return_object() {
+return NoexceptResumeTask{handle_type::from_promise(*this)};
+}
+};
+
+handle_type handler;
+};
+
+namespace no_throw {
+using InitNoThrowTask = NoexceptResumeTask;
+
+InitNoThrowTask coro_create() {
+co_return;
+}
+
+// CHECK-LABEL: define{{.*}} ptr @_ZN8no_throw11coro_createEv(
+// CHECK: init.ready:
+// CHECK-NEXT: call void 
@_ZN18NoexceptResumeTaskI14NontrivialTypeE23initial_suspend_awaiter12await_resumeEv(
+// CHECK-NEXT: call void @_ZN14NontrivialTypeD1Ev(
+}
+
+namespace throwing_dtor {
+using InitTaskWithThrowingDtor = 
NoexceptResumeTask;
+
+InitTaskWithThrowingDtor coro_create() {
+co_return;
+}
+
+// CHECK-LABEL: define{{.*}} ptr 

[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-28 Thread Yuxuan Chen via cfe-commits


@@ -129,7 +130,14 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData 
, AwaitKind Kind) {
   return Prefix;
 }
 
-static bool memberCallExpressionCanThrow(const Expr *E) {
+static bool ResumeExprCanThrow(const CoroutineSuspendExpr ) {
+  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(E)) {
+E = BindTempExpr->getSubExpr();
+  }

yuxuanchen1997 wrote:

I guess you are correct that this is easy to miss some cases. In my case I 
missed the fact that the destructor of the `BindTempExpr->getTemporary()` can 
throw if marked `noexcept(false)`. I updated the PR to cover this case and 
including corresponding tests. 

Next up I will try to see how many cases I'll need to cover in a recursive 
check on `children()` like the one in `Sema::checkFinalSuspendNoThrow`.

https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-27 Thread Chuanqi Xu via cfe-commits


@@ -129,7 +130,14 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData 
, AwaitKind Kind) {
   return Prefix;
 }
 
-static bool memberCallExpressionCanThrow(const Expr *E) {
+static bool ResumeExprCanThrow(const CoroutineSuspendExpr ) {
+  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(E)) {
+E = BindTempExpr->getSubExpr();
+  }

ChuanqiXu9 wrote:

Maybe it is not a such big task as you imaged, you can take a look at 
`Sema::checkFinalSuspendNoThrow` and we should be able to make a simpler change 
than that.

The reason why I don't like the current pattern is that, every time I wrote:

```
if (auto *WantedExpressionType = isa(E))
 E = WantedExpressionType->subExpr();
...
```

I found I always missed some situations.

https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-27 Thread Wei Wang via cfe-commits


@@ -129,7 +130,14 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData 
, AwaitKind Kind) {
   return Prefix;
 }
 
-static bool memberCallExpressionCanThrow(const Expr *E) {
+static bool ResumeExprCanThrow(const CoroutineSuspendExpr ) {
+  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(E)) {
+E = BindTempExpr->getSubExpr();
+  }

apolloww wrote:

I think we are only targeting the resume part of init_suspend here, so the 
cases are limited. Can we change the function name to something more specific, 
like `InitResumeExprCanThrow`?

https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-27 Thread Wei Wang via cfe-commits

https://github.com/apolloww deleted 
https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-27 Thread Yuxuan Chen via cfe-commits

https://github.com/yuxuanchen1997 edited 
https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-27 Thread Wei Wang via cfe-commits


@@ -129,7 +130,14 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData 
, AwaitKind Kind) {
   return Prefix;
 }
 
-static bool memberCallExpressionCanThrow(const Expr *E) {
+static bool ResumeExprCanThrow(const CoroutineSuspendExpr ) {
+  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(E)) {
+E = BindTempExpr->getSubExpr();
+  }

apolloww wrote:

I think we are only targeting the resume part of `init_suspend` here, so the 
cases are limited. Can we change the function name to something more specific, 
like `InitResumeExprCanThrow`?

https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-27 Thread Yuxuan Chen via cfe-commits


@@ -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 {

yuxuanchen1997 wrote:

I applied your suggested change. I think this name is still bikesheddable 
though. 

https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-27 Thread Yuxuan Chen via cfe-commits

https://github.com/yuxuanchen1997 updated 
https://github.com/llvm/llvm-project/pull/73160

>From 08e2293255a504043fe404cceaeb3ff1fc0dc344 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen 
Date: Tue, 21 Nov 2023 21:38:12 -0800
Subject: [PATCH] add checks for nested noexcept in cxxtempexpr

---
 clang/lib/CodeGen/CGCoroutine.cpp | 11 -
 .../coro-init-await-nontrivial-return.cpp | 44 ++-
 2 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/clang/lib/CodeGen/CGCoroutine.cpp 
b/clang/lib/CodeGen/CGCoroutine.cpp
index aaf122c0f83bc47..8aebc5563757cba 100644
--- a/clang/lib/CodeGen/CGCoroutine.cpp
+++ b/clang/lib/CodeGen/CGCoroutine.cpp
@@ -129,7 +129,14 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData 
, AwaitKind Kind) {
   return Prefix;
 }
 
-static bool memberCallExpressionCanThrow(const Expr *E) {
+static bool ResumeExprCanThrow(const CoroutineSuspendExpr ) {
+  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(E)) {
+E = BindTempExpr->getSubExpr();
+  }
   if (const auto *CE = dyn_cast(E))
 if (const auto *Proto =
 CE->getMethodDecl()->getType()->getAs())
@@ -233,7 +240,7 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction 
, CGCoroData 
   // 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..5d24841091f339c 100644
--- a/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp
+++ b/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp
@@ -7,6 +7,7 @@ struct NontrivialType {
   ~NontrivialType() {}
 };
 
+namespace can_throw {
 struct Task {
 struct promise_type;
 using handle_type = std::coroutine_handle;
@@ -38,9 +39,48 @@ 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 
@_ZN9can_throw4Task23initial_suspend_awaiter12await_resumeEv(
 // CHECK-NEXT: call void @_ZN14NontrivialTypeD1Ev(
 // CHECK-NEXT: store i1 false, ptr {{.*}}
+}
+
+namespace no_throw {
+struct InitNoThrowTask {
+struct promise_type;
+using handle_type = std::coroutine_handle;
+
+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 {}; }
+InitNoThrowTask get_return_object() {
+return InitNoThrowTask{handle_type::from_promise(*this)};
+}
+};
+
+handle_type handler;
+};
+
+InitNoThrowTask coro_create() {
+co_return;
+}
+
+// CHECK-LABEL: define{{.*}} ptr @_ZN8no_throw11coro_createEv(
+// CHECK: init.ready:
+// CHECK-NEXT: call void 
@_ZN8no_throw15InitNoThrowTask23initial_suspend_awaiter12await_resumeEv(
+// CHECK-NEXT: call void @_ZN14NontrivialTypeD1Ev(
+}

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-27 Thread Yuxuan Chen via cfe-commits

https://github.com/yuxuanchen1997 edited 
https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-27 Thread Yuxuan Chen via cfe-commits


@@ -129,7 +130,14 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData 
, AwaitKind Kind) {
   return Prefix;
 }
 
-static bool memberCallExpressionCanThrow(const Expr *E) {
+static bool ResumeExprCanThrow(const CoroutineSuspendExpr ) {
+  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(E)) {
+E = BindTempExpr->getSubExpr();
+  }

yuxuanchen1997 wrote:

I find this a little overkill for what we need. The old code here didn't intend 
to handle more cases either because it just expected the AST to be in a 
specific shape (`CXXMemberCallExpr`). This fix is merely just to amend its 
functionality to work on a temporary expression as well should there be a 
return value to be discarded. It should be clear intent here that we don't care 
about anything else. (Ideally, I want an assertion here that it's either of the 
two `Expr` types)

https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-22 Thread Chuanqi Xu via cfe-commits


@@ -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 {

ChuanqiXu9 wrote:

It looks a little bit confusing. Let's try to rename it to InitNoThrowTask.

https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-22 Thread Chuanqi Xu via cfe-commits


@@ -129,7 +130,14 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData 
, AwaitKind Kind) {
   return Prefix;
 }
 
-static bool memberCallExpressionCanThrow(const Expr *E) {
+static bool ResumeExprCanThrow(const CoroutineSuspendExpr ) {
+  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(E)) {
+E = BindTempExpr->getSubExpr();
+  }

ChuanqiXu9 wrote:

Such pattern match doesn't smell good. How about looking into its children 
recursively if we find `E` is not CXXMemberCallExpr?

https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-22 Thread Chuanqi Xu via cfe-commits


@@ -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"

ChuanqiXu9 wrote:

Is this change necessary?

https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-22 Thread Yuxuan Chen via cfe-commits

https://github.com/yuxuanchen1997 edited 
https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-22 Thread Yuxuan Chen via cfe-commits

https://github.com/yuxuanchen1997 edited 
https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] CGCoroutines skip emitting try block for value returning `noexcept` init `await_resume` calls (PR #73160)

2023-11-22 Thread Yuxuan Chen via cfe-commits

https://github.com/yuxuanchen1997 edited 
https://github.com/llvm/llvm-project/pull/73160
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits