BSD 4_4_Lite2 development
[unix-history] / usr / src / contrib / gcc-2.3.3 / cp-except.c
CommitLineData
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
5This file is part of GNU CC.
6
7GNU CC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU CC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU CC; see the file COPYING. If not, write to
19the 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
47void init_exception_processing ();
48void 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). */
55tree 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. */
58int sets_exception_throw_decl;
59
60/* The exception `type' currently in scope, or NULL_TREE if none. */
61tree current_exception_type;
62
63/* The exception handler object for the given scope. */
64tree current_exception_decl;
65rtx current_exception_name_as_rtx;
66rtx 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'. */
70tree current_exception_object;
71
72/* Cache `setjmp', `longjmp', `raise_exception', and `unhandled_exception'
73 after default conversion. Maybe later they will get built-in. */
74static 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. */
80static tree EHS_type;
81
82/* The global handler stack. */
83tree EHS_decl;
84
85/* Cached component refs to fields of `EHS_decl'. */
86static tree EHS_prev, EHS_handler, EHS_parms, EHS_name;
87static rtx EHS_parms_as_rtx, EHS_name_as_rtx;
88
89/* The parameter names of this exception type. */
90
91static tree last_exception_fields;
92static 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. */
98static tree
99exception_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
126tree
127lookup_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
151tree
152lookup_exception_tname (oname)
153 tree oname;
154{
155 return get_identifier (IDENTIFIER_POINTER (oname) + EXCEPTION_NAME_LENGTH);
156}
157
158tree
159lookup_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
200tree
201lookup_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
238tree
239finish_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
342void
343finish_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
444void
445end_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
453void
454cplus_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
500tree
501cplus_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
552void
553cplus_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. */
593static tree
594call_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. */
606void
607cplus_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. */
672void
673cplus_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
770extern tree cplus_exception_name ();
771
772tree
773ansi_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
798void
799cplus_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
879tree
880cplus_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}
916tree
917ansi_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
937void
938cplus_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
968void
969cplus_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
1060void
1061setup_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
1087void
1088init_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
1178void
1179init_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}