xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/EHScopeStack.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===-- EHScopeStack.h - Stack for cleanup IR generation --------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // These classes should be the minimum interface required for other parts of
100b57cec5SDimitry Andric // CodeGen to emit cleanups.  The implementation is in CGCleanup.cpp and other
110b57cec5SDimitry Andric // implemenentation details that are not widely needed are in CGCleanup.h.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #ifndef LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H
160b57cec5SDimitry Andric #define LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
190b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
200b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
210b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
220b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
230b57cec5SDimitry Andric #include "llvm/IR/Value.h"
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric namespace clang {
260b57cec5SDimitry Andric namespace CodeGen {
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric class CodeGenFunction;
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric /// A branch fixup.  These are required when emitting a goto to a
310b57cec5SDimitry Andric /// label which hasn't been emitted yet.  The goto is optimistically
320b57cec5SDimitry Andric /// emitted as a branch to the basic block for the label, and (if it
330b57cec5SDimitry Andric /// occurs in a scope with non-trivial cleanups) a fixup is added to
340b57cec5SDimitry Andric /// the innermost cleanup.  When a (normal) cleanup is popped, any
350b57cec5SDimitry Andric /// unresolved fixups in that scope are threaded through the cleanup.
360b57cec5SDimitry Andric struct BranchFixup {
370b57cec5SDimitry Andric   /// The block containing the terminator which needs to be modified
380b57cec5SDimitry Andric   /// into a switch if this fixup is resolved into the current scope.
390b57cec5SDimitry Andric   /// If null, LatestBranch points directly to the destination.
400b57cec5SDimitry Andric   llvm::BasicBlock *OptimisticBranchBlock;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   /// The ultimate destination of the branch.
430b57cec5SDimitry Andric   ///
440b57cec5SDimitry Andric   /// This can be set to null to indicate that this fixup was
450b57cec5SDimitry Andric   /// successfully resolved.
460b57cec5SDimitry Andric   llvm::BasicBlock *Destination;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   /// The destination index value.
490b57cec5SDimitry Andric   unsigned DestinationIndex;
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   /// The initial branch of the fixup.
520b57cec5SDimitry Andric   llvm::BranchInst *InitialBranch;
530b57cec5SDimitry Andric };
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric template <class T> struct InvariantValue {
560b57cec5SDimitry Andric   typedef T type;
570b57cec5SDimitry Andric   typedef T saved_type;
580b57cec5SDimitry Andric   static bool needsSaving(type value) { return false; }
590b57cec5SDimitry Andric   static saved_type save(CodeGenFunction &CGF, type value) { return value; }
600b57cec5SDimitry Andric   static type restore(CodeGenFunction &CGF, saved_type value) { return value; }
610b57cec5SDimitry Andric };
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric /// A metaprogramming class for ensuring that a value will dominate an
640b57cec5SDimitry Andric /// arbitrary position in a function.
650b57cec5SDimitry Andric template <class T> struct DominatingValue : InvariantValue<T> {};
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric template <class T, bool mightBeInstruction =
680b57cec5SDimitry Andric             std::is_base_of<llvm::Value, T>::value &&
690b57cec5SDimitry Andric             !std::is_base_of<llvm::Constant, T>::value &&
700b57cec5SDimitry Andric             !std::is_base_of<llvm::BasicBlock, T>::value>
710b57cec5SDimitry Andric struct DominatingPointer;
720b57cec5SDimitry Andric template <class T> struct DominatingPointer<T,false> : InvariantValue<T*> {};
730b57cec5SDimitry Andric // template <class T> struct DominatingPointer<T,true> at end of file
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric template <class T> struct DominatingValue<T*> : DominatingPointer<T> {};
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric enum CleanupKind : unsigned {
780b57cec5SDimitry Andric   /// Denotes a cleanup that should run when a scope is exited using exceptional
790b57cec5SDimitry Andric   /// control flow (a throw statement leading to stack unwinding, ).
800b57cec5SDimitry Andric   EHCleanup = 0x1,
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   /// Denotes a cleanup that should run when a scope is exited using normal
830b57cec5SDimitry Andric   /// control flow (falling off the end of the scope, return, goto, ...).
840b57cec5SDimitry Andric   NormalCleanup = 0x2,
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   NormalAndEHCleanup = EHCleanup | NormalCleanup,
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   LifetimeMarker = 0x8,
890b57cec5SDimitry Andric   NormalEHLifetimeMarker = LifetimeMarker | NormalAndEHCleanup,
900b57cec5SDimitry Andric };
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric /// A stack of scopes which respond to exceptions, including cleanups
930b57cec5SDimitry Andric /// and catch blocks.
940b57cec5SDimitry Andric class EHScopeStack {
950b57cec5SDimitry Andric public:
960b57cec5SDimitry Andric   /* Should switch to alignof(uint64_t) instead of 8, when EHCleanupScope can */
970b57cec5SDimitry Andric   enum { ScopeStackAlignment = 8 };
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric   /// A saved depth on the scope stack.  This is necessary because
1000b57cec5SDimitry Andric   /// pushing scopes onto the stack invalidates iterators.
1010b57cec5SDimitry Andric   class stable_iterator {
1020b57cec5SDimitry Andric     friend class EHScopeStack;
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric     /// Offset from StartOfData to EndOfBuffer.
1050b57cec5SDimitry Andric     ptrdiff_t Size;
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric     stable_iterator(ptrdiff_t Size) : Size(Size) {}
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   public:
1100b57cec5SDimitry Andric     static stable_iterator invalid() { return stable_iterator(-1); }
1110b57cec5SDimitry Andric     stable_iterator() : Size(-1) {}
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric     bool isValid() const { return Size >= 0; }
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric     /// Returns true if this scope encloses I.
1160b57cec5SDimitry Andric     /// Returns false if I is invalid.
1170b57cec5SDimitry Andric     /// This scope must be valid.
1180b57cec5SDimitry Andric     bool encloses(stable_iterator I) const { return Size <= I.Size; }
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric     /// Returns true if this scope strictly encloses I: that is,
1210b57cec5SDimitry Andric     /// if it encloses I and is not I.
1220b57cec5SDimitry Andric     /// Returns false is I is invalid.
1230b57cec5SDimitry Andric     /// This scope must be valid.
1240b57cec5SDimitry Andric     bool strictlyEncloses(stable_iterator I) const { return Size < I.Size; }
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric     friend bool operator==(stable_iterator A, stable_iterator B) {
1270b57cec5SDimitry Andric       return A.Size == B.Size;
1280b57cec5SDimitry Andric     }
1290b57cec5SDimitry Andric     friend bool operator!=(stable_iterator A, stable_iterator B) {
1300b57cec5SDimitry Andric       return A.Size != B.Size;
1310b57cec5SDimitry Andric     }
1320b57cec5SDimitry Andric   };
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   /// Information for lazily generating a cleanup.  Subclasses must be
1350b57cec5SDimitry Andric   /// POD-like: cleanups will not be destructed, and they will be
1360b57cec5SDimitry Andric   /// allocated on the cleanup stack and freely copied and moved
1370b57cec5SDimitry Andric   /// around.
1380b57cec5SDimitry Andric   ///
1390b57cec5SDimitry Andric   /// Cleanup implementations should generally be declared in an
1400b57cec5SDimitry Andric   /// anonymous namespace.
1410b57cec5SDimitry Andric   class Cleanup {
1420b57cec5SDimitry Andric     // Anchor the construction vtable.
1430b57cec5SDimitry Andric     virtual void anchor();
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric   protected:
1460b57cec5SDimitry Andric     ~Cleanup() = default;
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   public:
1490b57cec5SDimitry Andric     Cleanup(const Cleanup &) = default;
1500b57cec5SDimitry Andric     Cleanup(Cleanup &&) {}
15106c3fb27SDimitry Andric 
15206c3fb27SDimitry Andric     // The copy and move assignment operator is defined as deleted pending
15306c3fb27SDimitry Andric     // further motivation.
15406c3fb27SDimitry Andric     Cleanup &operator=(const Cleanup &) = delete;
15506c3fb27SDimitry Andric     Cleanup &operator=(Cleanup &&) = delete;
15606c3fb27SDimitry Andric 
1570b57cec5SDimitry Andric     Cleanup() = default;
1580b57cec5SDimitry Andric 
159fe6060f1SDimitry Andric     virtual bool isRedundantBeforeReturn() { return false; }
160fe6060f1SDimitry Andric 
1610b57cec5SDimitry Andric     /// Generation flags.
1620b57cec5SDimitry Andric     class Flags {
1630b57cec5SDimitry Andric       enum {
1640b57cec5SDimitry Andric         F_IsForEH = 0x1,
1650b57cec5SDimitry Andric         F_IsNormalCleanupKind = 0x2,
1665ffd83dbSDimitry Andric         F_IsEHCleanupKind = 0x4,
1675ffd83dbSDimitry Andric         F_HasExitSwitch = 0x8,
1680b57cec5SDimitry Andric       };
169*5f757f3fSDimitry Andric       unsigned flags = 0;
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric     public:
172*5f757f3fSDimitry Andric       Flags() = default;
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric       /// isForEH - true if the current emission is for an EH cleanup.
1750b57cec5SDimitry Andric       bool isForEHCleanup() const { return flags & F_IsForEH; }
1760b57cec5SDimitry Andric       bool isForNormalCleanup() const { return !isForEHCleanup(); }
1770b57cec5SDimitry Andric       void setIsForEHCleanup() { flags |= F_IsForEH; }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric       bool isNormalCleanupKind() const { return flags & F_IsNormalCleanupKind; }
1800b57cec5SDimitry Andric       void setIsNormalCleanupKind() { flags |= F_IsNormalCleanupKind; }
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric       /// isEHCleanupKind - true if the cleanup was pushed as an EH
1830b57cec5SDimitry Andric       /// cleanup.
1840b57cec5SDimitry Andric       bool isEHCleanupKind() const { return flags & F_IsEHCleanupKind; }
1850b57cec5SDimitry Andric       void setIsEHCleanupKind() { flags |= F_IsEHCleanupKind; }
1860b57cec5SDimitry Andric 
1875ffd83dbSDimitry Andric       bool hasExitSwitch() const { return flags & F_HasExitSwitch; }
1885ffd83dbSDimitry Andric       void setHasExitSwitch() { flags |= F_HasExitSwitch; }
1895ffd83dbSDimitry Andric     };
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric     /// Emit the cleanup.  For normal cleanups, this is run in the
1920b57cec5SDimitry Andric     /// same EH context as when the cleanup was pushed, i.e. the
1930b57cec5SDimitry Andric     /// immediately-enclosing context of the cleanup scope.  For
1940b57cec5SDimitry Andric     /// EH cleanups, this is run in a terminate context.
1950b57cec5SDimitry Andric     ///
1960b57cec5SDimitry Andric     // \param flags cleanup kind.
1970b57cec5SDimitry Andric     virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0;
1980b57cec5SDimitry Andric   };
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   /// ConditionalCleanup stores the saved form of its parameters,
2010b57cec5SDimitry Andric   /// then restores them and performs the cleanup.
2020b57cec5SDimitry Andric   template <class T, class... As>
2030b57cec5SDimitry Andric   class ConditionalCleanup final : public Cleanup {
2040b57cec5SDimitry Andric     typedef std::tuple<typename DominatingValue<As>::saved_type...> SavedTuple;
2050b57cec5SDimitry Andric     SavedTuple Saved;
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric     template <std::size_t... Is>
208a7dea167SDimitry Andric     T restore(CodeGenFunction &CGF, std::index_sequence<Is...>) {
2090b57cec5SDimitry Andric       // It's important that the restores are emitted in order. The braced init
2100b57cec5SDimitry Andric       // list guarantees that.
2110b57cec5SDimitry Andric       return T{DominatingValue<As>::restore(CGF, std::get<Is>(Saved))...};
2120b57cec5SDimitry Andric     }
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric     void Emit(CodeGenFunction &CGF, Flags flags) override {
215a7dea167SDimitry Andric       restore(CGF, std::index_sequence_for<As...>()).Emit(CGF, flags);
2160b57cec5SDimitry Andric     }
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric   public:
2190b57cec5SDimitry Andric     ConditionalCleanup(typename DominatingValue<As>::saved_type... A)
2200b57cec5SDimitry Andric         : Saved(A...) {}
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric     ConditionalCleanup(SavedTuple Tuple) : Saved(std::move(Tuple)) {}
2230b57cec5SDimitry Andric   };
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric private:
2260b57cec5SDimitry Andric   // The implementation for this class is in CGException.h and
2270b57cec5SDimitry Andric   // CGException.cpp; the definition is here because it's used as a
2280b57cec5SDimitry Andric   // member of CodeGenFunction.
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric   /// The start of the scope-stack buffer, i.e. the allocated pointer
2310b57cec5SDimitry Andric   /// for the buffer.  All of these pointers are either simultaneously
2320b57cec5SDimitry Andric   /// null or simultaneously valid.
2330b57cec5SDimitry Andric   char *StartOfBuffer;
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric   /// The end of the buffer.
2360b57cec5SDimitry Andric   char *EndOfBuffer;
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   /// The first valid entry in the buffer.
2390b57cec5SDimitry Andric   char *StartOfData;
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric   /// The innermost normal cleanup on the stack.
2420b57cec5SDimitry Andric   stable_iterator InnermostNormalCleanup;
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   /// The innermost EH scope on the stack.
2450b57cec5SDimitry Andric   stable_iterator InnermostEHScope;
2460b57cec5SDimitry Andric 
247fe6060f1SDimitry Andric   /// The CGF this Stack belong to
248fe6060f1SDimitry Andric   CodeGenFunction* CGF;
249fe6060f1SDimitry Andric 
2500b57cec5SDimitry Andric   /// The current set of branch fixups.  A branch fixup is a jump to
2510b57cec5SDimitry Andric   /// an as-yet unemitted label, i.e. a label for which we don't yet
2520b57cec5SDimitry Andric   /// know the EH stack depth.  Whenever we pop a cleanup, we have
2530b57cec5SDimitry Andric   /// to thread all the current branch fixups through it.
2540b57cec5SDimitry Andric   ///
2550b57cec5SDimitry Andric   /// Fixups are recorded as the Use of the respective branch or
2560b57cec5SDimitry Andric   /// switch statement.  The use points to the final destination.
2570b57cec5SDimitry Andric   /// When popping out of a cleanup, these uses are threaded through
2580b57cec5SDimitry Andric   /// the cleanup and adjusted to point to the new cleanup.
2590b57cec5SDimitry Andric   ///
2600b57cec5SDimitry Andric   /// Note that branches are allowed to jump into protected scopes
2610b57cec5SDimitry Andric   /// in certain situations;  e.g. the following code is legal:
2620b57cec5SDimitry Andric   ///     struct A { ~A(); }; // trivial ctor, non-trivial dtor
2630b57cec5SDimitry Andric   ///     goto foo;
2640b57cec5SDimitry Andric   ///     A a;
2650b57cec5SDimitry Andric   ///    foo:
2660b57cec5SDimitry Andric   ///     bar();
2670b57cec5SDimitry Andric   SmallVector<BranchFixup, 8> BranchFixups;
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   char *allocate(size_t Size);
2700b57cec5SDimitry Andric   void deallocate(size_t Size);
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric   void *pushCleanup(CleanupKind K, size_t DataSize);
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric public:
275fe6060f1SDimitry Andric   EHScopeStack()
276fe6060f1SDimitry Andric     : StartOfBuffer(nullptr), EndOfBuffer(nullptr), StartOfData(nullptr),
277fe6060f1SDimitry Andric       InnermostNormalCleanup(stable_end()), InnermostEHScope(stable_end()),
278fe6060f1SDimitry Andric       CGF(nullptr) {}
2790b57cec5SDimitry Andric   ~EHScopeStack() { delete[] StartOfBuffer; }
2800b57cec5SDimitry Andric 
28106c3fb27SDimitry Andric   EHScopeStack(const EHScopeStack &) = delete;
28206c3fb27SDimitry Andric   EHScopeStack &operator=(const EHScopeStack &) = delete;
28306c3fb27SDimitry Andric 
2840b57cec5SDimitry Andric   /// Push a lazily-created cleanup on the stack.
2850b57cec5SDimitry Andric   template <class T, class... As> void pushCleanup(CleanupKind Kind, As... A) {
2860b57cec5SDimitry Andric     static_assert(alignof(T) <= ScopeStackAlignment,
2870b57cec5SDimitry Andric                   "Cleanup's alignment is too large.");
2880b57cec5SDimitry Andric     void *Buffer = pushCleanup(Kind, sizeof(T));
2890b57cec5SDimitry Andric     Cleanup *Obj = new (Buffer) T(A...);
2900b57cec5SDimitry Andric     (void) Obj;
2910b57cec5SDimitry Andric   }
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric   /// Push a lazily-created cleanup on the stack. Tuple version.
2940b57cec5SDimitry Andric   template <class T, class... As>
2950b57cec5SDimitry Andric   void pushCleanupTuple(CleanupKind Kind, std::tuple<As...> A) {
2960b57cec5SDimitry Andric     static_assert(alignof(T) <= ScopeStackAlignment,
2970b57cec5SDimitry Andric                   "Cleanup's alignment is too large.");
2980b57cec5SDimitry Andric     void *Buffer = pushCleanup(Kind, sizeof(T));
2990b57cec5SDimitry Andric     Cleanup *Obj = new (Buffer) T(std::move(A));
3000b57cec5SDimitry Andric     (void) Obj;
3010b57cec5SDimitry Andric   }
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric   // Feel free to add more variants of the following:
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric   /// Push a cleanup with non-constant storage requirements on the
3060b57cec5SDimitry Andric   /// stack.  The cleanup type must provide an additional static method:
3070b57cec5SDimitry Andric   ///   static size_t getExtraSize(size_t);
3080b57cec5SDimitry Andric   /// The argument to this method will be the value N, which will also
3090b57cec5SDimitry Andric   /// be passed as the first argument to the constructor.
3100b57cec5SDimitry Andric   ///
3110b57cec5SDimitry Andric   /// The data stored in the extra storage must obey the same
3120b57cec5SDimitry Andric   /// restrictions as normal cleanup member data.
3130b57cec5SDimitry Andric   ///
3140b57cec5SDimitry Andric   /// The pointer returned from this method is valid until the cleanup
3150b57cec5SDimitry Andric   /// stack is modified.
3160b57cec5SDimitry Andric   template <class T, class... As>
3170b57cec5SDimitry Andric   T *pushCleanupWithExtra(CleanupKind Kind, size_t N, As... A) {
3180b57cec5SDimitry Andric     static_assert(alignof(T) <= ScopeStackAlignment,
3190b57cec5SDimitry Andric                   "Cleanup's alignment is too large.");
3200b57cec5SDimitry Andric     void *Buffer = pushCleanup(Kind, sizeof(T) + T::getExtraSize(N));
3210b57cec5SDimitry Andric     return new (Buffer) T(N, A...);
3220b57cec5SDimitry Andric   }
3230b57cec5SDimitry Andric 
3240b57cec5SDimitry Andric   void pushCopyOfCleanup(CleanupKind Kind, const void *Cleanup, size_t Size) {
3250b57cec5SDimitry Andric     void *Buffer = pushCleanup(Kind, Size);
3260b57cec5SDimitry Andric     std::memcpy(Buffer, Cleanup, Size);
3270b57cec5SDimitry Andric   }
3280b57cec5SDimitry Andric 
329fe6060f1SDimitry Andric   void setCGF(CodeGenFunction *inCGF) { CGF = inCGF; }
330fe6060f1SDimitry Andric 
3310b57cec5SDimitry Andric   /// Pops a cleanup scope off the stack.  This is private to CGCleanup.cpp.
3320b57cec5SDimitry Andric   void popCleanup();
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric   /// Push a set of catch handlers on the stack.  The catch is
3350b57cec5SDimitry Andric   /// uninitialized and will need to have the given number of handlers
3360b57cec5SDimitry Andric   /// set on it.
3370b57cec5SDimitry Andric   class EHCatchScope *pushCatch(unsigned NumHandlers);
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric   /// Pops a catch scope off the stack.  This is private to CGException.cpp.
3400b57cec5SDimitry Andric   void popCatch();
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric   /// Push an exceptions filter on the stack.
3430b57cec5SDimitry Andric   class EHFilterScope *pushFilter(unsigned NumFilters);
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric   /// Pops an exceptions filter off the stack.
3460b57cec5SDimitry Andric   void popFilter();
3470b57cec5SDimitry Andric 
3480b57cec5SDimitry Andric   /// Push a terminate handler on the stack.
3490b57cec5SDimitry Andric   void pushTerminate();
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric   /// Pops a terminate handler off the stack.
3520b57cec5SDimitry Andric   void popTerminate();
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric   // Returns true iff the current scope is either empty or contains only
3550b57cec5SDimitry Andric   // lifetime markers, i.e. no real cleanup code
3560b57cec5SDimitry Andric   bool containsOnlyLifetimeMarkers(stable_iterator Old) const;
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric   /// Determines whether the exception-scopes stack is empty.
3590b57cec5SDimitry Andric   bool empty() const { return StartOfData == EndOfBuffer; }
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric   bool requiresLandingPad() const;
3620b57cec5SDimitry Andric 
3630b57cec5SDimitry Andric   /// Determines whether there are any normal cleanups on the stack.
3640b57cec5SDimitry Andric   bool hasNormalCleanups() const {
3650b57cec5SDimitry Andric     return InnermostNormalCleanup != stable_end();
3660b57cec5SDimitry Andric   }
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric   /// Returns the innermost normal cleanup on the stack, or
3690b57cec5SDimitry Andric   /// stable_end() if there are no normal cleanups.
3700b57cec5SDimitry Andric   stable_iterator getInnermostNormalCleanup() const {
3710b57cec5SDimitry Andric     return InnermostNormalCleanup;
3720b57cec5SDimitry Andric   }
3730b57cec5SDimitry Andric   stable_iterator getInnermostActiveNormalCleanup() const;
3740b57cec5SDimitry Andric 
3750b57cec5SDimitry Andric   stable_iterator getInnermostEHScope() const {
3760b57cec5SDimitry Andric     return InnermostEHScope;
3770b57cec5SDimitry Andric   }
3780b57cec5SDimitry Andric 
3790b57cec5SDimitry Andric 
3800b57cec5SDimitry Andric   /// An unstable reference to a scope-stack depth.  Invalidated by
3810b57cec5SDimitry Andric   /// pushes but not pops.
3820b57cec5SDimitry Andric   class iterator;
3830b57cec5SDimitry Andric 
3840b57cec5SDimitry Andric   /// Returns an iterator pointing to the innermost EH scope.
3850b57cec5SDimitry Andric   iterator begin() const;
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric   /// Returns an iterator pointing to the outermost EH scope.
3880b57cec5SDimitry Andric   iterator end() const;
3890b57cec5SDimitry Andric 
3900b57cec5SDimitry Andric   /// Create a stable reference to the top of the EH stack.  The
3910b57cec5SDimitry Andric   /// returned reference is valid until that scope is popped off the
3920b57cec5SDimitry Andric   /// stack.
3930b57cec5SDimitry Andric   stable_iterator stable_begin() const {
3940b57cec5SDimitry Andric     return stable_iterator(EndOfBuffer - StartOfData);
3950b57cec5SDimitry Andric   }
3960b57cec5SDimitry Andric 
3970b57cec5SDimitry Andric   /// Create a stable reference to the bottom of the EH stack.
3980b57cec5SDimitry Andric   static stable_iterator stable_end() {
3990b57cec5SDimitry Andric     return stable_iterator(0);
4000b57cec5SDimitry Andric   }
4010b57cec5SDimitry Andric 
4020b57cec5SDimitry Andric   /// Translates an iterator into a stable_iterator.
4030b57cec5SDimitry Andric   stable_iterator stabilize(iterator it) const;
4040b57cec5SDimitry Andric 
4050b57cec5SDimitry Andric   /// Turn a stable reference to a scope depth into a unstable pointer
4060b57cec5SDimitry Andric   /// to the EH stack.
4070b57cec5SDimitry Andric   iterator find(stable_iterator save) const;
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric   /// Add a branch fixup to the current cleanup scope.
4100b57cec5SDimitry Andric   BranchFixup &addBranchFixup() {
4110b57cec5SDimitry Andric     assert(hasNormalCleanups() && "adding fixup in scope without cleanups");
4120b57cec5SDimitry Andric     BranchFixups.push_back(BranchFixup());
4130b57cec5SDimitry Andric     return BranchFixups.back();
4140b57cec5SDimitry Andric   }
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric   unsigned getNumBranchFixups() const { return BranchFixups.size(); }
4170b57cec5SDimitry Andric   BranchFixup &getBranchFixup(unsigned I) {
4180b57cec5SDimitry Andric     assert(I < getNumBranchFixups());
4190b57cec5SDimitry Andric     return BranchFixups[I];
4200b57cec5SDimitry Andric   }
4210b57cec5SDimitry Andric 
4220b57cec5SDimitry Andric   /// Pops lazily-removed fixups from the end of the list.  This
4230b57cec5SDimitry Andric   /// should only be called by procedures which have just popped a
4240b57cec5SDimitry Andric   /// cleanup or resolved one or more fixups.
4250b57cec5SDimitry Andric   void popNullFixups();
4260b57cec5SDimitry Andric 
4270b57cec5SDimitry Andric   /// Clears the branch-fixups list.  This should only be called by
4280b57cec5SDimitry Andric   /// ResolveAllBranchFixups.
4290b57cec5SDimitry Andric   void clearFixups() { BranchFixups.clear(); }
4300b57cec5SDimitry Andric };
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric } // namespace CodeGen
4330b57cec5SDimitry Andric } // namespace clang
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric #endif
436