Skip to content

Commit

Permalink
add checks for nested noexcept in cxxtempexpr
Browse files Browse the repository at this point in the history
  • Loading branch information
yuxuanchen1997 committed Nov 28, 2023
1 parent 3a6f02a commit dbd06bc
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 6 deletions.
28 changes: 24 additions & 4 deletions clang/lib/CodeGen/CGCoroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,32 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData &Coro, 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 &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)) {
auto *Temporary = BindTempExpr->getTemporary();
const auto *DtorProto = Temporary->getDestructor()
->getCanonicalDecl()
->getType()
->getAs<FunctionProtoType>();
bool DtorCanThrow = !FunctionProtoNoexcept(DtorProto);
if (DtorCanThrow) {
return true;
}
E = BindTempExpr->getSubExpr();
}
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)
if (FunctionProtoNoexcept(Proto))
return false;
return true;
}
Expand Down Expand Up @@ -233,7 +253,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);
Expand Down
66 changes: 64 additions & 2 deletions clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<promise_type>;
Expand Down Expand Up @@ -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 <typename R>
struct NoexceptResumeTask {
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) {}

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<NontrivialType>;

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<NontrivialTypeWithThrowingDtor>;

InitTaskWithThrowingDtor coro_create() {
co_return;
}

// CHECK-LABEL: define{{.*}} ptr @_ZN13throwing_dtor11coro_createEv(
// CHECK: init.ready:
// CHECK-NEXT: store i1 true, ptr {{.*}}
// CHECK-NEXT: call void @_ZN18NoexceptResumeTaskI30NontrivialTypeWithThrowingDtorE23initial_suspend_awaiter12await_resumeEv(
// CHECK-NEXT: call void @_ZN30NontrivialTypeWithThrowingDtorD1Ev(
// CHECK-NEXT: store i1 false, ptr {{.*}}
}

0 comments on commit dbd06bc

Please sign in to comment.