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