]>
Commit | Line | Data |
---|---|---|
0a8c4c0c | 1 | // Functions for Exception Support for -*- C++ -*- |
d34786e3 | 2 | |
e2c09482 BK |
3 | // Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 |
4 | // Free Software Foundation | |
5 | // | |
0a8c4c0c | 6 | // This file is part of GNU CC. |
e2c09482 | 7 | // |
0a8c4c0c BK |
8 | // GNU CC is free software; you can redistribute it and/or modify |
9 | // it under the terms of the GNU General Public License as published by | |
10 | // the Free Software Foundation; either version 2, or (at your option) | |
11 | // any later version. | |
12 | ||
13 | // GNU CC is distributed in the hope that it will be useful, | |
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | // GNU General Public License for more details. | |
17 | ||
18 | // You should have received a copy of the GNU General Public License | |
19 | // along with GNU CC; see the file COPYING. If not, write to | |
20 | // the Free Software Foundation, 59 Temple Place - Suite 330, | |
21 | // Boston, MA 02111-1307, USA. | |
22 | ||
23 | // As a special exception, you may use this file as part of a free software | |
24 | // library without restriction. Specifically, if other files instantiate | |
25 | // templates or use macros or inline functions from this file, or you compile | |
26 | // this file and link it with other files to produce an executable, this | |
27 | // file does not by itself cause the resulting executable to be covered by | |
28 | // the GNU General Public License. This exception does not however | |
29 | // invalidate any other reasons why the executable file might be covered by | |
30 | // the GNU General Public License. | |
31 | ||
0a8c4c0c BK |
32 | #include "typeinfo" |
33 | #include "exception" | |
6b76f569 | 34 | #include <cstddef> |
f1f0c5a2 | 35 | #include "exception_support.h" |
e2c09482 | 36 | #include "exception_defines.h" |
0a8c4c0c BK |
37 | |
38 | /* Define terminate, unexpected, set_terminate, set_unexpected as | |
39 | well as the default terminate func and default unexpected func. */ | |
40 | ||
17fd8a87 CD |
41 | /* __terminate and __terminate_set_func, defined in libgcc2. */ |
42 | typedef void (*__terminate_func_ptr)(void) __attribute__ ((__noreturn__)); | |
43 | extern "C" void __terminate (void) __attribute__ ((__noreturn__)); | |
44 | extern "C" __terminate_func_ptr __terminate_set_func (__terminate_func_ptr); | |
45 | ||
0a8c4c0c BK |
46 | using std::terminate; |
47 | ||
48 | void | |
49 | std::terminate () | |
50 | { | |
17fd8a87 | 51 | __terminate (); |
0a8c4c0c BK |
52 | } |
53 | ||
54 | void | |
55 | __default_unexpected () | |
56 | { | |
57 | terminate (); | |
58 | } | |
59 | ||
60 | static std::unexpected_handler __unexpected_func __attribute__((__noreturn__)) | |
61 | = __default_unexpected; | |
62 | ||
63 | std::terminate_handler | |
d34786e3 | 64 | std::set_terminate (std::terminate_handler func) throw() |
0a8c4c0c | 65 | { |
17fd8a87 | 66 | return __terminate_set_func (func); |
0a8c4c0c BK |
67 | } |
68 | ||
69 | std::unexpected_handler | |
d34786e3 | 70 | std::set_unexpected (std::unexpected_handler func) throw() |
0a8c4c0c BK |
71 | { |
72 | std::unexpected_handler old = __unexpected_func; | |
73 | ||
74 | __unexpected_func = func; | |
75 | return old; | |
76 | } | |
77 | ||
78 | void | |
79 | std::unexpected () | |
80 | { | |
81 | __unexpected_func (); | |
82 | } | |
83 | ||
0a8c4c0c | 84 | /* Language-specific EH info pointer, defined in libgcc2. */ |
0a8c4c0c | 85 | extern "C" cp_eh_info **__get_eh_info (); // actually void ** |
e2c09482 | 86 | #define CP_EH_INFO ((cp_eh_info *) *__get_eh_info ()) |
0a8c4c0c BK |
87 | |
88 | /* Exception allocate and free, defined in libgcc2. */ | |
6b76f569 | 89 | extern "C" void *__eh_alloc(std::size_t); |
0a8c4c0c BK |
90 | extern "C" void __eh_free(void *); |
91 | ||
92 | /* Is P the type_info node for a pointer of some kind? */ | |
0a8c4c0c BK |
93 | extern bool __is_pointer (void *); |
94 | ||
95 | ||
e2c09482 | 96 | #ifdef __EXCEPTIONS |
0a8c4c0c BK |
97 | /* OLD Compiler hook to return a pointer to the info for the current exception. |
98 | Used by get_eh_info (). This fudges the actualy returned value to | |
99 | point to the beginning of what USE to be the cp_eh_info structure. | |
100 | THis is so that old code that dereferences this pointer will find | |
101 | things where it expects it to be.*/ | |
102 | extern "C" void * | |
103 | __cp_exception_info (void) | |
104 | { | |
105 | return &((*__get_eh_info ())->value); | |
106 | } | |
107 | ||
0a8c4c0c BK |
108 | /* Old Compiler hook to return a pointer to the info for the current exception. |
109 | Used by get_eh_info (). */ | |
110 | ||
111 | extern "C" cp_eh_info * | |
112 | __cp_eh_info (void) | |
113 | { | |
114 | cp_eh_info *p = CP_EH_INFO; | |
115 | return p; | |
116 | } | |
117 | ||
118 | /* Compiler hook to return a pointer to the info for the current exception, | |
119 | Set the caught bit, and increment the number of handlers that are | |
120 | looking at this exception. This makes handlers smaller. */ | |
121 | ||
122 | extern "C" cp_eh_info * | |
123 | __start_cp_handler (void) | |
124 | { | |
125 | cp_eh_info *p = CP_EH_INFO; | |
126 | p->caught = 1; | |
127 | p->handlers++; | |
128 | return p; | |
129 | } | |
130 | ||
131 | extern "C" int __throw_type_match_rtti_2 (const void *, const void *, | |
132 | void *, void **); | |
133 | ||
134 | extern "C" void * | |
135 | __cplus_type_matcher (__eh_info *info_, void *match_info, | |
136 | exception_descriptor *exception_table) | |
137 | { | |
138 | cp_eh_info *info = (cp_eh_info *)info_; | |
139 | ||
140 | /* No exception table implies the old style mechanism, so don't check. */ | |
141 | if (exception_table != NULL | |
142 | && exception_table->lang.language != EH_LANG_C_plus_plus) | |
143 | return NULL; | |
144 | ||
145 | if (match_info == CATCH_ALL_TYPE) | |
146 | return (void *)1; | |
147 | ||
148 | /* we don't worry about version info yet, there is only one version! */ | |
149 | ||
150 | void *match_type = match_info; | |
151 | ||
0a8c4c0c BK |
152 | if (__throw_type_match_rtti_2 (match_type, info->type, |
153 | info->original_value, &info->value)) | |
154 | // Arbitrary non-null pointer. | |
155 | return (void *)1; | |
156 | else | |
157 | return NULL; | |
158 | } | |
159 | ||
160 | /* Compiler hook to push a new exception onto the stack. | |
161 | Used by expand_throw(). */ | |
162 | ||
163 | extern "C" void | |
164 | __cp_push_exception (void *value, void *type, cleanup_fn cleanup) | |
165 | { | |
166 | cp_eh_info *p = (cp_eh_info *) __eh_alloc (sizeof (cp_eh_info)); | |
167 | ||
168 | p->value = value; | |
169 | p->type = type; | |
170 | p->cleanup = cleanup; | |
171 | p->handlers = 0; | |
172 | p->caught = false; | |
173 | p->original_value = value; | |
174 | ||
175 | p->eh_info.match_function = __cplus_type_matcher; | |
176 | p->eh_info.language = EH_LANG_C_plus_plus; | |
177 | p->eh_info.version = 1; | |
178 | ||
179 | cp_eh_info **q = __get_eh_info (); | |
180 | ||
181 | p->next = *q; | |
182 | *q = p; | |
183 | } | |
184 | ||
185 | /* Compiler hook to pop an exception that has been finalized. Used by | |
186 | push_eh_cleanup(). P is the info for the exception caught by the | |
187 | current catch block. */ | |
188 | ||
189 | extern "C" void | |
96070989 | 190 | __cp_pop_exception (void* p_) |
0a8c4c0c | 191 | { |
96070989 | 192 | cp_eh_info *p = static_cast <cp_eh_info *> (p_); |
0a8c4c0c BK |
193 | cp_eh_info **stack = __get_eh_info (); |
194 | cp_eh_info **q = stack; | |
195 | ||
196 | --p->handlers; | |
197 | ||
198 | /* Do nothing if our exception is being rethrown (i.e. if the active | |
199 | exception is our exception and it is uncaught). */ | |
200 | if (p == *q && !p->caught) | |
201 | return; | |
202 | ||
203 | /* Don't really pop if there are still active handlers for our exception; | |
204 | rather, push it down past any uncaught exceptions. */ | |
205 | if (p->handlers != 0) | |
206 | { | |
207 | if (p == *q && p->next && !p->next->caught) | |
208 | { | |
209 | q = &(p->next); | |
210 | while (1) | |
211 | { | |
212 | if (*q == 0 || (*q)->caught) | |
213 | break; | |
214 | ||
215 | q = &((*q)->next); | |
216 | } | |
217 | *stack = p->next; | |
218 | p->next = *q; | |
219 | *q = p; | |
220 | } | |
221 | return; | |
222 | } | |
223 | ||
224 | for (; *q; q = &((*q)->next)) | |
225 | if (*q == p) | |
226 | break; | |
227 | ||
228 | if (! *q) | |
229 | terminate (); | |
230 | ||
231 | *q = p->next; | |
232 | ||
233 | if (p->cleanup) | |
234 | // value may have been adjusted. | |
235 | CALL_CLEANUP (p->cleanup, p->original_value); | |
236 | ||
237 | if (! __is_pointer (p->type)) | |
238 | __eh_free (p->original_value); // value may have been adjusted. | |
239 | ||
240 | __eh_free (p); | |
241 | } | |
242 | ||
243 | /* We're doing a rethrow. Find the currently handled exception, mark it | |
244 | uncaught, and move it to the top of the EH stack. */ | |
245 | ||
f1f0c5a2 | 246 | extern "C" cp_eh_info * |
0a8c4c0c BK |
247 | __uncatch_exception (void) |
248 | { | |
249 | cp_eh_info **stack = __get_eh_info (); | |
250 | cp_eh_info **q = stack; | |
251 | cp_eh_info *p; | |
252 | ||
253 | while (1) | |
254 | { | |
255 | p = *q; | |
256 | ||
257 | if (p == 0) | |
258 | terminate (); | |
259 | if (p->caught) | |
260 | break; | |
261 | ||
262 | q = &(p->next); | |
263 | } | |
264 | ||
265 | if (q != stack) | |
266 | { | |
267 | *q = p->next; | |
268 | p->next = *stack; | |
269 | *stack = p; | |
270 | } | |
271 | ||
272 | p->caught = false; | |
f1f0c5a2 MM |
273 | |
274 | return p; | |
275 | } | |
276 | ||
277 | /* Mark P as caught after we previously marked it as uncaught. */ | |
278 | ||
279 | extern "C" void | |
280 | __recatch_exception (cp_eh_info *p) | |
281 | { | |
282 | p->caught = true; | |
0a8c4c0c BK |
283 | } |
284 | ||
285 | /* As per [except.unexpected]: | |
286 | If an exception is thrown, we check it against the spec. If it doesn't | |
287 | match, we call unexpected (). If unexpected () throws, we check that | |
288 | exception against the spec. If it doesn't match, if the spec allows | |
289 | bad_exception we throw that; otherwise we call terminate (). | |
290 | ||
291 | The compiler treats an exception spec as a try block with a generic | |
292 | handler that just calls this function with a list of the allowed | |
293 | exception types, so we have an active exception that can be rethrown. | |
294 | ||
295 | This function does not return. */ | |
296 | ||
297 | extern "C" void | |
298 | __check_eh_spec (int n, const void **spec) | |
299 | { | |
300 | cp_eh_info *p = CP_EH_INFO; | |
301 | void *d; | |
302 | ||
303 | for (int i = 0; i < n; ++i) | |
304 | { | |
305 | if (__throw_type_match_rtti_2 (spec[i], p->type, p->value, &d)) | |
306 | throw; | |
307 | } | |
308 | ||
309 | try | |
310 | { | |
311 | std::unexpected (); | |
312 | } | |
313 | catch (...) | |
314 | { | |
315 | // __exception_info is an artificial var pushed into each catch block. | |
316 | if (p != __exception_info) | |
317 | { | |
318 | p = __exception_info; | |
319 | for (int i = 0; i < n; ++i) | |
320 | { | |
321 | if (__throw_type_match_rtti_2 (spec[i], p->type, p->value, &d)) | |
322 | throw; | |
323 | } | |
324 | } | |
325 | ||
326 | const std::type_info &bad_exc = typeid (std::bad_exception); | |
327 | for (int i = 0; i < n; ++i) | |
328 | { | |
329 | if (__throw_type_match_rtti_2 (spec[i], &bad_exc, p->value, &d)) | |
330 | throw std::bad_exception (); | |
331 | } | |
332 | ||
333 | terminate (); | |
334 | } | |
335 | } | |
336 | ||
337 | /* Special case of the above for throw() specs. */ | |
338 | ||
339 | extern "C" void | |
340 | __check_null_eh_spec (void) | |
341 | { | |
342 | __check_eh_spec (0, 0); | |
343 | } | |
e2c09482 | 344 | #endif //__EXCEPTIONS |
0a8c4c0c BK |
345 | |
346 | // Helpers for rtti. Although these don't return, we give them return types so | |
347 | // that the type system is not broken. | |
0a8c4c0c | 348 | extern "C" void * |
94083e5d | 349 | __cxa_bad_cast () |
0a8c4c0c | 350 | { |
e2c09482 BK |
351 | #ifdef __EXCEPTIONS |
352 | throw std::bad_cast(); | |
353 | #else | |
354 | std::abort(); | |
355 | #endif | |
0a8c4c0c BK |
356 | return 0; |
357 | } | |
358 | ||
359 | extern "C" std::type_info const & | |
94083e5d | 360 | __cxa_bad_typeid () |
0a8c4c0c | 361 | { |
e2c09482 BK |
362 | #ifdef __EXCEPTIONS |
363 | throw std::bad_typeid(); | |
364 | #else | |
365 | std::abort(); | |
366 | #endif | |
0a8c4c0c BK |
367 | return typeid (void); |
368 | } | |
369 | ||
370 | /* Has the current exception been caught? */ | |
0a8c4c0c | 371 | bool |
e2c09482 | 372 | std::uncaught_exception() throw() |
0a8c4c0c BK |
373 | { |
374 | cp_eh_info *p = CP_EH_INFO; | |
375 | return p && ! p->caught; | |
376 | } | |
377 | ||
f68147f7 BK |
378 | std::exception::~exception() throw() { } |
379 | ||
380 | std::bad_exception::~bad_exception() throw() { } | |
381 | ||
e2c09482 BK |
382 | const char* |
383 | std::exception::what() const throw() | |
384 | { return typeid (*this).name (); } | |
f68147f7 BK |
385 | |
386 | ||
387 | ||
388 |