Initial import from FreeBSD RELENG_4:
[games.git] / contrib / gcc / cp / except.c
1 /* Handle exceptional things in C++.
2    Copyright (C) 1989, 92-97, 1998, 1999 Free Software Foundation, Inc.
3    Contributed by Michael Tiemann <tiemann@cygnus.com>
4    Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
5    initial re-implementation courtesy Tad Hunt.
6
7 This file is part of GNU CC.
8
9 GNU CC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 GNU CC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GNU CC; see the file COPYING.  If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 /* $FreeBSD: src/contrib/gcc/cp/except.c,v 1.5 1999/10/16 07:53:19 obrien Exp $ */
25
26
27 #include "config.h"
28 #include "system.h"
29 #include "tree.h"
30 #include "rtl.h"
31 #include "cp-tree.h"
32 #include "flags.h"
33 #include "obstack.h"
34 #include "expr.h"
35 #include "output.h"
36 #include "except.h"
37 #include "function.h"
38 #include "defaults.h"
39 #include "toplev.h"
40 #include "eh-common.h"
41
42 rtx expand_builtin_return_addr  PROTO((enum built_in_function, int, rtx));
43
44 /* Holds the fndecl for __builtin_return_address.  */
45 tree builtin_return_address_fndecl;
46
47 /* A couple of backend routines from m88k.c */
48
49 static void push_eh_cleanup PROTO((void));
50 static tree build_eh_type_type PROTO((tree));
51 static tree build_eh_type PROTO((tree));
52 static void expand_end_eh_spec PROTO((tree));
53 static tree call_eh_info PROTO((void));
54 static void push_eh_info PROTO((void));
55 static tree get_eh_info PROTO((void));
56 static tree get_eh_value PROTO((void));
57 #if 0
58 static tree get_eh_type PROTO((void));
59 static tree get_eh_caught PROTO((void));
60 static tree get_eh_handlers PROTO((void));
61 #endif
62 static tree do_pop_exception PROTO((void));
63 static void process_start_catch_block PROTO((tree, tree));
64 static tree build_eh_type_type_ref PROTO((tree));
65 static tree build_terminate_handler PROTO((void));
66 static tree alloc_eh_object PROTO((tree));
67
68 #if 0
69 /* This is the startup, and finish stuff per exception table.  */
70
71 /* XXX - Tad: exception handling section */
72 #ifndef EXCEPT_SECTION_ASM_OP
73 #define EXCEPT_SECTION_ASM_OP   "section\t.gcc_except_table,\"a\",@progbits"
74 #endif
75
76 #ifdef EXCEPT_SECTION_ASM_OP
77
78  /* on machines which support it, the exception table lives in another section,
79         but it needs a label so we can reference it...  This sets up that
80     label! */
81 asm (EXCEPT_SECTION_ASM_OP);
82 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
83 asm (TEXT_SECTION_ASM_OP);
84
85 #endif /* EXCEPT_SECTION_ASM_OP */
86
87 #ifdef EXCEPT_SECTION_ASM_OP
88
89  /* we need to know where the end of the exception table is... so this
90     is how we do it! */
91
92 asm (EXCEPT_SECTION_ASM_OP);
93 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
94 asm (TEXT_SECTION_ASM_OP);
95
96 #endif /* EXCEPT_SECTION_ASM_OP */
97
98 #endif
99
100 #include "decl.h"
101 #include "insn-flags.h"
102 #include "obstack.h"
103
104 /* ======================================================================
105    Briefly the algorithm works like this:
106
107      When a constructor or start of a try block is encountered,
108      push_eh_entry (&eh_stack) is called.  Push_eh_entry () creates a
109      new entry in the unwind protection stack and returns a label to
110      output to start the protection for that block.
111
112      When a destructor or end try block is encountered, pop_eh_entry
113      (&eh_stack) is called.  Pop_eh_entry () returns the eh_entry it
114      created when push_eh_entry () was called.  The eh_entry structure
115      contains three things at this point.  The start protect label,
116      the end protect label, and the exception handler label.  The end
117      protect label should be output before the call to the destructor
118      (if any). If it was a destructor, then its parse tree is stored
119      in the finalization variable in the eh_entry structure.  Otherwise
120      the finalization variable is set to NULL to reflect the fact that
121      it is the end of a try block.  Next, this modified eh_entry node
122      is enqueued in the finalizations queue by calling
123      enqueue_eh_entry (&queue,entry).
124
125         +---------------------------------------------------------------+
126         |XXX: Will need modification to deal with partially             |
127         |                       constructed arrays of objects           |
128         |                                                               |
129         |       Basically, this consists of keeping track of how many   |
130         |       of the objects have been constructed already (this      |
131         |       should be in a register though, so that shouldn't be a  |
132         |       problem.                                                |
133         +---------------------------------------------------------------+
134
135      When a catch block is encountered, there is a lot of work to be
136      done.
137
138      Since we don't want to generate the catch block inline with the
139      regular flow of the function, we need to have some way of doing
140      so.  Luckily, we can use sequences to defer the catch sections.
141      When the start of a catch block is encountered, we start the
142      sequence.  After the catch block is generated, we end the
143      sequence.
144
145      Next we must insure that when the catch block is executed, all
146      finalizations for the matching try block have been completed.  If
147      any of those finalizations throw an exception, we must call
148      terminate according to the ARM (section r.15.6.1).  What this
149      means is that we need to dequeue and emit finalizations for each
150      entry in the eh_queue until we get to an entry with a NULL
151      finalization field.  For any of the finalization entries, if it
152      is not a call to terminate (), we must protect it by giving it
153      another start label, end label, and exception handler label,
154      setting its finalization tree to be a call to terminate (), and
155      enqueue'ing this new eh_entry to be output at an outer level.
156      Finally, after all that is done, we can get around to outputting
157      the catch block which basically wraps all the "catch (...) {...}"
158      statements in a big if/then/else construct that matches the
159      correct block to call.
160      
161      ===================================================================== */
162
163 /* local globals for function calls
164    ====================================================================== */
165
166 /* Used to cache "terminate" and "__throw_type_match*".  */
167 static tree Terminate, CatchMatch;
168
169 /* Used to cache __find_first_exception_table_match for throw.  */
170 static tree FirstExceptionMatch;
171
172 /* Used to cache a call to __unwind_function.  */
173 static tree Unwind;
174
175 /* ====================================================================== */
176
177
178 /* ========================================================================= */
179
180
181
182 /* local globals - these local globals are for storing data necessary for
183    generating the exception table and code in the correct order.
184
185    ========================================================================= */
186
187 extern rtx catch_clauses;
188 extern tree const_ptr_type_node;
189
190 /* ========================================================================= */
191
192 /* sets up all the global eh stuff that needs to be initialized at the
193    start of compilation.
194
195    This includes:
196                 - Setting up all the function call trees.  */
197
198 void
199 init_exception_processing ()
200 {
201   /* void vtype () */
202   tree vtype = build_function_type (void_type_node, void_list_node);
203   
204   if (flag_honor_std)
205     push_namespace (get_identifier ("std"));
206   Terminate = auto_function (get_identifier ("terminate"),
207                              vtype, NOT_BUILT_IN);
208   TREE_THIS_VOLATILE (Terminate) = 1;
209   if (flag_honor_std)
210     pop_namespace ();
211
212   push_lang_context (lang_name_c);
213
214   set_exception_lang_code (EH_LANG_C_plus_plus);
215   set_exception_version_code (1);
216
217   CatchMatch
218     = builtin_function (flag_rtti
219                         ? "__throw_type_match_rtti"
220                         : "__throw_type_match",
221                         build_function_type (ptr_type_node,
222                                              tree_cons (NULL_TREE, const_ptr_type_node,
223                                                         tree_cons (NULL_TREE, const_ptr_type_node,
224                                                                    tree_cons (NULL_TREE, ptr_type_node,
225                                                                               void_list_node)))),
226                         NOT_BUILT_IN, NULL_PTR);
227   FirstExceptionMatch
228     = builtin_function ("__find_first_exception_table_match",
229                         build_function_type (ptr_type_node,
230                                              tree_cons (NULL_TREE, ptr_type_node,
231                                                         void_list_node)),
232                         NOT_BUILT_IN, NULL_PTR);
233   Unwind
234     = builtin_function ("__unwind_function",
235                         build_function_type (void_type_node,
236                                              tree_cons (NULL_TREE, ptr_type_node,
237                                                         void_list_node)),
238                         NOT_BUILT_IN, NULL_PTR);
239
240   pop_lang_context ();
241
242   /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
243      be protected with __terminate.  */
244   protect_cleanup_actions_with_terminate = 1;
245 }
246
247 /* Retrieve a pointer to the cp_eh_info node for the current exception.  */
248
249 static tree
250 call_eh_info ()
251 {
252   tree fn;
253
254   fn = get_identifier ("__start_cp_handler");
255   if (IDENTIFIER_GLOBAL_VALUE (fn))
256     fn = IDENTIFIER_GLOBAL_VALUE (fn);
257   else
258     {
259       tree t1, t, fields[7];
260
261       /* Declare cp_eh_info * __start_cp_handler (void),
262          as defined in exception.cc. */
263       push_obstacks_nochange ();
264       end_temporary_allocation ();
265
266       /* struct cp_eh_info.  This must match exception.cc.  Note that this
267          type is not pushed anywhere.  */
268       t1= make_lang_type (RECORD_TYPE);
269       fields[0] = build_lang_field_decl (FIELD_DECL, 
270                     get_identifier ("handler_label"), ptr_type_node);
271       fields[1] = build_lang_field_decl (FIELD_DECL, 
272                     get_identifier ("dynamic_handler_chain"), ptr_type_node);
273       fields[2] = build_lang_field_decl (FIELD_DECL, 
274                     get_identifier ("info"), ptr_type_node);
275       fields[3] = build_lang_field_decl (FIELD_DECL, 
276                     get_identifier ("table_index"), ptr_type_node);
277       /* N.B.: The fourth field LEN is expected to be
278          the number of fields - 1, not the total number of fields.  */
279       finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
280       t1 = build_pointer_type (t1);
281
282       t1= make_lang_type (RECORD_TYPE);
283       fields[0] = build_lang_field_decl (FIELD_DECL, 
284                     get_identifier ("match_function"), ptr_type_node);
285       fields[1] = build_lang_field_decl (FIELD_DECL, 
286                     get_identifier ("language"), short_integer_type_node);
287       fields[2] = build_lang_field_decl (FIELD_DECL, 
288                     get_identifier ("version"), short_integer_type_node);
289       /* N.B.: The fourth field LEN is expected to be
290          the number of fields - 1, not the total number of fields.  */
291       finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node);
292       t = make_lang_type (RECORD_TYPE);
293       fields[0] = build_lang_field_decl (FIELD_DECL, 
294                                               get_identifier ("eh_info"), t1);
295       fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
296                                          ptr_type_node);
297       fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
298                                          ptr_type_node);
299       fields[3] = build_lang_field_decl
300         (FIELD_DECL, get_identifier ("cleanup"),
301          build_pointer_type (build_function_type
302                              (ptr_type_node, tree_cons
303                               (NULL_TREE, ptr_type_node, void_list_node))));
304       fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
305                                          boolean_type_node);
306       fields[5] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
307                                          build_pointer_type (t));
308       fields[6] = build_lang_field_decl
309         (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
310       /* N.B.: The fourth field LEN is expected to be
311          the number of fields - 1, not the total number of fields.  */
312       finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node);
313       t = build_pointer_type (t);
314
315       /* And now the function.  */
316       fn = build_lang_decl (FUNCTION_DECL, fn,
317                             build_function_type (t, void_list_node));
318       DECL_EXTERNAL (fn) = 1;
319       TREE_PUBLIC (fn) = 1;
320       DECL_ARTIFICIAL (fn) = 1;
321       pushdecl_top_level (fn);
322       make_function_rtl (fn);
323       pop_obstacks ();
324     }
325   mark_used (fn);
326   return build_function_call (fn, NULL_TREE);
327 }
328
329 /* Retrieve a pointer to the cp_eh_info node for the current exception
330    and save it in the current binding level.  */
331
332 static void
333 push_eh_info ()
334 {
335   tree decl, fn = call_eh_info ();
336
337   /* Remember the pointer to the current exception info; it won't change
338      during this catch block.  */
339   decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
340                      TREE_TYPE (fn));
341   DECL_ARTIFICIAL (decl) = 1;
342   DECL_INITIAL (decl) = fn;
343   decl = pushdecl (decl);
344   cp_finish_decl (decl, fn, NULL_TREE, 0, 0);
345 }
346
347 /* Returns a reference to the cp_eh_info node for the current exception.  */
348
349 static tree
350 get_eh_info ()
351 {
352   /* Look for the pointer pushed in push_eh_info.  */
353   tree t = lookup_name (get_identifier ("__exception_info"), 0);
354   return build_indirect_ref (t, NULL_PTR);
355 }
356
357 /* Returns a reference to the current exception object.  */
358
359 static tree
360 get_eh_value ()
361 {
362   return build_component_ref (get_eh_info (), get_identifier ("value"),
363                               NULL_TREE, 0);
364 }
365
366 /* Returns a reference to the current exception type.  */
367
368 #if 0
369 static tree
370 get_eh_type ()
371 {
372   return build_component_ref (get_eh_info (), get_identifier ("type"),
373                               NULL_TREE, 0);
374 }
375
376 /* Returns a reference to whether or not the current exception
377    has been caught.  */
378
379 static tree
380 get_eh_caught ()
381 {
382   return build_component_ref (get_eh_info (), get_identifier ("caught"),
383                               NULL_TREE, 0);
384 }
385
386 /* Returns a reference to whether or not the current exception
387    has been caught.  */
388
389 static tree
390 get_eh_handlers ()
391 {
392   return build_component_ref (get_eh_info (), get_identifier ("handlers"),
393                               NULL_TREE, 0);
394 }
395 #endif
396
397 /* Build a type value for use at runtime for a type that is matched
398    against by the exception handling system.  */
399
400 static tree
401 build_eh_type_type (type)
402      tree type;
403 {
404   const char *typestring;
405   tree exp;
406
407   if (type == error_mark_node)
408     return error_mark_node;
409
410   /* peel back references, so they match.  */
411   if (TREE_CODE (type) == REFERENCE_TYPE)
412     type = TREE_TYPE (type);
413
414   /* Peel off cv qualifiers.  */
415   type = TYPE_MAIN_VARIANT (type);
416
417   if (flag_rtti)
418     return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
419
420   typestring = build_overload_name (type, 1, 1);
421   exp = combine_strings (build_string (strlen (typestring)+1, typestring));
422   return build1 (ADDR_EXPR, ptr_type_node, exp);
423 }
424
425 /* Build the address of a runtime type for use in the runtime matching
426    field of the new exception model */
427
428 static tree
429 build_eh_type_type_ref (type)
430      tree type;
431 {
432   const char *typestring;
433   tree exp;
434
435   if (type == error_mark_node)
436     return error_mark_node;
437
438   /* peel back references, so they match.  */
439   if (TREE_CODE (type) == REFERENCE_TYPE)
440     type = TREE_TYPE (type);
441
442   /* Peel off cv qualifiers.  */
443   type = TYPE_MAIN_VARIANT (type);
444
445   push_obstacks_nochange ();
446   end_temporary_allocation ();
447
448   if (flag_rtti)
449     {
450       exp = get_tinfo_fn (type);
451       TREE_USED (exp) = 1;
452       mark_inline_for_output (exp);
453       exp = build1 (ADDR_EXPR, ptr_type_node, exp);
454     }
455   else
456     {
457       typestring = build_overload_name (type, 1, 1);
458       exp = combine_strings (build_string (strlen (typestring)+1, typestring));
459       exp = build1 (ADDR_EXPR, ptr_type_node, exp);
460     }
461   pop_obstacks ();
462   return (exp);
463 }
464
465
466 /* Build a type value for use at runtime for a exp that is thrown or
467    matched against by the exception handling system.  */
468
469 static tree
470 build_eh_type (exp)
471      tree exp;
472 {
473   if (flag_rtti)
474     {
475       exp = build_typeid (exp);
476       return build1 (ADDR_EXPR, ptr_type_node, exp);
477     }
478   return build_eh_type_type (TREE_TYPE (exp));
479 }
480
481 /* This routine is called to mark all the symbols representing runtime
482    type functions in the exception table as haveing been referenced.
483    This will make sure code is emitted for them. Called from finish_file. */
484 void 
485 mark_all_runtime_matches () 
486 {
487   int x,num;
488   void **ptr;
489   tree exp;
490   
491   num = find_all_handler_type_matches (&ptr);
492   if (num == 0 || ptr == NULL)
493     return;
494   
495   for (x=0; x <num; x++)
496     {
497       exp = (tree) ptr[x];
498       if (TREE_CODE (exp) == ADDR_EXPR)
499         {
500           exp = TREE_OPERAND (exp, 0);
501           if (TREE_CODE (exp) == FUNCTION_DECL)
502             TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
503         }
504     }
505   
506   free (ptr);
507 }
508
509 /* Build up a call to __cp_pop_exception, to destroy the exception object
510    for the current catch block.  HANDLER is either true or false, telling
511    the library whether or not it is being called from an exception handler;
512    if it is, it avoids destroying the object on rethrow.  */
513
514 static tree
515 do_pop_exception ()
516 {
517   tree fn, cleanup;
518   fn = get_identifier ("__cp_pop_exception");
519   if (IDENTIFIER_GLOBAL_VALUE (fn))
520     fn = IDENTIFIER_GLOBAL_VALUE (fn);
521   else
522     {
523       /* Declare void __cp_pop_exception (void *),
524          as defined in exception.cc. */
525       push_obstacks_nochange ();
526       end_temporary_allocation ();
527       fn = build_lang_decl
528         (FUNCTION_DECL, fn,
529          build_function_type (void_type_node, tree_cons
530                               (NULL_TREE, ptr_type_node, void_list_node)));
531       DECL_EXTERNAL (fn) = 1;
532       TREE_PUBLIC (fn) = 1;
533       DECL_ARTIFICIAL (fn) = 1;
534       pushdecl_top_level (fn);
535       make_function_rtl (fn);
536       pop_obstacks ();
537     }
538
539   mark_used (fn);
540   /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
541   cleanup = lookup_name (get_identifier ("__exception_info"), 0);
542   cleanup = build_function_call (fn, expr_tree_cons
543                                  (NULL_TREE, cleanup, NULL_TREE));
544   return cleanup;
545 }
546
547 /* This routine creates the cleanup for the current exception.  */
548
549 static void
550 push_eh_cleanup ()
551 {
552   int yes;
553
554   yes = suspend_momentary ();
555   /* All cleanups must last longer than normal.  */
556   expand_decl_cleanup (NULL_TREE, do_pop_exception ());
557   resume_momentary (yes);
558 }
559
560 /* Build up a call to terminate on the function obstack, for use as an
561    exception handler.  */
562
563 static tree
564 build_terminate_handler ()
565 {
566   int yes = suspend_momentary ();
567   tree term = build_function_call (Terminate, NULL_TREE);
568   resume_momentary (yes);
569   return term;
570 }
571
572 /* Call this to start a catch block. Typename is the typename, and identifier
573    is the variable to place the object in or NULL if the variable doesn't
574    matter.  If typename is NULL, that means its a "catch (...)" or catch
575    everything.  In that case we don't need to do any type checking.
576    (ie: it ends up as the "else" clause rather than an "else if" clause) */
577
578 void
579 expand_start_catch_block (declspecs, declarator)
580      tree declspecs, declarator;
581 {
582   tree decl;
583
584   if (processing_template_decl)
585     {
586       if (declspecs)
587         {
588           decl = grokdeclarator (declarator, declspecs, CATCHPARM,
589                                  1, NULL_TREE);
590           pushdecl (decl);
591           decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
592                                copy_to_permanent (declspecs),
593                                NULL_TREE);
594           add_tree (decl);
595         }
596       return;
597     }
598
599   if (! doing_eh (1))
600     return;
601
602   process_start_catch_block (declspecs, declarator);
603 }
604
605
606 /* This function performs the expand_start_catch_block functionality for 
607    exceptions implemented in the new style. __throw determines whether
608    a handler needs to be called or not, so the handler itself has to do
609    nothing additional. */
610
611 static void 
612 process_start_catch_block (declspecs, declarator)
613      tree declspecs, declarator;
614 {
615   tree decl = NULL_TREE;
616   tree init;
617
618   /* Create a binding level for the eh_info and the exception object
619      cleanup.  */
620   pushlevel (0);
621   expand_start_bindings (0);
622
623
624   if (declspecs)
625     {
626       decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
627
628       if (decl == NULL_TREE)
629         error ("invalid catch parameter");
630     }
631
632   if (decl)
633     start_catch_handler (build_eh_type_type_ref (TREE_TYPE (decl)));
634   else
635     start_catch_handler (CATCH_ALL_TYPE);
636
637   emit_line_note (input_filename, lineno);
638
639   push_eh_info ();
640
641   if (decl)
642     {
643       tree exp;
644       tree init_type;
645
646       /* Make sure we mark the catch param as used, otherwise we'll get
647          a warning about an unused ((anonymous)).  */
648       TREE_USED (decl) = 1;
649
650       /* Figure out the type that the initializer is.  */
651       init_type = TREE_TYPE (decl);
652       if (TREE_CODE (init_type) != REFERENCE_TYPE
653           && TREE_CODE (init_type) != POINTER_TYPE)
654         init_type = build_reference_type (init_type);
655
656       exp = get_eh_value ();
657
658       /* Since pointers are passed by value, initialize a reference to
659          pointer catch parm with the address of the value slot.  */
660       if (TREE_CODE (init_type) == REFERENCE_TYPE
661           && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
662         exp = build_unary_op (ADDR_EXPR, exp, 1);
663
664       exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
665
666       push_eh_cleanup ();
667
668       /* Create a binding level for the parm.  */
669       pushlevel (0);
670       expand_start_bindings (0);
671
672       init = convert_from_reference (exp);
673
674       /* If the constructor for the catch parm exits via an exception, we
675          must call terminate.  See eh23.C.  */
676       if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
677         {
678           /* Generate the copy constructor call directly so we can wrap it.
679              See also expand_default_init.  */
680           init = ocp_convert (TREE_TYPE (decl), init,
681                               CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
682           init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
683                         build_terminate_handler ());
684         }
685
686       /* Let `cp_finish_decl' know that this initializer is ok.  */
687       DECL_INITIAL (decl) = init;
688       decl = pushdecl (decl);
689
690       start_decl_1 (decl);
691       cp_finish_decl (decl, init, NULL_TREE, 0,
692                       LOOKUP_ONLYCONVERTING|DIRECT_BIND);
693     }
694   else
695     {
696       push_eh_cleanup ();
697
698       /* Create a binding level for the parm.  */
699       pushlevel (0);
700       expand_start_bindings (0);
701
702       /* Fall into the catch all section.  */
703     }
704
705   emit_line_note (input_filename, lineno);
706 }
707
708
709 /* Call this to end a catch block.  Its responsible for emitting the
710    code to handle jumping back to the correct place, and for emitting
711    the label to jump to if this catch block didn't match.  */
712
713 void
714 expand_end_catch_block ()
715 {
716   if (! doing_eh (1))
717     return;
718
719   /* Cleanup the EH parameter.  */
720   expand_end_bindings (getdecls (), kept_level_p (), 0);
721   poplevel (kept_level_p (), 1, 0);
722       
723   /* Cleanup the EH object.  */
724   expand_end_bindings (getdecls (), kept_level_p (), 0);
725   poplevel (kept_level_p (), 1, 0);
726
727   /* Fall to outside the try statement when done executing handler and
728      we fall off end of handler.  This is jump Lresume in the
729      documentation.  */
730   expand_goto (top_label_entry (&caught_return_label_stack));
731
732   end_catch_handler ();
733 }
734
735 /* An exception spec is implemented more or less like:
736
737    try {
738      function body;
739    } catch (...) {
740      void *p[] = { typeid(raises) };
741      __check_eh_spec (p, count);
742    }
743
744    __check_eh_spec in exception.cc handles all the details.  */
745
746 void
747 expand_start_eh_spec ()
748 {
749   expand_start_try_stmts ();
750 }
751
752 static void
753 expand_end_eh_spec (raises)
754      tree raises;
755 {
756   tree tmp, fn, decl, types = NULL_TREE;
757   int count = 0;
758
759   expand_start_all_catch ();
760   expand_start_catch_block (NULL_TREE, NULL_TREE);
761
762   /* Build up an array of type_infos.  */
763   for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
764     {
765       types = expr_tree_cons
766         (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
767       ++count;
768     }
769
770   types = build_nt (CONSTRUCTOR, NULL_TREE, types);
771   TREE_HAS_CONSTRUCTOR (types) = 1;
772
773   /* We can't pass the CONSTRUCTOR directly, so stick it in a variable.  */
774   tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
775   decl = build_decl (VAR_DECL, NULL_TREE, tmp);
776   DECL_ARTIFICIAL (decl) = 1;
777   DECL_INITIAL (decl) = types;
778   cp_finish_decl (decl, types, NULL_TREE, 0, 0);
779
780   decl = decay_conversion (decl);
781
782   fn = get_identifier ("__check_eh_spec");
783   if (IDENTIFIER_GLOBAL_VALUE (fn))
784     fn = IDENTIFIER_GLOBAL_VALUE (fn);
785   else
786     {
787       push_obstacks_nochange ();
788       end_temporary_allocation ();
789
790       tmp = tree_cons
791         (NULL_TREE, integer_type_node, tree_cons
792          (NULL_TREE, TREE_TYPE (decl), void_list_node));
793       tmp = build_function_type (void_type_node, tmp);
794   
795       fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
796       DECL_EXTERNAL (fn) = 1;
797       TREE_PUBLIC (fn) = 1;
798       DECL_ARTIFICIAL (fn) = 1;
799       TREE_THIS_VOLATILE (fn) = 1;
800       pushdecl_top_level (fn);
801       make_function_rtl (fn);
802       pop_obstacks ();
803     }
804
805   mark_used (fn);
806   tmp = expr_tree_cons (NULL_TREE, build_int_2 (count, 0), expr_tree_cons
807                         (NULL_TREE, decl, NULL_TREE));
808   tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
809   expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
810
811   expand_end_catch_block ();
812   expand_end_all_catch ();
813 }
814
815 /* This is called to expand all the toplevel exception handling
816    finalization for a function.  It should only be called once per
817    function.  */
818
819 void
820 expand_exception_blocks ()
821 {
822   do_pending_stack_adjust ();
823   push_to_sequence (catch_clauses);
824   expand_leftover_cleanups ();
825   do_pending_stack_adjust ();
826   catch_clauses = get_insns ();
827   end_sequence ();
828
829   /* Do this after we expand leftover cleanups, so that the
830      expand_eh_region_end that expand_end_eh_spec does will match the
831      right expand_eh_region_start, and make sure it comes out before
832      the terminate protected region.  */
833   if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
834     {
835      expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
836      do_pending_stack_adjust ();
837      push_to_sequence (catch_clauses);
838      expand_leftover_cleanups ();
839      do_pending_stack_adjust ();
840      catch_clauses = get_insns ();
841      end_sequence ();
842     }
843
844   if (catch_clauses)
845     {
846       rtx funcend = gen_label_rtx ();
847       emit_jump (funcend);
848
849       /* We cannot protect n regions this way if we must flow into the
850          EH region through the top of the region, as we have to with
851          the setjmp/longjmp approach.  */
852       if (exceptions_via_longjmp == 0)
853         expand_eh_region_start ();
854
855       emit_insns (catch_clauses);
856       catch_clauses = NULL_RTX;
857
858       if (exceptions_via_longjmp == 0)
859         expand_eh_region_end (build_terminate_handler ());
860
861       expand_leftover_cleanups ();
862
863       emit_label (funcend);
864     }
865 }
866
867 tree
868 start_anon_func ()
869 {
870   static int counter = 0;
871   int old_interface_unknown = interface_unknown;
872   char name[32];
873   tree params;
874   tree t;
875
876   push_cp_function_context (NULL_TREE);
877   push_to_top_level ();
878
879   /* No need to mangle this.  */
880   push_lang_context (lang_name_c);
881
882   interface_unknown = 1;
883
884   params = void_list_node;
885   /* tcf stands for throw clean function.  */
886   sprintf (name, "__tcf_%d", counter++);
887   t = make_call_declarator (get_identifier (name), params, NULL_TREE,
888                             NULL_TREE);
889   start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
890                                   void_list_node),
891                   t, NULL_TREE, 0);
892   store_parm_decls ();
893   pushlevel (0);
894   clear_last_expr ();
895   push_momentary ();
896   expand_start_bindings (0);
897   emit_line_note (input_filename, lineno);
898
899   interface_unknown = old_interface_unknown;
900
901   pop_lang_context ();
902
903   return current_function_decl;
904 }
905
906 void
907 end_anon_func ()
908 {
909   expand_end_bindings (getdecls (), 1, 0);
910   poplevel (1, 0, 0);
911   pop_momentary ();
912
913   finish_function (lineno, 0, 0);
914
915   pop_from_top_level ();
916   pop_cp_function_context (NULL_TREE);
917 }
918
919 /* Return a pointer to a buffer for an exception object of type TYPE.  */
920
921 static tree
922 alloc_eh_object (type)
923      tree type;
924 {
925   tree fn, exp;
926
927   fn = get_identifier ("__eh_alloc");
928   if (IDENTIFIER_GLOBAL_VALUE (fn))
929     fn = IDENTIFIER_GLOBAL_VALUE (fn);
930   else
931     {
932       /* Declare __eh_alloc (size_t), as defined in exception.cc.  */
933       tree tmp;
934       push_obstacks_nochange ();
935       end_temporary_allocation ();
936       tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
937       fn = build_lang_decl (FUNCTION_DECL, fn,
938                             build_function_type (ptr_type_node, tmp));
939       DECL_EXTERNAL (fn) = 1;
940       TREE_PUBLIC (fn) = 1;
941       DECL_ARTIFICIAL (fn) = 1;
942       pushdecl_top_level (fn);
943       make_function_rtl (fn);
944       pop_obstacks ();
945     }
946
947   mark_used (fn);
948   exp = build_function_call (fn, expr_tree_cons
949                              (NULL_TREE, size_in_bytes (type), NULL_TREE));
950   exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
951   return exp;
952 }
953
954 /* Expand a throw statement.  This follows the following
955    algorithm:
956
957         1. Allocate space to save the current PC onto the stack.
958         2. Generate and emit a label and save its address into the
959                 newly allocated stack space since we can't save the pc directly.
960         3. If this is the first call to throw in this function:
961                 generate a label for the throw block
962         4. jump to the throw block label.  */
963
964 void
965 expand_throw (exp)
966      tree exp;
967 {
968   tree fn;
969   static tree cleanup_type;
970
971   if (! doing_eh (1))
972     return;
973
974   if (exp)
975     {
976       tree throw_type;
977       tree cleanup = NULL_TREE, e;
978
979       /* throw expression */
980       /* First, decay it.  */
981       exp = decay_conversion (exp);
982
983       /* cleanup_type is void (*)(void *, int),
984          the internal type of a destructor. */
985       if (cleanup_type == NULL_TREE)
986         {
987           push_obstacks_nochange ();
988           end_temporary_allocation ();
989           cleanup_type = build_pointer_type
990             (build_function_type
991              (void_type_node, tree_cons
992               (NULL_TREE, ptr_type_node, tree_cons
993                (NULL_TREE, integer_type_node, void_list_node))));
994           pop_obstacks ();
995         }
996
997       if (TYPE_PTR_P (TREE_TYPE (exp)))
998         throw_type = build_eh_type (exp);
999       else
1000         {
1001           tree object, ptr;
1002
1003           /* OK, this is kind of wacky.  The WP says that we call
1004              terminate
1005
1006              when the exception handling mechanism, after completing
1007              evaluation of the expression to be thrown but before the
1008              exception is caught (_except.throw_), calls a user function
1009              that exits via an uncaught exception.
1010
1011              So we have to protect the actual initialization of the
1012              exception object with terminate(), but evaluate the expression
1013              first.  We also expand the call to __eh_alloc
1014              first.  Since there could be temps in the expression, we need
1015              to handle that, too.  */
1016
1017           expand_start_target_temps ();
1018
1019 #if 0
1020           /* Unfortunately, this doesn't work.  */
1021           preexpand_calls (exp);
1022 #else
1023           /* Store the throw expression into a temp.  This can be less
1024              efficient than storing it into the allocated space directly, but
1025              oh well.  To do this efficiently we would need to insinuate
1026              ourselves into expand_call.  */
1027           if (TREE_SIDE_EFFECTS (exp))
1028             {
1029               tree temp = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp));
1030               DECL_ARTIFICIAL (temp) = 1;
1031               DECL_RTL (temp) = assign_temp (TREE_TYPE (exp), 2, 0, 1);
1032               DECL_INITIAL (temp) = exp;
1033               cp_finish_decl (temp, exp, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
1034               exp = temp;
1035             }
1036 #endif
1037
1038           /* Allocate the space for the exception.  */
1039           ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
1040           expand_expr (ptr, const0_rtx, VOIDmode, 0);
1041
1042           expand_eh_region_start ();
1043
1044           object = build_indirect_ref (ptr, NULL_PTR);
1045           exp = build_modify_expr (object, INIT_EXPR, exp);
1046
1047           if (exp == error_mark_node)
1048             error ("  in thrown expression");
1049
1050           expand_expr (exp, const0_rtx, VOIDmode, 0);
1051           expand_eh_region_end (build_terminate_handler ());
1052           expand_end_target_temps ();
1053
1054           throw_type = build_eh_type (object);
1055
1056           if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
1057             {
1058               cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
1059                                          dtor_identifier, 0);
1060               cleanup = TREE_VALUE (cleanup);
1061               mark_used (cleanup);
1062               mark_addressable (cleanup);
1063               /* Pretend it's a normal function.  */
1064               cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
1065             }
1066
1067           exp = ptr;
1068         }
1069
1070       /* Cast EXP to `void *' so that it will match the prototype for
1071          __cp_push_exception.  */
1072       exp = convert (ptr_type_node, exp);
1073
1074       if (cleanup == NULL_TREE)
1075         {
1076           cleanup = build_int_2 (0, 0);
1077           TREE_TYPE (cleanup) = cleanup_type;
1078         }
1079
1080       fn = get_identifier ("__cp_push_exception");
1081       if (IDENTIFIER_GLOBAL_VALUE (fn))
1082         fn = IDENTIFIER_GLOBAL_VALUE (fn);
1083       else
1084         {
1085           /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1086              as defined in exception.cc.  */
1087           tree tmp;
1088           push_obstacks_nochange ();
1089           end_temporary_allocation ();
1090           tmp = tree_cons
1091             (NULL_TREE, ptr_type_node, tree_cons
1092              (NULL_TREE, ptr_type_node, tree_cons
1093               (NULL_TREE, cleanup_type, void_list_node)));
1094           fn = build_lang_decl (FUNCTION_DECL, fn,
1095                                 build_function_type (void_type_node, tmp));
1096           DECL_EXTERNAL (fn) = 1;
1097           TREE_PUBLIC (fn) = 1;
1098           DECL_ARTIFICIAL (fn) = 1;
1099           pushdecl_top_level (fn);
1100           make_function_rtl (fn);
1101           pop_obstacks ();
1102         }
1103
1104       mark_used (fn);
1105       e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons
1106                           (NULL_TREE, throw_type, expr_tree_cons
1107                            (NULL_TREE, cleanup, NULL_TREE)));
1108       e = build_function_call (fn, e);
1109       expand_expr (e, const0_rtx, VOIDmode, 0);
1110     }
1111   else
1112     {
1113       /* rethrow current exception; note that it's no longer caught.  */
1114
1115       tree fn = get_identifier ("__uncatch_exception");
1116       if (IDENTIFIER_GLOBAL_VALUE (fn))
1117         fn = IDENTIFIER_GLOBAL_VALUE (fn);
1118       else
1119         {
1120           /* Declare void __uncatch_exception (void)
1121              as defined in exception.cc. */
1122           push_obstacks_nochange ();
1123           end_temporary_allocation ();
1124           fn = build_lang_decl (FUNCTION_DECL, fn,
1125                                 build_function_type (void_type_node,
1126                                                      void_list_node));
1127           DECL_EXTERNAL (fn) = 1;
1128           TREE_PUBLIC (fn) = 1;
1129           DECL_ARTIFICIAL (fn) = 1;
1130           pushdecl_top_level (fn);
1131           make_function_rtl (fn);
1132           pop_obstacks ();
1133         }
1134
1135       mark_used (fn);
1136       exp = build_function_call (fn, NULL_TREE);
1137       expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
1138     }
1139
1140   expand_internal_throw ();
1141 }
1142
1143 /* Build a throw expression.  */
1144
1145 tree
1146 build_throw (e)
1147      tree e;
1148 {
1149   if (e == error_mark_node)
1150     return e;
1151
1152   if (processing_template_decl)
1153     return build_min (THROW_EXPR, void_type_node, e);
1154
1155   if (e == null_node)
1156     cp_warning ("throwing NULL, which has integral, not pointer type");
1157
1158   e = build1 (THROW_EXPR, void_type_node, e);
1159   TREE_SIDE_EFFECTS (e) = 1;
1160   TREE_USED (e) = 1;
1161
1162   return e;
1163 }