llvm.org GIT mirror llvm / 0028b2c
Be more typesafe Call terminate and unexpected where appropriate. Interface to libstdc++ as appropriate Initial cut at implementing function exception specifications git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@8169 91177308-0d34-0410-b5e6-96231b3b80d8 Chris Lattner 17 years ago
2 changed file(s) with 314 addition(s) and 74 deletion(s). Raw diff Collapse all Expand all
88
99 #include "c++-exception.h"
1010 #include
11 #include
1112
1213 //===----------------------------------------------------------------------===//
1314 // Generic exception support
2425 // __llvm_eh_has_uncaught_exception - This is used to implement
2526 // std::uncaught_exception.
2627 //
27 bool __llvm_eh_has_uncaught_exception(void) {
28 bool __llvm_eh_has_uncaught_exception() throw() {
2829 return UncaughtExceptionStack != 0;
2930 }
3031
3233 // current uncaught exception is of the specified language type. If so, it
3334 // returns a pointer to the exception area data.
3435 //
35 void *__llvm_eh_current_uncaught_exception_type(unsigned HandlerType) {
36 void *__llvm_eh_current_uncaught_exception_type(unsigned HandlerType) throw() {
3637 assert(UncaughtExceptionStack && "No uncaught exception!");
3738 if (UncaughtExceptionStack->ExceptionType == HandlerType)
3839 return UncaughtExceptionStack+1;
4344 //===----------------------------------------------------------------------===//
4445 // C++ Specific exception handling support...
4546 //
47 using namespace __cxxabiv1;
4648
4749 // __llvm_cxxeh_allocate_exception - This function allocates space for the
4850 // specified number of bytes, plus a C++ exception object header.
4951 //
50 void *__llvm_cxxeh_allocate_exception(unsigned NumBytes) {
52 void *__llvm_cxxeh_allocate_exception(unsigned NumBytes) throw() {
5153 // FIXME: This should eventually have back-up buffers for out-of-memory
5254 // situations.
5355 //
6365 // into the exception location throws. Otherwise it is called from the C++
6466 // exception object destructor.
6567 //
66 void __llvm_cxxeh_free_exception(void *ObjectPtr) {
68 void __llvm_cxxeh_free_exception(void *ObjectPtr) throw() {
6769 llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1;
6870 free(E);
6971 }
7274 // exception->ExceptionDestructor function pointer to destroy a caught
7375 // exception.
7476 //
75 static void cxx_destructor(llvm_exception *LE) {
77 static void cxx_destructor(llvm_exception *LE) /* might throw */{
7678 llvm_cxx_exception *E = get_cxx_exception(LE);
7779
7880 // The exception is no longer caught.
99101 // evaluated into it, this sets up all of the fields of the exception allowing
100102 // it to be thrown. After calling this, the code should call %llvm.unwind
101103 //
102 void __llvm_cxxeh_throw(void *ObjectPtr, const std::type_info *TypeInfoPtr,
103 void (*DtorPtr)(void*)) {
104 void __llvm_cxxeh_throw(void *ObjectPtr, void *TypeInfoPtr,
105 void (*DtorPtr)(void*)) throw() {
104106 llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1;
105107 E->BaseException.ExceptionDestructor = cxx_destructor;
106108 E->BaseException.ExceptionType = CXXException;
108110 UncaughtExceptionStack = &E->BaseException;
109111 E->BaseException.HandlerCount = 0;
110112
111 E->TypeInfo = TypeInfoPtr;
113 E->TypeInfo = (const std::type_info*)TypeInfoPtr;
112114 E->ExceptionObjectDestructor = DtorPtr;
113 E->UnexpectedHandler = 0; // FIXME
114 E->TerminateHandler = 0; // FIXME
115 }
116
117 // __llvm_cxxeh_current_uncaught_exception_isa - This function checks to see if
118 // the current uncaught exception is a C++ exception, and if it is of the
119 // specified type id. If so, it returns a pointer to the object adjusted as
120 // appropriate, otherwise it returns null.
121 //
122 void *__llvm_cxxeh_current_uncaught_exception_isa(
123 const std::type_info *CatchType) {
124 assert(UncaughtExceptionStack && "No uncaught exception!");
125 if (UncaughtExceptionStack->ExceptionType != CXXException)
126 return 0; // If it's not a c++ exception, it doesn't match!
127
128 // If it is a C++ exception, use the type info object stored in the exception
129 // to see if TypeID matches and, if so, to adjust the exception object
130 // pointer.
131 //
132 llvm_cxx_exception *E = get_cxx_exception(UncaughtExceptionStack);
133
115 E->UnexpectedHandler = __unexpected_handler;
116 E->TerminateHandler = __terminate_handler;
117 }
118
119
120 // CXXExceptionISA - use the type info object stored in the exception to see if
121 // TypeID matches and, if so, to adjust the exception object pointer.
122 //
123 static void *CXXExceptionISA(llvm_cxx_exception *E, const std::type_info *Type){
134124 // ThrownPtr is a pointer to the object being thrown...
135125 void *ThrownPtr = E+1;
136126 const std::type_info *ThrownType = E->TypeInfo;
146136 ThrownPtr = *(void **)ThrownPtr;
147137 #endif
148138
149 if (CatchType->__do_catch(ThrownType, &ThrownPtr, 1))
139 if (Type->__do_catch(ThrownType, &ThrownPtr, 1))
150140 return ThrownPtr;
151141
152142 return 0;
143 }
144
145 // __llvm_cxxeh_current_uncaught_exception_isa - This function checks to see if
146 // the current uncaught exception is a C++ exception, and if it is of the
147 // specified type id. If so, it returns a pointer to the object adjusted as
148 // appropriate, otherwise it returns null.
149 //
150 void *__llvm_cxxeh_current_uncaught_exception_isa(void *CatchType) throw() {
151 assert(UncaughtExceptionStack && "No uncaught exception!");
152 if (UncaughtExceptionStack->ExceptionType != CXXException)
153 return 0; // If it's not a c++ exception, it doesn't match!
154
155 // If it is a C++ exception, use the type info object stored in the exception
156 // to see if TypeID matches and, if so, to adjust the exception object
157 // pointer.
158 //
159 const std::type_info *Info = (const std::type_info *)CatchType;
160 return CXXExceptionISA(get_cxx_exception(UncaughtExceptionStack), Info);
153161 }
154162
155163
158166 // returns a pointer to the exception object portion of the exception. This
159167 // function must work with foreign exceptions.
160168 //
161 void *__llvm_cxxeh_begin_catch(void) {
169 void *__llvm_cxxeh_begin_catch() throw() {
162170 llvm_exception *E = UncaughtExceptionStack;
163171 assert(UncaughtExceptionStack && "There are no uncaught exceptions!?!?");
164172
182190 // object of the specified type. This function does never succeeds with foreign
183191 // exceptions (because they can never be of type CatchType).
184192 //
185 void *__llvm_cxxeh_begin_catch_if_isa(const std::type_info *CatchType) {
193 void *__llvm_cxxeh_begin_catch_if_isa(void *CatchType) throw() {
186194 void *ObjPtr = __llvm_cxxeh_current_uncaught_exception_isa(CatchType);
187195 if (!ObjPtr) return 0;
188196
196204 // top-level caught exception, destroying it if this is the last handler for the
197205 // exception.
198206 //
199 void __llvm_cxxeh_end_catch(void) {
207 void __llvm_cxxeh_end_catch() /* might throw */ {
200208 llvm_exception *E = CaughtExceptionStack;
201209 assert(E && "There are no caught exceptions!");
202210
204212 if (--E->HandlerCount == 0)
205213 E->ExceptionDestructor(E); // Release memory for the exception
206214 }
215
207216
208217 // __llvm_cxxeh_rethrow - This function turns the top-level caught exception
209218 // into an uncaught exception, in preparation for an llvm.unwind, which should
210219 // follow immediately after the call to this function. This function must be
211220 // prepared to deal with foreign exceptions.
212221 //
213 void __llvm_cxxeh_rethrow(void) {
222 void __llvm_cxxeh_rethrow() throw() {
214223 llvm_exception *E = CaughtExceptionStack;
215 if (E == 0) {
224 if (E == 0)
216225 // 15.1.8 - If there are no uncaught exceptions being thrown, 'throw;'
217226 // should call terminate.
218227 //
219 assert(0 && "FIXME: this should call E->Terminate!"); // FIXME!
220 }
228 __terminate(__terminate_handler);
221229
222230 // Otherwise we have an exception to rethrow. Move it back to the uncaught
223231 // stack.
228236 // Return to the caller, which should perform the unwind now.
229237 }
230238
239 static bool ExceptionSpecificationPermitsException(llvm_exception *E,
240 const std::type_info *Info,
241 va_list Args) {
242 // The only way it could match one of the types is if it is a C++ exception.
243 if (E->ExceptionType != CXXException) return false;
244
245 llvm_cxx_exception *Ex = get_cxx_exception(E);
246
247 // Scan the list of accepted types, checking to see if the uncaught
248 // exception is any of them.
249 do {
250 // Check to see if the exception matches one of the types allowed by the
251 // exception specification. If so, return to the caller to have the
252 // exception rethrown.
253 if (CXXExceptionISA(Ex, Info))
254 return true;
255
256 Info = va_arg(Args, std::type_info *);
257 } while (Info);
258 return false;
259 }
260
261
262 // __llvm_cxxeh_check_eh_spec - If a function with an exception specification is
263 // throwing an exception, this function gets called with the list of type_info
264 // objects that it is allowing to propagate. Check to see if the current
265 // uncaught exception is one of these types, and if so, allow it to be thrown by
266 // returning to the caller, which should immediately follow this call with
267 // llvm.unwind.
268 //
269 // Note that this function does not throw any exceptions, but we can't put an
270 // exception specification on it or else we'll get infinite loops!
271 //
272 void __llvm_cxxeh_check_eh_spec(void *Info, ...) {
273 const std::type_info *TypeInfo = (const std::type_info *)Info;
274 llvm_exception *E = UncaughtExceptionStack;
275 assert(E && "No uncaught exceptions!");
276
277 if (TypeInfo == 0) { // Empty exception specification
278 // Whatever exception this is, it is not allowed by the (empty) spec, call
279 // unexpected, according to 15.4.8.
280 try {
281 __llvm_cxxeh_begin_catch(); // Start the catch
282 __llvm_cxxeh_end_catch(); // Free the exception
283 __unexpected(__unexpected_handler);
284 } catch (...) {
285 // Any exception thrown by unexpected cannot match the ehspec. Call
286 // terminate, according to 15.4.9.
287 __terminate(__terminate_handler);
288 }
289 }
290
291 // Check to see if the exception matches one of the types allowed by the
292 // exception specification. If so, return to the caller to have the
293 // exception rethrown.
294
295 va_list Args;
296 va_start(Args, Info);
297 bool Ok = ExceptionSpecificationPermitsException(E, TypeInfo, Args);
298 va_end(Args);
299 if (Ok) return;
300
301 // Ok, now we know that the exception is either not a C++ exception (thus not
302 // permitted to pass through) or not a C++ exception that is allowed. Kill
303 // the exception and call the unexpected handler.
304 try {
305 __llvm_cxxeh_begin_catch(); // Start the catch
306 __llvm_cxxeh_end_catch(); // Free the exception
307 } catch (...) {
308 __terminate(__terminate_handler); // Exception dtor threw
309 }
310
311 try {
312 __unexpected(__unexpected_handler);
313 } catch (...) {
314 // If the unexpected handler threw an exception, we will get here. Since
315 // entering the try block calls ..._begin_catch, we need to "rethrow" the
316 // exception to make it uncaught again. Exiting the catch will then leave
317 // it in the uncaught state.
318 __llvm_cxxeh_rethrow();
319 }
320
321 // Grab the newly caught exception. If this exception is permitted by the
322 // specification, allow it to be thrown.
323 E = UncaughtExceptionStack;
324 assert(E && "No uncaught exceptions!");
325
326 va_start(Args, Info);
327 Ok = ExceptionSpecificationPermitsException(E, TypeInfo, Args);
328 va_end(Args);
329 if (Ok) return;
330
331 // Final case, check to see if we can throw an std::bad_exception.
332 try {
333 throw std::bad_exception();
334 } catch (...) {
335 __llvm_cxxeh_rethrow();
336 }
337
338 // Grab the new bad_exception...
339 E = UncaughtExceptionStack;
340 assert(E && "No uncaught exceptions!");
341
342 // If it's permitted, allow it to be thrown instead.
343 va_start(Args, Info);
344 Ok = ExceptionSpecificationPermitsException(E, TypeInfo, Args);
345 va_end(Args);
346 if (Ok) return;
347
348 // Otherwise, we are out of options, terminate, according to 15.5.2.2.
349 __terminate(__terminate_handler);
350 }
88
99 #include "c++-exception.h"
1010 #include
11 #include
1112
1213 //===----------------------------------------------------------------------===//
1314 // Generic exception support
2425 // __llvm_eh_has_uncaught_exception - This is used to implement
2526 // std::uncaught_exception.
2627 //
27 bool __llvm_eh_has_uncaught_exception(void) {
28 bool __llvm_eh_has_uncaught_exception() throw() {
2829 return UncaughtExceptionStack != 0;
2930 }
3031
3233 // current uncaught exception is of the specified language type. If so, it
3334 // returns a pointer to the exception area data.
3435 //
35 void *__llvm_eh_current_uncaught_exception_type(unsigned HandlerType) {
36 void *__llvm_eh_current_uncaught_exception_type(unsigned HandlerType) throw() {
3637 assert(UncaughtExceptionStack && "No uncaught exception!");
3738 if (UncaughtExceptionStack->ExceptionType == HandlerType)
3839 return UncaughtExceptionStack+1;
4344 //===----------------------------------------------------------------------===//
4445 // C++ Specific exception handling support...
4546 //
47 using namespace __cxxabiv1;
4648
4749 // __llvm_cxxeh_allocate_exception - This function allocates space for the
4850 // specified number of bytes, plus a C++ exception object header.
4951 //
50 void *__llvm_cxxeh_allocate_exception(unsigned NumBytes) {
52 void *__llvm_cxxeh_allocate_exception(unsigned NumBytes) throw() {
5153 // FIXME: This should eventually have back-up buffers for out-of-memory
5254 // situations.
5355 //
6365 // into the exception location throws. Otherwise it is called from the C++
6466 // exception object destructor.
6567 //
66 void __llvm_cxxeh_free_exception(void *ObjectPtr) {
68 void __llvm_cxxeh_free_exception(void *ObjectPtr) throw() {
6769 llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1;
6870 free(E);
6971 }
7274 // exception->ExceptionDestructor function pointer to destroy a caught
7375 // exception.
7476 //
75 static void cxx_destructor(llvm_exception *LE) {
77 static void cxx_destructor(llvm_exception *LE) /* might throw */{
7678 llvm_cxx_exception *E = get_cxx_exception(LE);
7779
7880 // The exception is no longer caught.
99101 // evaluated into it, this sets up all of the fields of the exception allowing
100102 // it to be thrown. After calling this, the code should call %llvm.unwind
101103 //
102 void __llvm_cxxeh_throw(void *ObjectPtr, const std::type_info *TypeInfoPtr,
103 void (*DtorPtr)(void*)) {
104 void __llvm_cxxeh_throw(void *ObjectPtr, void *TypeInfoPtr,
105 void (*DtorPtr)(void*)) throw() {
104106 llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1;
105107 E->BaseException.ExceptionDestructor = cxx_destructor;
106108 E->BaseException.ExceptionType = CXXException;
108110 UncaughtExceptionStack = &E->BaseException;
109111 E->BaseException.HandlerCount = 0;
110112
111 E->TypeInfo = TypeInfoPtr;
113 E->TypeInfo = (const std::type_info*)TypeInfoPtr;
112114 E->ExceptionObjectDestructor = DtorPtr;
113 E->UnexpectedHandler = 0; // FIXME
114 E->TerminateHandler = 0; // FIXME
115 }
116
117 // __llvm_cxxeh_current_uncaught_exception_isa - This function checks to see if
118 // the current uncaught exception is a C++ exception, and if it is of the
119 // specified type id. If so, it returns a pointer to the object adjusted as
120 // appropriate, otherwise it returns null.
121 //
122 void *__llvm_cxxeh_current_uncaught_exception_isa(
123 const std::type_info *CatchType) {
124 assert(UncaughtExceptionStack && "No uncaught exception!");
125 if (UncaughtExceptionStack->ExceptionType != CXXException)
126 return 0; // If it's not a c++ exception, it doesn't match!
127
128 // If it is a C++ exception, use the type info object stored in the exception
129 // to see if TypeID matches and, if so, to adjust the exception object
130 // pointer.
131 //
132 llvm_cxx_exception *E = get_cxx_exception(UncaughtExceptionStack);
133
115 E->UnexpectedHandler = __unexpected_handler;
116 E->TerminateHandler = __terminate_handler;
117 }
118
119
120 // CXXExceptionISA - use the type info object stored in the exception to see if
121 // TypeID matches and, if so, to adjust the exception object pointer.
122 //
123 static void *CXXExceptionISA(llvm_cxx_exception *E, const std::type_info *Type){
134124 // ThrownPtr is a pointer to the object being thrown...
135125 void *ThrownPtr = E+1;
136126 const std::type_info *ThrownType = E->TypeInfo;
146136 ThrownPtr = *(void **)ThrownPtr;
147137 #endif
148138
149 if (CatchType->__do_catch(ThrownType, &ThrownPtr, 1))
139 if (Type->__do_catch(ThrownType, &ThrownPtr, 1))
150140 return ThrownPtr;
151141
152142 return 0;
143 }
144
145 // __llvm_cxxeh_current_uncaught_exception_isa - This function checks to see if
146 // the current uncaught exception is a C++ exception, and if it is of the
147 // specified type id. If so, it returns a pointer to the object adjusted as
148 // appropriate, otherwise it returns null.
149 //
150 void *__llvm_cxxeh_current_uncaught_exception_isa(void *CatchType) throw() {
151 assert(UncaughtExceptionStack && "No uncaught exception!");
152 if (UncaughtExceptionStack->ExceptionType != CXXException)
153 return 0; // If it's not a c++ exception, it doesn't match!
154
155 // If it is a C++ exception, use the type info object stored in the exception
156 // to see if TypeID matches and, if so, to adjust the exception object
157 // pointer.
158 //
159 const std::type_info *Info = (const std::type_info *)CatchType;
160 return CXXExceptionISA(get_cxx_exception(UncaughtExceptionStack), Info);
153161 }
154162
155163
158166 // returns a pointer to the exception object portion of the exception. This
159167 // function must work with foreign exceptions.
160168 //
161 void *__llvm_cxxeh_begin_catch(void) {
169 void *__llvm_cxxeh_begin_catch() throw() {
162170 llvm_exception *E = UncaughtExceptionStack;
163171 assert(UncaughtExceptionStack && "There are no uncaught exceptions!?!?");
164172
182190 // object of the specified type. This function does never succeeds with foreign
183191 // exceptions (because they can never be of type CatchType).
184192 //
185 void *__llvm_cxxeh_begin_catch_if_isa(const std::type_info *CatchType) {
193 void *__llvm_cxxeh_begin_catch_if_isa(void *CatchType) throw() {
186194 void *ObjPtr = __llvm_cxxeh_current_uncaught_exception_isa(CatchType);
187195 if (!ObjPtr) return 0;
188196
196204 // top-level caught exception, destroying it if this is the last handler for the
197205 // exception.
198206 //
199 void __llvm_cxxeh_end_catch(void) {
207 void __llvm_cxxeh_end_catch() /* might throw */ {
200208 llvm_exception *E = CaughtExceptionStack;
201209 assert(E && "There are no caught exceptions!");
202210
204212 if (--E->HandlerCount == 0)
205213 E->ExceptionDestructor(E); // Release memory for the exception
206214 }
215
207216
208217 // __llvm_cxxeh_rethrow - This function turns the top-level caught exception
209218 // into an uncaught exception, in preparation for an llvm.unwind, which should
210219 // follow immediately after the call to this function. This function must be
211220 // prepared to deal with foreign exceptions.
212221 //
213 void __llvm_cxxeh_rethrow(void) {
222 void __llvm_cxxeh_rethrow() throw() {
214223 llvm_exception *E = CaughtExceptionStack;
215 if (E == 0) {
224 if (E == 0)
216225 // 15.1.8 - If there are no uncaught exceptions being thrown, 'throw;'
217226 // should call terminate.
218227 //
219 assert(0 && "FIXME: this should call E->Terminate!"); // FIXME!
220 }
228 __terminate(__terminate_handler);
221229
222230 // Otherwise we have an exception to rethrow. Move it back to the uncaught
223231 // stack.
228236 // Return to the caller, which should perform the unwind now.
229237 }
230238
239 static bool ExceptionSpecificationPermitsException(llvm_exception *E,
240 const std::type_info *Info,
241 va_list Args) {
242 // The only way it could match one of the types is if it is a C++ exception.
243 if (E->ExceptionType != CXXException) return false;
244
245 llvm_cxx_exception *Ex = get_cxx_exception(E);
246
247 // Scan the list of accepted types, checking to see if the uncaught
248 // exception is any of them.
249 do {
250 // Check to see if the exception matches one of the types allowed by the
251 // exception specification. If so, return to the caller to have the
252 // exception rethrown.
253 if (CXXExceptionISA(Ex, Info))
254 return true;
255
256 Info = va_arg(Args, std::type_info *);
257 } while (Info);
258 return false;
259 }
260
261
262 // __llvm_cxxeh_check_eh_spec - If a function with an exception specification is
263 // throwing an exception, this function gets called with the list of type_info
264 // objects that it is allowing to propagate. Check to see if the current
265 // uncaught exception is one of these types, and if so, allow it to be thrown by
266 // returning to the caller, which should immediately follow this call with
267 // llvm.unwind.
268 //
269 // Note that this function does not throw any exceptions, but we can't put an
270 // exception specification on it or else we'll get infinite loops!
271 //
272 void __llvm_cxxeh_check_eh_spec(void *Info, ...) {
273 const std::type_info *TypeInfo = (const std::type_info *)Info;
274 llvm_exception *E = UncaughtExceptionStack;
275 assert(E && "No uncaught exceptions!");
276
277 if (TypeInfo == 0) { // Empty exception specification
278 // Whatever exception this is, it is not allowed by the (empty) spec, call
279 // unexpected, according to 15.4.8.
280 try {
281 __llvm_cxxeh_begin_catch(); // Start the catch
282 __llvm_cxxeh_end_catch(); // Free the exception
283 __unexpected(__unexpected_handler);
284 } catch (...) {
285 // Any exception thrown by unexpected cannot match the ehspec. Call
286 // terminate, according to 15.4.9.
287 __terminate(__terminate_handler);
288 }
289 }
290
291 // Check to see if the exception matches one of the types allowed by the
292 // exception specification. If so, return to the caller to have the
293 // exception rethrown.
294
295 va_list Args;
296 va_start(Args, Info);
297 bool Ok = ExceptionSpecificationPermitsException(E, TypeInfo, Args);
298 va_end(Args);
299 if (Ok) return;
300
301 // Ok, now we know that the exception is either not a C++ exception (thus not
302 // permitted to pass through) or not a C++ exception that is allowed. Kill
303 // the exception and call the unexpected handler.
304 try {
305 __llvm_cxxeh_begin_catch(); // Start the catch
306 __llvm_cxxeh_end_catch(); // Free the exception
307 } catch (...) {
308 __terminate(__terminate_handler); // Exception dtor threw
309 }
310
311 try {
312 __unexpected(__unexpected_handler);
313 } catch (...) {
314 // If the unexpected handler threw an exception, we will get here. Since
315 // entering the try block calls ..._begin_catch, we need to "rethrow" the
316 // exception to make it uncaught again. Exiting the catch will then leave
317 // it in the uncaught state.
318 __llvm_cxxeh_rethrow();
319 }
320
321 // Grab the newly caught exception. If this exception is permitted by the
322 // specification, allow it to be thrown.
323 E = UncaughtExceptionStack;
324 assert(E && "No uncaught exceptions!");
325
326 va_start(Args, Info);
327 Ok = ExceptionSpecificationPermitsException(E, TypeInfo, Args);
328 va_end(Args);
329 if (Ok) return;
330
331 // Final case, check to see if we can throw an std::bad_exception.
332 try {
333 throw std::bad_exception();
334 } catch (...) {
335 __llvm_cxxeh_rethrow();
336 }
337
338 // Grab the new bad_exception...
339 E = UncaughtExceptionStack;
340 assert(E && "No uncaught exceptions!");
341
342 // If it's permitted, allow it to be thrown instead.
343 va_start(Args, Info);
344 Ok = ExceptionSpecificationPermitsException(E, TypeInfo, Args);
345 va_end(Args);
346 if (Ok) return;
347
348 // Otherwise, we are out of options, terminate, according to 15.5.2.2.
349 __terminate(__terminate_handler);
350 }