|
@@ -130,6 +130,16 @@ 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;
|
|
|
+}
|
|
|
+
|
|
|
// Emit suspend expression which roughly looks like:
|
|
|
//
|
|
|
// auto && x = CommonExpr();
|
|
@@ -217,8 +227,12 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Co
|
|
|
|
|
|
// Emit await_resume expression.
|
|
|
CGF.EmitBlock(ReadyBlock);
|
|
|
+
|
|
|
+ // Exception handling requires additional IR. If the 'await_resume' function
|
|
|
+ // is marked as 'noexcept', we avoid generating this additional IR.
|
|
|
CXXTryStmt *TryStmt = nullptr;
|
|
|
- if (Coro.ExceptionHandler && Kind == AwaitKind::Init) {
|
|
|
+ if (Coro.ExceptionHandler && Kind == AwaitKind::Init &&
|
|
|
+ memberCallExpressionCanThrow(S.getResumeExpr())) {
|
|
|
Coro.ResumeEHVar =
|
|
|
CGF.CreateTempAlloca(Builder.getInt1Ty(), Prefix + Twine("resume.eh"));
|
|
|
Builder.CreateFlagStore(true, Coro.ResumeEHVar);
|
|
@@ -625,12 +639,20 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
|
|
|
CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal;
|
|
|
|
|
|
if (CurCoro.Data->ExceptionHandler) {
|
|
|
- BasicBlock *BodyBB = createBasicBlock("coro.resumed.body");
|
|
|
- BasicBlock *ContBB = createBasicBlock("coro.resumed.cont");
|
|
|
- Value *SkipBody =
|
|
|
- Builder.CreateFlagLoad(CurCoro.Data->ResumeEHVar, "coro.resumed.eh");
|
|
|
- Builder.CreateCondBr(SkipBody, ContBB, BodyBB);
|
|
|
- EmitBlock(BodyBB);
|
|
|
+ // If we generated IR to record whether an exception was thrown from
|
|
|
+ // 'await_resume', then use that IR to determine whether the coroutine
|
|
|
+ // body should be skipped.
|
|
|
+ // If we didn't generate the IR (perhaps because 'await_resume' was marked
|
|
|
+ // as 'noexcept'), then we skip this check.
|
|
|
+ BasicBlock *ContBB = nullptr;
|
|
|
+ if (CurCoro.Data->ResumeEHVar) {
|
|
|
+ BasicBlock *BodyBB = createBasicBlock("coro.resumed.body");
|
|
|
+ ContBB = createBasicBlock("coro.resumed.cont");
|
|
|
+ Value *SkipBody = Builder.CreateFlagLoad(CurCoro.Data->ResumeEHVar,
|
|
|
+ "coro.resumed.eh");
|
|
|
+ Builder.CreateCondBr(SkipBody, ContBB, BodyBB);
|
|
|
+ EmitBlock(BodyBB);
|
|
|
+ }
|
|
|
|
|
|
auto Loc = S.getLocStart();
|
|
|
CXXCatchStmt Catch(Loc, /*exDecl=*/nullptr,
|
|
@@ -642,7 +664,8 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
|
|
|
emitBodyAndFallthrough(*this, S, TryStmt->getTryBlock());
|
|
|
ExitCXXTryStmt(*TryStmt);
|
|
|
|
|
|
- EmitBlock(ContBB);
|
|
|
+ if (ContBB)
|
|
|
+ EmitBlock(ContBB);
|
|
|
}
|
|
|
else {
|
|
|
emitBodyAndFallthrough(*this, S, S.getBody());
|