|
@@ -44,6 +44,15 @@ struct clang::CodeGen::CGCoroData {
|
|
// A branch to this block is emitted when coroutine needs to suspend.
|
|
// A branch to this block is emitted when coroutine needs to suspend.
|
|
llvm::BasicBlock *SuspendBB = nullptr;
|
|
llvm::BasicBlock *SuspendBB = nullptr;
|
|
|
|
|
|
|
|
+ // The promise type's 'unhandled_exception' handler, if it defines one.
|
|
|
|
+ Stmt *ExceptionHandler = nullptr;
|
|
|
|
+
|
|
|
|
+ // A temporary i1 alloca that stores whether 'await_resume' threw an
|
|
|
|
+ // exception. If it did, 'true' is stored in this variable, and the coroutine
|
|
|
|
+ // body must be skipped. If the promise type does not define an exception
|
|
|
|
+ // handler, this is null.
|
|
|
|
+ llvm::Value *ResumeEHVar = nullptr;
|
|
|
|
+
|
|
// Stores the jump destination just before the coroutine memory is freed.
|
|
// Stores the jump destination just before the coroutine memory is freed.
|
|
// This is the destination that every suspend point jumps to for the cleanup
|
|
// This is the destination that every suspend point jumps to for the cleanup
|
|
// branch.
|
|
// branch.
|
|
@@ -208,11 +217,32 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Co
|
|
|
|
|
|
// Emit await_resume expression.
|
|
// Emit await_resume expression.
|
|
CGF.EmitBlock(ReadyBlock);
|
|
CGF.EmitBlock(ReadyBlock);
|
|
|
|
+ CXXTryStmt *TryStmt = nullptr;
|
|
|
|
+ if (Coro.ExceptionHandler && Kind == AwaitKind::Init) {
|
|
|
|
+ Coro.ResumeEHVar =
|
|
|
|
+ CGF.CreateTempAlloca(Builder.getInt1Ty(), Prefix + Twine("resume.eh"));
|
|
|
|
+ Builder.CreateFlagStore(true, Coro.ResumeEHVar);
|
|
|
|
+
|
|
|
|
+ auto Loc = S.getResumeExpr()->getExprLoc();
|
|
|
|
+ auto *Catch = new (CGF.getContext())
|
|
|
|
+ CXXCatchStmt(Loc, /*exDecl=*/nullptr, Coro.ExceptionHandler);
|
|
|
|
+ auto *TryBody =
|
|
|
|
+ CompoundStmt::Create(CGF.getContext(), S.getResumeExpr(), Loc, Loc);
|
|
|
|
+ TryStmt = CXXTryStmt::Create(CGF.getContext(), Loc, TryBody, Catch);
|
|
|
|
+ CGF.EnterCXXTryStmt(*TryStmt);
|
|
|
|
+ }
|
|
|
|
+
|
|
LValueOrRValue Res;
|
|
LValueOrRValue Res;
|
|
if (forLValue)
|
|
if (forLValue)
|
|
Res.LV = CGF.EmitLValue(S.getResumeExpr());
|
|
Res.LV = CGF.EmitLValue(S.getResumeExpr());
|
|
else
|
|
else
|
|
Res.RV = CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult);
|
|
Res.RV = CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult);
|
|
|
|
+
|
|
|
|
+ if (TryStmt) {
|
|
|
|
+ Builder.CreateFlagStore(false, Coro.ResumeEHVar);
|
|
|
|
+ CGF.ExitCXXTryStmt(*TryStmt);
|
|
|
|
+ }
|
|
|
|
+
|
|
return Res;
|
|
return Res;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -588,19 +618,31 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
|
|
EHStack.pushCleanup<CallCoroEnd>(EHCleanup);
|
|
EHStack.pushCleanup<CallCoroEnd>(EHCleanup);
|
|
|
|
|
|
CurCoro.Data->CurrentAwaitKind = AwaitKind::Init;
|
|
CurCoro.Data->CurrentAwaitKind = AwaitKind::Init;
|
|
|
|
+ CurCoro.Data->ExceptionHandler = S.getExceptionHandler();
|
|
EmitStmt(S.getInitSuspendStmt());
|
|
EmitStmt(S.getInitSuspendStmt());
|
|
CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB);
|
|
CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB);
|
|
|
|
|
|
CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal;
|
|
CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal;
|
|
|
|
|
|
- if (auto *OnException = S.getExceptionHandler()) {
|
|
|
|
|
|
+ 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);
|
|
|
|
+
|
|
auto Loc = S.getLocStart();
|
|
auto Loc = S.getLocStart();
|
|
- CXXCatchStmt Catch(Loc, /*exDecl=*/nullptr, OnException);
|
|
|
|
- auto *TryStmt = CXXTryStmt::Create(getContext(), Loc, S.getBody(), &Catch);
|
|
|
|
|
|
+ CXXCatchStmt Catch(Loc, /*exDecl=*/nullptr,
|
|
|
|
+ CurCoro.Data->ExceptionHandler);
|
|
|
|
+ auto *TryStmt =
|
|
|
|
+ CXXTryStmt::Create(getContext(), Loc, S.getBody(), &Catch);
|
|
|
|
|
|
EnterCXXTryStmt(*TryStmt);
|
|
EnterCXXTryStmt(*TryStmt);
|
|
emitBodyAndFallthrough(*this, S, TryStmt->getTryBlock());
|
|
emitBodyAndFallthrough(*this, S, TryStmt->getTryBlock());
|
|
ExitCXXTryStmt(*TryStmt);
|
|
ExitCXXTryStmt(*TryStmt);
|
|
|
|
+
|
|
|
|
+ EmitBlock(ContBB);
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
emitBodyAndFallthrough(*this, S, S.getBody());
|
|
emitBodyAndFallthrough(*this, S, S.getBody());
|