Commit | Line | Data |
---|---|---|
9bf86ebb PR |
1 | /* Handle exceptional things in C++. |
2 | Copyright (C) 1989, 1992, 1993 Free Software Foundation, Inc. | |
3 | Contributed by Michael Tiemann (tiemann@cygnus.com) | |
4 | ||
5 | This file is part of GNU CC. | |
6 | ||
7 | GNU CC is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GNU CC is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GNU CC; see the file COPYING. If not, write to | |
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | ||
21 | ||
22 | /* High-level class interface. */ | |
23 | ||
24 | #include "config.h" | |
25 | #include "tree.h" | |
26 | #include "rtl.h" | |
27 | #include "cp-tree.h" | |
28 | #include "flags.h" | |
29 | /* On Suns this can get you to the right definition if you | |
30 | set the right value for TARGET. */ | |
31 | #include <setjmp.h> | |
32 | #ifdef sequent | |
33 | /* Can you believe they forgot this? */ | |
34 | #define _JBLEN 11 | |
35 | #endif | |
36 | ||
37 | #ifndef _JBLEN | |
38 | #define _JBLEN (sizeof(jmp_buf)/sizeof(int)) | |
39 | #endif | |
40 | ||
41 | #undef NULL | |
42 | #define NULL (char *)0 | |
43 | ||
44 | /* This should be part of `ansi_opname', or at least be defined by the std. */ | |
45 | #define EXCEPTION_NAME_PREFIX "__ex" | |
46 | #define EXCEPTION_NAME_LENGTH 4 | |
47 | ||
48 | void init_exception_processing (); | |
49 | void init_exception_processing_1 (); | |
50 | ||
51 | /* If non-zero, a VAR_DECL whose cleanup will cause a throw to the | |
52 | next exception handler. Its value says whether to throw or not. | |
53 | In the case of functions which do not issue a RAISE, it should be | |
54 | possible to optimize away this VAR_DECL (and overhead associated | |
55 | with it). */ | |
56 | tree exception_throw_decl; | |
57 | /* Use this to know that we did not set `exception_throw_decl', | |
58 | until GCC optimizer is smart enough to figure it out for itself. */ | |
59 | int sets_exception_throw_decl; | |
60 | ||
61 | /* The exception `type' currently in scope, or NULL_TREE if none. */ | |
62 | tree current_exception_type; | |
63 | ||
64 | /* The exception handler object for the given scope. */ | |
65 | tree current_exception_decl; | |
66 | rtx current_exception_name_as_rtx; | |
67 | rtx current_exception_parms_as_rtx; | |
68 | ||
69 | /* The ``object'' view of the current exception parameters. | |
70 | We cast up from the `parms' field to `current_exception_type'. */ | |
71 | tree current_exception_object; | |
72 | ||
73 | /* Cache `setjmp', `longjmp', `raise_exception', and `unhandled_exception' | |
74 | after default conversion. Maybe later they will get built-in. */ | |
75 | static tree BISJ, BILJ, BIR, BIUE; | |
76 | ||
77 | /* Local variables which give the appearance that exception | |
78 | handling is part of the language and the execution model. */ | |
79 | ||
80 | /* The type of the exception handler stack. */ | |
81 | static tree EHS_type; | |
82 | ||
83 | /* The global handler stack. */ | |
84 | tree EHS_decl; | |
85 | ||
86 | /* Cached component refs to fields of `EHS_decl'. */ | |
87 | static tree EHS_prev, EHS_handler, EHS_parms, EHS_name; | |
88 | static rtx EHS_parms_as_rtx, EHS_name_as_rtx; | |
89 | ||
90 | /* The parameter names of this exception type. */ | |
91 | ||
92 | static tree last_exception_fields; | |
93 | static tree last_exception_field_types; | |
94 | ||
95 | /* When ID is VOID_TYPE_NODE, it means ``raise all''. | |
96 | Cannot be inline, since it uses `alloca', and that | |
97 | breaks code which pushes the result of this function | |
98 | on the stack. */ | |
99 | static tree | |
100 | exception_object_name (prefix, id) | |
101 | tree prefix; | |
102 | tree id; | |
103 | { | |
104 | /* First, cons up the `name' of this exception. */ | |
105 | char *name; | |
106 | int length = (id == void_type_node ? 3 : IDENTIFIER_LENGTH (id)) + EXCEPTION_NAME_LENGTH; | |
107 | ||
108 | if (prefix) | |
109 | length += IDENTIFIER_LENGTH (prefix) + 2; | |
110 | ||
111 | name = (char *)alloca (length); | |
112 | strcpy (name, EXCEPTION_NAME_PREFIX); | |
113 | length = EXCEPTION_NAME_LENGTH; | |
114 | if (prefix) | |
115 | { | |
116 | strcpy (name + length, IDENTIFIER_POINTER (prefix)); | |
117 | #ifdef JOINER | |
118 | name[length + IDENTIFIER_LENGTH (prefix)] = JOINER; | |
119 | #else | |
120 | name[length + IDENTIFIER_LENGTH (prefix)] = '_'; | |
121 | #endif | |
122 | length += IDENTIFIER_LENGTH (prefix) + 1; | |
123 | } | |
124 | if (id == void_type_node) | |
125 | strcpy (name + length, "all"); | |
126 | else | |
127 | strcpy (name + length, IDENTIFIER_POINTER (id)); | |
128 | return get_identifier (name); | |
129 | } | |
130 | ||
131 | tree | |
132 | lookup_exception_cname (ctype, cname, raise_id) | |
133 | tree ctype, cname; | |
134 | tree raise_id; | |
135 | { | |
136 | tree this_cname = TREE_PURPOSE (raise_id); | |
137 | if (this_cname == NULL_TREE) | |
138 | { | |
139 | if (cname) | |
140 | { | |
141 | tree name = TREE_VALUE (raise_id); | |
142 | if (purpose_member (name, CLASSTYPE_TAGS (ctype))) | |
143 | this_cname = cname; | |
144 | } | |
145 | } | |
146 | else if (this_cname == void_type_node) | |
147 | this_cname = NULL_TREE; | |
148 | else if (TREE_CODE (this_cname) != IDENTIFIER_NODE) | |
149 | { | |
150 | sorry ("multiple scope refs in `cplus_expand_raise_stmt'"); | |
151 | this_cname = error_mark_node; | |
152 | } | |
153 | return this_cname; | |
154 | } | |
155 | ||
156 | tree | |
157 | lookup_exception_tname (oname) | |
158 | tree oname; | |
159 | { | |
160 | return get_identifier (IDENTIFIER_POINTER (oname) + EXCEPTION_NAME_LENGTH); | |
161 | } | |
162 | ||
163 | tree | |
164 | lookup_exception_object (cname, name, complain) | |
165 | tree cname, name; | |
166 | int complain; | |
167 | { | |
168 | tree oname; | |
169 | tree decl; | |
170 | ||
171 | if (cname == void_type_node) | |
172 | cname = NULL_TREE; | |
173 | else if (cname && TREE_CODE (cname) != IDENTIFIER_NODE) | |
174 | { | |
175 | sorry ("multiple scope refs in `lookup_exception_object'"); | |
176 | cname = NULL_TREE; | |
177 | } | |
178 | oname = exception_object_name (cname, name); | |
179 | decl = IDENTIFIER_GLOBAL_VALUE (oname); | |
180 | if (decl == NULL_TREE || TREE_CODE (decl) != VAR_DECL) | |
181 | { | |
182 | if (complain) | |
183 | { | |
184 | push_obstacks_nochange (); | |
185 | ||
186 | if (cname) | |
187 | error ("no exception name object for name `%s::%s'", | |
188 | IDENTIFIER_POINTER (cname), | |
189 | IDENTIFIER_POINTER (name)); | |
190 | else | |
191 | error ("no exception name object for name `%s'", | |
192 | IDENTIFIER_POINTER (name)); | |
193 | end_temporary_allocation (); | |
194 | /* Avoid further error messages. */ | |
195 | pushdecl_top_level (build_lang_field_decl (VAR_DECL, | |
196 | exception_object_name (cname, name), | |
197 | error_mark_node)); | |
198 | pop_obstacks (); | |
199 | } | |
200 | return NULL_TREE; | |
201 | } | |
202 | return decl; | |
203 | } | |
204 | ||
205 | tree | |
206 | lookup_exception_type (ctype, cname, raise_id) | |
207 | tree ctype, cname; | |
208 | tree raise_id; | |
209 | { | |
210 | tree name = TREE_VALUE (raise_id); | |
211 | tree purpose = TREE_PURPOSE (raise_id); | |
212 | ||
213 | if (cname && purpose == NULL_TREE) | |
214 | purpose = cname; | |
215 | ||
216 | if (purpose && purpose != void_type_node) | |
217 | { | |
218 | tree link = NULL_TREE; | |
219 | ||
220 | if (TREE_CODE (purpose) != IDENTIFIER_NODE) | |
221 | { | |
222 | sorry ("multiple scope refs in `lookup_exception_type'"); | |
223 | TREE_PURPOSE (raise_id) = NULL_TREE; | |
224 | return NULL_TREE; | |
225 | } | |
226 | if (! is_aggr_typedef (purpose, 1)) | |
227 | return NULL_TREE; | |
228 | ctype = IDENTIFIER_TYPE_VALUE (purpose); | |
229 | link = purpose_member (name, CLASSTYPE_TAGS (ctype)); | |
230 | if (link) | |
231 | return TREE_VALUE (link); | |
232 | } | |
233 | ||
234 | ctype = lookup_name (name, 1); | |
235 | if (ctype && TREE_CODE (ctype) == TYPE_DECL) | |
236 | ctype = TREE_TYPE (ctype); | |
237 | if (ctype && TREE_CODE (ctype) == RECORD_TYPE | |
238 | && CLASSTYPE_DECLARED_EXCEPTION (ctype)) | |
239 | return ctype; | |
240 | return NULL_TREE; | |
241 | } | |
242 | ||
243 | tree | |
244 | finish_exception (e, list_of_fieldlists) | |
245 | tree e; | |
246 | tree list_of_fieldlists; | |
247 | { | |
248 | tree parmtypes = NULL_TREE, name_field; | |
249 | tree cname = TYPE_NAME (e); | |
250 | ||
251 | if (TREE_CODE (cname) == TYPE_DECL) | |
252 | cname = DECL_NAME (cname); | |
253 | ||
254 | if (last_exception_fields) | |
255 | error ("cannot declare exceptions within exceptions"); | |
256 | if (list_of_fieldlists && ! ANON_AGGRNAME_P (cname)) | |
257 | error_with_aggr_type (e, "exception name `%s' must follow body declaration"); | |
258 | if (list_of_fieldlists) | |
259 | { | |
260 | tree prev, field; | |
261 | ||
262 | /* Note: no public, private, or protected allowed. */ | |
263 | if (TREE_CHAIN (list_of_fieldlists)) | |
264 | error ("visibility declarations invalid in exception declaration"); | |
265 | else if (TREE_PURPOSE (list_of_fieldlists) != (tree)visibility_default) | |
266 | error ("visibility declarations invalid in exception declaration"); | |
267 | TREE_PURPOSE (list_of_fieldlists) = (tree)visibility_default; | |
268 | ||
269 | /* Note also: no member function declarations allowed. */ | |
270 | for (prev = 0, field = TREE_VALUE (list_of_fieldlists); | |
271 | field; prev = field, field = TREE_CHAIN (field)) | |
272 | { | |
273 | switch (TREE_CODE (field)) | |
274 | { | |
275 | case FIELD_DECL: | |
276 | /* ok. */ | |
277 | parmtypes = tree_cons (NULL_TREE, TREE_TYPE (field), parmtypes); | |
278 | continue; | |
279 | case FUNCTION_DECL: | |
280 | error_with_decl (field, "declaration of function `%s' in exception invalid"); | |
281 | break; | |
282 | case VAR_DECL: | |
283 | if (TREE_STATIC (field)) | |
284 | error_with_decl (field, "declaration of static variable `%s' in exception invalid"); | |
285 | else | |
286 | error_with_decl (field, "declaration of constant field `%s' in exception invalid"); | |
287 | break; | |
288 | case CONST_DECL: | |
289 | error_with_decl (field, "declaration of enum value `%s' in exception invalid"); | |
290 | break; | |
291 | case SCOPE_REF: | |
292 | error ("use of `::' in exception context invalid"); | |
293 | break; | |
294 | } | |
295 | if (prev) | |
296 | TREE_CHAIN (prev) = TREE_CHAIN (field); | |
297 | else | |
298 | TREE_VALUE (list_of_fieldlists) = TREE_CHAIN (field); | |
299 | } | |
300 | } | |
301 | ||
302 | /* Now that we've cleaned up the fields, add a name identifier at front. */ | |
303 | name_field = build_lang_field_decl (FIELD_DECL, get_identifier ("__name"), | |
304 | ptr_type_node); | |
305 | if (list_of_fieldlists) | |
306 | { | |
307 | TREE_CHAIN (name_field) = TREE_VALUE (list_of_fieldlists); | |
308 | TREE_VALUE (list_of_fieldlists) = name_field; | |
309 | } | |
310 | else | |
311 | list_of_fieldlists = build_tree_list (NULL_TREE, name_field); | |
312 | ||
313 | last_exception_fields = TREE_VALUE (list_of_fieldlists); | |
314 | if (parmtypes) | |
315 | { | |
316 | last_exception_field_types = nreverse (parmtypes); | |
317 | /* Set the TREE_CHAIN of what is now at the end of the | |
318 | list to `void_list_node'. */ | |
319 | TREE_CHAIN (parmtypes) = void_list_node; | |
320 | } | |
321 | else | |
322 | last_exception_field_types = void_list_node; | |
323 | ||
324 | popclass (0); | |
325 | ||
326 | #if 0 | |
327 | /* Remove aggregate types from the list of tags, | |
328 | since these appear at global scope. */ | |
329 | while (x && IS_AGGR_TYPE (TREE_VALUE (x))) | |
330 | x = TREE_CHAIN (x); | |
331 | CLASSTYPE_TAGS (t) = x; | |
332 | y = x; | |
333 | while (x) | |
334 | { | |
335 | if (IS_AGGR_TYPE (TREE_VALUE (x))) | |
336 | TREE_CHAIN (y) = TREE_CHAIN (x); | |
337 | x = TREE_CHAIN (x); | |
338 | } | |
339 | #endif | |
340 | ||
341 | if (flag_cadillac) | |
342 | cadillac_finish_exception (e); | |
343 | ||
344 | return e; | |
345 | } | |
346 | ||
347 | void | |
348 | finish_exception_decl (cname, decl) | |
349 | tree cname, decl; | |
350 | { | |
351 | /* In cp-decl.h. */ | |
352 | extern tree last_function_parms; | |
353 | ||
354 | /* An exception declaration. */ | |
355 | tree t, ctor; | |
356 | tree parmdecls = NULL_TREE, fields; | |
357 | tree list_of_fieldlists = temp_tree_cons (NULL_TREE, | |
358 | copy_list (last_exception_fields), | |
359 | NULL_TREE); | |
360 | tree edecl = build_lang_field_decl (VAR_DECL, | |
361 | exception_object_name (cname, DECL_NAME (decl)), | |
362 | ptr_type_node); | |
363 | ||
364 | DECL_LANGUAGE (edecl) = lang_c; | |
365 | TREE_STATIC (edecl) = 1; | |
366 | TREE_PUBLIC (edecl) = 1; | |
367 | finish_decl (pushdecl (edecl), NULL_TREE, NULL_TREE, 0); | |
368 | ||
369 | /* Now instantiate the exception decl. */ | |
370 | t = xref_tag (exception_type_node, DECL_NAME (decl), NULL_TREE); | |
371 | ||
372 | /* finish_struct will pop this. */ | |
373 | pushclass (t, 0); | |
374 | ||
375 | /* Now add a constructor which takes as parameters all the types we | |
376 | just defined. */ | |
377 | ctor = build_lang_decl (FUNCTION_DECL, DECL_NAME (decl), | |
378 | build_cplus_method_type (t, TYPE_POINTER_TO (t), | |
379 | last_exception_field_types)); | |
380 | /* Don't take `name'. The constructor handles that. */ | |
381 | fields = TREE_CHAIN (TREE_VALUE (list_of_fieldlists)); | |
382 | while (fields) | |
383 | { | |
384 | tree parm = build_decl (PARM_DECL, DECL_NAME (fields), TREE_TYPE (fields)); | |
385 | /* Since there is a prototype, args are passed in their own types. */ | |
386 | DECL_ARG_TYPE (parm) = TREE_TYPE (parm); | |
387 | #ifdef PROMOTE_PROTOTYPES | |
388 | if (TREE_CODE (TREE_TYPE (fields)) == INTEGER_TYPE | |
389 | && TYPE_PRECISION (TREE_TYPE (fields)) < TYPE_PRECISION (integer_type_node)) | |
390 | DECL_ARG_TYPE (parm) = integer_type_node; | |
391 | #endif | |
392 | TREE_CHAIN (parm) = parmdecls; | |
393 | parmdecls = parm; | |
394 | fields = TREE_CHAIN (fields); | |
395 | } | |
396 | fields = TREE_VALUE (list_of_fieldlists); | |
397 | last_function_parms = nreverse (parmdecls); | |
398 | ||
399 | DECL_CONSTRUCTOR_P (ctor) = 1; | |
400 | TYPE_HAS_CONSTRUCTOR (t) = 1; | |
401 | grokclassfn (t, DECL_NAME (decl), ctor, NO_SPECIAL, NULL_TREE); | |
402 | DECL_EXTERNAL (ctor) = 1; | |
403 | TREE_STATIC (ctor) = 1; | |
404 | TREE_PUBLIC (ctor) = 0; | |
405 | DECL_INLINE (ctor) = 1; | |
406 | make_decl_rtl (ctor, NULL_PTR, 1); | |
407 | finish_decl (ctor, NULL_TREE, NULL_TREE, 0); | |
408 | TREE_CHAIN (ctor) = TREE_VALUE (list_of_fieldlists); | |
409 | TREE_VALUE (list_of_fieldlists) = ctor; | |
410 | ||
411 | finish_struct (t, list_of_fieldlists, 0); | |
412 | ||
413 | if (current_function_decl) | |
414 | error ("cannot define exception inside function scope"); | |
415 | else | |
416 | { | |
417 | enum debug_info_type old_write_symbols = write_symbols; | |
418 | write_symbols = NO_DEBUG; | |
419 | ||
420 | /* Now build the constructor for this exception. */ | |
421 | parmdecls = DECL_ARGUMENTS (ctor); | |
422 | start_function (NULL_TREE, ctor, 0, 1); | |
423 | store_parm_decls (); | |
424 | pushlevel (0); | |
425 | clear_last_expr (); | |
426 | push_momentary (); | |
427 | expand_start_bindings (0); | |
428 | ||
429 | /* Move all the parameters to the fields, skipping `this'. */ | |
430 | parmdecls = TREE_CHAIN (parmdecls); | |
431 | /* Install `name' of this exception handler. */ | |
432 | DECL_INITIAL (fields) = build_unary_op (ADDR_EXPR, edecl, 0); | |
433 | fields = TREE_CHAIN (fields); | |
434 | /* Install all the values. */ | |
435 | while (fields) | |
436 | { | |
437 | /* Set up the initialization for this field. */ | |
438 | DECL_INITIAL (fields) = parmdecls; | |
439 | fields = TREE_CHAIN (fields); | |
440 | parmdecls = TREE_CHAIN (parmdecls); | |
441 | } | |
442 | emit_base_init (t, 0); | |
443 | ||
444 | finish_function (DECL_SOURCE_LINE (ctor), 1); | |
445 | write_symbols = old_write_symbols; | |
446 | } | |
447 | } | |
448 | ||
449 | void | |
450 | end_exception_decls () | |
451 | { | |
452 | last_exception_field_types = NULL_TREE; | |
453 | last_exception_fields = NULL_TREE; | |
454 | } | |
455 | \f | |
456 | /* Statement-level exception semantics. */ | |
457 | ||
458 | void | |
459 | cplus_expand_start_try (implicit) | |
460 | int implicit; | |
461 | { | |
462 | tree call_to_setjmp; | |
463 | tree handler, ref; | |
464 | ||
465 | /* Start a new block enclosing the whole handler. */ | |
466 | if (implicit) | |
467 | { | |
468 | pushlevel_temporary (1); | |
469 | } | |
470 | else | |
471 | { | |
472 | pushlevel (0); | |
473 | clear_last_expr (); | |
474 | push_momentary (); | |
475 | ||
476 | /* Encompass whole exception handler in one big binding contour. | |
477 | If RAISE should throw out of the whole TRY/EXCEPT block, call | |
478 | `expand_start_bindings' with argument of 1. */ | |
479 | expand_start_bindings (0); | |
480 | } | |
481 | ||
482 | /* Allocate handler in that block. It's real name will come later. | |
483 | Note that it will be the first name in this binding contour. */ | |
484 | handler = get_temp_name (EHS_type, 0); | |
485 | DECL_INITIAL (handler) = error_mark_node; | |
486 | finish_decl (handler, NULL_TREE, NULL_TREE, 0); | |
487 | ||
488 | /* Must come after call to `finish_decl', else the cleanup for the temp | |
489 | for the handler will cause the contour we just created to be popped. */ | |
490 | if (implicit) | |
491 | declare_implicit_exception (); | |
492 | ||
493 | /* Catch via `setjmp'. */ | |
494 | ref = build_component_ref (handler, get_identifier ("handler"), NULL_TREE, 0); | |
495 | call_to_setjmp = build_function_call (BISJ, build_tree_list (NULL_TREE, ref)); | |
496 | ||
497 | /* RAISE throws to EXCEPT part. */ | |
498 | expand_start_try (build_binary_op (EQ_EXPR, call_to_setjmp, integer_zero_node, 1), 0, 1); | |
499 | } | |
500 | ||
501 | /* If KEEP is 1, then declarations in the TRY statement are worth keeping. | |
502 | If KEEP is 2, then the TRY statement was generated by the compiler. | |
503 | If KEEP is 0, the declarations in the TRY statement contain errors. */ | |
504 | ||
505 | tree | |
506 | cplus_expand_end_try (keep) | |
507 | int keep; | |
508 | { | |
509 | tree decls, decl, block; | |
510 | ||
511 | if (keep < 2) | |
512 | pop_implicit_try_blocks (NULL_TREE); | |
513 | ||
514 | decls = getdecls (); | |
515 | ||
516 | /* Emit code to avoid falling through into a default | |
517 | handler that might come later. */ | |
518 | expand_end_try (); | |
519 | ||
520 | /* Pops binding contour local to TRY, and get the exception handler | |
521 | object built by `...start_try'. */ | |
522 | switch (keep) | |
523 | { | |
524 | case 0: | |
525 | expand_end_bindings (decls, 0, 1); | |
526 | block = poplevel (0, 0, 0); | |
527 | pop_momentary (); | |
528 | decl = getdecls (); | |
529 | break; | |
530 | ||
531 | case 1: | |
532 | expand_end_bindings (decls, 1, 1); | |
533 | block = poplevel (1, 1, 0); | |
534 | pop_momentary (); | |
535 | decl = getdecls (); | |
536 | break; | |
537 | ||
538 | default: | |
539 | decl = tree_last (decls); | |
540 | block = NULL_TREE; | |
541 | break; | |
542 | } | |
543 | ||
544 | my_friendly_assert (TREE_CODE (decl) == VAR_DECL | |
545 | && TREE_TYPE (decl) == EHS_type, 203); | |
546 | if (block) | |
547 | { | |
548 | BLOCK_HANDLER_BLOCK (block) = 1; | |
549 | TREE_USED (block) = 1; | |
550 | } | |
551 | ||
552 | /* Pass it back so that its rtl can be bound to its name | |
553 | (or vice versa). */ | |
554 | return decl; | |
555 | } | |
556 | ||
557 | void | |
558 | cplus_expand_start_except (name, decl) | |
559 | tree name, decl; | |
560 | { | |
561 | int yes; | |
562 | tree tmp, init; | |
563 | ||
564 | expand_start_except (0, 1); | |
565 | ||
566 | /* This is internal `eh'. */ | |
567 | current_exception_decl = decl; | |
568 | current_exception_name_as_rtx | |
569 | = expand_expr (build (COMPONENT_REF, ptr_type_node, | |
570 | current_exception_decl, TREE_OPERAND (EHS_name, 1)), | |
571 | 0, 0, 0); | |
572 | init = build (COMPONENT_REF, ptr_type_node, decl, TREE_OPERAND (EHS_parms, 1)); | |
573 | current_exception_parms_as_rtx = expand_expr (init, 0, 0, 0); | |
574 | ||
575 | if (name) | |
576 | { | |
577 | /* Get the exception object into scope (user declared `ex'). */ | |
578 | tmp = pushdecl (build_decl (VAR_DECL, name, ptr_type_node)); | |
579 | DECL_INITIAL (tmp) = error_mark_node; | |
580 | finish_decl (tmp, init, 0, 0); | |
581 | } | |
582 | current_exception_type = NULL_TREE; | |
583 | yes = suspend_momentary (); | |
584 | if (name) | |
585 | { | |
586 | /* From now on, send the user to our faked-up object. */ | |
587 | current_exception_object = build1 (INDIRECT_REF, void_type_node, tmp); | |
588 | IDENTIFIER_LOCAL_VALUE (name) = current_exception_object; | |
589 | } | |
590 | resume_momentary (yes); | |
591 | ||
592 | /* Pop exception handler stack. */ | |
593 | expand_assignment (EHS_decl, EHS_prev, 0, 0); | |
594 | } | |
595 | ||
596 | /* Generate the call to `unhandled_exception' that is appropriate | |
597 | for this particular unhandled exception. */ | |
598 | static tree | |
599 | call_to_unhandled_exception () | |
600 | { | |
601 | extern int lineno; | |
602 | extern tree combine_strings (); | |
603 | tree parms = tree_cons (NULL_TREE, | |
604 | combine_strings (build_string (strlen (input_filename + 1), input_filename)), | |
605 | build_tree_list (NULL_TREE, build_int_2 (lineno, 0))); | |
606 | return build_function_call (BIUE, parms); | |
607 | } | |
608 | ||
609 | /* Note that this must be mirror image of `...start_try'. | |
610 | DFAULT is the default clause, if there was one. | |
611 | DFAULT is ERROR_MARK_NODE when this ends an implicit handler. */ | |
612 | void | |
613 | cplus_expand_end_except (dfault) | |
614 | tree dfault; | |
615 | { | |
616 | extern tree expand_end_except (); /* stmt.c. */ | |
617 | tree decls, raised; | |
618 | ||
619 | if (dfault == NULL_TREE) | |
620 | { | |
621 | /* Uncaught exception at outermost level. If raised locally, | |
622 | reraise the exception. Otherwise, generate code to call `abort'. */ | |
623 | if (in_try_block (1) == 0) | |
624 | { | |
625 | expand_start_cond (build (EQ_EXPR, integer_type_node, | |
626 | exception_throw_decl, integer_zero_node), 0); | |
627 | expand_expr (call_to_unhandled_exception (), 0, VOIDmode, 0); | |
628 | expand_end_cond (); | |
629 | } | |
630 | /* Try the next handler. */ | |
631 | if (! expand_escape_except ()) | |
632 | compiler_error ("except nesting botch"); | |
633 | } | |
634 | ||
635 | raised = expand_end_except (); | |
636 | ||
637 | decls = getdecls (); | |
638 | expand_end_bindings (decls, decls != 0, 1); | |
639 | poplevel (decls != 0, 1, 0); | |
640 | ||
641 | /* Implicit handlers do not use the momentary obstack. */ | |
642 | if (dfault != error_mark_node) | |
643 | pop_momentary (); | |
644 | ||
645 | if (! in_try_block (1)) | |
646 | { | |
647 | /* Check that this function is not raising exceptions | |
648 | it is not supposed to. */ | |
649 | while (raised) | |
650 | { | |
651 | error_with_decl (TREE_VALUE (raised), "exception `%s' raised but not declared raisable"); | |
652 | raised = TREE_CHAIN (raised); | |
653 | } | |
654 | } | |
655 | else if (dfault == NULL_TREE || dfault == error_mark_node) | |
656 | { | |
657 | expand_start_cond (build (NE_EXPR, integer_type_node, | |
658 | exception_throw_decl, | |
659 | integer_zero_node), 0); | |
660 | /* We fell off the end of this try block. Try going to the next. | |
661 | The escape_label will be the beginning of the next try block. */ | |
662 | if (! expand_escape_except ()) | |
663 | compiler_error ("except nesting botch"); | |
664 | expand_end_cond (); | |
665 | } | |
666 | } | |
667 | ||
668 | /* Generate code to raise exception RAISE_ID. | |
669 | If EXP is NULL_TREE, then PARMS is the list of parameters to use | |
670 | for constructing this exception. | |
671 | If EXP is non-NULL, then it is an already constructed object | |
672 | of the kind that we want. | |
673 | ||
674 | FOR_RERAISE is non-zero if this raise is called by reraise. In | |
675 | this case we do not need to emit extra gotos to avoid warning messages; | |
676 | the caller will do that once after all the exceptions it reraises | |
677 | are handled and raised. */ | |
678 | void | |
679 | cplus_expand_raise (raise_id, parms, exp, for_reraise) | |
680 | tree raise_id; | |
681 | tree parms; | |
682 | tree exp; | |
683 | int for_reraise; | |
684 | { | |
685 | /* Allocate new exception of appropriate type, passing | |
686 | PARMS to its constructor. */ | |
687 | tree cname, name; | |
688 | tree decl; | |
689 | tree xexp = exp; | |
690 | ||
691 | cname = lookup_exception_cname (current_class_type, current_class_name, raise_id); | |
692 | if (cname == error_mark_node) | |
693 | return; | |
694 | name = TREE_VALUE (raise_id); | |
695 | ||
696 | decl = lookup_exception_object (cname, name, 1); | |
697 | if (decl == NULL_TREE) | |
698 | return; | |
699 | ||
700 | if (exp == NULL_TREE) | |
701 | { | |
702 | exp = build_method_call (NULL_TREE, name, parms, NULL_TREE, LOOKUP_COMPLAIN); | |
703 | if (exp == error_mark_node) | |
704 | return; | |
705 | } | |
706 | ||
707 | if (in_try_block (1)) | |
708 | { | |
709 | expand_raise (decl); | |
710 | } | |
711 | else if (! current_function_decl) | |
712 | { | |
713 | if (xexp == NULL_TREE) | |
714 | error_with_decl (decl, "invalid raise of `%s' outside of functions"); | |
715 | else | |
716 | error_with_decl (decl, "invalid reraise of `%s' outside of functions"); | |
717 | } | |
718 | else | |
719 | { | |
720 | /* Test this raise against what this function permits. */ | |
721 | tree names = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)); | |
722 | while (names) | |
723 | { | |
724 | if (decl == TREE_TYPE (names)) | |
725 | break; | |
726 | names = TREE_CHAIN (names); | |
727 | } | |
728 | if (names == NULL_TREE) | |
729 | { | |
730 | error ("current function not declared to raise exception `%s'", | |
731 | IDENTIFIER_POINTER (name)); | |
732 | return; | |
733 | } | |
734 | } | |
735 | ||
736 | store_expr (exp, EHS_parms_as_rtx, 0); | |
737 | ||
738 | /* Set the global exception handler stack's NAME field | |
739 | to the `name' of this exception. The global exception | |
740 | handler stack is the container for the exception object | |
741 | we just built. | |
742 | ||
743 | We go through a function call to make life easier when debugging. */ | |
744 | #if 0 | |
745 | expand_assignment (EHS_name, build_unary_op (ADDR_EXPR, decl, 0), 0, 0); | |
746 | #else | |
747 | parms = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, EHS_name, 0), | |
748 | build_tree_list (NULL_TREE, | |
749 | build_unary_op (ADDR_EXPR, decl, 0))); | |
750 | expand_expr (build_function_call (BIR, parms), 0, 0, 0); | |
751 | #endif | |
752 | ||
753 | /* Activate thrower. If we are inside a TRY statement, | |
754 | we can cheat and not do this, saving a longjmp. */ | |
755 | if (in_try_block (1) == 0) | |
756 | { | |
757 | sets_exception_throw_decl = 1; | |
758 | emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx); | |
759 | } | |
760 | ||
761 | if (xexp == NULL_TREE) | |
762 | { | |
763 | /* Invoke destructors for current procedure or handler. */ | |
764 | if (! expand_escape_except ()) | |
765 | compiler_error ("except nesting botch"); | |
766 | /* Throw via `longjmp'... Done as side-effect of goto. */ | |
767 | } | |
768 | /* To avoid spurious warning messages, we add a goto to the end | |
769 | of the function. This code is dead, and the compiler should | |
770 | know how to delete it, but for now, we are stuck with it. */ | |
771 | if (! for_reraise | |
772 | && TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) | |
773 | expand_null_return (); | |
774 | } | |
775 | ||
776 | extern tree cplus_exception_name (); | |
777 | ||
778 | tree | |
779 | ansi_exception_object_lookup (type) | |
780 | tree type; | |
781 | { | |
782 | tree raise_id = cplus_exception_name (type); | |
783 | tree decl; | |
784 | ||
785 | decl = IDENTIFIER_GLOBAL_VALUE (raise_id); | |
786 | if (decl == NULL_TREE || TREE_CODE (decl) != VAR_DECL) | |
787 | { | |
788 | push_obstacks_nochange (); | |
789 | end_temporary_allocation (); | |
790 | decl = build_decl (VAR_DECL, raise_id, ptr_type_node); | |
791 | TREE_PUBLIC (decl) = 1; | |
792 | TREE_STATIC (decl) = 1; | |
793 | pushdecl_top_level (decl); | |
794 | make_decl_rtl (decl, (char*)0, 1); | |
795 | pop_obstacks (); | |
796 | } | |
797 | return decl; | |
798 | } | |
799 | ||
800 | /* Generate code to throw an exception using EXP. | |
801 | Usng ANSI syntax and semantics. | |
802 | If EXP is NULL_TREE< re-raise instead. */ | |
803 | ||
804 | void | |
805 | cplus_expand_throw (exp) | |
806 | tree exp; | |
807 | { | |
808 | tree parms; | |
809 | int for_reraise; | |
810 | /* Allocate new exception of appropriate type, passing | |
811 | PARMS to its constructor. */ | |
812 | tree decl = ansi_exception_object_lookup (TREE_TYPE (exp)); | |
813 | tree xexp = exp; | |
814 | ||
815 | if (in_try_block (1)) | |
816 | { | |
817 | #if 1 | |
818 | my_friendly_abort (35); | |
819 | #else | |
820 | expand_raise (decl); | |
821 | #endif | |
822 | } | |
823 | else if (! current_function_decl) | |
824 | error ("invalid throw outside of functions"); | |
825 | else | |
826 | { | |
827 | #if 0 | |
828 | /* Test this raise against what this function permits. */ | |
829 | tree names = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)); | |
830 | while (names) | |
831 | { | |
832 | if (decl == TREE_TYPE (names)) | |
833 | break; | |
834 | names = TREE_CHAIN (names); | |
835 | } | |
836 | if (names == NULL_TREE) | |
837 | { | |
838 | error ("current function not declared to raise exception `%s'", | |
839 | IDENTIFIER_POINTER (name)); | |
840 | return; | |
841 | } | |
842 | #endif | |
843 | } | |
844 | ||
845 | store_expr (exp, EHS_parms_as_rtx, 0); | |
846 | ||
847 | /* Set the global exception handler stack's NAME field | |
848 | to the `name' of this exception. The global exception | |
849 | handler stack is the container for the exception object | |
850 | we just built. | |
851 | ||
852 | We go through a function call to make life easier when debugging. */ | |
853 | #if 0 | |
854 | expand_assignment (EHS_name, build_unary_op (ADDR_EXPR, decl, 0), 0, 0); | |
855 | #else | |
856 | parms = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, EHS_name, 0), | |
857 | build_tree_list (NULL_TREE, | |
858 | build_unary_op (ADDR_EXPR, decl, 0))); | |
859 | expand_expr (build_function_call (BIR, parms), 0, 0, 0); | |
860 | #endif | |
861 | ||
862 | /* Activate thrower. If we are inside a TRY statement, | |
863 | we can cheat and not do this, saving a longjmp. */ | |
864 | if (in_try_block (1) == 0) | |
865 | { | |
866 | sets_exception_throw_decl = 1; | |
867 | emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx); | |
868 | } | |
869 | ||
870 | if (xexp == NULL_TREE) | |
871 | { | |
872 | /* Invoke destructors for current procedure or handler. */ | |
873 | if (! expand_escape_except ()) | |
874 | compiler_error ("except nesting botch"); | |
875 | /* Throw via `longjmp'... Done as side-effect of goto. */ | |
876 | } | |
877 | ||
878 | /* XXX: for_reraise is never set above here. */ | |
879 | /* To avoid spurious warning messages, we add a goto to the end | |
880 | of the function. This code is dead, and the compiler should | |
881 | know how to delete it, but for now, we are stuck with it. */ | |
882 | if (! for_reraise | |
883 | && TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) | |
884 | expand_null_return (); | |
885 | } | |
886 | ||
887 | tree | |
888 | cplus_expand_start_catch (raise_id) | |
889 | tree raise_id; | |
890 | { | |
891 | tree cname = lookup_exception_cname (current_class_type, current_class_name, raise_id); | |
892 | tree decl; | |
893 | tree cond; | |
894 | ||
895 | if (cname == error_mark_node) | |
896 | { | |
897 | decl = error_mark_node; | |
898 | cond = error_mark_node; | |
899 | } | |
900 | else | |
901 | { | |
902 | decl = lookup_exception_object (cname, TREE_VALUE (raise_id), 1); | |
903 | if (decl == NULL_TREE) | |
904 | cond = error_mark_node; | |
905 | else | |
906 | cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0), | |
907 | build (COMPONENT_REF, ptr_type_node, | |
908 | current_exception_decl, | |
909 | TREE_OPERAND (EHS_name, 1)), | |
910 | 1); | |
911 | } | |
912 | expand_start_cond (cond, 0); | |
913 | ||
914 | /* Does nothing right now. */ | |
915 | expand_catch (decl); | |
916 | if (current_exception_type | |
917 | && TYPE_NEEDS_DESTRUCTOR (current_exception_type)) | |
918 | { | |
919 | /* Make a cleanup for the name-specific exception object now in scope. */ | |
920 | tree cleanup = maybe_build_cleanup (current_exception_object); | |
921 | expand_start_bindings (0); | |
922 | expand_decl_cleanup (NULL_TREE, cleanup); | |
923 | } | |
924 | return decl; | |
925 | } | |
926 | tree | |
927 | ansi_expand_start_catch (raise_type) | |
928 | tree raise_type; | |
929 | { | |
930 | tree decl = ansi_exception_object_lookup (raise_type); | |
931 | tree cond; | |
932 | ||
933 | if (decl == NULL_TREE) | |
934 | cond = error_mark_node; | |
935 | else | |
936 | cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0), | |
937 | build (COMPONENT_REF, ptr_type_node, | |
938 | current_exception_decl, | |
939 | TREE_OPERAND (EHS_name, 1)), | |
940 | 1); | |
941 | expand_start_cond (cond, 0); | |
942 | ||
943 | /* Does nothing right now. */ | |
944 | expand_catch (decl); | |
945 | return decl; | |
946 | } | |
947 | ||
948 | void | |
949 | cplus_expand_end_catch (for_reraise) | |
950 | int for_reraise; | |
951 | { | |
952 | if (current_exception_type | |
953 | && TYPE_NEEDS_DESTRUCTOR (current_exception_type)) | |
954 | { | |
955 | /* Destroy the specific exception object now in scope. */ | |
956 | expand_end_bindings (getdecls (), 0, 1); | |
957 | } | |
958 | if (for_reraise) | |
959 | { | |
960 | if (! expand_escape_except ()) | |
961 | my_friendly_abort (36); | |
962 | } | |
963 | else | |
964 | { | |
965 | if (! expand_end_catch ()) | |
966 | my_friendly_abort (37); | |
967 | } | |
968 | expand_end_cond (); | |
969 | } | |
970 | ||
971 | /* Reraise an exception. | |
972 | If EXCEPTIONS is NULL_TREE, it means reraise whatever exception was caught. | |
973 | If EXCEPTIONS is an IDENTIFIER_NODE, it means reraise the exception | |
974 | object named by EXCEPTIONS. This must be a variable declared in | |
975 | an `except' clause. | |
976 | If EXCEPTIONS is a TREE_LIST, it is the list of exceptions we are | |
977 | willing to reraise. */ | |
978 | ||
979 | void | |
980 | cplus_expand_reraise (exceptions) | |
981 | tree exceptions; | |
982 | { | |
983 | tree ex_ptr; | |
984 | tree ex_object = current_exception_object; | |
985 | rtx ex_ptr_as_rtx; | |
986 | ||
987 | if (exceptions && TREE_CODE (exceptions) == IDENTIFIER_NODE) | |
988 | { | |
989 | /* Don't get tripped up if its TREE_TYPE is `error_mark_node'. */ | |
990 | ex_object = IDENTIFIER_LOCAL_VALUE (exceptions); | |
991 | if (ex_object == NULL_TREE || TREE_CODE (ex_object) != INDIRECT_REF) | |
992 | { | |
993 | error ("`%s' is not an exception decl", IDENTIFIER_POINTER (exceptions)); | |
994 | return; | |
995 | } | |
996 | my_friendly_assert (TREE_CODE (TREE_OPERAND (ex_object, 0)) == VAR_DECL, | |
997 | 204); | |
998 | exceptions = NULL_TREE; | |
999 | } | |
1000 | ||
1001 | ex_ptr = build1 (NOP_EXPR, ptr_type_node, TREE_OPERAND (ex_object, 0)); | |
1002 | ex_ptr_as_rtx = expand_expr (ex_ptr, 0, 0, 0); | |
1003 | ||
1004 | /* reraise ALL, used by compiler. */ | |
1005 | if (exceptions == NULL_TREE) | |
1006 | { | |
1007 | /* Now treat reraise like catch/raise. */ | |
1008 | expand_catch (error_mark_node); | |
1009 | expand_raise (error_mark_node); | |
1010 | emit_move_insn (EHS_name_as_rtx, current_exception_name_as_rtx); | |
1011 | store_expr ((tree) EHS_parms_as_rtx, current_exception_parms_as_rtx, 0); | |
1012 | if (in_try_block (1) == 0) | |
1013 | { | |
1014 | sets_exception_throw_decl = 1; | |
1015 | emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx); | |
1016 | } | |
1017 | /* Set to zero so that destructor will not be called. */ | |
1018 | emit_move_insn (ex_ptr_as_rtx, const0_rtx); | |
1019 | if (! expand_escape_except ()) | |
1020 | my_friendly_abort (38); | |
1021 | ||
1022 | /* To avoid spurious warning messages, we add a goto to the end | |
1023 | of the function. This code is dead, and the compiler should | |
1024 | know how to delete it, but for now, we are stuck with it. */ | |
1025 | if (TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) | |
1026 | expand_null_return (); | |
1027 | ||
1028 | return; | |
1029 | } | |
1030 | ||
1031 | /* reraise from a list of exceptions. */ | |
1032 | while (exceptions) | |
1033 | { | |
1034 | tree type = lookup_exception_type (current_class_type, current_class_name, | |
1035 | exceptions); | |
1036 | if (type == NULL_TREE) | |
1037 | { | |
1038 | error ("`%s' is not an exception type", | |
1039 | IDENTIFIER_POINTER (TREE_VALUE (exceptions))); | |
1040 | current_exception_type = NULL_TREE; | |
1041 | TREE_TYPE (ex_object) = error_mark_node; | |
1042 | TREE_TYPE (ex_ptr) = error_mark_node; | |
1043 | } | |
1044 | else | |
1045 | { | |
1046 | current_exception_type = type; | |
1047 | /* In-place union. */ | |
1048 | TREE_TYPE (ex_object) = type; | |
1049 | TREE_TYPE (ex_ptr) = TYPE_POINTER_TO (type); | |
1050 | } | |
1051 | ||
1052 | /* Now treat reraise like catch/raise. */ | |
1053 | cplus_expand_start_catch (exceptions); | |
1054 | cplus_expand_raise (exceptions, NULL_TREE, ex_ptr, 1); | |
1055 | /* Set to zero so that destructor will not be called. */ | |
1056 | if (TREE_TYPE (ex_ptr) != error_mark_node) | |
1057 | emit_move_insn (ex_ptr_as_rtx, const0_rtx); | |
1058 | cplus_expand_end_catch (1); | |
1059 | exceptions = TREE_CHAIN (exceptions); | |
1060 | } | |
1061 | /* Don't propagate any unhandled exceptions. */ | |
1062 | expand_expr (call_to_unhandled_exception (), 0, VOIDmode, 0); | |
1063 | ||
1064 | /* To avoid spurious warning messages, we add a goto to the end | |
1065 | of the function. This code is dead, and the compiler should | |
1066 | know how to delete it, but for now, we are stuck with it. */ | |
1067 | if (TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) | |
1068 | expand_null_return (); | |
1069 | } | |
1070 | \f | |
1071 | void | |
1072 | setup_exception_throw_decl () | |
1073 | { | |
1074 | tree call_to_longjmp, parms; | |
1075 | ||
1076 | int old = suspend_momentary (); | |
1077 | ||
1078 | exception_throw_decl = build_decl (VAR_DECL, get_identifier (THROW_NAME), integer_type_node); | |
1079 | pushdecl (exception_throw_decl); | |
1080 | parms = tree_cons (NULL_TREE, EHS_handler, | |
1081 | build_tree_list (0, integer_one_node)); | |
1082 | call_to_longjmp = build_function_call (BILJ, parms); | |
1083 | ||
1084 | expand_decl (exception_throw_decl); | |
1085 | expand_decl_cleanup (exception_throw_decl, | |
1086 | build (COND_EXPR, void_type_node, | |
1087 | exception_throw_decl, | |
1088 | call_to_longjmp, integer_zero_node)); | |
1089 | DECL_INITIAL (exception_throw_decl) = integer_zero_node; | |
1090 | sets_exception_throw_decl = 0; | |
1091 | resume_momentary (old); | |
1092 | ||
1093 | /* Cache these, since they won't change throughout the function. */ | |
1094 | EHS_parms_as_rtx = expand_expr (EHS_parms, 0, 0, 0); | |
1095 | EHS_name_as_rtx = expand_expr (EHS_name, 0, 0, 0); | |
1096 | } | |
1097 | ||
1098 | void | |
1099 | init_exception_processing () | |
1100 | { | |
1101 | extern tree build_function_type (), define_function (); | |
1102 | extern tree unhandled_exception_fndecl; | |
1103 | tree cname = get_identifier ("ExceptionHandler"); | |
1104 | tree field, chain; | |
1105 | tree ctor, dtor; | |
1106 | tree jmp_buf_type = build_array_type (integer_type_node, | |
1107 | build_index_type (build_int_2 (_JBLEN-1, 0))); | |
1108 | tree jmp_buf_arg_type = build_pointer_type (integer_type_node); | |
1109 | ||
1110 | tree parmtypes = hash_tree_chain (jmp_buf_arg_type, void_list_node); | |
1111 | tree setjmp_fndecl, longjmp_fndecl, raise_fndecl; | |
1112 | ||
1113 | int old_interface_only = interface_only; | |
1114 | int old_interface_unknown = interface_unknown; | |
1115 | interface_only = 1; | |
1116 | interface_unknown = 0; | |
1117 | EHS_type = xref_tag (record_type_node, cname, NULL_TREE); | |
1118 | push_lang_context (lang_name_c); | |
1119 | setjmp_fndecl = define_function ("setjmp", | |
1120 | build_function_type (integer_type_node, | |
1121 | parmtypes), | |
1122 | NOT_BUILT_IN, pushdecl, 0); | |
1123 | BISJ = default_conversion (setjmp_fndecl); | |
1124 | parmtypes = hash_tree_chain (jmp_buf_arg_type, | |
1125 | hash_tree_chain (integer_type_node, void_list_node)); | |
1126 | longjmp_fndecl = define_function ("longjmp", | |
1127 | build_function_type (void_type_node, parmtypes), | |
1128 | NOT_BUILT_IN, pushdecl, 0); | |
1129 | raise_fndecl = define_function ("__raise_exception", | |
1130 | build_function_type (void_type_node, | |
1131 | hash_tree_chain (ptr_type_node, | |
1132 | hash_tree_chain (build_pointer_type (ptr_type_node), void_list_node))), | |
1133 | NOT_BUILT_IN, pushdecl, 0); | |
1134 | BILJ = default_conversion (longjmp_fndecl); | |
1135 | BIR = default_conversion (raise_fndecl); | |
1136 | BIUE = default_conversion (unhandled_exception_fndecl); | |
1137 | ||
1138 | pop_lang_context (); | |
1139 | ||
1140 | /* finish_struct will pop this. */ | |
1141 | pushclass (EHS_type, 0); | |
1142 | field = build_lang_field_decl (FIELD_DECL, get_identifier ("parms"), ptr_type_node); | |
1143 | chain = field; | |
1144 | field = build_lang_field_decl (FIELD_DECL, get_identifier ("name"), | |
1145 | build_pointer_type (default_function_type)); | |
1146 | TREE_CHAIN (field) = chain; | |
1147 | chain = field; | |
1148 | field = build_lang_field_decl (FIELD_DECL, get_identifier ("handler"), jmp_buf_type); | |
1149 | TREE_CHAIN (field) = chain; | |
1150 | chain = field; | |
1151 | field = build_lang_field_decl (FIELD_DECL, get_identifier ("prev"), | |
1152 | TYPE_POINTER_TO (EHS_type)); | |
1153 | TREE_CHAIN (field) = chain; | |
1154 | chain = field; | |
1155 | ||
1156 | ctor = build_lang_decl (FUNCTION_DECL, cname, | |
1157 | build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node)); | |
1158 | DECL_CONSTRUCTOR_P (ctor) = 1; | |
1159 | TREE_STATIC (ctor) = 1; | |
1160 | TREE_PUBLIC (ctor) = 1; | |
1161 | DECL_EXTERNAL (ctor) = 1; | |
1162 | grokclassfn (EHS_type, cname, ctor, NO_SPECIAL, 0); | |
1163 | grok_ctor_properties (EHS_type, ctor); | |
1164 | finish_decl (pushdecl (ctor), NULL_TREE, NULL_TREE, 0); | |
1165 | /* Must copy the node here because the FUNCTION_DECL | |
1166 | used inside the struct ain't the same as the | |
1167 | FUNCTION_DECL we stick into the global binding | |
1168 | contour. */ | |
1169 | ctor = copy_node (ctor); | |
1170 | TREE_CHAIN (ctor) = chain; | |
1171 | chain = ctor; | |
1172 | dtor = build_lang_decl (FUNCTION_DECL, cname, | |
1173 | build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node)); | |
1174 | TREE_STATIC (dtor) = 1; | |
1175 | TREE_PUBLIC (dtor) = 1; | |
1176 | DECL_EXTERNAL (dtor) = 1; | |
1177 | grokclassfn (EHS_type, cname, dtor, DTOR_FLAG, 0); | |
1178 | finish_decl (pushdecl (dtor), NULL_TREE, NULL_TREE, 0); | |
1179 | /* Copy for the same reason as copying ctor. */ | |
1180 | dtor = copy_node (dtor); | |
1181 | TREE_CHAIN (dtor) = chain; | |
1182 | chain = dtor; | |
1183 | TYPE_HAS_CONSTRUCTOR (EHS_type) = 1; | |
1184 | TYPE_HAS_DESTRUCTOR (EHS_type) = 1; | |
1185 | finish_struct (EHS_type, temp_tree_cons (NULL_TREE, chain, NULL_TREE), 0); | |
1186 | interface_only = old_interface_only; | |
1187 | interface_unknown = old_interface_unknown; | |
1188 | } | |
1189 | ||
1190 | void | |
1191 | init_exception_processing_1 () | |
1192 | { | |
1193 | register tree EHS_id = get_identifier ("exceptionHandlerStack"); | |
1194 | ||
1195 | EHS_decl = IDENTIFIER_GLOBAL_VALUE (EHS_id); | |
1196 | ||
1197 | /* If we have no other definition, default to library implementation. */ | |
1198 | if (EHS_decl == NULL_TREE) | |
1199 | { | |
1200 | EHS_decl = build_decl (VAR_DECL, EHS_id, TYPE_POINTER_TO (EHS_type)); | |
1201 | /* If we don't push this, its definition, should it be encountered, | |
1202 | will not be seen. */ | |
1203 | EHS_decl = pushdecl (EHS_decl); | |
1204 | DECL_EXTERNAL (EHS_decl) = 1; | |
1205 | TREE_STATIC (EHS_decl) = 1; | |
1206 | TREE_PUBLIC (EHS_decl) = 1; | |
1207 | finish_decl (EHS_decl, NULL_TREE, NULL_TREE, 0); | |
1208 | } | |
1209 | else if (TREE_CODE (EHS_decl) != VAR_DECL | |
1210 | || TREE_TYPE (EHS_decl) != TYPE_POINTER_TO (EHS_type)) | |
1211 | fatal ("exception handling declarations conflict with compiler's internal model"); | |
1212 | ||
1213 | if (EHS_prev == NULL_TREE) | |
1214 | { | |
1215 | register tree EHS_DECL = build1 (INDIRECT_REF, EHS_type, EHS_decl); | |
1216 | EHS_prev = build_component_ref (EHS_DECL, get_identifier ("prev"), 0, 0); | |
1217 | EHS_handler = build_component_ref (EHS_DECL, get_identifier ("handler"), 0, 0); | |
1218 | EHS_parms = build_component_ref (EHS_DECL, get_identifier ("parms"), 0, 0); | |
1219 | EHS_name = build_component_ref (EHS_DECL, get_identifier ("name"), 0, 0); | |
1220 | } | |
1221 | } |