|  | //===-- CGCleanup.h - Classes for cleanups IR generation --------*- C++ -*-===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // These classes support the generation of LLVM IR for cleanups. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef LLVM_CLANG_LIB_CODEGEN_CGCLEANUP_H | 
|  | #define LLVM_CLANG_LIB_CODEGEN_CGCLEANUP_H | 
|  |  | 
|  | #include "EHScopeStack.h" | 
|  |  | 
|  | #include "Address.h" | 
|  | #include "llvm/ADT/SmallPtrSet.h" | 
|  | #include "llvm/ADT/SmallVector.h" | 
|  |  | 
|  | namespace llvm { | 
|  | class BasicBlock; | 
|  | class Value; | 
|  | class ConstantInt; | 
|  | class AllocaInst; | 
|  | } | 
|  |  | 
|  | namespace clang { | 
|  | class FunctionDecl; | 
|  | namespace CodeGen { | 
|  | class CodeGenModule; | 
|  | class CodeGenFunction; | 
|  |  | 
|  | /// The MS C++ ABI needs a pointer to RTTI data plus some flags to describe the | 
|  | /// type of a catch handler, so we use this wrapper. | 
|  | struct CatchTypeInfo { | 
|  | llvm::Constant *RTTI; | 
|  | unsigned Flags; | 
|  | }; | 
|  |  | 
|  | /// A protected scope for zero-cost EH handling. | 
|  | class EHScope { | 
|  | llvm::BasicBlock *CachedLandingPad; | 
|  | llvm::BasicBlock *CachedEHDispatchBlock; | 
|  |  | 
|  | EHScopeStack::stable_iterator EnclosingEHScope; | 
|  |  | 
|  | class CommonBitFields { | 
|  | friend class EHScope; | 
|  | unsigned Kind : 3; | 
|  | }; | 
|  | enum { NumCommonBits = 3 }; | 
|  |  | 
|  | protected: | 
|  | class CatchBitFields { | 
|  | friend class EHCatchScope; | 
|  | unsigned : NumCommonBits; | 
|  |  | 
|  | unsigned NumHandlers : 32 - NumCommonBits; | 
|  | }; | 
|  |  | 
|  | class CleanupBitFields { | 
|  | friend class EHCleanupScope; | 
|  | unsigned : NumCommonBits; | 
|  |  | 
|  | /// Whether this cleanup needs to be run along normal edges. | 
|  | unsigned IsNormalCleanup : 1; | 
|  |  | 
|  | /// Whether this cleanup needs to be run along exception edges. | 
|  | unsigned IsEHCleanup : 1; | 
|  |  | 
|  | /// Whether this cleanup is currently active. | 
|  | unsigned IsActive : 1; | 
|  |  | 
|  | /// Whether this cleanup is a lifetime marker | 
|  | unsigned IsLifetimeMarker : 1; | 
|  |  | 
|  | /// Whether the normal cleanup should test the activation flag. | 
|  | unsigned TestFlagInNormalCleanup : 1; | 
|  |  | 
|  | /// Whether the EH cleanup should test the activation flag. | 
|  | unsigned TestFlagInEHCleanup : 1; | 
|  |  | 
|  | /// The amount of extra storage needed by the Cleanup. | 
|  | /// Always a multiple of the scope-stack alignment. | 
|  | unsigned CleanupSize : 12; | 
|  | }; | 
|  |  | 
|  | class FilterBitFields { | 
|  | friend class EHFilterScope; | 
|  | unsigned : NumCommonBits; | 
|  |  | 
|  | unsigned NumFilters : 32 - NumCommonBits; | 
|  | }; | 
|  |  | 
|  | union { | 
|  | CommonBitFields CommonBits; | 
|  | CatchBitFields CatchBits; | 
|  | CleanupBitFields CleanupBits; | 
|  | FilterBitFields FilterBits; | 
|  | }; | 
|  |  | 
|  | public: | 
|  | enum Kind { Cleanup, Catch, Terminate, Filter, PadEnd }; | 
|  |  | 
|  | EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope) | 
|  | : CachedLandingPad(nullptr), CachedEHDispatchBlock(nullptr), | 
|  | EnclosingEHScope(enclosingEHScope) { | 
|  | CommonBits.Kind = kind; | 
|  | } | 
|  |  | 
|  | Kind getKind() const { return static_cast<Kind>(CommonBits.Kind); } | 
|  |  | 
|  | llvm::BasicBlock *getCachedLandingPad() const { | 
|  | return CachedLandingPad; | 
|  | } | 
|  |  | 
|  | void setCachedLandingPad(llvm::BasicBlock *block) { | 
|  | CachedLandingPad = block; | 
|  | } | 
|  |  | 
|  | llvm::BasicBlock *getCachedEHDispatchBlock() const { | 
|  | return CachedEHDispatchBlock; | 
|  | } | 
|  |  | 
|  | void setCachedEHDispatchBlock(llvm::BasicBlock *block) { | 
|  | CachedEHDispatchBlock = block; | 
|  | } | 
|  |  | 
|  | bool hasEHBranches() const { | 
|  | if (llvm::BasicBlock *block = getCachedEHDispatchBlock()) | 
|  | return !block->use_empty(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | EHScopeStack::stable_iterator getEnclosingEHScope() const { | 
|  | return EnclosingEHScope; | 
|  | } | 
|  | }; | 
|  |  | 
|  | /// A scope which attempts to handle some, possibly all, types of | 
|  | /// exceptions. | 
|  | /// | 
|  | /// Objective C \@finally blocks are represented using a cleanup scope | 
|  | /// after the catch scope. | 
|  | class EHCatchScope : public EHScope { | 
|  | // In effect, we have a flexible array member | 
|  | //   Handler Handlers[0]; | 
|  | // But that's only standard in C99, not C++, so we have to do | 
|  | // annoying pointer arithmetic instead. | 
|  |  | 
|  | public: | 
|  | struct Handler { | 
|  | /// A type info value, or null (C++ null, not an LLVM null pointer) | 
|  | /// for a catch-all. | 
|  | CatchTypeInfo Type; | 
|  |  | 
|  | /// The catch handler for this type. | 
|  | llvm::BasicBlock *Block; | 
|  |  | 
|  | bool isCatchAll() const { return Type.RTTI == nullptr; } | 
|  | }; | 
|  |  | 
|  | private: | 
|  | friend class EHScopeStack; | 
|  |  | 
|  | Handler *getHandlers() { | 
|  | return reinterpret_cast<Handler*>(this+1); | 
|  | } | 
|  |  | 
|  | const Handler *getHandlers() const { | 
|  | return reinterpret_cast<const Handler*>(this+1); | 
|  | } | 
|  |  | 
|  | public: | 
|  | static size_t getSizeForNumHandlers(unsigned N) { | 
|  | return sizeof(EHCatchScope) + N * sizeof(Handler); | 
|  | } | 
|  |  | 
|  | EHCatchScope(unsigned numHandlers, | 
|  | EHScopeStack::stable_iterator enclosingEHScope) | 
|  | : EHScope(Catch, enclosingEHScope) { | 
|  | CatchBits.NumHandlers = numHandlers; | 
|  | assert(CatchBits.NumHandlers == numHandlers && "NumHandlers overflow?"); | 
|  | } | 
|  |  | 
|  | unsigned getNumHandlers() const { | 
|  | return CatchBits.NumHandlers; | 
|  | } | 
|  |  | 
|  | void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) { | 
|  | setHandler(I, CatchTypeInfo{nullptr, 0}, Block); | 
|  | } | 
|  |  | 
|  | void setHandler(unsigned I, llvm::Constant *Type, llvm::BasicBlock *Block) { | 
|  | assert(I < getNumHandlers()); | 
|  | getHandlers()[I].Type = CatchTypeInfo{Type, 0}; | 
|  | getHandlers()[I].Block = Block; | 
|  | } | 
|  |  | 
|  | void setHandler(unsigned I, CatchTypeInfo Type, llvm::BasicBlock *Block) { | 
|  | assert(I < getNumHandlers()); | 
|  | getHandlers()[I].Type = Type; | 
|  | getHandlers()[I].Block = Block; | 
|  | } | 
|  |  | 
|  | const Handler &getHandler(unsigned I) const { | 
|  | assert(I < getNumHandlers()); | 
|  | return getHandlers()[I]; | 
|  | } | 
|  |  | 
|  | // Clear all handler blocks. | 
|  | // FIXME: it's better to always call clearHandlerBlocks in DTOR and have a | 
|  | // 'takeHandler' or some such function which removes ownership from the | 
|  | // EHCatchScope object if the handlers should live longer than EHCatchScope. | 
|  | void clearHandlerBlocks() { | 
|  | for (unsigned I = 0, N = getNumHandlers(); I != N; ++I) | 
|  | delete getHandler(I).Block; | 
|  | } | 
|  |  | 
|  | typedef const Handler *iterator; | 
|  | iterator begin() const { return getHandlers(); } | 
|  | iterator end() const { return getHandlers() + getNumHandlers(); } | 
|  |  | 
|  | static bool classof(const EHScope *Scope) { | 
|  | return Scope->getKind() == Catch; | 
|  | } | 
|  | }; | 
|  |  | 
|  | /// A cleanup scope which generates the cleanup blocks lazily. | 
|  | class alignas(8) EHCleanupScope : public EHScope { | 
|  | /// The nearest normal cleanup scope enclosing this one. | 
|  | EHScopeStack::stable_iterator EnclosingNormal; | 
|  |  | 
|  | /// The nearest EH scope enclosing this one. | 
|  | EHScopeStack::stable_iterator EnclosingEH; | 
|  |  | 
|  | /// The dual entry/exit block along the normal edge.  This is lazily | 
|  | /// created if needed before the cleanup is popped. | 
|  | llvm::BasicBlock *NormalBlock; | 
|  |  | 
|  | /// An optional i1 variable indicating whether this cleanup has been | 
|  | /// activated yet. | 
|  | llvm::AllocaInst *ActiveFlag; | 
|  |  | 
|  | /// Extra information required for cleanups that have resolved | 
|  | /// branches through them.  This has to be allocated on the side | 
|  | /// because everything on the cleanup stack has be trivially | 
|  | /// movable. | 
|  | struct ExtInfo { | 
|  | /// The destinations of normal branch-afters and branch-throughs. | 
|  | llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches; | 
|  |  | 
|  | /// Normal branch-afters. | 
|  | SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4> | 
|  | BranchAfters; | 
|  | }; | 
|  | mutable struct ExtInfo *ExtInfo; | 
|  |  | 
|  | /// The number of fixups required by enclosing scopes (not including | 
|  | /// this one).  If this is the top cleanup scope, all the fixups | 
|  | /// from this index onwards belong to this scope. | 
|  | unsigned FixupDepth; | 
|  |  | 
|  | struct ExtInfo &getExtInfo() { | 
|  | if (!ExtInfo) ExtInfo = new struct ExtInfo(); | 
|  | return *ExtInfo; | 
|  | } | 
|  |  | 
|  | const struct ExtInfo &getExtInfo() const { | 
|  | if (!ExtInfo) ExtInfo = new struct ExtInfo(); | 
|  | return *ExtInfo; | 
|  | } | 
|  |  | 
|  | public: | 
|  | /// Gets the size required for a lazy cleanup scope with the given | 
|  | /// cleanup-data requirements. | 
|  | static size_t getSizeForCleanupSize(size_t Size) { | 
|  | return sizeof(EHCleanupScope) + Size; | 
|  | } | 
|  |  | 
|  | size_t getAllocatedSize() const { | 
|  | return sizeof(EHCleanupScope) + CleanupBits.CleanupSize; | 
|  | } | 
|  |  | 
|  | EHCleanupScope(bool isNormal, bool isEH, bool isActive, | 
|  | unsigned cleanupSize, unsigned fixupDepth, | 
|  | EHScopeStack::stable_iterator enclosingNormal, | 
|  | EHScopeStack::stable_iterator enclosingEH) | 
|  | : EHScope(EHScope::Cleanup, enclosingEH), | 
|  | EnclosingNormal(enclosingNormal), NormalBlock(nullptr), | 
|  | ActiveFlag(nullptr), ExtInfo(nullptr), FixupDepth(fixupDepth) { | 
|  | CleanupBits.IsNormalCleanup = isNormal; | 
|  | CleanupBits.IsEHCleanup = isEH; | 
|  | CleanupBits.IsActive = isActive; | 
|  | CleanupBits.IsLifetimeMarker = false; | 
|  | CleanupBits.TestFlagInNormalCleanup = false; | 
|  | CleanupBits.TestFlagInEHCleanup = false; | 
|  | CleanupBits.CleanupSize = cleanupSize; | 
|  |  | 
|  | assert(CleanupBits.CleanupSize == cleanupSize && "cleanup size overflow"); | 
|  | } | 
|  |  | 
|  | void Destroy() { | 
|  | delete ExtInfo; | 
|  | } | 
|  | // Objects of EHCleanupScope are not destructed. Use Destroy(). | 
|  | ~EHCleanupScope() = delete; | 
|  |  | 
|  | bool isNormalCleanup() const { return CleanupBits.IsNormalCleanup; } | 
|  | llvm::BasicBlock *getNormalBlock() const { return NormalBlock; } | 
|  | void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; } | 
|  |  | 
|  | bool isEHCleanup() const { return CleanupBits.IsEHCleanup; } | 
|  |  | 
|  | bool isActive() const { return CleanupBits.IsActive; } | 
|  | void setActive(bool A) { CleanupBits.IsActive = A; } | 
|  |  | 
|  | bool isLifetimeMarker() const { return CleanupBits.IsLifetimeMarker; } | 
|  | void setLifetimeMarker() { CleanupBits.IsLifetimeMarker = true; } | 
|  |  | 
|  | bool hasActiveFlag() const { return ActiveFlag != nullptr; } | 
|  | Address getActiveFlag() const { | 
|  | return Address(ActiveFlag, CharUnits::One()); | 
|  | } | 
|  | void setActiveFlag(Address Var) { | 
|  | assert(Var.getAlignment().isOne()); | 
|  | ActiveFlag = cast<llvm::AllocaInst>(Var.getPointer()); | 
|  | } | 
|  |  | 
|  | void setTestFlagInNormalCleanup() { | 
|  | CleanupBits.TestFlagInNormalCleanup = true; | 
|  | } | 
|  | bool shouldTestFlagInNormalCleanup() const { | 
|  | return CleanupBits.TestFlagInNormalCleanup; | 
|  | } | 
|  |  | 
|  | void setTestFlagInEHCleanup() { | 
|  | CleanupBits.TestFlagInEHCleanup = true; | 
|  | } | 
|  | bool shouldTestFlagInEHCleanup() const { | 
|  | return CleanupBits.TestFlagInEHCleanup; | 
|  | } | 
|  |  | 
|  | unsigned getFixupDepth() const { return FixupDepth; } | 
|  | EHScopeStack::stable_iterator getEnclosingNormalCleanup() const { | 
|  | return EnclosingNormal; | 
|  | } | 
|  |  | 
|  | size_t getCleanupSize() const { return CleanupBits.CleanupSize; } | 
|  | void *getCleanupBuffer() { return this + 1; } | 
|  |  | 
|  | EHScopeStack::Cleanup *getCleanup() { | 
|  | return reinterpret_cast<EHScopeStack::Cleanup*>(getCleanupBuffer()); | 
|  | } | 
|  |  | 
|  | /// True if this cleanup scope has any branch-afters or branch-throughs. | 
|  | bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); } | 
|  |  | 
|  | /// Add a branch-after to this cleanup scope.  A branch-after is a | 
|  | /// branch from a point protected by this (normal) cleanup to a | 
|  | /// point in the normal cleanup scope immediately containing it. | 
|  | /// For example, | 
|  | ///   for (;;) { A a; break; } | 
|  | /// contains a branch-after. | 
|  | /// | 
|  | /// Branch-afters each have their own destination out of the | 
|  | /// cleanup, guaranteed distinct from anything else threaded through | 
|  | /// it.  Therefore branch-afters usually force a switch after the | 
|  | /// cleanup. | 
|  | void addBranchAfter(llvm::ConstantInt *Index, | 
|  | llvm::BasicBlock *Block) { | 
|  | struct ExtInfo &ExtInfo = getExtInfo(); | 
|  | if (ExtInfo.Branches.insert(Block).second) | 
|  | ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index)); | 
|  | } | 
|  |  | 
|  | /// Return the number of unique branch-afters on this scope. | 
|  | unsigned getNumBranchAfters() const { | 
|  | return ExtInfo ? ExtInfo->BranchAfters.size() : 0; | 
|  | } | 
|  |  | 
|  | llvm::BasicBlock *getBranchAfterBlock(unsigned I) const { | 
|  | assert(I < getNumBranchAfters()); | 
|  | return ExtInfo->BranchAfters[I].first; | 
|  | } | 
|  |  | 
|  | llvm::ConstantInt *getBranchAfterIndex(unsigned I) const { | 
|  | assert(I < getNumBranchAfters()); | 
|  | return ExtInfo->BranchAfters[I].second; | 
|  | } | 
|  |  | 
|  | /// Add a branch-through to this cleanup scope.  A branch-through is | 
|  | /// a branch from a scope protected by this (normal) cleanup to an | 
|  | /// enclosing scope other than the immediately-enclosing normal | 
|  | /// cleanup scope. | 
|  | /// | 
|  | /// In the following example, the branch through B's scope is a | 
|  | /// branch-through, while the branch through A's scope is a | 
|  | /// branch-after: | 
|  | ///   for (;;) { A a; B b; break; } | 
|  | /// | 
|  | /// All branch-throughs have a common destination out of the | 
|  | /// cleanup, one possibly shared with the fall-through.  Therefore | 
|  | /// branch-throughs usually don't force a switch after the cleanup. | 
|  | /// | 
|  | /// \return true if the branch-through was new to this scope | 
|  | bool addBranchThrough(llvm::BasicBlock *Block) { | 
|  | return getExtInfo().Branches.insert(Block).second; | 
|  | } | 
|  |  | 
|  | /// Determines if this cleanup scope has any branch throughs. | 
|  | bool hasBranchThroughs() const { | 
|  | if (!ExtInfo) return false; | 
|  | return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size()); | 
|  | } | 
|  |  | 
|  | static bool classof(const EHScope *Scope) { | 
|  | return (Scope->getKind() == Cleanup); | 
|  | } | 
|  | }; | 
|  | // NOTE: there's a bunch of different data classes tacked on after an | 
|  | // EHCleanupScope. It is asserted (in EHScopeStack::pushCleanup*) that | 
|  | // they don't require greater alignment than ScopeStackAlignment. So, | 
|  | // EHCleanupScope ought to have alignment equal to that -- not more | 
|  | // (would be misaligned by the stack allocator), and not less (would | 
|  | // break the appended classes). | 
|  | static_assert(alignof(EHCleanupScope) == EHScopeStack::ScopeStackAlignment, | 
|  | "EHCleanupScope expected alignment"); | 
|  |  | 
|  | /// An exceptions scope which filters exceptions thrown through it. | 
|  | /// Only exceptions matching the filter types will be permitted to be | 
|  | /// thrown. | 
|  | /// | 
|  | /// This is used to implement C++ exception specifications. | 
|  | class EHFilterScope : public EHScope { | 
|  | // Essentially ends in a flexible array member: | 
|  | // llvm::Value *FilterTypes[0]; | 
|  |  | 
|  | llvm::Value **getFilters() { | 
|  | return reinterpret_cast<llvm::Value**>(this+1); | 
|  | } | 
|  |  | 
|  | llvm::Value * const *getFilters() const { | 
|  | return reinterpret_cast<llvm::Value* const *>(this+1); | 
|  | } | 
|  |  | 
|  | public: | 
|  | EHFilterScope(unsigned numFilters) | 
|  | : EHScope(Filter, EHScopeStack::stable_end()) { | 
|  | FilterBits.NumFilters = numFilters; | 
|  | assert(FilterBits.NumFilters == numFilters && "NumFilters overflow"); | 
|  | } | 
|  |  | 
|  | static size_t getSizeForNumFilters(unsigned numFilters) { | 
|  | return sizeof(EHFilterScope) + numFilters * sizeof(llvm::Value*); | 
|  | } | 
|  |  | 
|  | unsigned getNumFilters() const { return FilterBits.NumFilters; } | 
|  |  | 
|  | void setFilter(unsigned i, llvm::Value *filterValue) { | 
|  | assert(i < getNumFilters()); | 
|  | getFilters()[i] = filterValue; | 
|  | } | 
|  |  | 
|  | llvm::Value *getFilter(unsigned i) const { | 
|  | assert(i < getNumFilters()); | 
|  | return getFilters()[i]; | 
|  | } | 
|  |  | 
|  | static bool classof(const EHScope *scope) { | 
|  | return scope->getKind() == Filter; | 
|  | } | 
|  | }; | 
|  |  | 
|  | /// An exceptions scope which calls std::terminate if any exception | 
|  | /// reaches it. | 
|  | class EHTerminateScope : public EHScope { | 
|  | public: | 
|  | EHTerminateScope(EHScopeStack::stable_iterator enclosingEHScope) | 
|  | : EHScope(Terminate, enclosingEHScope) {} | 
|  | static size_t getSize() { return sizeof(EHTerminateScope); } | 
|  |  | 
|  | static bool classof(const EHScope *scope) { | 
|  | return scope->getKind() == Terminate; | 
|  | } | 
|  | }; | 
|  |  | 
|  | class EHPadEndScope : public EHScope { | 
|  | public: | 
|  | EHPadEndScope(EHScopeStack::stable_iterator enclosingEHScope) | 
|  | : EHScope(PadEnd, enclosingEHScope) {} | 
|  | static size_t getSize() { return sizeof(EHPadEndScope); } | 
|  |  | 
|  | static bool classof(const EHScope *scope) { | 
|  | return scope->getKind() == PadEnd; | 
|  | } | 
|  | }; | 
|  |  | 
|  | /// A non-stable pointer into the scope stack. | 
|  | class EHScopeStack::iterator { | 
|  | char *Ptr; | 
|  |  | 
|  | friend class EHScopeStack; | 
|  | explicit iterator(char *Ptr) : Ptr(Ptr) {} | 
|  |  | 
|  | public: | 
|  | iterator() : Ptr(nullptr) {} | 
|  |  | 
|  | EHScope *get() const { | 
|  | return reinterpret_cast<EHScope*>(Ptr); | 
|  | } | 
|  |  | 
|  | EHScope *operator->() const { return get(); } | 
|  | EHScope &operator*() const { return *get(); } | 
|  |  | 
|  | iterator &operator++() { | 
|  | size_t Size; | 
|  | switch (get()->getKind()) { | 
|  | case EHScope::Catch: | 
|  | Size = EHCatchScope::getSizeForNumHandlers( | 
|  | static_cast<const EHCatchScope *>(get())->getNumHandlers()); | 
|  | break; | 
|  |  | 
|  | case EHScope::Filter: | 
|  | Size = EHFilterScope::getSizeForNumFilters( | 
|  | static_cast<const EHFilterScope *>(get())->getNumFilters()); | 
|  | break; | 
|  |  | 
|  | case EHScope::Cleanup: | 
|  | Size = static_cast<const EHCleanupScope *>(get())->getAllocatedSize(); | 
|  | break; | 
|  |  | 
|  | case EHScope::Terminate: | 
|  | Size = EHTerminateScope::getSize(); | 
|  | break; | 
|  |  | 
|  | case EHScope::PadEnd: | 
|  | Size = EHPadEndScope::getSize(); | 
|  | break; | 
|  | } | 
|  | Ptr += llvm::alignTo(Size, ScopeStackAlignment); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | iterator next() { | 
|  | iterator copy = *this; | 
|  | ++copy; | 
|  | return copy; | 
|  | } | 
|  |  | 
|  | iterator operator++(int) { | 
|  | iterator copy = *this; | 
|  | operator++(); | 
|  | return copy; | 
|  | } | 
|  |  | 
|  | bool encloses(iterator other) const { return Ptr >= other.Ptr; } | 
|  | bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; } | 
|  |  | 
|  | bool operator==(iterator other) const { return Ptr == other.Ptr; } | 
|  | bool operator!=(iterator other) const { return Ptr != other.Ptr; } | 
|  | }; | 
|  |  | 
|  | inline EHScopeStack::iterator EHScopeStack::begin() const { | 
|  | return iterator(StartOfData); | 
|  | } | 
|  |  | 
|  | inline EHScopeStack::iterator EHScopeStack::end() const { | 
|  | return iterator(EndOfBuffer); | 
|  | } | 
|  |  | 
|  | inline void EHScopeStack::popCatch() { | 
|  | assert(!empty() && "popping exception stack when not empty"); | 
|  |  | 
|  | EHCatchScope &scope = cast<EHCatchScope>(*begin()); | 
|  | InnermostEHScope = scope.getEnclosingEHScope(); | 
|  | deallocate(EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers())); | 
|  | } | 
|  |  | 
|  | inline void EHScopeStack::popTerminate() { | 
|  | assert(!empty() && "popping exception stack when not empty"); | 
|  |  | 
|  | EHTerminateScope &scope = cast<EHTerminateScope>(*begin()); | 
|  | InnermostEHScope = scope.getEnclosingEHScope(); | 
|  | deallocate(EHTerminateScope::getSize()); | 
|  | } | 
|  |  | 
|  | inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const { | 
|  | assert(sp.isValid() && "finding invalid savepoint"); | 
|  | assert(sp.Size <= stable_begin().Size && "finding savepoint after pop"); | 
|  | return iterator(EndOfBuffer - sp.Size); | 
|  | } | 
|  |  | 
|  | inline EHScopeStack::stable_iterator | 
|  | EHScopeStack::stabilize(iterator ir) const { | 
|  | assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer); | 
|  | return stable_iterator(EndOfBuffer - ir.Ptr); | 
|  | } | 
|  |  | 
|  | /// The exceptions personality for a function. | 
|  | struct EHPersonality { | 
|  | const char *PersonalityFn; | 
|  |  | 
|  | // If this is non-null, this personality requires a non-standard | 
|  | // function for rethrowing an exception after a catchall cleanup. | 
|  | // This function must have prototype void(void*). | 
|  | const char *CatchallRethrowFn; | 
|  |  | 
|  | static const EHPersonality &get(CodeGenModule &CGM, const FunctionDecl *FD); | 
|  | static const EHPersonality &get(CodeGenFunction &CGF); | 
|  |  | 
|  | static const EHPersonality GNU_C; | 
|  | static const EHPersonality GNU_C_SJLJ; | 
|  | static const EHPersonality GNU_C_SEH; | 
|  | static const EHPersonality GNU_ObjC; | 
|  | static const EHPersonality GNU_ObjC_SJLJ; | 
|  | static const EHPersonality GNU_ObjC_SEH; | 
|  | static const EHPersonality GNUstep_ObjC; | 
|  | static const EHPersonality GNU_ObjCXX; | 
|  | static const EHPersonality NeXT_ObjC; | 
|  | static const EHPersonality GNU_CPlusPlus; | 
|  | static const EHPersonality GNU_CPlusPlus_SJLJ; | 
|  | static const EHPersonality GNU_CPlusPlus_SEH; | 
|  | static const EHPersonality MSVC_except_handler; | 
|  | static const EHPersonality MSVC_C_specific_handler; | 
|  | static const EHPersonality MSVC_CxxFrameHandler3; | 
|  | static const EHPersonality GNU_Wasm_CPlusPlus; | 
|  |  | 
|  | /// Does this personality use landingpads or the family of pad instructions | 
|  | /// designed to form funclets? | 
|  | bool usesFuncletPads() const { | 
|  | return isMSVCPersonality() || isWasmPersonality(); | 
|  | } | 
|  |  | 
|  | bool isMSVCPersonality() const { | 
|  | return this == &MSVC_except_handler || this == &MSVC_C_specific_handler || | 
|  | this == &MSVC_CxxFrameHandler3; | 
|  | } | 
|  |  | 
|  | bool isWasmPersonality() const { return this == &GNU_Wasm_CPlusPlus; } | 
|  |  | 
|  | bool isMSVCXXPersonality() const { return this == &MSVC_CxxFrameHandler3; } | 
|  | }; | 
|  | } | 
|  | } | 
|  |  | 
|  | #endif |