]>
Commit | Line | Data |
---|---|---|
5156628f | 1 | // Functions for Exception Support for -*- C++ -*- |
e5e809f4 | 2 | // Copyright (C) 1994, 1995, 1996, 1998 Free Software Foundation |
5156628f MS |
3 | |
4 | // This file is part of GNU CC. | |
5 | ||
6 | // GNU CC is free software; you can redistribute it and/or modify | |
7 | // it under the terms of the GNU General Public License as published by | |
8 | // the Free Software Foundation; either version 2, or (at your option) | |
9 | // any later version. | |
10 | ||
11 | // GNU CC is distributed in the hope that it will be useful, | |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | // GNU General Public License for more details. | |
15 | ||
16 | // You should have received a copy of the GNU General Public License | |
17 | // along with GNU CC; see the file COPYING. If not, write to | |
18 | // the Free Software Foundation, 59 Temple Place - Suite 330, | |
19 | // Boston, MA 02111-1307, USA. | |
20 | ||
21 | // As a special exception, if you link this library with other files, | |
22 | // some of which are compiled with GCC, to produce an executable, | |
23 | // this library does not by itself cause the resulting executable | |
24 | // to be covered by the GNU General Public License. | |
25 | // This exception does not however invalidate any other reasons why | |
26 | // the executable file might be covered by the GNU General Public License. | |
27 | ||
28 | #pragma implementation "exception" | |
29 | ||
30 | #include "typeinfo" | |
31 | #include "exception" | |
f4a23343 | 32 | #include <stddef.h> |
9a0d1e1b | 33 | #include "eh-common.h" |
5156628f | 34 | |
eb66be0e MS |
35 | /* Define terminate, unexpected, set_terminate, set_unexpected as |
36 | well as the default terminate func and default unexpected func. */ | |
37 | ||
2c73f9f5 ML |
38 | extern std::terminate_handler __terminate_func __attribute__((__noreturn__)); |
39 | using std::terminate; | |
5156628f MS |
40 | |
41 | void | |
2c73f9f5 | 42 | std::terminate () |
5156628f | 43 | { |
eb66be0e | 44 | __terminate_func (); |
5156628f MS |
45 | } |
46 | ||
47 | void | |
48 | __default_unexpected () | |
49 | { | |
eb66be0e | 50 | terminate (); |
5156628f MS |
51 | } |
52 | ||
2c73f9f5 | 53 | static std::unexpected_handler __unexpected_func __attribute__((__noreturn__)) |
6c20b7e9 | 54 | = __default_unexpected; |
5156628f | 55 | |
2c73f9f5 ML |
56 | std::terminate_handler |
57 | std::set_terminate (std::terminate_handler func) | |
5156628f | 58 | { |
2c73f9f5 | 59 | std::terminate_handler old = __terminate_func; |
5156628f MS |
60 | |
61 | __terminate_func = func; | |
62 | return old; | |
63 | } | |
64 | ||
2c73f9f5 ML |
65 | std::unexpected_handler |
66 | std::set_unexpected (std::unexpected_handler func) | |
5156628f | 67 | { |
2c73f9f5 | 68 | std::unexpected_handler old = __unexpected_func; |
5156628f MS |
69 | |
70 | __unexpected_func = func; | |
71 | return old; | |
72 | } | |
73 | ||
5156628f | 74 | void |
2c73f9f5 | 75 | std::unexpected () |
5156628f MS |
76 | { |
77 | __unexpected_func (); | |
78 | } | |
79 | ||
6874c264 | 80 | /* C++-specific state about the current exception. |
20b90169 JM |
81 | This must match init_exception_processing(). |
82 | ||
83 | Note that handlers and caught are not redundant; when rethrown, an | |
84 | exception can have multiple active handlers and still be considered | |
85 | uncaught. */ | |
6874c264 JM |
86 | |
87 | struct cp_eh_info | |
88 | { | |
9a0d1e1b | 89 | __eh_info eh_info; |
6874c264 JM |
90 | void *value; |
91 | void *type; | |
92 | void (*cleanup)(void *, int); | |
93 | bool caught; | |
94 | cp_eh_info *next; | |
20b90169 | 95 | long handlers; |
6874c264 JM |
96 | }; |
97 | ||
154bba13 | 98 | /* Language-specific EH info pointer, defined in libgcc2. */ |
6874c264 | 99 | |
154bba13 | 100 | extern "C" cp_eh_info **__get_eh_info (); // actually void ** |
6874c264 JM |
101 | |
102 | /* Is P the type_info node for a pointer of some kind? */ | |
103 | ||
104 | extern bool __is_pointer (void *); | |
105 | ||
a1622f83 AM |
106 | |
107 | /* OLD Compiler hook to return a pointer to the info for the current exception. | |
108 | Used by get_eh_info (). This fudges the actualy returned value to | |
109 | point to the beginning of what USE to be the cp_eh_info structure. | |
110 | THis is so that old code that dereferences this pointer will find | |
111 | things where it expects it to be.*/ | |
112 | extern "C" void * | |
113 | __cp_exception_info (void) | |
114 | { | |
115 | return &((*__get_eh_info ())->value); | |
116 | } | |
117 | ||
6874c264 JM |
118 | /* Compiler hook to return a pointer to the info for the current exception. |
119 | Used by get_eh_info (). */ | |
120 | ||
121 | extern "C" cp_eh_info * | |
a1622f83 | 122 | __cp_eh_info (void) |
6874c264 | 123 | { |
154bba13 | 124 | return *__get_eh_info (); |
6874c264 JM |
125 | } |
126 | ||
f4a23343 JM |
127 | /* Allocate a buffer for a cp_eh_info and an exception object of size SIZE, |
128 | and return a pointer to the beginning of the object's space. */ | |
129 | ||
130 | extern "C" void * malloc (size_t); | |
131 | extern "C" void * | |
132 | __eh_alloc (size_t size) | |
133 | { | |
134 | void *p = malloc (size); | |
135 | if (p == 0) | |
136 | terminate (); | |
137 | return p; | |
138 | } | |
139 | ||
140 | /* Free the memory for an cp_eh_info and associated exception, given | |
141 | a pointer to the cp_eh_info. */ | |
142 | ||
143 | extern "C" void free (void *); | |
144 | extern "C" void | |
145 | __eh_free (void *p) | |
146 | { | |
147 | free (p); | |
148 | } | |
149 | ||
9a0d1e1b | 150 | |
9a0d1e1b AM |
151 | typedef void * (* rtimetype) (void); |
152 | ||
153 | extern "C" void * | |
154 | __cplus_type_matcher (cp_eh_info *info, exception_table *matching_info, | |
155 | exception_descriptor *exception_table) | |
156 | { | |
157 | void *ret; | |
158 | ||
159 | if (exception_table->lang.language != EH_LANG_C_plus_plus) | |
160 | return NULL; | |
161 | ||
162 | /* we don't worry about version info yet, there is only one version! */ | |
163 | ||
164 | void *match_type = ((rtimetype) (matching_info->match_info)) (); | |
165 | ret = __throw_type_match_rtti (match_type, info->type, info->value); | |
166 | return ret; | |
167 | } | |
9a0d1e1b AM |
168 | |
169 | ||
6874c264 JM |
170 | /* Compiler hook to push a new exception onto the stack. |
171 | Used by expand_throw(). */ | |
172 | ||
173 | extern "C" void | |
174 | __cp_push_exception (void *value, void *type, void (*cleanup)(void *, int)) | |
175 | { | |
f4a23343 JM |
176 | cp_eh_info *p = (cp_eh_info *) __eh_alloc (sizeof (cp_eh_info)); |
177 | ||
6874c264 JM |
178 | p->value = value; |
179 | p->type = type; | |
180 | p->cleanup = cleanup; | |
20b90169 | 181 | p->handlers = 0; |
6874c264 | 182 | p->caught = false; |
154bba13 | 183 | |
9a0d1e1b AM |
184 | p->eh_info.match_function = __cplus_type_matcher; |
185 | p->eh_info.language = EH_LANG_C_plus_plus; | |
186 | p->eh_info.version = 1; | |
187 | p->eh_info.coerced_value = NULL; | |
9a0d1e1b | 188 | |
154bba13 TT |
189 | cp_eh_info **q = __get_eh_info (); |
190 | ||
191 | p->next = *q; | |
192 | *q = p; | |
6874c264 JM |
193 | } |
194 | ||
195 | /* Compiler hook to pop an exception that has been finalized. Used by | |
c7ae64f2 | 196 | push_eh_cleanup(). P is the info for the exception caught by the |
de35891e | 197 | current catch block. */ |
6874c264 JM |
198 | |
199 | extern "C" void | |
de35891e | 200 | __cp_pop_exception (cp_eh_info *p) |
6874c264 | 201 | { |
154bba13 | 202 | cp_eh_info **q = __get_eh_info (); |
c7ae64f2 | 203 | |
20b90169 JM |
204 | --p->handlers; |
205 | ||
de35891e JM |
206 | /* Don't really pop if there are still active handlers for our exception, |
207 | or if our exception is being rethrown (i.e. if the active exception is | |
208 | our exception and it is uncaught). */ | |
209 | if (p->handlers != 0 | |
210 | || (p == *q && !p->caught)) | |
c7ae64f2 JM |
211 | return; |
212 | ||
213 | for (; *q; q = &((*q)->next)) | |
214 | if (*q == p) | |
215 | break; | |
216 | ||
217 | if (! *q) | |
218 | terminate (); | |
219 | ||
220 | *q = p->next; | |
6874c264 JM |
221 | |
222 | if (p->cleanup) | |
f4a23343 JM |
223 | /* 2 is a magic value for destructors; see build_delete(). */ |
224 | p->cleanup (p->value, 2); | |
225 | ||
226 | if (! __is_pointer (p->type)) | |
227 | __eh_free (p->value); | |
228 | ||
229 | __eh_free (p); | |
6874c264 JM |
230 | } |
231 | ||
232 | extern "C" void | |
233 | __uncatch_exception (void) | |
234 | { | |
a1622f83 | 235 | cp_eh_info *p = __cp_eh_info (); |
f4a23343 JM |
236 | if (p == 0) |
237 | terminate (); | |
238 | p->caught = false; | |
6874c264 JM |
239 | } |
240 | ||
6c20b7e9 JM |
241 | /* As per [except.unexpected]: |
242 | If an exception is thrown, we check it against the spec. If it doesn't | |
243 | match, we call unexpected (). If unexpected () throws, we check that | |
244 | exception against the spec. If it doesn't match, if the spec allows | |
245 | bad_exception we throw that; otherwise we call terminate (). | |
246 | ||
247 | The compiler treats an exception spec as a try block with a generic | |
248 | handler that just calls this function with a list of the allowed | |
249 | exception types, so we have an active exception that can be rethrown. | |
250 | ||
251 | This function does not return. */ | |
252 | ||
253 | extern "C" void | |
254 | __check_eh_spec (int n, const void **spec) | |
255 | { | |
a1622f83 | 256 | cp_eh_info *p = __cp_eh_info (); |
6c20b7e9 JM |
257 | |
258 | for (int i = 0; i < n; ++i) | |
259 | { | |
260 | if (__throw_type_match_rtti (spec[i], p->type, p->value)) | |
261 | throw; | |
262 | } | |
263 | ||
264 | try | |
265 | { | |
2c73f9f5 | 266 | std::unexpected (); |
6c20b7e9 JM |
267 | } |
268 | catch (...) | |
269 | { | |
270 | // __exception_info is an artificial var pushed into each catch block. | |
de35891e | 271 | if (p != __exception_info) |
6c20b7e9 | 272 | { |
de35891e JM |
273 | p = __exception_info; |
274 | for (int i = 0; i < n; ++i) | |
275 | { | |
276 | if (__throw_type_match_rtti (spec[i], p->type, p->value)) | |
277 | throw; | |
278 | } | |
6c20b7e9 JM |
279 | } |
280 | ||
2c73f9f5 | 281 | const std::type_info &bad_exc = typeid (std::bad_exception); |
6c20b7e9 JM |
282 | for (int i = 0; i < n; ++i) |
283 | { | |
284 | if (__throw_type_match_rtti (spec[i], &bad_exc, p->value)) | |
2c73f9f5 | 285 | throw std::bad_exception (); |
6c20b7e9 JM |
286 | } |
287 | ||
288 | terminate (); | |
289 | } | |
290 | } | |
291 | ||
5156628f MS |
292 | extern "C" void |
293 | __throw_bad_cast (void) | |
294 | { | |
2c73f9f5 | 295 | throw std::bad_cast (); |
5156628f MS |
296 | } |
297 | ||
298 | extern "C" void | |
299 | __throw_bad_typeid (void) | |
300 | { | |
2c73f9f5 | 301 | throw std::bad_typeid (); |
5156628f MS |
302 | } |
303 | ||
6874c264 JM |
304 | /* Has the current exception been caught? */ |
305 | ||
5156628f | 306 | bool |
2c73f9f5 | 307 | std::uncaught_exception () |
5156628f | 308 | { |
a1622f83 | 309 | cp_eh_info *p = __cp_eh_info (); |
6874c264 | 310 | return p && ! p->caught; |
5156628f MS |
311 | } |
312 | ||
2c73f9f5 | 313 | const char * std::exception:: |
5156628f MS |
314 | what () const |
315 | { | |
316 | return typeid (*this).name (); | |
317 | } |