OSDN Git Service

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