This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / gnu / usr.bin / cc / cc1plus / cp-except.c
CommitLineData
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
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#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
48void init_exception_processing ();
49void 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). */
56tree 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. */
59int sets_exception_throw_decl;
60
61/* The exception `type' currently in scope, or NULL_TREE if none. */
62tree current_exception_type;
63
64/* The exception handler object for the given scope. */
65tree current_exception_decl;
66rtx current_exception_name_as_rtx;
67rtx 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'. */
71tree current_exception_object;
72
73/* Cache `setjmp', `longjmp', `raise_exception', and `unhandled_exception'
74 after default conversion. Maybe later they will get built-in. */
75static 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. */
81static tree EHS_type;
82
83/* The global handler stack. */
84tree EHS_decl;
85
86/* Cached component refs to fields of `EHS_decl'. */
87static tree EHS_prev, EHS_handler, EHS_parms, EHS_name;
88static rtx EHS_parms_as_rtx, EHS_name_as_rtx;
89
90/* The parameter names of this exception type. */
91
92static tree last_exception_fields;
93static 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. */
99static tree
100exception_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
131tree
132lookup_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
156tree
157lookup_exception_tname (oname)
158 tree oname;
159{
160 return get_identifier (IDENTIFIER_POINTER (oname) + EXCEPTION_NAME_LENGTH);
161}
162
163tree
164lookup_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
205tree
206lookup_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
243tree
244finish_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
347void
348finish_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
449void
450end_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
458void
459cplus_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
505tree
506cplus_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
557void
558cplus_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. */
598static tree
599call_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. */
612void
613cplus_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. */
678void
679cplus_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
776extern tree cplus_exception_name ();
777
778tree
779ansi_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
804void
805cplus_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
887tree
888cplus_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}
926tree
927ansi_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
948void
949cplus_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
979void
980cplus_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
1071void
1072setup_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
1098void
1099init_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
1190void
1191init_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}