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