|
|
1.1 root 1: /* Handle exceptional things in C++.
2: Copyright (C) 1989, 1992 Free Software Foundation, Inc.
3: Contributed by Michael Tiemann ([email protected])
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"
1.1.1.3 ! root 32: #include "rtl.h"
1.1 root 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;
1.1.1.3 ! root 65: rtx current_exception_name_as_rtx;
! 66: rtx current_exception_parms_as_rtx;
1.1 root 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;
1.1.1.3 ! root 87: static rtx EHS_parms_as_rtx, EHS_name_as_rtx;
1.1 root 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);
1.1.1.3 ! root 397: DECL_EXTERNAL (ctor) = 1;
1.1 root 398: TREE_STATIC (ctor) = 1;
399: TREE_PUBLIC (ctor) = 0;
1.1.1.3 ! root 400: DECL_INLINE (ctor) = 1;
1.1 root 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:
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:
1.1.1.3 ! root 539: my_friendly_assert (TREE_CODE (decl) == VAR_DECL
! 540: && TREE_TYPE (decl) == EHS_type, 203);
1.1 root 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)
1.1.1.3 ! root 774: tree type;
1.1 root 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
1.1.1.2 root 812: my_friendly_abort (35);
1.1 root 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 ())
1.1.1.2 root 950: my_friendly_abort (36);
1.1 root 951: }
952: else
953: {
954: if (! expand_end_catch ())
1.1.1.2 root 955: my_friendly_abort (37);
1.1 root 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;
1.1.1.3 ! root 974: rtx ex_ptr_as_rtx;
1.1 root 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: }
1.1.1.3 ! root 985: my_friendly_assert (TREE_CODE (TREE_OPERAND (ex_object, 0)) == VAR_DECL,
! 986: 204);
1.1 root 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);
1.1.1.3 ! root 999: emit_move_insn (EHS_name_as_rtx, current_exception_name_as_rtx);
1.1 root 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 ())
1.1.1.2 root 1009: my_friendly_abort (38);
1.1 root 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:
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;
1.1.1.3 ! root 1149: DECL_EXTERNAL (ctor) = 1;
1.1 root 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;
1.1.1.3 ! root 1164: DECL_EXTERNAL (dtor) = 1;
1.1 root 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);
1.1.1.3 ! root 1192: DECL_EXTERNAL (EHS_decl) = 1;
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.