Path: blob/main/contrib/llvm-project/clang/lib/CodeGen/CGException.cpp
35233 views
//===--- CGException.cpp - Emit LLVM Code for C++ exceptions ----*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This contains code dealing with C++ exception related code generation.9//10//===----------------------------------------------------------------------===//1112#include "CGCXXABI.h"13#include "CGCleanup.h"14#include "CGObjCRuntime.h"15#include "CodeGenFunction.h"16#include "ConstantEmitter.h"17#include "TargetInfo.h"18#include "clang/AST/Mangle.h"19#include "clang/AST/StmtCXX.h"20#include "clang/AST/StmtObjC.h"21#include "clang/AST/StmtVisitor.h"22#include "clang/Basic/DiagnosticSema.h"23#include "clang/Basic/TargetBuiltins.h"24#include "llvm/IR/IntrinsicInst.h"25#include "llvm/IR/Intrinsics.h"26#include "llvm/IR/IntrinsicsWebAssembly.h"27#include "llvm/Support/SaveAndRestore.h"2829using namespace clang;30using namespace CodeGen;3132static llvm::FunctionCallee getFreeExceptionFn(CodeGenModule &CGM) {33// void __cxa_free_exception(void *thrown_exception);3435llvm::FunctionType *FTy =36llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false);3738return CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");39}4041static llvm::FunctionCallee getSehTryBeginFn(CodeGenModule &CGM) {42llvm::FunctionType *FTy =43llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);44return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.begin");45}4647static llvm::FunctionCallee getSehTryEndFn(CodeGenModule &CGM) {48llvm::FunctionType *FTy =49llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);50return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end");51}5253static llvm::FunctionCallee getUnexpectedFn(CodeGenModule &CGM) {54// void __cxa_call_unexpected(void *thrown_exception);5556llvm::FunctionType *FTy =57llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false);5859return CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");60}6162llvm::FunctionCallee CodeGenModule::getTerminateFn() {63// void __terminate();6465llvm::FunctionType *FTy =66llvm::FunctionType::get(VoidTy, /*isVarArg=*/false);6768StringRef name;6970// In C++, use std::terminate().71if (getLangOpts().CPlusPlus &&72getTarget().getCXXABI().isItaniumFamily()) {73name = "_ZSt9terminatev";74} else if (getLangOpts().CPlusPlus &&75getTarget().getCXXABI().isMicrosoft()) {76if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015))77name = "__std_terminate";78else79name = "?terminate@@YAXXZ";80} else if (getLangOpts().ObjC &&81getLangOpts().ObjCRuntime.hasTerminate())82name = "objc_terminate";83else84name = "abort";85return CreateRuntimeFunction(FTy, name);86}8788static llvm::FunctionCallee getCatchallRethrowFn(CodeGenModule &CGM,89StringRef Name) {90llvm::FunctionType *FTy =91llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false);9293return CGM.CreateRuntimeFunction(FTy, Name);94}9596const EHPersonality EHPersonality::GNU_C = { "__gcc_personality_v0", nullptr };97const EHPersonality98EHPersonality::GNU_C_SJLJ = { "__gcc_personality_sj0", nullptr };99const EHPersonality100EHPersonality::GNU_C_SEH = { "__gcc_personality_seh0", nullptr };101const EHPersonality102EHPersonality::NeXT_ObjC = { "__objc_personality_v0", nullptr };103const EHPersonality104EHPersonality::GNU_CPlusPlus = { "__gxx_personality_v0", nullptr };105const EHPersonality106EHPersonality::GNU_CPlusPlus_SJLJ = { "__gxx_personality_sj0", nullptr };107const EHPersonality108EHPersonality::GNU_CPlusPlus_SEH = { "__gxx_personality_seh0", nullptr };109const EHPersonality110EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0", "objc_exception_throw"};111const EHPersonality112EHPersonality::GNU_ObjC_SJLJ = {"__gnu_objc_personality_sj0", "objc_exception_throw"};113const EHPersonality114EHPersonality::GNU_ObjC_SEH = {"__gnu_objc_personality_seh0", "objc_exception_throw"};115const EHPersonality116EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", nullptr };117const EHPersonality118EHPersonality::GNUstep_ObjC = { "__gnustep_objc_personality_v0", nullptr };119const EHPersonality120EHPersonality::MSVC_except_handler = { "_except_handler3", nullptr };121const EHPersonality122EHPersonality::MSVC_C_specific_handler = { "__C_specific_handler", nullptr };123const EHPersonality124EHPersonality::MSVC_CxxFrameHandler3 = { "__CxxFrameHandler3", nullptr };125const EHPersonality126EHPersonality::GNU_Wasm_CPlusPlus = { "__gxx_wasm_personality_v0", nullptr };127const EHPersonality EHPersonality::XL_CPlusPlus = {"__xlcxx_personality_v1",128nullptr};129const EHPersonality EHPersonality::ZOS_CPlusPlus = {"__zos_cxx_personality_v2",130nullptr};131132static const EHPersonality &getCPersonality(const TargetInfo &Target,133const LangOptions &L) {134const llvm::Triple &T = Target.getTriple();135if (T.isWindowsMSVCEnvironment())136return EHPersonality::MSVC_CxxFrameHandler3;137if (L.hasSjLjExceptions())138return EHPersonality::GNU_C_SJLJ;139if (L.hasDWARFExceptions())140return EHPersonality::GNU_C;141if (L.hasSEHExceptions())142return EHPersonality::GNU_C_SEH;143return EHPersonality::GNU_C;144}145146static const EHPersonality &getObjCPersonality(const TargetInfo &Target,147const LangOptions &L) {148const llvm::Triple &T = Target.getTriple();149if (T.isWindowsMSVCEnvironment())150return EHPersonality::MSVC_CxxFrameHandler3;151152switch (L.ObjCRuntime.getKind()) {153case ObjCRuntime::FragileMacOSX:154return getCPersonality(Target, L);155case ObjCRuntime::MacOSX:156case ObjCRuntime::iOS:157case ObjCRuntime::WatchOS:158return EHPersonality::NeXT_ObjC;159case ObjCRuntime::GNUstep:160if (T.isOSCygMing())161return EHPersonality::GNU_CPlusPlus_SEH;162else if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))163return EHPersonality::GNUstep_ObjC;164[[fallthrough]];165case ObjCRuntime::GCC:166case ObjCRuntime::ObjFW:167if (L.hasSjLjExceptions())168return EHPersonality::GNU_ObjC_SJLJ;169if (L.hasSEHExceptions())170return EHPersonality::GNU_ObjC_SEH;171return EHPersonality::GNU_ObjC;172}173llvm_unreachable("bad runtime kind");174}175176static const EHPersonality &getCXXPersonality(const TargetInfo &Target,177const LangOptions &L) {178const llvm::Triple &T = Target.getTriple();179if (T.isWindowsMSVCEnvironment())180return EHPersonality::MSVC_CxxFrameHandler3;181if (T.isOSAIX())182return EHPersonality::XL_CPlusPlus;183if (L.hasSjLjExceptions())184return EHPersonality::GNU_CPlusPlus_SJLJ;185if (L.hasDWARFExceptions())186return EHPersonality::GNU_CPlusPlus;187if (L.hasSEHExceptions())188return EHPersonality::GNU_CPlusPlus_SEH;189if (L.hasWasmExceptions())190return EHPersonality::GNU_Wasm_CPlusPlus;191if (T.isOSzOS())192return EHPersonality::ZOS_CPlusPlus;193return EHPersonality::GNU_CPlusPlus;194}195196/// Determines the personality function to use when both C++197/// and Objective-C exceptions are being caught.198static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target,199const LangOptions &L) {200if (Target.getTriple().isWindowsMSVCEnvironment())201return EHPersonality::MSVC_CxxFrameHandler3;202203switch (L.ObjCRuntime.getKind()) {204// In the fragile ABI, just use C++ exception handling and hope205// they're not doing crazy exception mixing.206case ObjCRuntime::FragileMacOSX:207return getCXXPersonality(Target, L);208209// The ObjC personality defers to the C++ personality for non-ObjC210// handlers. Unlike the C++ case, we use the same personality211// function on targets using (backend-driven) SJLJ EH.212case ObjCRuntime::MacOSX:213case ObjCRuntime::iOS:214case ObjCRuntime::WatchOS:215return getObjCPersonality(Target, L);216217case ObjCRuntime::GNUstep:218return Target.getTriple().isOSCygMing() ? EHPersonality::GNU_CPlusPlus_SEH219: EHPersonality::GNU_ObjCXX;220221// The GCC runtime's personality function inherently doesn't support222// mixed EH. Use the ObjC personality just to avoid returning null.223case ObjCRuntime::GCC:224case ObjCRuntime::ObjFW:225return getObjCPersonality(Target, L);226}227llvm_unreachable("bad runtime kind");228}229230static const EHPersonality &getSEHPersonalityMSVC(const llvm::Triple &T) {231if (T.getArch() == llvm::Triple::x86)232return EHPersonality::MSVC_except_handler;233return EHPersonality::MSVC_C_specific_handler;234}235236const EHPersonality &EHPersonality::get(CodeGenModule &CGM,237const FunctionDecl *FD) {238const llvm::Triple &T = CGM.getTarget().getTriple();239const LangOptions &L = CGM.getLangOpts();240const TargetInfo &Target = CGM.getTarget();241242// Functions using SEH get an SEH personality.243if (FD && FD->usesSEHTry())244return getSEHPersonalityMSVC(T);245246if (L.ObjC)247return L.CPlusPlus ? getObjCXXPersonality(Target, L)248: getObjCPersonality(Target, L);249return L.CPlusPlus ? getCXXPersonality(Target, L)250: getCPersonality(Target, L);251}252253const EHPersonality &EHPersonality::get(CodeGenFunction &CGF) {254const auto *FD = CGF.CurCodeDecl;255// For outlined finallys and filters, use the SEH personality in case they256// contain more SEH. This mostly only affects finallys. Filters could257// hypothetically use gnu statement expressions to sneak in nested SEH.258FD = FD ? FD : CGF.CurSEHParent.getDecl();259return get(CGF.CGM, dyn_cast_or_null<FunctionDecl>(FD));260}261262static llvm::FunctionCallee getPersonalityFn(CodeGenModule &CGM,263const EHPersonality &Personality) {264return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty, true),265Personality.PersonalityFn,266llvm::AttributeList(), /*Local=*/true);267}268269static llvm::Constant *getOpaquePersonalityFn(CodeGenModule &CGM,270const EHPersonality &Personality) {271llvm::FunctionCallee Fn = getPersonalityFn(CGM, Personality);272return cast<llvm::Constant>(Fn.getCallee());273}274275/// Check whether a landingpad instruction only uses C++ features.276static bool LandingPadHasOnlyCXXUses(llvm::LandingPadInst *LPI) {277for (unsigned I = 0, E = LPI->getNumClauses(); I != E; ++I) {278// Look for something that would've been returned by the ObjC279// runtime's GetEHType() method.280llvm::Value *Val = LPI->getClause(I)->stripPointerCasts();281if (LPI->isCatch(I)) {282// Check if the catch value has the ObjC prefix.283if (llvm::GlobalVariable *GV = dyn_cast<llvm::GlobalVariable>(Val))284// ObjC EH selector entries are always global variables with285// names starting like this.286if (GV->getName().starts_with("OBJC_EHTYPE"))287return false;288} else {289// Check if any of the filter values have the ObjC prefix.290llvm::Constant *CVal = cast<llvm::Constant>(Val);291for (llvm::User::op_iterator292II = CVal->op_begin(), IE = CVal->op_end(); II != IE; ++II) {293if (llvm::GlobalVariable *GV =294cast<llvm::GlobalVariable>((*II)->stripPointerCasts()))295// ObjC EH selector entries are always global variables with296// names starting like this.297if (GV->getName().starts_with("OBJC_EHTYPE"))298return false;299}300}301}302return true;303}304305/// Check whether a personality function could reasonably be swapped306/// for a C++ personality function.307static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) {308for (llvm::User *U : Fn->users()) {309// Conditionally white-list bitcasts.310if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(U)) {311if (CE->getOpcode() != llvm::Instruction::BitCast) return false;312if (!PersonalityHasOnlyCXXUses(CE))313return false;314continue;315}316317// Otherwise it must be a function.318llvm::Function *F = dyn_cast<llvm::Function>(U);319if (!F) return false;320321for (auto BB = F->begin(), E = F->end(); BB != E; ++BB) {322if (BB->isLandingPad())323if (!LandingPadHasOnlyCXXUses(BB->getLandingPadInst()))324return false;325}326}327328return true;329}330331/// Try to use the C++ personality function in ObjC++. Not doing this332/// can cause some incompatibilities with gcc, which is more333/// aggressive about only using the ObjC++ personality in a function334/// when it really needs it.335void CodeGenModule::SimplifyPersonality() {336// If we're not in ObjC++ -fexceptions, there's nothing to do.337if (!LangOpts.CPlusPlus || !LangOpts.ObjC || !LangOpts.Exceptions)338return;339340// Both the problem this endeavors to fix and the way the logic341// above works is specific to the NeXT runtime.342if (!LangOpts.ObjCRuntime.isNeXTFamily())343return;344345const EHPersonality &ObjCXX = EHPersonality::get(*this, /*FD=*/nullptr);346const EHPersonality &CXX = getCXXPersonality(getTarget(), LangOpts);347if (&ObjCXX == &CXX)348return;349350assert(std::strcmp(ObjCXX.PersonalityFn, CXX.PersonalityFn) != 0 &&351"Different EHPersonalities using the same personality function.");352353llvm::Function *Fn = getModule().getFunction(ObjCXX.PersonalityFn);354355// Nothing to do if it's unused.356if (!Fn || Fn->use_empty()) return;357358// Can't do the optimization if it has non-C++ uses.359if (!PersonalityHasOnlyCXXUses(Fn)) return;360361// Create the C++ personality function and kill off the old362// function.363llvm::FunctionCallee CXXFn = getPersonalityFn(*this, CXX);364365// This can happen if the user is screwing with us.366if (Fn->getType() != CXXFn.getCallee()->getType())367return;368369Fn->replaceAllUsesWith(CXXFn.getCallee());370Fn->eraseFromParent();371}372373/// Returns the value to inject into a selector to indicate the374/// presence of a catch-all.375static llvm::Constant *getCatchAllValue(CodeGenFunction &CGF) {376// Possibly we should use @llvm.eh.catch.all.value here.377return llvm::ConstantPointerNull::get(CGF.Int8PtrTy);378}379380namespace {381/// A cleanup to free the exception object if its initialization382/// throws.383struct FreeException final : EHScopeStack::Cleanup {384llvm::Value *exn;385FreeException(llvm::Value *exn) : exn(exn) {}386void Emit(CodeGenFunction &CGF, Flags flags) override {387CGF.EmitNounwindRuntimeCall(getFreeExceptionFn(CGF.CGM), exn);388}389};390} // end anonymous namespace391392// Emits an exception expression into the given location. This393// differs from EmitAnyExprToMem only in that, if a final copy-ctor394// call is required, an exception within that copy ctor causes395// std::terminate to be invoked.396void CodeGenFunction::EmitAnyExprToExn(const Expr *e, Address addr) {397// Make sure the exception object is cleaned up if there's an398// exception during initialization.399pushFullExprCleanup<FreeException>(EHCleanup, addr.emitRawPointer(*this));400EHScopeStack::stable_iterator cleanup = EHStack.stable_begin();401402// __cxa_allocate_exception returns a void*; we need to cast this403// to the appropriate type for the object.404llvm::Type *ty = ConvertTypeForMem(e->getType());405Address typedAddr = addr.withElementType(ty);406407// FIXME: this isn't quite right! If there's a final unelided call408// to a copy constructor, then according to [except.terminate]p1 we409// must call std::terminate() if that constructor throws, because410// technically that copy occurs after the exception expression is411// evaluated but before the exception is caught. But the best way412// to handle that is to teach EmitAggExpr to do the final copy413// differently if it can't be elided.414EmitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(),415/*IsInit*/ true);416417// Deactivate the cleanup block.418DeactivateCleanupBlock(419cleanup, cast<llvm::Instruction>(typedAddr.emitRawPointer(*this)));420}421422Address CodeGenFunction::getExceptionSlot() {423if (!ExceptionSlot)424ExceptionSlot = CreateTempAlloca(Int8PtrTy, "exn.slot");425return Address(ExceptionSlot, Int8PtrTy, getPointerAlign());426}427428Address CodeGenFunction::getEHSelectorSlot() {429if (!EHSelectorSlot)430EHSelectorSlot = CreateTempAlloca(Int32Ty, "ehselector.slot");431return Address(EHSelectorSlot, Int32Ty, CharUnits::fromQuantity(4));432}433434llvm::Value *CodeGenFunction::getExceptionFromSlot() {435return Builder.CreateLoad(getExceptionSlot(), "exn");436}437438llvm::Value *CodeGenFunction::getSelectorFromSlot() {439return Builder.CreateLoad(getEHSelectorSlot(), "sel");440}441442void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,443bool KeepInsertionPoint) {444// If the exception is being emitted in an OpenMP target region,445// and the target is a GPU, we do not support exception handling.446// Therefore, we emit a trap which will abort the program, and447// prompt a warning indicating that a trap will be emitted.448const llvm::Triple &T = Target.getTriple();449if (CGM.getLangOpts().OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN())) {450EmitTrapCall(llvm::Intrinsic::trap);451return;452}453if (const Expr *SubExpr = E->getSubExpr()) {454QualType ThrowType = SubExpr->getType();455if (ThrowType->isObjCObjectPointerType()) {456const Stmt *ThrowStmt = E->getSubExpr();457const ObjCAtThrowStmt S(E->getExprLoc(), const_cast<Stmt *>(ThrowStmt));458CGM.getObjCRuntime().EmitThrowStmt(*this, S, false);459} else {460CGM.getCXXABI().emitThrow(*this, E);461}462} else {463CGM.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true);464}465466// throw is an expression, and the expression emitters expect us467// to leave ourselves at a valid insertion point.468if (KeepInsertionPoint)469EmitBlock(createBasicBlock("throw.cont"));470}471472void CodeGenFunction::EmitStartEHSpec(const Decl *D) {473if (!CGM.getLangOpts().CXXExceptions)474return;475476const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);477if (!FD) {478// Check if CapturedDecl is nothrow and create terminate scope for it.479if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) {480if (CD->isNothrow())481EHStack.pushTerminate();482}483return;484}485const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>();486if (!Proto)487return;488489ExceptionSpecificationType EST = Proto->getExceptionSpecType();490// In C++17 and later, 'throw()' aka EST_DynamicNone is treated the same way491// as noexcept. In earlier standards, it is handled in this block, along with492// 'throw(X...)'.493if (EST == EST_Dynamic ||494(EST == EST_DynamicNone && !getLangOpts().CPlusPlus17)) {495// TODO: Revisit exception specifications for the MS ABI. There is a way to496// encode these in an object file but MSVC doesn't do anything with it.497if (getTarget().getCXXABI().isMicrosoft())498return;499// In Wasm EH we currently treat 'throw()' in the same way as 'noexcept'. In500// case of throw with types, we ignore it and print a warning for now.501// TODO Correctly handle exception specification in Wasm EH502if (CGM.getLangOpts().hasWasmExceptions()) {503if (EST == EST_DynamicNone)504EHStack.pushTerminate();505else506CGM.getDiags().Report(D->getLocation(),507diag::warn_wasm_dynamic_exception_spec_ignored)508<< FD->getExceptionSpecSourceRange();509return;510}511// Currently Emscripten EH only handles 'throw()' but not 'throw' with512// types. 'throw()' handling will be done in JS glue code so we don't need513// to do anything in that case. Just print a warning message in case of514// throw with types.515// TODO Correctly handle exception specification in Emscripten EH516if (getTarget().getCXXABI() == TargetCXXABI::WebAssembly &&517CGM.getLangOpts().getExceptionHandling() ==518LangOptions::ExceptionHandlingKind::None &&519EST == EST_Dynamic)520CGM.getDiags().Report(D->getLocation(),521diag::warn_wasm_dynamic_exception_spec_ignored)522<< FD->getExceptionSpecSourceRange();523524unsigned NumExceptions = Proto->getNumExceptions();525EHFilterScope *Filter = EHStack.pushFilter(NumExceptions);526527for (unsigned I = 0; I != NumExceptions; ++I) {528QualType Ty = Proto->getExceptionType(I);529QualType ExceptType = Ty.getNonReferenceType().getUnqualifiedType();530llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType,531/*ForEH=*/true);532Filter->setFilter(I, EHType);533}534} else if (Proto->canThrow() == CT_Cannot) {535// noexcept functions are simple terminate scopes.536if (!getLangOpts().EHAsynch) // -EHa: HW exception still can occur537EHStack.pushTerminate();538}539}540541/// Emit the dispatch block for a filter scope if necessary.542static void emitFilterDispatchBlock(CodeGenFunction &CGF,543EHFilterScope &filterScope) {544llvm::BasicBlock *dispatchBlock = filterScope.getCachedEHDispatchBlock();545if (!dispatchBlock) return;546if (dispatchBlock->use_empty()) {547delete dispatchBlock;548return;549}550551CGF.EmitBlockAfterUses(dispatchBlock);552553// If this isn't a catch-all filter, we need to check whether we got554// here because the filter triggered.555if (filterScope.getNumFilters()) {556// Load the selector value.557llvm::Value *selector = CGF.getSelectorFromSlot();558llvm::BasicBlock *unexpectedBB = CGF.createBasicBlock("ehspec.unexpected");559560llvm::Value *zero = CGF.Builder.getInt32(0);561llvm::Value *failsFilter =562CGF.Builder.CreateICmpSLT(selector, zero, "ehspec.fails");563CGF.Builder.CreateCondBr(failsFilter, unexpectedBB,564CGF.getEHResumeBlock(false));565566CGF.EmitBlock(unexpectedBB);567}568569// Call __cxa_call_unexpected. This doesn't need to be an invoke570// because __cxa_call_unexpected magically filters exceptions571// according to the last landing pad the exception was thrown572// into. Seriously.573llvm::Value *exn = CGF.getExceptionFromSlot();574CGF.EmitRuntimeCall(getUnexpectedFn(CGF.CGM), exn)575->setDoesNotReturn();576CGF.Builder.CreateUnreachable();577}578579void CodeGenFunction::EmitEndEHSpec(const Decl *D) {580if (!CGM.getLangOpts().CXXExceptions)581return;582583const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);584if (!FD) {585// Check if CapturedDecl is nothrow and pop terminate scope for it.586if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) {587if (CD->isNothrow() && !EHStack.empty())588EHStack.popTerminate();589}590return;591}592const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>();593if (!Proto)594return;595596ExceptionSpecificationType EST = Proto->getExceptionSpecType();597if (EST == EST_Dynamic ||598(EST == EST_DynamicNone && !getLangOpts().CPlusPlus17)) {599// TODO: Revisit exception specifications for the MS ABI. There is a way to600// encode these in an object file but MSVC doesn't do anything with it.601if (getTarget().getCXXABI().isMicrosoft())602return;603// In wasm we currently treat 'throw()' in the same way as 'noexcept'. In604// case of throw with types, we ignore it and print a warning for now.605// TODO Correctly handle exception specification in wasm606if (CGM.getLangOpts().hasWasmExceptions()) {607if (EST == EST_DynamicNone)608EHStack.popTerminate();609return;610}611EHFilterScope &filterScope = cast<EHFilterScope>(*EHStack.begin());612emitFilterDispatchBlock(*this, filterScope);613EHStack.popFilter();614} else if (Proto->canThrow() == CT_Cannot &&615/* possible empty when under async exceptions */616!EHStack.empty()) {617EHStack.popTerminate();618}619}620621void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {622const llvm::Triple &T = Target.getTriple();623// If we encounter a try statement on in an OpenMP target region offloaded to624// a GPU, we treat it as a basic block.625const bool IsTargetDevice =626(CGM.getLangOpts().OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN()));627if (!IsTargetDevice)628EnterCXXTryStmt(S);629EmitStmt(S.getTryBlock());630if (!IsTargetDevice)631ExitCXXTryStmt(S);632}633634void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {635unsigned NumHandlers = S.getNumHandlers();636EHCatchScope *CatchScope = EHStack.pushCatch(NumHandlers);637638for (unsigned I = 0; I != NumHandlers; ++I) {639const CXXCatchStmt *C = S.getHandler(I);640641llvm::BasicBlock *Handler = createBasicBlock("catch");642if (C->getExceptionDecl()) {643// FIXME: Dropping the reference type on the type into makes it644// impossible to correctly implement catch-by-reference645// semantics for pointers. Unfortunately, this is what all646// existing compilers do, and it's not clear that the standard647// personality routine is capable of doing this right. See C++ DR 388:648// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#388649Qualifiers CaughtTypeQuals;650QualType CaughtType = CGM.getContext().getUnqualifiedArrayType(651C->getCaughtType().getNonReferenceType(), CaughtTypeQuals);652653CatchTypeInfo TypeInfo{nullptr, 0};654if (CaughtType->isObjCObjectPointerType())655TypeInfo.RTTI = CGM.getObjCRuntime().GetEHType(CaughtType);656else657TypeInfo = CGM.getCXXABI().getAddrOfCXXCatchHandlerType(658CaughtType, C->getCaughtType());659CatchScope->setHandler(I, TypeInfo, Handler);660} else {661// No exception decl indicates '...', a catch-all.662CatchScope->setHandler(I, CGM.getCXXABI().getCatchAllTypeInfo(), Handler);663// Under async exceptions, catch(...) need to catch HW exception too664// Mark scope with SehTryBegin as a SEH __try scope665if (getLangOpts().EHAsynch)666EmitSehTryScopeBegin();667}668}669}670671llvm::BasicBlock *672CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) {673if (EHPersonality::get(*this).usesFuncletPads())674return getFuncletEHDispatchBlock(si);675676// The dispatch block for the end of the scope chain is a block that677// just resumes unwinding.678if (si == EHStack.stable_end())679return getEHResumeBlock(true);680681// Otherwise, we should look at the actual scope.682EHScope &scope = *EHStack.find(si);683684llvm::BasicBlock *dispatchBlock = scope.getCachedEHDispatchBlock();685if (!dispatchBlock) {686switch (scope.getKind()) {687case EHScope::Catch: {688// Apply a special case to a single catch-all.689EHCatchScope &catchScope = cast<EHCatchScope>(scope);690if (catchScope.getNumHandlers() == 1 &&691catchScope.getHandler(0).isCatchAll()) {692dispatchBlock = catchScope.getHandler(0).Block;693694// Otherwise, make a dispatch block.695} else {696dispatchBlock = createBasicBlock("catch.dispatch");697}698break;699}700701case EHScope::Cleanup:702dispatchBlock = createBasicBlock("ehcleanup");703break;704705case EHScope::Filter:706dispatchBlock = createBasicBlock("filter.dispatch");707break;708709case EHScope::Terminate:710dispatchBlock = getTerminateHandler();711break;712}713scope.setCachedEHDispatchBlock(dispatchBlock);714}715return dispatchBlock;716}717718llvm::BasicBlock *719CodeGenFunction::getFuncletEHDispatchBlock(EHScopeStack::stable_iterator SI) {720// Returning nullptr indicates that the previous dispatch block should unwind721// to caller.722if (SI == EHStack.stable_end())723return nullptr;724725// Otherwise, we should look at the actual scope.726EHScope &EHS = *EHStack.find(SI);727728llvm::BasicBlock *DispatchBlock = EHS.getCachedEHDispatchBlock();729if (DispatchBlock)730return DispatchBlock;731732if (EHS.getKind() == EHScope::Terminate)733DispatchBlock = getTerminateFunclet();734else735DispatchBlock = createBasicBlock();736CGBuilderTy Builder(*this, DispatchBlock);737738switch (EHS.getKind()) {739case EHScope::Catch:740DispatchBlock->setName("catch.dispatch");741break;742743case EHScope::Cleanup:744DispatchBlock->setName("ehcleanup");745break;746747case EHScope::Filter:748llvm_unreachable("exception specifications not handled yet!");749750case EHScope::Terminate:751DispatchBlock->setName("terminate");752break;753}754EHS.setCachedEHDispatchBlock(DispatchBlock);755return DispatchBlock;756}757758/// Check whether this is a non-EH scope, i.e. a scope which doesn't759/// affect exception handling. Currently, the only non-EH scopes are760/// normal-only cleanup scopes.761static bool isNonEHScope(const EHScope &S) {762switch (S.getKind()) {763case EHScope::Cleanup:764return !cast<EHCleanupScope>(S).isEHCleanup();765case EHScope::Filter:766case EHScope::Catch:767case EHScope::Terminate:768return false;769}770771llvm_unreachable("Invalid EHScope Kind!");772}773774llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() {775assert(EHStack.requiresLandingPad());776assert(!EHStack.empty());777778// If exceptions are disabled/ignored and SEH is not in use, then there is no779// invoke destination. SEH "works" even if exceptions are off. In practice,780// this means that C++ destructors and other EH cleanups don't run, which is781// consistent with MSVC's behavior, except in the presence of -EHa782const LangOptions &LO = CGM.getLangOpts();783if (!LO.Exceptions || LO.IgnoreExceptions) {784if (!LO.Borland && !LO.MicrosoftExt)785return nullptr;786if (!currentFunctionUsesSEHTry())787return nullptr;788}789790// CUDA device code doesn't have exceptions.791if (LO.CUDA && LO.CUDAIsDevice)792return nullptr;793794// Check the innermost scope for a cached landing pad. If this is795// a non-EH cleanup, we'll check enclosing scopes in EmitLandingPad.796llvm::BasicBlock *LP = EHStack.begin()->getCachedLandingPad();797if (LP) return LP;798799const EHPersonality &Personality = EHPersonality::get(*this);800801if (!CurFn->hasPersonalityFn())802CurFn->setPersonalityFn(getOpaquePersonalityFn(CGM, Personality));803804if (Personality.usesFuncletPads()) {805// We don't need separate landing pads in the funclet model.806LP = getEHDispatchBlock(EHStack.getInnermostEHScope());807} else {808// Build the landing pad for this scope.809LP = EmitLandingPad();810}811812assert(LP);813814// Cache the landing pad on the innermost scope. If this is a815// non-EH scope, cache the landing pad on the enclosing scope, too.816for (EHScopeStack::iterator ir = EHStack.begin(); true; ++ir) {817ir->setCachedLandingPad(LP);818if (!isNonEHScope(*ir)) break;819}820821return LP;822}823824llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {825assert(EHStack.requiresLandingPad());826assert(!CGM.getLangOpts().IgnoreExceptions &&827"LandingPad should not be emitted when -fignore-exceptions are in "828"effect.");829EHScope &innermostEHScope = *EHStack.find(EHStack.getInnermostEHScope());830switch (innermostEHScope.getKind()) {831case EHScope::Terminate:832return getTerminateLandingPad();833834case EHScope::Catch:835case EHScope::Cleanup:836case EHScope::Filter:837if (llvm::BasicBlock *lpad = innermostEHScope.getCachedLandingPad())838return lpad;839}840841// Save the current IR generation state.842CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP();843auto DL = ApplyDebugLocation::CreateDefaultArtificial(*this, CurEHLocation);844845// Create and configure the landing pad.846llvm::BasicBlock *lpad = createBasicBlock("lpad");847EmitBlock(lpad);848849llvm::LandingPadInst *LPadInst =850Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty), 0);851852llvm::Value *LPadExn = Builder.CreateExtractValue(LPadInst, 0);853Builder.CreateStore(LPadExn, getExceptionSlot());854llvm::Value *LPadSel = Builder.CreateExtractValue(LPadInst, 1);855Builder.CreateStore(LPadSel, getEHSelectorSlot());856857// Save the exception pointer. It's safe to use a single exception858// pointer per function because EH cleanups can never have nested859// try/catches.860// Build the landingpad instruction.861862// Accumulate all the handlers in scope.863bool hasCatchAll = false;864bool hasCleanup = false;865bool hasFilter = false;866SmallVector<llvm::Value*, 4> filterTypes;867llvm::SmallPtrSet<llvm::Value*, 4> catchTypes;868for (EHScopeStack::iterator I = EHStack.begin(), E = EHStack.end(); I != E;869++I) {870871switch (I->getKind()) {872case EHScope::Cleanup:873// If we have a cleanup, remember that.874hasCleanup = (hasCleanup || cast<EHCleanupScope>(*I).isEHCleanup());875continue;876877case EHScope::Filter: {878assert(I.next() == EHStack.end() && "EH filter is not end of EH stack");879assert(!hasCatchAll && "EH filter reached after catch-all");880881// Filter scopes get added to the landingpad in weird ways.882EHFilterScope &filter = cast<EHFilterScope>(*I);883hasFilter = true;884885// Add all the filter values.886for (unsigned i = 0, e = filter.getNumFilters(); i != e; ++i)887filterTypes.push_back(filter.getFilter(i));888goto done;889}890891case EHScope::Terminate:892// Terminate scopes are basically catch-alls.893assert(!hasCatchAll);894hasCatchAll = true;895goto done;896897case EHScope::Catch:898break;899}900901EHCatchScope &catchScope = cast<EHCatchScope>(*I);902for (unsigned hi = 0, he = catchScope.getNumHandlers(); hi != he; ++hi) {903EHCatchScope::Handler handler = catchScope.getHandler(hi);904assert(handler.Type.Flags == 0 &&905"landingpads do not support catch handler flags");906907// If this is a catch-all, register that and abort.908if (!handler.Type.RTTI) {909assert(!hasCatchAll);910hasCatchAll = true;911goto done;912}913914// Check whether we already have a handler for this type.915if (catchTypes.insert(handler.Type.RTTI).second)916// If not, add it directly to the landingpad.917LPadInst->addClause(handler.Type.RTTI);918}919}920921done:922// If we have a catch-all, add null to the landingpad.923assert(!(hasCatchAll && hasFilter));924if (hasCatchAll) {925LPadInst->addClause(getCatchAllValue(*this));926927// If we have an EH filter, we need to add those handlers in the928// right place in the landingpad, which is to say, at the end.929} else if (hasFilter) {930// Create a filter expression: a constant array indicating which filter931// types there are. The personality routine only lands here if the filter932// doesn't match.933SmallVector<llvm::Constant*, 8> Filters;934llvm::ArrayType *AType =935llvm::ArrayType::get(!filterTypes.empty() ?936filterTypes[0]->getType() : Int8PtrTy,937filterTypes.size());938939for (unsigned i = 0, e = filterTypes.size(); i != e; ++i)940Filters.push_back(cast<llvm::Constant>(filterTypes[i]));941llvm::Constant *FilterArray = llvm::ConstantArray::get(AType, Filters);942LPadInst->addClause(FilterArray);943944// Also check whether we need a cleanup.945if (hasCleanup)946LPadInst->setCleanup(true);947948// Otherwise, signal that we at least have cleanups.949} else if (hasCleanup) {950LPadInst->setCleanup(true);951}952953assert((LPadInst->getNumClauses() > 0 || LPadInst->isCleanup()) &&954"landingpad instruction has no clauses!");955956// Tell the backend how to generate the landing pad.957Builder.CreateBr(getEHDispatchBlock(EHStack.getInnermostEHScope()));958959// Restore the old IR generation state.960Builder.restoreIP(savedIP);961962return lpad;963}964965static void emitCatchPadBlock(CodeGenFunction &CGF, EHCatchScope &CatchScope) {966llvm::BasicBlock *DispatchBlock = CatchScope.getCachedEHDispatchBlock();967assert(DispatchBlock);968969CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveIP();970CGF.EmitBlockAfterUses(DispatchBlock);971972llvm::Value *ParentPad = CGF.CurrentFuncletPad;973if (!ParentPad)974ParentPad = llvm::ConstantTokenNone::get(CGF.getLLVMContext());975llvm::BasicBlock *UnwindBB =976CGF.getEHDispatchBlock(CatchScope.getEnclosingEHScope());977978unsigned NumHandlers = CatchScope.getNumHandlers();979llvm::CatchSwitchInst *CatchSwitch =980CGF.Builder.CreateCatchSwitch(ParentPad, UnwindBB, NumHandlers);981982// Test against each of the exception types we claim to catch.983for (unsigned I = 0; I < NumHandlers; ++I) {984const EHCatchScope::Handler &Handler = CatchScope.getHandler(I);985986CatchTypeInfo TypeInfo = Handler.Type;987if (!TypeInfo.RTTI)988TypeInfo.RTTI = llvm::Constant::getNullValue(CGF.VoidPtrTy);989990CGF.Builder.SetInsertPoint(Handler.Block);991992if (EHPersonality::get(CGF).isMSVCXXPersonality()) {993CGF.Builder.CreateCatchPad(994CatchSwitch, {TypeInfo.RTTI, CGF.Builder.getInt32(TypeInfo.Flags),995llvm::Constant::getNullValue(CGF.VoidPtrTy)});996} else {997CGF.Builder.CreateCatchPad(CatchSwitch, {TypeInfo.RTTI});998}9991000CatchSwitch->addHandler(Handler.Block);1001}1002CGF.Builder.restoreIP(SavedIP);1003}10041005// Wasm uses Windows-style EH instructions, but it merges all catch clauses into1006// one big catchpad, within which we use Itanium's landingpad-style selector1007// comparison instructions.1008static void emitWasmCatchPadBlock(CodeGenFunction &CGF,1009EHCatchScope &CatchScope) {1010llvm::BasicBlock *DispatchBlock = CatchScope.getCachedEHDispatchBlock();1011assert(DispatchBlock);10121013CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveIP();1014CGF.EmitBlockAfterUses(DispatchBlock);10151016llvm::Value *ParentPad = CGF.CurrentFuncletPad;1017if (!ParentPad)1018ParentPad = llvm::ConstantTokenNone::get(CGF.getLLVMContext());1019llvm::BasicBlock *UnwindBB =1020CGF.getEHDispatchBlock(CatchScope.getEnclosingEHScope());10211022unsigned NumHandlers = CatchScope.getNumHandlers();1023llvm::CatchSwitchInst *CatchSwitch =1024CGF.Builder.CreateCatchSwitch(ParentPad, UnwindBB, NumHandlers);10251026// We don't use a landingpad instruction, so generate intrinsic calls to1027// provide exception and selector values.1028llvm::BasicBlock *WasmCatchStartBlock = CGF.createBasicBlock("catch.start");1029CatchSwitch->addHandler(WasmCatchStartBlock);1030CGF.EmitBlockAfterUses(WasmCatchStartBlock);10311032// Create a catchpad instruction.1033SmallVector<llvm::Value *, 4> CatchTypes;1034for (unsigned I = 0, E = NumHandlers; I < E; ++I) {1035const EHCatchScope::Handler &Handler = CatchScope.getHandler(I);1036CatchTypeInfo TypeInfo = Handler.Type;1037if (!TypeInfo.RTTI)1038TypeInfo.RTTI = llvm::Constant::getNullValue(CGF.VoidPtrTy);1039CatchTypes.push_back(TypeInfo.RTTI);1040}1041auto *CPI = CGF.Builder.CreateCatchPad(CatchSwitch, CatchTypes);10421043// Create calls to wasm.get.exception and wasm.get.ehselector intrinsics.1044// Before they are lowered appropriately later, they provide values for the1045// exception and selector.1046llvm::Function *GetExnFn =1047CGF.CGM.getIntrinsic(llvm::Intrinsic::wasm_get_exception);1048llvm::Function *GetSelectorFn =1049CGF.CGM.getIntrinsic(llvm::Intrinsic::wasm_get_ehselector);1050llvm::CallInst *Exn = CGF.Builder.CreateCall(GetExnFn, CPI);1051CGF.Builder.CreateStore(Exn, CGF.getExceptionSlot());1052llvm::CallInst *Selector = CGF.Builder.CreateCall(GetSelectorFn, CPI);10531054llvm::Function *TypeIDFn =1055CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for, {CGF.VoidPtrTy});10561057// If there's only a single catch-all, branch directly to its handler.1058if (CatchScope.getNumHandlers() == 1 &&1059CatchScope.getHandler(0).isCatchAll()) {1060CGF.Builder.CreateBr(CatchScope.getHandler(0).Block);1061CGF.Builder.restoreIP(SavedIP);1062return;1063}10641065// Test against each of the exception types we claim to catch.1066for (unsigned I = 0, E = NumHandlers;; ++I) {1067assert(I < E && "ran off end of handlers!");1068const EHCatchScope::Handler &Handler = CatchScope.getHandler(I);1069CatchTypeInfo TypeInfo = Handler.Type;1070if (!TypeInfo.RTTI)1071TypeInfo.RTTI = llvm::Constant::getNullValue(CGF.VoidPtrTy);10721073// Figure out the next block.1074llvm::BasicBlock *NextBlock;10751076bool EmitNextBlock = false, NextIsEnd = false;10771078// If this is the last handler, we're at the end, and the next block is a1079// block that contains a call to the rethrow function, so we can unwind to1080// the enclosing EH scope. The call itself will be generated later.1081if (I + 1 == E) {1082NextBlock = CGF.createBasicBlock("rethrow");1083EmitNextBlock = true;1084NextIsEnd = true;10851086// If the next handler is a catch-all, we're at the end, and the1087// next block is that handler.1088} else if (CatchScope.getHandler(I + 1).isCatchAll()) {1089NextBlock = CatchScope.getHandler(I + 1).Block;1090NextIsEnd = true;10911092// Otherwise, we're not at the end and we need a new block.1093} else {1094NextBlock = CGF.createBasicBlock("catch.fallthrough");1095EmitNextBlock = true;1096}10971098// Figure out the catch type's index in the LSDA's type table.1099llvm::CallInst *TypeIndex = CGF.Builder.CreateCall(TypeIDFn, TypeInfo.RTTI);1100TypeIndex->setDoesNotThrow();11011102llvm::Value *MatchesTypeIndex =1103CGF.Builder.CreateICmpEQ(Selector, TypeIndex, "matches");1104CGF.Builder.CreateCondBr(MatchesTypeIndex, Handler.Block, NextBlock);11051106if (EmitNextBlock)1107CGF.EmitBlock(NextBlock);1108if (NextIsEnd)1109break;1110}11111112CGF.Builder.restoreIP(SavedIP);1113}11141115/// Emit the structure of the dispatch block for the given catch scope.1116/// It is an invariant that the dispatch block already exists.1117static void emitCatchDispatchBlock(CodeGenFunction &CGF,1118EHCatchScope &catchScope) {1119if (EHPersonality::get(CGF).isWasmPersonality())1120return emitWasmCatchPadBlock(CGF, catchScope);1121if (EHPersonality::get(CGF).usesFuncletPads())1122return emitCatchPadBlock(CGF, catchScope);11231124llvm::BasicBlock *dispatchBlock = catchScope.getCachedEHDispatchBlock();1125assert(dispatchBlock);11261127// If there's only a single catch-all, getEHDispatchBlock returned1128// that catch-all as the dispatch block.1129if (catchScope.getNumHandlers() == 1 &&1130catchScope.getHandler(0).isCatchAll()) {1131assert(dispatchBlock == catchScope.getHandler(0).Block);1132return;1133}11341135CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveIP();1136CGF.EmitBlockAfterUses(dispatchBlock);11371138// Select the right handler.1139llvm::Function *llvm_eh_typeid_for =1140CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for, {CGF.VoidPtrTy});1141llvm::Type *argTy = llvm_eh_typeid_for->getArg(0)->getType();1142LangAS globAS = CGF.CGM.GetGlobalVarAddressSpace(nullptr);11431144// Load the selector value.1145llvm::Value *selector = CGF.getSelectorFromSlot();11461147// Test against each of the exception types we claim to catch.1148for (unsigned i = 0, e = catchScope.getNumHandlers(); ; ++i) {1149assert(i < e && "ran off end of handlers!");1150const EHCatchScope::Handler &handler = catchScope.getHandler(i);11511152llvm::Value *typeValue = handler.Type.RTTI;1153assert(handler.Type.Flags == 0 &&1154"landingpads do not support catch handler flags");1155assert(typeValue && "fell into catch-all case!");1156// With opaque ptrs, only the address space can be a mismatch.1157if (typeValue->getType() != argTy)1158typeValue =1159CGF.getTargetHooks().performAddrSpaceCast(CGF, typeValue, globAS,1160LangAS::Default, argTy);11611162// Figure out the next block.1163bool nextIsEnd;1164llvm::BasicBlock *nextBlock;11651166// If this is the last handler, we're at the end, and the next1167// block is the block for the enclosing EH scope.1168if (i + 1 == e) {1169nextBlock = CGF.getEHDispatchBlock(catchScope.getEnclosingEHScope());1170nextIsEnd = true;11711172// If the next handler is a catch-all, we're at the end, and the1173// next block is that handler.1174} else if (catchScope.getHandler(i+1).isCatchAll()) {1175nextBlock = catchScope.getHandler(i+1).Block;1176nextIsEnd = true;11771178// Otherwise, we're not at the end and we need a new block.1179} else {1180nextBlock = CGF.createBasicBlock("catch.fallthrough");1181nextIsEnd = false;1182}11831184// Figure out the catch type's index in the LSDA's type table.1185llvm::CallInst *typeIndex =1186CGF.Builder.CreateCall(llvm_eh_typeid_for, typeValue);1187typeIndex->setDoesNotThrow();11881189llvm::Value *matchesTypeIndex =1190CGF.Builder.CreateICmpEQ(selector, typeIndex, "matches");1191CGF.Builder.CreateCondBr(matchesTypeIndex, handler.Block, nextBlock);11921193// If the next handler is a catch-all, we're completely done.1194if (nextIsEnd) {1195CGF.Builder.restoreIP(savedIP);1196return;1197}1198// Otherwise we need to emit and continue at that block.1199CGF.EmitBlock(nextBlock);1200}1201}12021203void CodeGenFunction::popCatchScope() {1204EHCatchScope &catchScope = cast<EHCatchScope>(*EHStack.begin());1205if (catchScope.hasEHBranches())1206emitCatchDispatchBlock(*this, catchScope);1207EHStack.popCatch();1208}12091210void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {1211unsigned NumHandlers = S.getNumHandlers();1212EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin());1213assert(CatchScope.getNumHandlers() == NumHandlers);1214llvm::BasicBlock *DispatchBlock = CatchScope.getCachedEHDispatchBlock();12151216// If the catch was not required, bail out now.1217if (!CatchScope.hasEHBranches()) {1218CatchScope.clearHandlerBlocks();1219EHStack.popCatch();1220return;1221}12221223// Emit the structure of the EH dispatch for this catch.1224emitCatchDispatchBlock(*this, CatchScope);12251226// Copy the handler blocks off before we pop the EH stack. Emitting1227// the handlers might scribble on this memory.1228SmallVector<EHCatchScope::Handler, 8> Handlers(1229CatchScope.begin(), CatchScope.begin() + NumHandlers);12301231EHStack.popCatch();12321233// The fall-through block.1234llvm::BasicBlock *ContBB = createBasicBlock("try.cont");12351236// We just emitted the body of the try; jump to the continue block.1237if (HaveInsertPoint())1238Builder.CreateBr(ContBB);12391240// Determine if we need an implicit rethrow for all these catch handlers;1241// see the comment below.1242bool doImplicitRethrow = false;1243if (IsFnTryBlock)1244doImplicitRethrow = isa<CXXDestructorDecl>(CurCodeDecl) ||1245isa<CXXConstructorDecl>(CurCodeDecl);12461247// Wasm uses Windows-style EH instructions, but merges all catch clauses into1248// one big catchpad. So we save the old funclet pad here before we traverse1249// each catch handler.1250SaveAndRestore RestoreCurrentFuncletPad(CurrentFuncletPad);1251llvm::BasicBlock *WasmCatchStartBlock = nullptr;1252if (EHPersonality::get(*this).isWasmPersonality()) {1253auto *CatchSwitch =1254cast<llvm::CatchSwitchInst>(DispatchBlock->getFirstNonPHI());1255WasmCatchStartBlock = CatchSwitch->hasUnwindDest()1256? CatchSwitch->getSuccessor(1)1257: CatchSwitch->getSuccessor(0);1258auto *CPI = cast<llvm::CatchPadInst>(WasmCatchStartBlock->getFirstNonPHI());1259CurrentFuncletPad = CPI;1260}12611262// Perversely, we emit the handlers backwards precisely because we1263// want them to appear in source order. In all of these cases, the1264// catch block will have exactly one predecessor, which will be a1265// particular block in the catch dispatch. However, in the case of1266// a catch-all, one of the dispatch blocks will branch to two1267// different handlers, and EmitBlockAfterUses will cause the second1268// handler to be moved before the first.1269bool HasCatchAll = false;1270for (unsigned I = NumHandlers; I != 0; --I) {1271HasCatchAll |= Handlers[I - 1].isCatchAll();1272llvm::BasicBlock *CatchBlock = Handlers[I-1].Block;1273EmitBlockAfterUses(CatchBlock);12741275// Catch the exception if this isn't a catch-all.1276const CXXCatchStmt *C = S.getHandler(I-1);12771278// Enter a cleanup scope, including the catch variable and the1279// end-catch.1280RunCleanupsScope CatchScope(*this);12811282// Initialize the catch variable and set up the cleanups.1283SaveAndRestore RestoreCurrentFuncletPad(CurrentFuncletPad);1284CGM.getCXXABI().emitBeginCatch(*this, C);12851286// Emit the PGO counter increment.1287incrementProfileCounter(C);12881289// Perform the body of the catch.1290EmitStmt(C->getHandlerBlock());12911292// [except.handle]p11:1293// The currently handled exception is rethrown if control1294// reaches the end of a handler of the function-try-block of a1295// constructor or destructor.12961297// It is important that we only do this on fallthrough and not on1298// return. Note that it's illegal to put a return in a1299// constructor function-try-block's catch handler (p14), so this1300// really only applies to destructors.1301if (doImplicitRethrow && HaveInsertPoint()) {1302CGM.getCXXABI().emitRethrow(*this, /*isNoReturn*/false);1303Builder.CreateUnreachable();1304Builder.ClearInsertionPoint();1305}13061307// Fall out through the catch cleanups.1308CatchScope.ForceCleanup();13091310// Branch out of the try.1311if (HaveInsertPoint())1312Builder.CreateBr(ContBB);1313}13141315// Because in wasm we merge all catch clauses into one big catchpad, in case1316// none of the types in catch handlers matches after we test against each of1317// them, we should unwind to the next EH enclosing scope. We generate a call1318// to rethrow function here to do that.1319if (EHPersonality::get(*this).isWasmPersonality() && !HasCatchAll) {1320assert(WasmCatchStartBlock);1321// Navigate for the "rethrow" block we created in emitWasmCatchPadBlock().1322// Wasm uses landingpad-style conditional branches to compare selectors, so1323// we follow the false destination for each of the cond branches to reach1324// the rethrow block.1325llvm::BasicBlock *RethrowBlock = WasmCatchStartBlock;1326while (llvm::Instruction *TI = RethrowBlock->getTerminator()) {1327auto *BI = cast<llvm::BranchInst>(TI);1328assert(BI->isConditional());1329RethrowBlock = BI->getSuccessor(1);1330}1331assert(RethrowBlock != WasmCatchStartBlock && RethrowBlock->empty());1332Builder.SetInsertPoint(RethrowBlock);1333llvm::Function *RethrowInCatchFn =1334CGM.getIntrinsic(llvm::Intrinsic::wasm_rethrow);1335EmitNoreturnRuntimeCallOrInvoke(RethrowInCatchFn, {});1336}13371338EmitBlock(ContBB);1339incrementProfileCounter(&S);1340}13411342namespace {1343struct CallEndCatchForFinally final : EHScopeStack::Cleanup {1344llvm::Value *ForEHVar;1345llvm::FunctionCallee EndCatchFn;1346CallEndCatchForFinally(llvm::Value *ForEHVar,1347llvm::FunctionCallee EndCatchFn)1348: ForEHVar(ForEHVar), EndCatchFn(EndCatchFn) {}13491350void Emit(CodeGenFunction &CGF, Flags flags) override {1351llvm::BasicBlock *EndCatchBB = CGF.createBasicBlock("finally.endcatch");1352llvm::BasicBlock *CleanupContBB =1353CGF.createBasicBlock("finally.cleanup.cont");13541355llvm::Value *ShouldEndCatch =1356CGF.Builder.CreateFlagLoad(ForEHVar, "finally.endcatch");1357CGF.Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB);1358CGF.EmitBlock(EndCatchBB);1359CGF.EmitRuntimeCallOrInvoke(EndCatchFn); // catch-all, so might throw1360CGF.EmitBlock(CleanupContBB);1361}1362};13631364struct PerformFinally final : EHScopeStack::Cleanup {1365const Stmt *Body;1366llvm::Value *ForEHVar;1367llvm::FunctionCallee EndCatchFn;1368llvm::FunctionCallee RethrowFn;1369llvm::Value *SavedExnVar;13701371PerformFinally(const Stmt *Body, llvm::Value *ForEHVar,1372llvm::FunctionCallee EndCatchFn,1373llvm::FunctionCallee RethrowFn, llvm::Value *SavedExnVar)1374: Body(Body), ForEHVar(ForEHVar), EndCatchFn(EndCatchFn),1375RethrowFn(RethrowFn), SavedExnVar(SavedExnVar) {}13761377void Emit(CodeGenFunction &CGF, Flags flags) override {1378// Enter a cleanup to call the end-catch function if one was provided.1379if (EndCatchFn)1380CGF.EHStack.pushCleanup<CallEndCatchForFinally>(NormalAndEHCleanup,1381ForEHVar, EndCatchFn);13821383// Save the current cleanup destination in case there are1384// cleanups in the finally block.1385llvm::Value *SavedCleanupDest =1386CGF.Builder.CreateLoad(CGF.getNormalCleanupDestSlot(),1387"cleanup.dest.saved");13881389// Emit the finally block.1390CGF.EmitStmt(Body);13911392// If the end of the finally is reachable, check whether this was1393// for EH. If so, rethrow.1394if (CGF.HaveInsertPoint()) {1395llvm::BasicBlock *RethrowBB = CGF.createBasicBlock("finally.rethrow");1396llvm::BasicBlock *ContBB = CGF.createBasicBlock("finally.cont");13971398llvm::Value *ShouldRethrow =1399CGF.Builder.CreateFlagLoad(ForEHVar, "finally.shouldthrow");1400CGF.Builder.CreateCondBr(ShouldRethrow, RethrowBB, ContBB);14011402CGF.EmitBlock(RethrowBB);1403if (SavedExnVar) {1404CGF.EmitRuntimeCallOrInvoke(RethrowFn,1405CGF.Builder.CreateAlignedLoad(CGF.Int8PtrTy, SavedExnVar,1406CGF.getPointerAlign()));1407} else {1408CGF.EmitRuntimeCallOrInvoke(RethrowFn);1409}1410CGF.Builder.CreateUnreachable();14111412CGF.EmitBlock(ContBB);14131414// Restore the cleanup destination.1415CGF.Builder.CreateStore(SavedCleanupDest,1416CGF.getNormalCleanupDestSlot());1417}14181419// Leave the end-catch cleanup. As an optimization, pretend that1420// the fallthrough path was inaccessible; we've dynamically proven1421// that we're not in the EH case along that path.1422if (EndCatchFn) {1423CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();1424CGF.PopCleanupBlock();1425CGF.Builder.restoreIP(SavedIP);1426}14271428// Now make sure we actually have an insertion point or the1429// cleanup gods will hate us.1430CGF.EnsureInsertPoint();1431}1432};1433} // end anonymous namespace14341435/// Enters a finally block for an implementation using zero-cost1436/// exceptions. This is mostly general, but hard-codes some1437/// language/ABI-specific behavior in the catch-all sections.1438void CodeGenFunction::FinallyInfo::enter(CodeGenFunction &CGF, const Stmt *body,1439llvm::FunctionCallee beginCatchFn,1440llvm::FunctionCallee endCatchFn,1441llvm::FunctionCallee rethrowFn) {1442assert((!!beginCatchFn) == (!!endCatchFn) &&1443"begin/end catch functions not paired");1444assert(rethrowFn && "rethrow function is required");14451446BeginCatchFn = beginCatchFn;14471448// The rethrow function has one of the following two types:1449// void (*)()1450// void (*)(void*)1451// In the latter case we need to pass it the exception object.1452// But we can't use the exception slot because the @finally might1453// have a landing pad (which would overwrite the exception slot).1454llvm::FunctionType *rethrowFnTy = rethrowFn.getFunctionType();1455SavedExnVar = nullptr;1456if (rethrowFnTy->getNumParams())1457SavedExnVar = CGF.CreateTempAlloca(CGF.Int8PtrTy, "finally.exn");14581459// A finally block is a statement which must be executed on any edge1460// out of a given scope. Unlike a cleanup, the finally block may1461// contain arbitrary control flow leading out of itself. In1462// addition, finally blocks should always be executed, even if there1463// are no catch handlers higher on the stack. Therefore, we1464// surround the protected scope with a combination of a normal1465// cleanup (to catch attempts to break out of the block via normal1466// control flow) and an EH catch-all (semantically "outside" any try1467// statement to which the finally block might have been attached).1468// The finally block itself is generated in the context of a cleanup1469// which conditionally leaves the catch-all.14701471// Jump destination for performing the finally block on an exception1472// edge. We'll never actually reach this block, so unreachable is1473// fine.1474RethrowDest = CGF.getJumpDestInCurrentScope(CGF.getUnreachableBlock());14751476// Whether the finally block is being executed for EH purposes.1477ForEHVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), "finally.for-eh");1478CGF.Builder.CreateFlagStore(false, ForEHVar);14791480// Enter a normal cleanup which will perform the @finally block.1481CGF.EHStack.pushCleanup<PerformFinally>(NormalCleanup, body,1482ForEHVar, endCatchFn,1483rethrowFn, SavedExnVar);14841485// Enter a catch-all scope.1486llvm::BasicBlock *catchBB = CGF.createBasicBlock("finally.catchall");1487EHCatchScope *catchScope = CGF.EHStack.pushCatch(1);1488catchScope->setCatchAllHandler(0, catchBB);1489}14901491void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) {1492// Leave the finally catch-all.1493EHCatchScope &catchScope = cast<EHCatchScope>(*CGF.EHStack.begin());1494llvm::BasicBlock *catchBB = catchScope.getHandler(0).Block;14951496CGF.popCatchScope();14971498// If there are any references to the catch-all block, emit it.1499if (catchBB->use_empty()) {1500delete catchBB;1501} else {1502CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveAndClearIP();1503CGF.EmitBlock(catchBB);15041505llvm::Value *exn = nullptr;15061507// If there's a begin-catch function, call it.1508if (BeginCatchFn) {1509exn = CGF.getExceptionFromSlot();1510CGF.EmitNounwindRuntimeCall(BeginCatchFn, exn);1511}15121513// If we need to remember the exception pointer to rethrow later, do so.1514if (SavedExnVar) {1515if (!exn) exn = CGF.getExceptionFromSlot();1516CGF.Builder.CreateAlignedStore(exn, SavedExnVar, CGF.getPointerAlign());1517}15181519// Tell the cleanups in the finally block that we're do this for EH.1520CGF.Builder.CreateFlagStore(true, ForEHVar);15211522// Thread a jump through the finally cleanup.1523CGF.EmitBranchThroughCleanup(RethrowDest);15241525CGF.Builder.restoreIP(savedIP);1526}15271528// Finally, leave the @finally cleanup.1529CGF.PopCleanupBlock();1530}15311532llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {1533if (TerminateLandingPad)1534return TerminateLandingPad;15351536CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();15371538// This will get inserted at the end of the function.1539TerminateLandingPad = createBasicBlock("terminate.lpad");1540Builder.SetInsertPoint(TerminateLandingPad);15411542// Tell the backend that this is a landing pad.1543const EHPersonality &Personality = EHPersonality::get(*this);15441545if (!CurFn->hasPersonalityFn())1546CurFn->setPersonalityFn(getOpaquePersonalityFn(CGM, Personality));15471548llvm::LandingPadInst *LPadInst =1549Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty), 0);1550LPadInst->addClause(getCatchAllValue(*this));15511552llvm::Value *Exn = nullptr;1553if (getLangOpts().CPlusPlus)1554Exn = Builder.CreateExtractValue(LPadInst, 0);1555llvm::CallInst *terminateCall =1556CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn);1557terminateCall->setDoesNotReturn();1558Builder.CreateUnreachable();15591560// Restore the saved insertion state.1561Builder.restoreIP(SavedIP);15621563return TerminateLandingPad;1564}15651566llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {1567if (TerminateHandler)1568return TerminateHandler;15691570// Set up the terminate handler. This block is inserted at the very1571// end of the function by FinishFunction.1572TerminateHandler = createBasicBlock("terminate.handler");1573CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();1574Builder.SetInsertPoint(TerminateHandler);15751576llvm::Value *Exn = nullptr;1577if (getLangOpts().CPlusPlus)1578Exn = getExceptionFromSlot();1579llvm::CallInst *terminateCall =1580CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn);1581terminateCall->setDoesNotReturn();1582Builder.CreateUnreachable();15831584// Restore the saved insertion state.1585Builder.restoreIP(SavedIP);15861587return TerminateHandler;1588}15891590llvm::BasicBlock *CodeGenFunction::getTerminateFunclet() {1591assert(EHPersonality::get(*this).usesFuncletPads() &&1592"use getTerminateLandingPad for non-funclet EH");15931594llvm::BasicBlock *&TerminateFunclet = TerminateFunclets[CurrentFuncletPad];1595if (TerminateFunclet)1596return TerminateFunclet;15971598CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();15991600// Set up the terminate handler. This block is inserted at the very1601// end of the function by FinishFunction.1602TerminateFunclet = createBasicBlock("terminate.handler");1603Builder.SetInsertPoint(TerminateFunclet);16041605// Create the cleanuppad using the current parent pad as its token. Use 'none'1606// if this is a top-level terminate scope, which is the common case.1607SaveAndRestore RestoreCurrentFuncletPad(CurrentFuncletPad);1608llvm::Value *ParentPad = CurrentFuncletPad;1609if (!ParentPad)1610ParentPad = llvm::ConstantTokenNone::get(CGM.getLLVMContext());1611CurrentFuncletPad = Builder.CreateCleanupPad(ParentPad);16121613// Emit the __std_terminate call.1614llvm::CallInst *terminateCall =1615CGM.getCXXABI().emitTerminateForUnexpectedException(*this, nullptr);1616terminateCall->setDoesNotReturn();1617Builder.CreateUnreachable();16181619// Restore the saved insertion state.1620Builder.restoreIP(SavedIP);16211622return TerminateFunclet;1623}16241625llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {1626if (EHResumeBlock) return EHResumeBlock;16271628CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();16291630// We emit a jump to a notional label at the outermost unwind state.1631EHResumeBlock = createBasicBlock("eh.resume");1632Builder.SetInsertPoint(EHResumeBlock);16331634const EHPersonality &Personality = EHPersonality::get(*this);16351636// This can always be a call because we necessarily didn't find1637// anything on the EH stack which needs our help.1638const char *RethrowName = Personality.CatchallRethrowFn;1639if (RethrowName != nullptr && !isCleanup) {1640EmitRuntimeCall(getCatchallRethrowFn(CGM, RethrowName),1641getExceptionFromSlot())->setDoesNotReturn();1642Builder.CreateUnreachable();1643Builder.restoreIP(SavedIP);1644return EHResumeBlock;1645}16461647// Recreate the landingpad's return value for the 'resume' instruction.1648llvm::Value *Exn = getExceptionFromSlot();1649llvm::Value *Sel = getSelectorFromSlot();16501651llvm::Type *LPadType = llvm::StructType::get(Exn->getType(), Sel->getType());1652llvm::Value *LPadVal = llvm::PoisonValue::get(LPadType);1653LPadVal = Builder.CreateInsertValue(LPadVal, Exn, 0, "lpad.val");1654LPadVal = Builder.CreateInsertValue(LPadVal, Sel, 1, "lpad.val");16551656Builder.CreateResume(LPadVal);1657Builder.restoreIP(SavedIP);1658return EHResumeBlock;1659}16601661void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {1662EnterSEHTryStmt(S);1663{1664JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave");16651666SEHTryEpilogueStack.push_back(&TryExit);16671668llvm::BasicBlock *TryBB = nullptr;1669// IsEHa: emit an invoke to _seh_try_begin() runtime for -EHa1670if (getLangOpts().EHAsynch) {1671EmitRuntimeCallOrInvoke(getSehTryBeginFn(CGM));1672if (SEHTryEpilogueStack.size() == 1) // outermost only1673TryBB = Builder.GetInsertBlock();1674}16751676EmitStmt(S.getTryBlock());16771678// Volatilize all blocks in Try, till current insert point1679if (TryBB) {1680llvm::SmallPtrSet<llvm::BasicBlock *, 10> Visited;1681VolatilizeTryBlocks(TryBB, Visited);1682}16831684SEHTryEpilogueStack.pop_back();16851686if (!TryExit.getBlock()->use_empty())1687EmitBlock(TryExit.getBlock(), /*IsFinished=*/true);1688else1689delete TryExit.getBlock();1690}1691ExitSEHTryStmt(S);1692}16931694// Recursively walk through blocks in a _try1695// and make all memory instructions volatile1696void CodeGenFunction::VolatilizeTryBlocks(1697llvm::BasicBlock *BB, llvm::SmallPtrSet<llvm::BasicBlock *, 10> &V) {1698if (BB == SEHTryEpilogueStack.back()->getBlock() /* end of Try */ ||1699!V.insert(BB).second /* already visited */ ||1700!BB->getParent() /* not emitted */ || BB->empty())1701return;17021703if (!BB->isEHPad()) {1704for (llvm::BasicBlock::iterator J = BB->begin(), JE = BB->end(); J != JE;1705++J) {1706if (auto LI = dyn_cast<llvm::LoadInst>(J)) {1707LI->setVolatile(true);1708} else if (auto SI = dyn_cast<llvm::StoreInst>(J)) {1709SI->setVolatile(true);1710} else if (auto* MCI = dyn_cast<llvm::MemIntrinsic>(J)) {1711MCI->setVolatile(llvm::ConstantInt::get(Builder.getInt1Ty(), 1));1712}1713}1714}1715const llvm::Instruction *TI = BB->getTerminator();1716if (TI) {1717unsigned N = TI->getNumSuccessors();1718for (unsigned I = 0; I < N; I++)1719VolatilizeTryBlocks(TI->getSuccessor(I), V);1720}1721}17221723namespace {1724struct PerformSEHFinally final : EHScopeStack::Cleanup {1725llvm::Function *OutlinedFinally;1726PerformSEHFinally(llvm::Function *OutlinedFinally)1727: OutlinedFinally(OutlinedFinally) {}17281729void Emit(CodeGenFunction &CGF, Flags F) override {1730ASTContext &Context = CGF.getContext();1731CodeGenModule &CGM = CGF.CGM;17321733CallArgList Args;17341735// Compute the two argument values.1736QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy};1737llvm::Value *FP = nullptr;1738// If CFG.IsOutlinedSEHHelper is true, then we are within a finally block.1739if (CGF.IsOutlinedSEHHelper) {1740FP = &CGF.CurFn->arg_begin()[1];1741} else {1742llvm::Function *LocalAddrFn =1743CGM.getIntrinsic(llvm::Intrinsic::localaddress);1744FP = CGF.Builder.CreateCall(LocalAddrFn);1745}17461747llvm::Value *IsForEH =1748llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());17491750// Except _leave and fall-through at the end, all other exits in a _try1751// (return/goto/continue/break) are considered as abnormal terminations1752// since _leave/fall-through is always Indexed 0,1753// just use NormalCleanupDestSlot (>= 1 for goto/return/..),1754// as 1st Arg to indicate abnormal termination1755if (!F.isForEHCleanup() && F.hasExitSwitch()) {1756Address Addr = CGF.getNormalCleanupDestSlot();1757llvm::Value *Load = CGF.Builder.CreateLoad(Addr, "cleanup.dest");1758llvm::Value *Zero = llvm::Constant::getNullValue(CGM.Int32Ty);1759IsForEH = CGF.Builder.CreateICmpNE(Load, Zero);1760}17611762Args.add(RValue::get(IsForEH), ArgTys[0]);1763Args.add(RValue::get(FP), ArgTys[1]);17641765// Arrange a two-arg function info and type.1766const CGFunctionInfo &FnInfo =1767CGM.getTypes().arrangeBuiltinFunctionCall(Context.VoidTy, Args);17681769auto Callee = CGCallee::forDirect(OutlinedFinally);1770CGF.EmitCall(FnInfo, Callee, ReturnValueSlot(), Args);1771}1772};1773} // end anonymous namespace17741775namespace {1776/// Find all local variable captures in the statement.1777struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {1778CodeGenFunction &ParentCGF;1779const VarDecl *ParentThis;1780llvm::SmallSetVector<const VarDecl *, 4> Captures;1781Address SEHCodeSlot = Address::invalid();1782CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis)1783: ParentCGF(ParentCGF), ParentThis(ParentThis) {}17841785// Return true if we need to do any capturing work.1786bool foundCaptures() {1787return !Captures.empty() || SEHCodeSlot.isValid();1788}17891790void Visit(const Stmt *S) {1791// See if this is a capture, then recurse.1792ConstStmtVisitor<CaptureFinder>::Visit(S);1793for (const Stmt *Child : S->children())1794if (Child)1795Visit(Child);1796}17971798void VisitDeclRefExpr(const DeclRefExpr *E) {1799// If this is already a capture, just make sure we capture 'this'.1800if (E->refersToEnclosingVariableOrCapture())1801Captures.insert(ParentThis);18021803const auto *D = dyn_cast<VarDecl>(E->getDecl());1804if (D && D->isLocalVarDeclOrParm() && D->hasLocalStorage())1805Captures.insert(D);1806}18071808void VisitCXXThisExpr(const CXXThisExpr *E) {1809Captures.insert(ParentThis);1810}18111812void VisitCallExpr(const CallExpr *E) {1813// We only need to add parent frame allocations for these builtins in x86.1814if (ParentCGF.getTarget().getTriple().getArch() != llvm::Triple::x86)1815return;18161817unsigned ID = E->getBuiltinCallee();1818switch (ID) {1819case Builtin::BI__exception_code:1820case Builtin::BI_exception_code:1821// This is the simple case where we are the outermost finally. All we1822// have to do here is make sure we escape this and recover it in the1823// outlined handler.1824if (!SEHCodeSlot.isValid())1825SEHCodeSlot = ParentCGF.SEHCodeSlotStack.back();1826break;1827}1828}1829};1830} // end anonymous namespace18311832Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF,1833Address ParentVar,1834llvm::Value *ParentFP) {1835llvm::CallInst *RecoverCall = nullptr;1836CGBuilderTy Builder(*this, AllocaInsertPt);1837if (auto *ParentAlloca =1838dyn_cast_or_null<llvm::AllocaInst>(ParentVar.getBasePointer())) {1839// Mark the variable escaped if nobody else referenced it and compute the1840// localescape index.1841auto InsertPair = ParentCGF.EscapedLocals.insert(1842std::make_pair(ParentAlloca, ParentCGF.EscapedLocals.size()));1843int FrameEscapeIdx = InsertPair.first->second;1844// call ptr @llvm.localrecover(ptr @parentFn, ptr %fp, i32 N)1845llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration(1846&CGM.getModule(), llvm::Intrinsic::localrecover);1847RecoverCall = Builder.CreateCall(1848FrameRecoverFn, {ParentCGF.CurFn, ParentFP,1849llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)});18501851} else {1852// If the parent didn't have an alloca, we're doing some nested outlining.1853// Just clone the existing localrecover call, but tweak the FP argument to1854// use our FP value. All other arguments are constants.1855auto *ParentRecover = cast<llvm::IntrinsicInst>(1856ParentVar.emitRawPointer(*this)->stripPointerCasts());1857assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::localrecover &&1858"expected alloca or localrecover in parent LocalDeclMap");1859RecoverCall = cast<llvm::CallInst>(ParentRecover->clone());1860RecoverCall->setArgOperand(1, ParentFP);1861RecoverCall->insertBefore(AllocaInsertPt);1862}18631864// Bitcast the variable, rename it, and insert it in the local decl map.1865llvm::Value *ChildVar =1866Builder.CreateBitCast(RecoverCall, ParentVar.getType());1867ChildVar->setName(ParentVar.getName());1868return ParentVar.withPointer(ChildVar, KnownNonNull);1869}18701871void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,1872const Stmt *OutlinedStmt,1873bool IsFilter) {1874// Find all captures in the Stmt.1875CaptureFinder Finder(ParentCGF, ParentCGF.CXXABIThisDecl);1876Finder.Visit(OutlinedStmt);18771878// We can exit early on x86_64 when there are no captures. We just have to1879// save the exception code in filters so that __exception_code() works.1880if (!Finder.foundCaptures() &&1881CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) {1882if (IsFilter)1883EmitSEHExceptionCodeSave(ParentCGF, nullptr, nullptr);1884return;1885}18861887llvm::Value *EntryFP = nullptr;1888CGBuilderTy Builder(CGM, AllocaInsertPt);1889if (IsFilter && CGM.getTarget().getTriple().getArch() == llvm::Triple::x86) {1890// 32-bit SEH filters need to be careful about FP recovery. The end of the1891// EH registration is passed in as the EBP physical register. We can1892// recover that with llvm.frameaddress(1).1893EntryFP = Builder.CreateCall(1894CGM.getIntrinsic(llvm::Intrinsic::frameaddress, AllocaInt8PtrTy),1895{Builder.getInt32(1)});1896} else {1897// Otherwise, for x64 and 32-bit finally functions, the parent FP is the1898// second parameter.1899auto AI = CurFn->arg_begin();1900++AI;1901EntryFP = &*AI;1902}19031904llvm::Value *ParentFP = EntryFP;1905if (IsFilter) {1906// Given whatever FP the runtime provided us in EntryFP, recover the true1907// frame pointer of the parent function. We only need to do this in filters,1908// since finally funclets recover the parent FP for us.1909llvm::Function *RecoverFPIntrin =1910CGM.getIntrinsic(llvm::Intrinsic::eh_recoverfp);1911ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentCGF.CurFn, EntryFP});19121913// if the parent is a _finally, the passed-in ParentFP is the FP1914// of parent _finally, not Establisher's FP (FP of outermost function).1915// Establkisher FP is 2nd paramenter passed into parent _finally.1916// Fortunately, it's always saved in parent's frame. The following1917// code retrieves it, and escapes it so that spill instruction won't be1918// optimized away.1919if (ParentCGF.ParentCGF != nullptr) {1920// Locate and escape Parent's frame_pointer.addr alloca1921// Depending on target, should be 1st/2nd one in LocalDeclMap.1922// Let's just scan for ImplicitParamDecl with VoidPtrTy.1923llvm::AllocaInst *FramePtrAddrAlloca = nullptr;1924for (auto &I : ParentCGF.LocalDeclMap) {1925const VarDecl *D = cast<VarDecl>(I.first);1926if (isa<ImplicitParamDecl>(D) &&1927D->getType() == getContext().VoidPtrTy) {1928assert(D->getName().starts_with("frame_pointer"));1929FramePtrAddrAlloca =1930cast<llvm::AllocaInst>(I.second.getBasePointer());1931break;1932}1933}1934assert(FramePtrAddrAlloca);1935auto InsertPair = ParentCGF.EscapedLocals.insert(1936std::make_pair(FramePtrAddrAlloca, ParentCGF.EscapedLocals.size()));1937int FrameEscapeIdx = InsertPair.first->second;19381939// an example of a filter's prolog::1940// %0 = call ptr @llvm.eh.recoverfp(@"?fin$0@0@main@@",..)1941// %1 = call ptr @llvm.localrecover(@"?fin$0@0@main@@",..)1942// %2 = load ptr, ptr %1, align 81943// ==> %2 is the frame-pointer of outermost host function1944llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration(1945&CGM.getModule(), llvm::Intrinsic::localrecover);1946ParentFP = Builder.CreateCall(1947FrameRecoverFn, {ParentCGF.CurFn, ParentFP,1948llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)});1949ParentFP = Builder.CreateLoad(1950Address(ParentFP, CGM.VoidPtrTy, getPointerAlign()));1951}1952}19531954// Create llvm.localrecover calls for all captures.1955for (const VarDecl *VD : Finder.Captures) {1956if (VD->getType()->isVariablyModifiedType()) {1957CGM.ErrorUnsupported(VD, "VLA captured by SEH");1958continue;1959}1960assert((isa<ImplicitParamDecl>(VD) || VD->isLocalVarDeclOrParm()) &&1961"captured non-local variable");19621963auto L = ParentCGF.LambdaCaptureFields.find(VD);1964if (L != ParentCGF.LambdaCaptureFields.end()) {1965LambdaCaptureFields[VD] = L->second;1966continue;1967}19681969// If this decl hasn't been declared yet, it will be declared in the1970// OutlinedStmt.1971auto I = ParentCGF.LocalDeclMap.find(VD);1972if (I == ParentCGF.LocalDeclMap.end())1973continue;19741975Address ParentVar = I->second;1976Address Recovered =1977recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP);1978setAddrOfLocalVar(VD, Recovered);19791980if (isa<ImplicitParamDecl>(VD)) {1981CXXABIThisAlignment = ParentCGF.CXXABIThisAlignment;1982CXXThisAlignment = ParentCGF.CXXThisAlignment;1983CXXABIThisValue = Builder.CreateLoad(Recovered, "this");1984if (ParentCGF.LambdaThisCaptureField) {1985LambdaThisCaptureField = ParentCGF.LambdaThisCaptureField;1986// We are in a lambda function where "this" is captured so the1987// CXXThisValue need to be loaded from the lambda capture1988LValue ThisFieldLValue =1989EmitLValueForLambdaField(LambdaThisCaptureField);1990if (!LambdaThisCaptureField->getType()->isPointerType()) {1991CXXThisValue = ThisFieldLValue.getAddress().emitRawPointer(*this);1992} else {1993CXXThisValue = EmitLoadOfLValue(ThisFieldLValue, SourceLocation())1994.getScalarVal();1995}1996} else {1997CXXThisValue = CXXABIThisValue;1998}1999}2000}20012002if (Finder.SEHCodeSlot.isValid()) {2003SEHCodeSlotStack.push_back(2004recoverAddrOfEscapedLocal(ParentCGF, Finder.SEHCodeSlot, ParentFP));2005}20062007if (IsFilter)2008EmitSEHExceptionCodeSave(ParentCGF, ParentFP, EntryFP);2009}20102011/// Arrange a function prototype that can be called by Windows exception2012/// handling personalities. On Win64, the prototype looks like:2013/// RetTy func(void *EHPtrs, void *ParentFP);2014void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,2015bool IsFilter,2016const Stmt *OutlinedStmt) {2017SourceLocation StartLoc = OutlinedStmt->getBeginLoc();20182019// Get the mangled function name.2020SmallString<128> Name;2021{2022llvm::raw_svector_ostream OS(Name);2023GlobalDecl ParentSEHFn = ParentCGF.CurSEHParent;2024assert(ParentSEHFn && "No CurSEHParent!");2025MangleContext &Mangler = CGM.getCXXABI().getMangleContext();2026if (IsFilter)2027Mangler.mangleSEHFilterExpression(ParentSEHFn, OS);2028else2029Mangler.mangleSEHFinallyBlock(ParentSEHFn, OS);2030}20312032FunctionArgList Args;2033if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 || !IsFilter) {2034// All SEH finally functions take two parameters. Win64 filters take two2035// parameters. Win32 filters take no parameters.2036if (IsFilter) {2037Args.push_back(ImplicitParamDecl::Create(2038getContext(), /*DC=*/nullptr, StartLoc,2039&getContext().Idents.get("exception_pointers"),2040getContext().VoidPtrTy, ImplicitParamKind::Other));2041} else {2042Args.push_back(ImplicitParamDecl::Create(2043getContext(), /*DC=*/nullptr, StartLoc,2044&getContext().Idents.get("abnormal_termination"),2045getContext().UnsignedCharTy, ImplicitParamKind::Other));2046}2047Args.push_back(ImplicitParamDecl::Create(2048getContext(), /*DC=*/nullptr, StartLoc,2049&getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy,2050ImplicitParamKind::Other));2051}20522053QualType RetTy = IsFilter ? getContext().LongTy : getContext().VoidTy;20542055const CGFunctionInfo &FnInfo =2056CGM.getTypes().arrangeBuiltinFunctionDeclaration(RetTy, Args);20572058llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);2059llvm::Function *Fn = llvm::Function::Create(2060FnTy, llvm::GlobalValue::InternalLinkage, Name.str(), &CGM.getModule());20612062IsOutlinedSEHHelper = true;20632064StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,2065OutlinedStmt->getBeginLoc(), OutlinedStmt->getBeginLoc());2066CurSEHParent = ParentCGF.CurSEHParent;20672068CGM.SetInternalFunctionAttributes(GlobalDecl(), CurFn, FnInfo);2069EmitCapturedLocals(ParentCGF, OutlinedStmt, IsFilter);2070}20712072/// Create a stub filter function that will ultimately hold the code of the2073/// filter expression. The EH preparation passes in LLVM will outline the code2074/// from the main function body into this stub.2075llvm::Function *2076CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,2077const SEHExceptStmt &Except) {2078const Expr *FilterExpr = Except.getFilterExpr();2079startOutlinedSEHHelper(ParentCGF, true, FilterExpr);20802081// Emit the original filter expression, convert to i32, and return.2082llvm::Value *R = EmitScalarExpr(FilterExpr);2083R = Builder.CreateIntCast(R, ConvertType(getContext().LongTy),2084FilterExpr->getType()->isSignedIntegerType());2085Builder.CreateStore(R, ReturnValue);20862087FinishFunction(FilterExpr->getEndLoc());20882089return CurFn;2090}20912092llvm::Function *2093CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,2094const SEHFinallyStmt &Finally) {2095const Stmt *FinallyBlock = Finally.getBlock();2096startOutlinedSEHHelper(ParentCGF, false, FinallyBlock);20972098// Emit the original filter expression, convert to i32, and return.2099EmitStmt(FinallyBlock);21002101FinishFunction(FinallyBlock->getEndLoc());21022103return CurFn;2104}21052106void CodeGenFunction::EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF,2107llvm::Value *ParentFP,2108llvm::Value *EntryFP) {2109// Get the pointer to the EXCEPTION_POINTERS struct. This is returned by the2110// __exception_info intrinsic.2111if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) {2112// On Win64, the info is passed as the first parameter to the filter.2113SEHInfo = &*CurFn->arg_begin();2114SEHCodeSlotStack.push_back(2115CreateMemTemp(getContext().IntTy, "__exception_code"));2116} else {2117// On Win32, the EBP on entry to the filter points to the end of an2118// exception registration object. It contains 6 32-bit fields, and the info2119// pointer is stored in the second field. So, GEP 20 bytes backwards and2120// load the pointer.2121SEHInfo = Builder.CreateConstInBoundsGEP1_32(Int8Ty, EntryFP, -20);2122SEHInfo = Builder.CreateAlignedLoad(Int8PtrTy, SEHInfo, getPointerAlign());2123SEHCodeSlotStack.push_back(recoverAddrOfEscapedLocal(2124ParentCGF, ParentCGF.SEHCodeSlotStack.back(), ParentFP));2125}21262127// Save the exception code in the exception slot to unify exception access in2128// the filter function and the landing pad.2129// struct EXCEPTION_POINTERS {2130// EXCEPTION_RECORD *ExceptionRecord;2131// CONTEXT *ContextRecord;2132// };2133// int exceptioncode = exception_pointers->ExceptionRecord->ExceptionCode;2134llvm::Type *RecordTy = llvm::PointerType::getUnqual(getLLVMContext());2135llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy);2136llvm::Value *Rec = Builder.CreateStructGEP(PtrsTy, SEHInfo, 0);2137Rec = Builder.CreateAlignedLoad(RecordTy, Rec, getPointerAlign());2138llvm::Value *Code = Builder.CreateAlignedLoad(Int32Ty, Rec, getIntAlign());2139assert(!SEHCodeSlotStack.empty() && "emitting EH code outside of __except");2140Builder.CreateStore(Code, SEHCodeSlotStack.back());2141}21422143llvm::Value *CodeGenFunction::EmitSEHExceptionInfo() {2144// Sema should diagnose calling this builtin outside of a filter context, but2145// don't crash if we screw up.2146if (!SEHInfo)2147return llvm::UndefValue::get(Int8PtrTy);2148assert(SEHInfo->getType() == Int8PtrTy);2149return SEHInfo;2150}21512152llvm::Value *CodeGenFunction::EmitSEHExceptionCode() {2153assert(!SEHCodeSlotStack.empty() && "emitting EH code outside of __except");2154return Builder.CreateLoad(SEHCodeSlotStack.back());2155}21562157llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {2158// Abnormal termination is just the first parameter to the outlined finally2159// helper.2160auto AI = CurFn->arg_begin();2161return Builder.CreateZExt(&*AI, Int32Ty);2162}21632164void CodeGenFunction::pushSEHCleanup(CleanupKind Kind,2165llvm::Function *FinallyFunc) {2166EHStack.pushCleanup<PerformSEHFinally>(Kind, FinallyFunc);2167}21682169void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {2170CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);2171HelperCGF.ParentCGF = this;2172if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {2173// Outline the finally block.2174llvm::Function *FinallyFunc =2175HelperCGF.GenerateSEHFinallyFunction(*this, *Finally);21762177// Push a cleanup for __finally blocks.2178EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc);2179return;2180}21812182// Otherwise, we must have an __except block.2183const SEHExceptStmt *Except = S.getExceptHandler();2184assert(Except);2185EHCatchScope *CatchScope = EHStack.pushCatch(1);2186SEHCodeSlotStack.push_back(2187CreateMemTemp(getContext().IntTy, "__exception_code"));21882189// If the filter is known to evaluate to 1, then we can use the clause2190// "catch i8* null". We can't do this on x86 because the filter has to save2191// the exception code.2192llvm::Constant *C =2193ConstantEmitter(*this).tryEmitAbstract(Except->getFilterExpr(),2194getContext().IntTy);2195if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 && C &&2196C->isOneValue()) {2197CatchScope->setCatchAllHandler(0, createBasicBlock("__except"));2198return;2199}22002201// In general, we have to emit an outlined filter function. Use the function2202// in place of the RTTI typeinfo global that C++ EH uses.2203llvm::Function *FilterFunc =2204HelperCGF.GenerateSEHFilterFunction(*this, *Except);2205CatchScope->setHandler(0, FilterFunc, createBasicBlock("__except.ret"));2206}22072208void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {2209// Just pop the cleanup if it's a __finally block.2210if (S.getFinallyHandler()) {2211PopCleanupBlock();2212return;2213}22142215// IsEHa: emit an invoke _seh_try_end() to mark end of FT flow2216if (getLangOpts().EHAsynch && Builder.GetInsertBlock()) {2217llvm::FunctionCallee SehTryEnd = getSehTryEndFn(CGM);2218EmitRuntimeCallOrInvoke(SehTryEnd);2219}22202221// Otherwise, we must have an __except block.2222const SEHExceptStmt *Except = S.getExceptHandler();2223assert(Except && "__try must have __finally xor __except");2224EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin());22252226// Don't emit the __except block if the __try block lacked invokes.2227// TODO: Model unwind edges from instructions, either with iload / istore or2228// a try body function.2229if (!CatchScope.hasEHBranches()) {2230CatchScope.clearHandlerBlocks();2231EHStack.popCatch();2232SEHCodeSlotStack.pop_back();2233return;2234}22352236// The fall-through block.2237llvm::BasicBlock *ContBB = createBasicBlock("__try.cont");22382239// We just emitted the body of the __try; jump to the continue block.2240if (HaveInsertPoint())2241Builder.CreateBr(ContBB);22422243// Check if our filter function returned true.2244emitCatchDispatchBlock(*this, CatchScope);22452246// Grab the block before we pop the handler.2247llvm::BasicBlock *CatchPadBB = CatchScope.getHandler(0).Block;2248EHStack.popCatch();22492250EmitBlockAfterUses(CatchPadBB);22512252// __except blocks don't get outlined into funclets, so immediately do a2253// catchret.2254llvm::CatchPadInst *CPI =2255cast<llvm::CatchPadInst>(CatchPadBB->getFirstNonPHI());2256llvm::BasicBlock *ExceptBB = createBasicBlock("__except");2257Builder.CreateCatchRet(CPI, ExceptBB);2258EmitBlock(ExceptBB);22592260// On Win64, the exception code is returned in EAX. Copy it into the slot.2261if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) {2262llvm::Function *SEHCodeIntrin =2263CGM.getIntrinsic(llvm::Intrinsic::eh_exceptioncode);2264llvm::Value *Code = Builder.CreateCall(SEHCodeIntrin, {CPI});2265Builder.CreateStore(Code, SEHCodeSlotStack.back());2266}22672268// Emit the __except body.2269EmitStmt(Except->getBlock());22702271// End the lifetime of the exception code.2272SEHCodeSlotStack.pop_back();22732274if (HaveInsertPoint())2275Builder.CreateBr(ContBB);22762277EmitBlock(ContBB);2278}22792280void CodeGenFunction::EmitSEHLeaveStmt(const SEHLeaveStmt &S) {2281// If this code is reachable then emit a stop point (if generating2282// debug info). We have to do this ourselves because we are on the2283// "simple" statement path.2284if (HaveInsertPoint())2285EmitStopPoint(&S);22862287// This must be a __leave from a __finally block, which we warn on and is UB.2288// Just emit unreachable.2289if (!isSEHTryScope()) {2290Builder.CreateUnreachable();2291Builder.ClearInsertionPoint();2292return;2293}22942295EmitBranchThroughCleanup(*SEHTryEpilogueStack.back());2296}229722982299