Update aosp/master clang for rebase to r235153
Change-Id: Ia94bbcb6da7c75b6e7c2afedd1001094d62a7324
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 223b8f7..ff12a9a 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -19,8 +19,11 @@
#include "clang/AST/Mangle.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtVisitor.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace CodeGen;
@@ -406,13 +409,6 @@
return Builder.CreateLoad(getEHSelectorSlot(), "sel");
}
-llvm::Value *CodeGenFunction::getAbnormalTerminationSlot() {
- if (!AbnormalTerminationSlot)
- AbnormalTerminationSlot =
- CreateTempAlloca(Int8Ty, "abnormal.termination.slot");
- return AbnormalTerminationSlot;
-}
-
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,
bool KeepInsertionPoint) {
if (const Expr *SubExpr = E->getSubExpr()) {
@@ -458,6 +454,10 @@
EHStack.pushTerminate();
}
} else if (EST == EST_Dynamic || EST == EST_DynamicNone) {
+ // TODO: Revisit exception specifications for the MS ABI. There is a way to
+ // encode these in an object file but MSVC doesn't do anything with it.
+ if (getTarget().getCXXABI().isMicrosoft())
+ return;
unsigned NumExceptions = Proto->getNumExceptions();
EHFilterScope *Filter = EHStack.pushFilter(NumExceptions);
@@ -532,6 +532,10 @@
EHStack.popTerminate();
}
} else if (EST == EST_Dynamic || EST == EST_DynamicNone) {
+ // TODO: Revisit exception specifications for the MS ABI. There is a way to
+ // encode these in an object file but MSVC doesn't do anything with it.
+ if (getTarget().getCXXABI().isMicrosoft())
+ return;
EHFilterScope &filterScope = cast<EHFilterScope>(*EHStack.begin());
emitFilterDispatchBlock(*this, filterScope);
EHStack.popFilter();
@@ -568,7 +572,7 @@
TypeInfo = CGM.getObjCRuntime().GetEHType(CaughtType);
else
TypeInfo =
- CGM.getAddrOfCXXHandlerMapEntry(CaughtType, C->getCaughtType());
+ CGM.getAddrOfCXXCatchHandlerType(CaughtType, C->getCaughtType());
CatchScope->setHandler(I, TypeInfo, Handler);
} else {
// No exception decl indicates '...', a catch-all.
@@ -1277,8 +1281,7 @@
return;
}
- SEHFinallyInfo FI;
- EnterSEHTryStmt(S, FI);
+ EnterSEHTryStmt(S);
{
JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave");
@@ -1291,109 +1294,224 @@
else
delete TryExit.getBlock();
}
- ExitSEHTryStmt(S, FI);
+ ExitSEHTryStmt(S);
}
namespace {
-struct PerformSEHFinally : EHScopeStack::Cleanup {
- CodeGenFunction::SEHFinallyInfo *FI;
- PerformSEHFinally(CodeGenFunction::SEHFinallyInfo *FI) : FI(FI) {}
+struct PerformSEHFinally : EHScopeStack::Cleanup {
+ llvm::Function *OutlinedFinally;
+ PerformSEHFinally(llvm::Function *OutlinedFinally)
+ : OutlinedFinally(OutlinedFinally) {}
void Emit(CodeGenFunction &CGF, Flags F) override {
- // Cleanups are emitted at most twice: once for normal control flow and once
- // for exception control flow. Branch into the finally block, and remember
- // the continuation block so we can branch out later.
- if (!FI->FinallyBB) {
- FI->FinallyBB = CGF.createBasicBlock("__finally");
- FI->FinallyBB->insertInto(CGF.CurFn);
- FI->FinallyBB->moveAfter(CGF.Builder.GetInsertBlock());
- }
+ ASTContext &Context = CGF.getContext();
+ QualType ArgTys[2] = {Context.BoolTy, Context.VoidPtrTy};
+ FunctionProtoType::ExtProtoInfo EPI;
+ const auto *FTP = cast<FunctionType>(
+ Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
- // Set the termination status and branch in.
- CGF.Builder.CreateStore(
- llvm::ConstantInt::get(CGF.Int8Ty, F.isForEHCleanup()),
- CGF.getAbnormalTerminationSlot());
- CGF.Builder.CreateBr(FI->FinallyBB);
+ CallArgList Args;
+ llvm::Value *IsForEH =
+ llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());
+ Args.add(RValue::get(IsForEH), ArgTys[0]);
- // Create a continuation block for normal or exceptional control.
- if (F.isForEHCleanup()) {
- assert(!FI->ResumeBB && "double emission for EH");
- FI->ResumeBB = CGF.createBasicBlock("__finally.resume");
- CGF.EmitBlock(FI->ResumeBB);
- } else {
- assert(F.isForNormalCleanup() && !FI->ContBB && "double normal emission");
- FI->ContBB = CGF.createBasicBlock("__finally.cont");
- CGF.EmitBlock(FI->ContBB);
- // Try to keep source order.
- FI->ContBB->moveAfter(FI->FinallyBB);
- }
+ CodeGenModule &CGM = CGF.CGM;
+ llvm::Value *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0);
+ llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress);
+ llvm::Value *FP = CGF.Builder.CreateCall(FrameAddr, Zero);
+ Args.add(RValue::get(FP), ArgTys[1]);
+
+ const CGFunctionInfo &FnInfo =
+ CGM.getTypes().arrangeFreeFunctionCall(Args, FTP, /*chainCall=*/false);
+ CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
}
};
}
+namespace {
+/// Find all local variable captures in the statement.
+struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
+ CodeGenFunction &ParentCGF;
+ const VarDecl *ParentThis;
+ SmallVector<const VarDecl *, 4> Captures;
+ CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis)
+ : ParentCGF(ParentCGF), ParentThis(ParentThis) {}
+
+ void Visit(const Stmt *S) {
+ // See if this is a capture, then recurse.
+ ConstStmtVisitor<CaptureFinder>::Visit(S);
+ for (const Stmt *Child : S->children())
+ if (Child)
+ Visit(Child);
+ }
+
+ void VisitDeclRefExpr(const DeclRefExpr *E) {
+ // If this is already a capture, just make sure we capture 'this'.
+ if (E->refersToEnclosingVariableOrCapture()) {
+ Captures.push_back(ParentThis);
+ return;
+ }
+
+ const auto *D = dyn_cast<VarDecl>(E->getDecl());
+ if (D && D->isLocalVarDeclOrParm() && D->hasLocalStorage())
+ Captures.push_back(D);
+ }
+
+ void VisitCXXThisExpr(const CXXThisExpr *E) {
+ Captures.push_back(ParentThis);
+ }
+};
+}
+
+void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
+ const Stmt *OutlinedStmt,
+ llvm::Value *ParentFP) {
+ // Find all captures in the Stmt.
+ CaptureFinder Finder(ParentCGF, ParentCGF.CXXABIThisDecl);
+ Finder.Visit(OutlinedStmt);
+
+ // Typically there are no captures and we can exit early.
+ if (Finder.Captures.empty())
+ return;
+
+ // Prepare the first two arguments to llvm.framerecover.
+ llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration(
+ &CGM.getModule(), llvm::Intrinsic::framerecover);
+ llvm::Constant *ParentI8Fn =
+ llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
+
+ // Create llvm.framerecover calls for all captures.
+ for (const VarDecl *VD : Finder.Captures) {
+ if (isa<ImplicitParamDecl>(VD)) {
+ CGM.ErrorUnsupported(VD, "'this' captured by SEH");
+ CXXThisValue = llvm::UndefValue::get(ConvertTypeForMem(VD->getType()));
+ continue;
+ }
+ if (VD->getType()->isVariablyModifiedType()) {
+ CGM.ErrorUnsupported(VD, "VLA captured by SEH");
+ continue;
+ }
+ assert((isa<ImplicitParamDecl>(VD) || VD->isLocalVarDeclOrParm()) &&
+ "captured non-local variable");
+
+ // If this decl hasn't been declared yet, it will be declared in the
+ // OutlinedStmt.
+ auto I = ParentCGF.LocalDeclMap.find(VD);
+ if (I == ParentCGF.LocalDeclMap.end())
+ continue;
+ llvm::Value *ParentVar = I->second;
+
+ llvm::CallInst *RecoverCall = nullptr;
+ CGBuilderTy Builder(AllocaInsertPt);
+ if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar)) {
+ // Mark the variable escaped if nobody else referenced it and compute the
+ // frameescape index.
+ auto InsertPair =
+ ParentCGF.EscapedLocals.insert(std::make_pair(ParentAlloca, -1));
+ if (InsertPair.second)
+ InsertPair.first->second = ParentCGF.EscapedLocals.size() - 1;
+ int FrameEscapeIdx = InsertPair.first->second;
+ // call i8* @llvm.framerecover(i8* bitcast(@parentFn), i8* %fp, i32 N)
+ RecoverCall =
+ Builder.CreateCall3(FrameRecoverFn, ParentI8Fn, ParentFP,
+ llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx));
+
+ } else {
+ // If the parent didn't have an alloca, we're doing some nested outlining.
+ // Just clone the existing framerecover call, but tweak the FP argument to
+ // use our FP value. All other arguments are constants.
+ auto *ParentRecover =
+ cast<llvm::IntrinsicInst>(ParentVar->stripPointerCasts());
+ assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::framerecover &&
+ "expected alloca or framerecover in parent LocalDeclMap");
+ RecoverCall = cast<llvm::CallInst>(ParentRecover->clone());
+ RecoverCall->setArgOperand(1, ParentFP);
+ RecoverCall->insertBefore(AllocaInsertPt);
+ }
+
+ // Bitcast the variable, rename it, and insert it in the local decl map.
+ llvm::Value *ChildVar =
+ Builder.CreateBitCast(RecoverCall, ParentVar->getType());
+ ChildVar->setName(ParentVar->getName());
+ LocalDeclMap[VD] = ChildVar;
+ }
+}
+
+/// Arrange a function prototype that can be called by Windows exception
+/// handling personalities. On Win64, the prototype looks like:
+/// RetTy func(void *EHPtrs, void *ParentFP);
+void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
+ StringRef Name, QualType RetTy,
+ FunctionArgList &Args,
+ const Stmt *OutlinedStmt) {
+ llvm::Function *ParentFn = ParentCGF.CurFn;
+ const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ RetTy, Args, FunctionType::ExtInfo(), /*isVariadic=*/false);
+
+ llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
+ llvm::Function *Fn = llvm::Function::Create(
+ FnTy, llvm::GlobalValue::InternalLinkage, Name.str(), &CGM.getModule());
+ // The filter is either in the same comdat as the function, or it's internal.
+ if (llvm::Comdat *C = ParentFn->getComdat()) {
+ Fn->setComdat(C);
+ } else if (ParentFn->hasWeakLinkage() || ParentFn->hasLinkOnceLinkage()) {
+ llvm::Comdat *C = CGM.getModule().getOrInsertComdat(ParentFn->getName());
+ ParentFn->setComdat(C);
+ Fn->setComdat(C);
+ } else {
+ Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
+ }
+
+ IsOutlinedSEHHelper = true;
+
+ StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,
+ OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart());
+
+ CGM.SetLLVMFunctionAttributes(nullptr, FnInfo, CurFn);
+
+ auto AI = Fn->arg_begin();
+ ++AI;
+ EmitCapturedLocals(ParentCGF, OutlinedStmt, &*AI);
+}
+
/// Create a stub filter function that will ultimately hold the code of the
/// filter expression. The EH preparation passes in LLVM will outline the code
/// from the main function body into this stub.
llvm::Function *
CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
const SEHExceptStmt &Except) {
- const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
- llvm::Function *ParentFn = ParentCGF.CurFn;
+ const Expr *FilterExpr = Except.getFilterExpr();
+ SourceLocation StartLoc = FilterExpr->getLocStart();
- Expr *FilterExpr = Except.getFilterExpr();
+ SEHPointersDecl = ImplicitParamDecl::Create(
+ getContext(), nullptr, StartLoc,
+ &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);
+ FunctionArgList Args;
+ Args.push_back(SEHPointersDecl);
+ Args.push_back(ImplicitParamDecl::Create(
+ getContext(), nullptr, StartLoc,
+ &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
// Get the mangled function name.
SmallString<128> Name;
{
llvm::raw_svector_ostream OS(Name);
+ const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);
assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");
CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS);
}
- // Arrange a function with the declaration:
- // int filt(EXCEPTION_POINTERS *exception_pointers, void *frame_pointer)
- QualType RetTy = getContext().IntTy;
- FunctionArgList Args;
- SEHPointersDecl = ImplicitParamDecl::Create(
- getContext(), nullptr, FilterExpr->getLocStart(),
- &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);
- Args.push_back(SEHPointersDecl);
- Args.push_back(ImplicitParamDecl::Create(
- getContext(), nullptr, FilterExpr->getLocStart(),
- &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
- const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration(
- RetTy, Args, FunctionType::ExtInfo(), /*isVariadic=*/false);
- llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
- llvm::Function *Fn = llvm::Function::Create(FnTy, ParentFn->getLinkage(),
- Name.str(), &CGM.getModule());
- // The filter is either in the same comdat as the function, or it's internal.
- if (llvm::Comdat *C = ParentFn->getComdat()) {
- Fn->setComdat(C);
- } else if (ParentFn->hasWeakLinkage() || ParentFn->hasLinkOnceLinkage()) {
- // FIXME: Unreachable with Rafael's changes?
- llvm::Comdat *C = CGM.getModule().getOrInsertComdat(ParentFn->getName());
- ParentFn->setComdat(C);
- Fn->setComdat(C);
- } else {
- Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
- }
+ startOutlinedSEHHelper(ParentCGF, Name, getContext().IntTy, Args, FilterExpr);
- StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,
- FilterExpr->getLocStart(), FilterExpr->getLocStart());
+ // Mark finally block calls as nounwind and noinline to make LLVM's job a
+ // little easier.
+ // FIXME: Remove these restrictions in the future.
+ CurFn->addFnAttr(llvm::Attribute::NoUnwind);
+ CurFn->addFnAttr(llvm::Attribute::NoInline);
EmitSEHExceptionCodeSave();
- // Insert dummy allocas for every local variable in scope. We'll initialize
- // them and prune the unused ones after we find out which ones were
- // referenced.
- for (const auto &DeclPtrs : ParentCGF.LocalDeclMap) {
- const Decl *VD = DeclPtrs.first;
- llvm::Value *Ptr = DeclPtrs.second;
- auto *ValTy = cast<llvm::PointerType>(Ptr->getType())->getElementType();
- LocalDeclMap[VD] = CreateTempAlloca(ValTy, Ptr->getName() + ".filt");
- }
-
// Emit the original filter expression, convert to i32, and return.
llvm::Value *R = EmitScalarExpr(FilterExpr);
R = Builder.CreateIntCast(R, CGM.IntTy,
@@ -1402,18 +1520,42 @@
FinishFunction(FilterExpr->getLocEnd());
- for (const auto &DeclPtrs : ParentCGF.LocalDeclMap) {
- const Decl *VD = DeclPtrs.first;
- auto *Alloca = cast<llvm::AllocaInst>(LocalDeclMap[VD]);
- if (Alloca->hasNUses(0)) {
- Alloca->eraseFromParent();
- continue;
- }
- ErrorUnsupported(FilterExpr,
- "SEH filter expression local variable capture");
+ return CurFn;
+}
+
+llvm::Function *
+CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
+ const SEHFinallyStmt &Finally) {
+ const Stmt *FinallyBlock = Finally.getBlock();
+ SourceLocation StartLoc = FinallyBlock->getLocStart();
+
+ FunctionArgList Args;
+ Args.push_back(ImplicitParamDecl::Create(
+ getContext(), nullptr, StartLoc,
+ &getContext().Idents.get("abnormal_termination"), getContext().BoolTy));
+ Args.push_back(ImplicitParamDecl::Create(
+ getContext(), nullptr, StartLoc,
+ &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
+
+ // Get the mangled function name.
+ SmallString<128> Name;
+ {
+ llvm::raw_svector_ostream OS(Name);
+ const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
+ const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);
+ assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");
+ CGM.getCXXABI().getMangleContext().mangleSEHFinallyBlock(Parent, OS);
}
- return Fn;
+ startOutlinedSEHHelper(ParentCGF, Name, getContext().VoidTy, Args,
+ FinallyBlock);
+
+ // Emit the original filter expression, convert to i32, and return.
+ EmitStmt(FinallyBlock);
+
+ FinishFunction(FinallyBlock->getLocEnd());
+
+ return CurFn;
}
void CodeGenFunction::EmitSEHExceptionCodeSave() {
@@ -1429,7 +1571,7 @@
llvm::Type *RecordTy = CGM.Int32Ty->getPointerTo();
llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy, nullptr);
Ptrs = Builder.CreateBitCast(Ptrs, PtrsTy->getPointerTo());
- llvm::Value *Rec = Builder.CreateStructGEP(Ptrs, 0);
+ llvm::Value *Rec = Builder.CreateStructGEP(PtrsTy, Ptrs, 0);
Rec = Builder.CreateLoad(Rec);
llvm::Value *Code = Builder.CreateLoad(Rec);
Code = Builder.CreateZExt(Code, CGM.IntPtrTy);
@@ -1457,21 +1599,24 @@
}
llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {
- // Load from the abnormal termination slot. It will be uninitialized outside
- // of __finally blocks, which we should warn or error on.
- llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot());
- return Builder.CreateZExt(IsEH, Int32Ty);
+ // Abnormal termination is just the first parameter to the outlined finally
+ // helper.
+ auto AI = CurFn->arg_begin();
+ return Builder.CreateZExt(&*AI, Int32Ty);
}
-void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {
- if (S.getFinallyHandler()) {
+void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
+ CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
+ if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
// Push a cleanup for __finally blocks.
- EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, &FI);
+ llvm::Function *FinallyFunc =
+ HelperCGF.GenerateSEHFinallyFunction(*this, *Finally);
+ EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc);
return;
}
// Otherwise, we must have an __except block.
- SEHExceptStmt *Except = S.getExceptHandler();
+ const SEHExceptStmt *Except = S.getExceptHandler();
assert(Except);
EHCatchScope *CatchScope = EHStack.pushCatch(1);
@@ -1486,40 +1631,17 @@
// In general, we have to emit an outlined filter function. Use the function
// in place of the RTTI typeinfo global that C++ EH uses.
- CodeGenFunction FilterCGF(CGM, /*suppressNewContext=*/true);
llvm::Function *FilterFunc =
- FilterCGF.GenerateSEHFilterFunction(*this, *Except);
+ HelperCGF.GenerateSEHFilterFunction(*this, *Except);
llvm::Constant *OpaqueFunc =
llvm::ConstantExpr::getBitCast(FilterFunc, Int8PtrTy);
CatchScope->setHandler(0, OpaqueFunc, createBasicBlock("__except"));
}
-void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {
+void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
// Just pop the cleanup if it's a __finally block.
- if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
+ if (S.getFinallyHandler()) {
PopCleanupBlock();
- assert(FI.ContBB && "did not emit normal cleanup");
-
- // Emit the code into FinallyBB.
- CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();
- Builder.SetInsertPoint(FI.FinallyBB);
- EmitStmt(Finally->getBlock());
-
- if (HaveInsertPoint()) {
- if (FI.ResumeBB) {
- llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot(),
- "abnormal.termination");
- IsEH = Builder.CreateICmpEQ(IsEH, llvm::ConstantInt::get(Int8Ty, 0));
- Builder.CreateCondBr(IsEH, FI.ContBB, FI.ResumeBB);
- } else {
- // There was nothing exceptional in the try body, so we only have normal
- // control flow.
- Builder.CreateBr(FI.ContBB);
- }
- }
-
- Builder.restoreIP(SavedIP);
-
return;
}
@@ -1569,7 +1691,13 @@
if (HaveInsertPoint())
EmitStopPoint(&S);
- assert(!SEHTryEpilogueStack.empty() &&
- "sema should have rejected this __leave");
+ // This must be a __leave from a __finally block, which we warn on and is UB.
+ // Just emit unreachable.
+ if (!isSEHTryScope()) {
+ Builder.CreateUnreachable();
+ Builder.ClearInsertionPoint();
+ return;
+ }
+
EmitBranchThroughCleanup(*SEHTryEpilogueStack.back());
}