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