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