Chris Lattner | 79b81bf | 2003-08-30 22:47:59 +0000 | [diff] [blame] | 1 | //===- C++-Exception.cpp - Exception handling support for C++ exceptions --===// |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 2 | // |
| 3 | // This file defines the methods used to implement C++ exception handling in |
| 4 | // terms of the invoke and %llvm.unwind intrinsic. These primitives implement |
| 5 | // an exception handling ABI similar (but simpler and more efficient than) the |
| 6 | // Itanium C++ ABI exception handling standard. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
Chris Lattner | 79b81bf | 2003-08-30 22:47:59 +0000 | [diff] [blame] | 10 | #include "C++-Exception.h" |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 11 | #include <cstdlib> |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 12 | #include <cstdarg> |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 13 | |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 14 | //#define DEBUG |
| 15 | |
| 16 | #ifdef DEBUG |
Brian Gaeke | b8a4ed6 | 2003-10-10 18:46:52 +0000 | [diff] [blame^] | 17 | #include <cstdio> |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 18 | #endif |
| 19 | |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 20 | // LastCaughtException - The last exception caught by this handler. This is for |
| 21 | // implementation of _rethrow and _get_last_caught. |
| 22 | // |
Chris Lattner | 8d90749 | 2003-08-30 23:17:51 +0000 | [diff] [blame] | 23 | // FIXME: This should be thread-local! |
| 24 | // |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 25 | static llvm_exception *LastCaughtException = 0; |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 26 | |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 27 | |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 28 | using namespace __cxxabiv1; |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 29 | |
| 30 | // __llvm_cxxeh_allocate_exception - This function allocates space for the |
| 31 | // specified number of bytes, plus a C++ exception object header. |
| 32 | // |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 33 | void *__llvm_cxxeh_allocate_exception(unsigned NumBytes) throw() { |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 34 | // FIXME: This should eventually have back-up buffers for out-of-memory |
| 35 | // situations. |
| 36 | // |
| 37 | llvm_cxx_exception *E = |
| 38 | (llvm_cxx_exception *)malloc(NumBytes+sizeof(llvm_cxx_exception)); |
Misha Brukman | 8b2bd4e | 2003-10-10 17:57:28 +0000 | [diff] [blame] | 39 | E->BaseException.ExceptionType = 0; // initialize to invalid |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 40 | |
| 41 | return E+1; // return the pointer after the header |
| 42 | } |
| 43 | |
| 44 | // __llvm_cxxeh_free_exception - Low-level function to free an exception. This |
| 45 | // is called directly from generated C++ code if evaluating the exception value |
| 46 | // into the exception location throws. Otherwise it is called from the C++ |
| 47 | // exception object destructor. |
| 48 | // |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 49 | void __llvm_cxxeh_free_exception(void *ObjectPtr) throw() { |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 50 | llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1; |
| 51 | free(E); |
| 52 | } |
| 53 | |
| 54 | // cxx_destructor - This function is called through the generic |
| 55 | // exception->ExceptionDestructor function pointer to destroy a caught |
| 56 | // exception. |
| 57 | // |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 58 | static void cxx_destructor(llvm_exception *LE) /* might throw */{ |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 59 | assert(LE->Next == 0 && "On the uncaught stack??"); |
Chris Lattner | 5e22eb1 | 2003-08-27 04:51:26 +0000 | [diff] [blame] | 60 | llvm_cxx_exception *E = get_cxx_exception(LE); |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 61 | |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 62 | struct ExceptionFreer { |
| 63 | void *Ptr; |
| 64 | ExceptionFreer(void *P) : Ptr(P) {} |
| 65 | ~ExceptionFreer() { |
| 66 | // Free the memory for the exception, when the function is left, even if |
| 67 | // the exception object dtor throws its own exception! |
| 68 | __llvm_cxxeh_free_exception(Ptr); |
| 69 | } |
| 70 | } EF(E+1); |
| 71 | |
| 72 | // Run the exception object dtor if it exists. */ |
| 73 | if (E->ExceptionObjectDestructor) |
| 74 | E->ExceptionObjectDestructor(E); |
| 75 | } |
| 76 | |
| 77 | // __llvm_cxxeh_throw - Given a pointer to memory which has an exception object |
| 78 | // evaluated into it, this sets up all of the fields of the exception allowing |
| 79 | // it to be thrown. After calling this, the code should call %llvm.unwind |
| 80 | // |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 81 | void __llvm_cxxeh_throw(void *ObjectPtr, void *TypeInfoPtr, |
| 82 | void (*DtorPtr)(void*)) throw() { |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 83 | llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1; |
| 84 | E->BaseException.ExceptionDestructor = cxx_destructor; |
| 85 | E->BaseException.ExceptionType = CXXException; |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 86 | E->BaseException.HandlerCount = 0; |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 87 | E->BaseException.isRethrown = 0; |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 88 | |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 89 | E->TypeInfo = (const std::type_info*)TypeInfoPtr; |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 90 | E->ExceptionObjectDestructor = DtorPtr; |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 91 | E->UnexpectedHandler = __unexpected_handler; |
| 92 | E->TerminateHandler = __terminate_handler; |
Chris Lattner | 8d90749 | 2003-08-30 23:17:51 +0000 | [diff] [blame] | 93 | |
| 94 | __llvm_eh_add_uncaught_exception(&E->BaseException); |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 95 | } |
| 96 | |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 97 | |
| 98 | // CXXExceptionISA - use the type info object stored in the exception to see if |
| 99 | // TypeID matches and, if so, to adjust the exception object pointer. |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 100 | // |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 101 | static void *CXXExceptionISA(llvm_cxx_exception *E, |
| 102 | const std::type_info *Type) throw() { |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 103 | // ThrownPtr is a pointer to the object being thrown... |
| 104 | void *ThrownPtr = E+1; |
| 105 | const std::type_info *ThrownType = E->TypeInfo; |
| 106 | |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 107 | #if 0 |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 108 | // FIXME: this code exists in the GCC exception handling library: I haven't |
| 109 | // thought about this yet, so it should be verified at some point! |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 110 | |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 111 | // Pointer types need to adjust the actual pointer, not |
| 112 | // the pointer to pointer that is the exception object. |
| 113 | // This also has the effect of passing pointer types |
| 114 | // "by value" through the __cxa_begin_catch return value. |
| 115 | if (ThrownType->__is_pointer_p()) |
| 116 | ThrownPtr = *(void **)ThrownPtr; |
| 117 | #endif |
| 118 | |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 119 | if (Type->__do_catch(ThrownType, &ThrownPtr, 1)) { |
| 120 | #ifdef DEBUG |
| 121 | printf("isa<%s>(%s): 0x%p -> 0x%p\n", Type->name(), ThrownType->name(), |
| 122 | E+1, ThrownPtr); |
| 123 | #endif |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 124 | return ThrownPtr; |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 125 | } |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 126 | |
| 127 | return 0; |
| 128 | } |
| 129 | |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 130 | // __llvm_cxxeh_current_uncaught_exception_isa - This function checks to see if |
| 131 | // the current uncaught exception is a C++ exception, and if it is of the |
| 132 | // specified type id. If so, it returns a pointer to the object adjusted as |
| 133 | // appropriate, otherwise it returns null. |
| 134 | // |
| 135 | void *__llvm_cxxeh_current_uncaught_exception_isa(void *CatchType) throw() { |
Chris Lattner | 8d90749 | 2003-08-30 23:17:51 +0000 | [diff] [blame] | 136 | void *EPtr = __llvm_eh_current_uncaught_exception_type(CXXException); |
| 137 | if (EPtr == 0) return 0; // If it's not a c++ exception, it doesn't match! |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 138 | |
| 139 | // If it is a C++ exception, use the type info object stored in the exception |
| 140 | // to see if TypeID matches and, if so, to adjust the exception object |
| 141 | // pointer. |
| 142 | // |
| 143 | const std::type_info *Info = (const std::type_info *)CatchType; |
Chris Lattner | 8d90749 | 2003-08-30 23:17:51 +0000 | [diff] [blame] | 144 | return CXXExceptionISA((llvm_cxx_exception*)EPtr - 1, Info); |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 145 | } |
| 146 | |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 147 | |
Chris Lattner | 2b338325 | 2003-08-26 23:46:53 +0000 | [diff] [blame] | 148 | // __llvm_cxxeh_begin_catch - This function is called by "exception handlers", |
| 149 | // which transition an exception from being uncaught to being caught. It |
| 150 | // returns a pointer to the exception object portion of the exception. This |
| 151 | // function must work with foreign exceptions. |
| 152 | // |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 153 | void *__llvm_cxxeh_begin_catch() throw() { |
Chris Lattner | 8d90749 | 2003-08-30 23:17:51 +0000 | [diff] [blame] | 154 | llvm_exception *E = __llvm_eh_pop_from_uncaught_stack(); |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 155 | |
Chris Lattner | 2b338325 | 2003-08-26 23:46:53 +0000 | [diff] [blame] | 156 | // The exception is now caught. |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 157 | LastCaughtException = E; |
| 158 | E->Next = 0; |
| 159 | E->isRethrown = 0; |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 160 | |
Chris Lattner | 2b338325 | 2003-08-26 23:46:53 +0000 | [diff] [blame] | 161 | // Increment the handler count for this exception. |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 162 | E->HandlerCount++; |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 163 | |
| 164 | #ifdef DEBUG |
| 165 | printf("Exiting begin_catch Ex=0x%p HandlerCount=%d!\n", E+1, |
| 166 | E->HandlerCount); |
| 167 | #endif |
Chris Lattner | 2b338325 | 2003-08-26 23:46:53 +0000 | [diff] [blame] | 168 | |
| 169 | // Return a pointer to the raw exception object. |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 170 | return E+1; |
| 171 | } |
| 172 | |
Chris Lattner | 2b338325 | 2003-08-26 23:46:53 +0000 | [diff] [blame] | 173 | // __llvm_cxxeh_begin_catch_if_isa - This function checks to see if the current |
| 174 | // uncaught exception is of the specified type. If not, it returns a null |
| 175 | // pointer, otherwise it 'catches' the exception and returns a pointer to the |
| 176 | // object of the specified type. This function does never succeeds with foreign |
| 177 | // exceptions (because they can never be of type CatchType). |
| 178 | // |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 179 | void *__llvm_cxxeh_begin_catch_if_isa(void *CatchType) throw() { |
Chris Lattner | 2b338325 | 2003-08-26 23:46:53 +0000 | [diff] [blame] | 180 | void *ObjPtr = __llvm_cxxeh_current_uncaught_exception_isa(CatchType); |
| 181 | if (!ObjPtr) return 0; |
| 182 | |
| 183 | // begin_catch, meaning that the object is now "caught", not "uncaught" |
| 184 | __llvm_cxxeh_begin_catch(); |
| 185 | return ObjPtr; |
| 186 | } |
| 187 | |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 188 | // __llvm_cxxeh_get_last_caught - Return the last exception that was caught by |
| 189 | // ...begin_catch. |
| 190 | // |
| 191 | void *__llvm_cxxeh_get_last_caught() throw() { |
| 192 | assert(LastCaughtException && "No exception caught!!"); |
| 193 | return LastCaughtException+1; |
| 194 | } |
Chris Lattner | 2b338325 | 2003-08-26 23:46:53 +0000 | [diff] [blame] | 195 | |
| 196 | // __llvm_cxxeh_end_catch - This function decrements the HandlerCount of the |
| 197 | // top-level caught exception, destroying it if this is the last handler for the |
| 198 | // exception. |
| 199 | // |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 200 | void __llvm_cxxeh_end_catch(void *Ex) /* might throw */ { |
| 201 | llvm_exception *E = (llvm_exception*)Ex - 1; |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 202 | assert(E && "There are no caught exceptions!"); |
| 203 | |
Chris Lattner | 2b338325 | 2003-08-26 23:46:53 +0000 | [diff] [blame] | 204 | // If this is the last handler using the exception, destroy it now! |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 205 | if (--E->HandlerCount == 0 && !E->isRethrown) { |
| 206 | #ifdef DEBUG |
| 207 | printf("Destroying exception!\n"); |
| 208 | #endif |
Chris Lattner | 2b338325 | 2003-08-26 23:46:53 +0000 | [diff] [blame] | 209 | E->ExceptionDestructor(E); // Release memory for the exception |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 210 | } |
| 211 | #ifdef DEBUG |
| 212 | printf("Exiting end_catch Ex=0x%p HandlerCount=%d!\n", Ex, E->HandlerCount); |
| 213 | #endif |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 214 | } |
| 215 | |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 216 | // __llvm_cxxeh_call_terminate - This function is called when the dtor for an |
| 217 | // object being destroyed due to an exception throw throws an exception. This |
| 218 | // is illegal because it would cause multiple exceptions to be active at one |
| 219 | // time. |
Chris Lattner | 3926a83 | 2003-08-28 14:35:52 +0000 | [diff] [blame] | 220 | void __llvm_cxxeh_call_terminate() throw() { |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 221 | void (*Handler)(void) = __terminate_handler; |
Chris Lattner | 8d90749 | 2003-08-30 23:17:51 +0000 | [diff] [blame] | 222 | if (__llvm_eh_has_uncaught_exception()) |
| 223 | if (void *EPtr = __llvm_eh_current_uncaught_exception_type(CXXException)) |
| 224 | Handler = ((llvm_cxx_exception*)EPtr - 1)->TerminateHandler; |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 225 | __terminate(Handler); |
Chris Lattner | 3926a83 | 2003-08-28 14:35:52 +0000 | [diff] [blame] | 226 | } |
| 227 | |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 228 | |
Chris Lattner | 2b338325 | 2003-08-26 23:46:53 +0000 | [diff] [blame] | 229 | // __llvm_cxxeh_rethrow - This function turns the top-level caught exception |
| 230 | // into an uncaught exception, in preparation for an llvm.unwind, which should |
| 231 | // follow immediately after the call to this function. This function must be |
| 232 | // prepared to deal with foreign exceptions. |
| 233 | // |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 234 | void __llvm_cxxeh_rethrow() throw() { |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 235 | llvm_exception *E = LastCaughtException; |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 236 | if (E == 0) |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 237 | // 15.1.8 - If there are no exceptions being thrown, 'throw;' should call |
| 238 | // terminate. |
Chris Lattner | 2b338325 | 2003-08-26 23:46:53 +0000 | [diff] [blame] | 239 | // |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 240 | __terminate(__terminate_handler); |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 241 | |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 242 | // Otherwise we have an exception to rethrow. Mark the exception as such. |
| 243 | E->isRethrown = 1; |
| 244 | |
| 245 | // Add the exception to the top of the uncaught stack, to preserve the |
| 246 | // invariant that the top of the uncaught stack is the current exception. |
Chris Lattner | 8d90749 | 2003-08-30 23:17:51 +0000 | [diff] [blame] | 247 | __llvm_eh_add_uncaught_exception(E); |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 248 | |
Chris Lattner | 2b338325 | 2003-08-26 23:46:53 +0000 | [diff] [blame] | 249 | // Return to the caller, which should perform the unwind now. |
Chris Lattner | bbaaa11 | 2003-08-25 22:35:36 +0000 | [diff] [blame] | 250 | } |
| 251 | |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 252 | static bool ExceptionSpecificationPermitsException(llvm_exception *E, |
| 253 | const std::type_info *Info, |
| 254 | va_list Args) { |
| 255 | // The only way it could match one of the types is if it is a C++ exception. |
| 256 | if (E->ExceptionType != CXXException) return false; |
| 257 | |
| 258 | llvm_cxx_exception *Ex = get_cxx_exception(E); |
| 259 | |
| 260 | // Scan the list of accepted types, checking to see if the uncaught |
| 261 | // exception is any of them. |
| 262 | do { |
| 263 | // Check to see if the exception matches one of the types allowed by the |
| 264 | // exception specification. If so, return to the caller to have the |
| 265 | // exception rethrown. |
| 266 | if (CXXExceptionISA(Ex, Info)) |
| 267 | return true; |
| 268 | |
| 269 | Info = va_arg(Args, std::type_info *); |
| 270 | } while (Info); |
| 271 | return false; |
| 272 | } |
| 273 | |
| 274 | |
| 275 | // __llvm_cxxeh_check_eh_spec - If a function with an exception specification is |
| 276 | // throwing an exception, this function gets called with the list of type_info |
| 277 | // objects that it is allowing to propagate. Check to see if the current |
| 278 | // uncaught exception is one of these types, and if so, allow it to be thrown by |
| 279 | // returning to the caller, which should immediately follow this call with |
| 280 | // llvm.unwind. |
| 281 | // |
| 282 | // Note that this function does not throw any exceptions, but we can't put an |
| 283 | // exception specification on it or else we'll get infinite loops! |
| 284 | // |
| 285 | void __llvm_cxxeh_check_eh_spec(void *Info, ...) { |
| 286 | const std::type_info *TypeInfo = (const std::type_info *)Info; |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 287 | |
| 288 | if (TypeInfo == 0) { // Empty exception specification |
| 289 | // Whatever exception this is, it is not allowed by the (empty) spec, call |
| 290 | // unexpected, according to 15.4.8. |
| 291 | try { |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 292 | void *Ex = __llvm_cxxeh_begin_catch(); // Start the catch |
| 293 | __llvm_cxxeh_end_catch(Ex); // Free the exception |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 294 | __unexpected(__unexpected_handler); |
| 295 | } catch (...) { |
| 296 | // Any exception thrown by unexpected cannot match the ehspec. Call |
| 297 | // terminate, according to 15.4.9. |
| 298 | __terminate(__terminate_handler); |
| 299 | } |
| 300 | } |
| 301 | |
Chris Lattner | 8d90749 | 2003-08-30 23:17:51 +0000 | [diff] [blame] | 302 | llvm_exception *E = __llvm_eh_get_uncaught_exception(); |
| 303 | assert(E && "No uncaught exceptions!"); |
| 304 | |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 305 | // Check to see if the exception matches one of the types allowed by the |
| 306 | // exception specification. If so, return to the caller to have the |
| 307 | // exception rethrown. |
| 308 | |
| 309 | va_list Args; |
| 310 | va_start(Args, Info); |
| 311 | bool Ok = ExceptionSpecificationPermitsException(E, TypeInfo, Args); |
| 312 | va_end(Args); |
| 313 | if (Ok) return; |
| 314 | |
| 315 | // Ok, now we know that the exception is either not a C++ exception (thus not |
| 316 | // permitted to pass through) or not a C++ exception that is allowed. Kill |
| 317 | // the exception and call the unexpected handler. |
| 318 | try { |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 319 | void *Ex = __llvm_cxxeh_begin_catch(); // Start the catch |
| 320 | __llvm_cxxeh_end_catch(Ex); // Free the exception |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 321 | } catch (...) { |
Chris Lattner | 4f08308 | 2003-08-28 19:58:51 +0000 | [diff] [blame] | 322 | __terminate(__terminate_handler); // Exception dtor threw |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 323 | } |
| 324 | |
| 325 | try { |
| 326 | __unexpected(__unexpected_handler); |
| 327 | } catch (...) { |
| 328 | // If the unexpected handler threw an exception, we will get here. Since |
| 329 | // entering the try block calls ..._begin_catch, we need to "rethrow" the |
| 330 | // exception to make it uncaught again. Exiting the catch will then leave |
| 331 | // it in the uncaught state. |
| 332 | __llvm_cxxeh_rethrow(); |
| 333 | } |
| 334 | |
| 335 | // Grab the newly caught exception. If this exception is permitted by the |
| 336 | // specification, allow it to be thrown. |
Chris Lattner | 8d90749 | 2003-08-30 23:17:51 +0000 | [diff] [blame] | 337 | E = __llvm_eh_get_uncaught_exception(); |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 338 | |
| 339 | va_start(Args, Info); |
| 340 | Ok = ExceptionSpecificationPermitsException(E, TypeInfo, Args); |
| 341 | va_end(Args); |
| 342 | if (Ok) return; |
| 343 | |
| 344 | // Final case, check to see if we can throw an std::bad_exception. |
| 345 | try { |
| 346 | throw std::bad_exception(); |
| 347 | } catch (...) { |
| 348 | __llvm_cxxeh_rethrow(); |
| 349 | } |
| 350 | |
| 351 | // Grab the new bad_exception... |
Chris Lattner | 8d90749 | 2003-08-30 23:17:51 +0000 | [diff] [blame] | 352 | E = __llvm_eh_get_uncaught_exception(); |
Chris Lattner | 9dddce6 | 2003-08-27 23:00:11 +0000 | [diff] [blame] | 353 | |
| 354 | // If it's permitted, allow it to be thrown instead. |
| 355 | va_start(Args, Info); |
| 356 | Ok = ExceptionSpecificationPermitsException(E, TypeInfo, Args); |
| 357 | va_end(Args); |
| 358 | if (Ok) return; |
| 359 | |
| 360 | // Otherwise, we are out of options, terminate, according to 15.5.2.2. |
| 361 | __terminate(__terminate_handler); |
| 362 | } |