OSDN Git Service

e5afb897177da30a66b597c92cf1c6880e167a33
[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_obstacks_nochange ();
244       end_temporary_allocation ();
245
246       /* struct cp_eh_info.  This must match exception.cc.  Note that this
247          type is not pushed anywhere.  */
248       t1= make_lang_type (RECORD_TYPE);
249       fields[0] = build_lang_field_decl (FIELD_DECL, 
250                     get_identifier ("handler_label"), ptr_type_node);
251       fields[1] = build_lang_field_decl (FIELD_DECL, 
252                     get_identifier ("dynamic_handler_chain"), ptr_type_node);
253       fields[2] = build_lang_field_decl (FIELD_DECL, 
254                     get_identifier ("info"), ptr_type_node);
255       fields[3] = build_lang_field_decl (FIELD_DECL, 
256                     get_identifier ("table_index"), ptr_type_node);
257       /* N.B.: The fourth field LEN is expected to be
258          the number of fields - 1, not the total number of fields.  */
259       finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
260       t1 = build_pointer_type (t1);
261
262       t1= make_lang_type (RECORD_TYPE);
263       fields[0] = build_lang_field_decl (FIELD_DECL, 
264                     get_identifier ("match_function"), ptr_type_node);
265       fields[1] = build_lang_field_decl (FIELD_DECL, 
266                     get_identifier ("language"), short_integer_type_node);
267       fields[2] = build_lang_field_decl (FIELD_DECL, 
268                     get_identifier ("version"), short_integer_type_node);
269       /* N.B.: The fourth field LEN is expected to be
270          the number of fields - 1, not the total number of fields.  */
271       finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node);
272       t = make_lang_type (RECORD_TYPE);
273       fields[0] = build_lang_field_decl (FIELD_DECL, 
274                                               get_identifier ("eh_info"), t1);
275       fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
276                                          ptr_type_node);
277       fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
278                                          ptr_type_node);
279       fields[3] = build_lang_field_decl
280         (FIELD_DECL, get_identifier ("cleanup"),
281          build_pointer_type (build_function_type
282                              (ptr_type_node, tree_cons
283                               (NULL_TREE, ptr_type_node, void_list_node))));
284       fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
285                                          boolean_type_node);
286       fields[5] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
287                                          build_pointer_type (t));
288       fields[6] = build_lang_field_decl
289         (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
290       /* N.B.: The fourth field LEN is expected to be
291          the number of fields - 1, not the total number of fields.  */
292       finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node);
293       t = build_pointer_type (t);
294
295       /* And now the function.  */
296       fn = build_lang_decl (FUNCTION_DECL, fn,
297                             build_function_type (t, void_list_node));
298       DECL_EXTERNAL (fn) = 1;
299       TREE_PUBLIC (fn) = 1;
300       DECL_ARTIFICIAL (fn) = 1;
301       pushdecl_top_level (fn);
302       make_function_rtl (fn);
303       pop_obstacks ();
304     }
305   mark_used (fn);
306   return build_function_call (fn, NULL_TREE);
307 }
308
309 /* Retrieve a pointer to the cp_eh_info node for the current exception
310    and save it in the current binding level.  */
311
312 static void
313 push_eh_info ()
314 {
315   tree decl, fn = call_eh_info ();
316
317   /* Remember the pointer to the current exception info; it won't change
318      during this catch block.  */
319   decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
320                      TREE_TYPE (fn));
321   DECL_ARTIFICIAL (decl) = 1;
322   DECL_INITIAL (decl) = fn;
323   decl = pushdecl (decl);
324   cp_finish_decl (decl, fn, NULL_TREE, 0, 0);
325 }
326
327 /* Returns a reference to the cp_eh_info node for the current exception.  */
328
329 static tree
330 get_eh_info ()
331 {
332   /* Look for the pointer pushed in push_eh_info.  */
333   tree t = lookup_name (get_identifier ("__exception_info"), 0);
334   return build_indirect_ref (t, NULL_PTR);
335 }
336
337 /* Returns a reference to the current exception object.  */
338
339 static tree
340 get_eh_value ()
341 {
342   return build_component_ref (get_eh_info (), get_identifier ("value"),
343                               NULL_TREE, 0);
344 }
345
346 /* Returns a reference to the current exception type.  */
347
348 #if 0
349 static tree
350 get_eh_type ()
351 {
352   return build_component_ref (get_eh_info (), get_identifier ("type"),
353                               NULL_TREE, 0);
354 }
355
356 /* Returns a reference to whether or not the current exception
357    has been caught.  */
358
359 static tree
360 get_eh_caught ()
361 {
362   return build_component_ref (get_eh_info (), get_identifier ("caught"),
363                               NULL_TREE, 0);
364 }
365
366 /* Returns a reference to whether or not the current exception
367    has been caught.  */
368
369 static tree
370 get_eh_handlers ()
371 {
372   return build_component_ref (get_eh_info (), get_identifier ("handlers"),
373                               NULL_TREE, 0);
374 }
375 #endif
376
377 /* Build a type value for use at runtime for a type that is matched
378    against by the exception handling system.  */
379
380 static tree
381 build_eh_type_type (type)
382      tree type;
383 {
384   const char *typestring;
385   tree exp;
386
387   if (type == error_mark_node)
388     return error_mark_node;
389
390   /* peel back references, so they match.  */
391   if (TREE_CODE (type) == REFERENCE_TYPE)
392     type = TREE_TYPE (type);
393
394   /* Peel off cv qualifiers.  */
395   type = TYPE_MAIN_VARIANT (type);
396
397   if (flag_rtti)
398     return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
399
400   typestring = build_overload_name (type, 1, 1);
401   exp = combine_strings (build_string (strlen (typestring)+1, typestring));
402   return build1 (ADDR_EXPR, ptr_type_node, exp);
403 }
404
405 /* Build the address of a runtime type for use in the runtime matching
406    field of the new exception model */
407
408 static tree
409 build_eh_type_type_ref (type)
410      tree type;
411 {
412   const char *typestring;
413   tree exp;
414
415   if (type == error_mark_node)
416     return error_mark_node;
417
418   /* peel back references, so they match.  */
419   if (TREE_CODE (type) == REFERENCE_TYPE)
420     type = TREE_TYPE (type);
421
422   /* Peel off cv qualifiers.  */
423   type = TYPE_MAIN_VARIANT (type);
424
425   push_obstacks_nochange ();
426   end_temporary_allocation ();
427
428   if (flag_rtti)
429     {
430       exp = get_tinfo_fn (type);
431       TREE_USED (exp) = 1;
432       mark_inline_for_output (exp);
433       exp = build1 (ADDR_EXPR, ptr_type_node, exp);
434     }
435   else
436     {
437       typestring = build_overload_name (type, 1, 1);
438       exp = combine_strings (build_string (strlen (typestring)+1, typestring));
439       exp = build1 (ADDR_EXPR, ptr_type_node, exp);
440     }
441   pop_obstacks ();
442   return (exp);
443 }
444
445
446 /* Build a type value for use at runtime for a exp that is thrown or
447    matched against by the exception handling system.  */
448
449 static tree
450 build_eh_type (exp)
451      tree exp;
452 {
453   if (flag_rtti)
454     {
455       exp = build_typeid (exp);
456       return build1 (ADDR_EXPR, ptr_type_node, exp);
457     }
458   return build_eh_type_type (TREE_TYPE (exp));
459 }
460
461 /* This routine is called to mark all the symbols representing runtime
462    type functions in the exception table as haveing been referenced.
463    This will make sure code is emitted for them. Called from finish_file. */
464 void 
465 mark_all_runtime_matches () 
466 {
467   int x,num;
468   void **ptr;
469   tree exp;
470   
471   num = find_all_handler_type_matches (&ptr);
472   if (num == 0 || ptr == NULL)
473     return;
474   
475   for (x=0; x <num; x++)
476     {
477       exp = (tree) ptr[x];
478       if (TREE_CODE (exp) == ADDR_EXPR)
479         {
480           exp = TREE_OPERAND (exp, 0);
481           if (TREE_CODE (exp) == FUNCTION_DECL)
482             TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
483         }
484     }
485   
486   free (ptr);
487 }
488
489 /* Build up a call to __cp_pop_exception, to destroy the exception object
490    for the current catch block.  HANDLER is either true or false, telling
491    the library whether or not it is being called from an exception handler;
492    if it is, it avoids destroying the object on rethrow.  */
493
494 static tree
495 do_pop_exception ()
496 {
497   tree fn, cleanup;
498   fn = get_identifier ("__cp_pop_exception");
499   if (IDENTIFIER_GLOBAL_VALUE (fn))
500     fn = IDENTIFIER_GLOBAL_VALUE (fn);
501   else
502     {
503       /* Declare void __cp_pop_exception (void *),
504          as defined in exception.cc. */
505       push_obstacks_nochange ();
506       end_temporary_allocation ();
507       fn = build_lang_decl
508         (FUNCTION_DECL, fn,
509          build_function_type (void_type_node, tree_cons
510                               (NULL_TREE, ptr_type_node, void_list_node)));
511       DECL_EXTERNAL (fn) = 1;
512       TREE_PUBLIC (fn) = 1;
513       DECL_ARTIFICIAL (fn) = 1;
514       pushdecl_top_level (fn);
515       make_function_rtl (fn);
516       pop_obstacks ();
517     }
518
519   mark_used (fn);
520   /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
521   cleanup = lookup_name (get_identifier ("__exception_info"), 0);
522   cleanup = build_function_call (fn, expr_tree_cons
523                                  (NULL_TREE, cleanup, NULL_TREE));
524   return cleanup;
525 }
526
527 /* This routine creates the cleanup for the current exception.  */
528
529 static void
530 push_eh_cleanup ()
531 {
532   int yes;
533
534   yes = suspend_momentary ();
535   /* All cleanups must last longer than normal.  */
536   expand_decl_cleanup (NULL_TREE, do_pop_exception ());
537   resume_momentary (yes);
538 }
539
540 /* Build up a call to terminate on the function obstack, for use as an
541    exception handler.  */
542
543 static tree
544 build_terminate_handler ()
545 {
546   int yes = suspend_momentary ();
547   tree term = build_function_call (Terminate, NULL_TREE);
548   resume_momentary (yes);
549   return term;
550 }
551
552 /* Call this to start a catch block. Typename is the typename, and identifier
553    is the variable to place the object in or NULL if the variable doesn't
554    matter.  If typename is NULL, that means its a "catch (...)" or catch
555    everything.  In that case we don't need to do any type checking.
556    (ie: it ends up as the "else" clause rather than an "else if" clause) */
557
558 void
559 expand_start_catch_block (declspecs, declarator)
560      tree declspecs, declarator;
561 {
562   tree decl;
563
564   if (processing_template_decl)
565     {
566       if (declspecs)
567         {
568           decl = grokdeclarator (declarator, declspecs, CATCHPARM,
569                                  1, NULL_TREE);
570           pushdecl (decl);
571           decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
572                                copy_to_permanent (declspecs),
573                                NULL_TREE);
574           add_tree (decl);
575         }
576       return;
577     }
578
579   if (! doing_eh (1))
580     return;
581
582   process_start_catch_block (declspecs, declarator);
583 }
584
585
586 /* This function performs the expand_start_catch_block functionality for 
587    exceptions implemented in the new style. __throw determines whether
588    a handler needs to be called or not, so the handler itself has to do
589    nothing additional. */
590
591 static void 
592 process_start_catch_block (declspecs, declarator)
593      tree declspecs, declarator;
594 {
595   tree decl = NULL_TREE;
596   tree init;
597
598   /* Create a binding level for the eh_info and the exception object
599      cleanup.  */
600   pushlevel (0);
601   expand_start_bindings (0);
602
603
604   if (declspecs)
605     {
606       decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
607
608       if (decl == NULL_TREE)
609         error ("invalid catch parameter");
610       else if (!complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE))
611         decl = NULL_TREE;
612     }
613
614   if (decl)
615     start_catch_handler (build_eh_type_type_ref (TREE_TYPE (decl)));
616   else
617     start_catch_handler (CATCH_ALL_TYPE);
618
619   emit_line_note (input_filename, lineno);
620
621   push_eh_info ();
622
623   if (decl)
624     {
625       tree exp;
626       tree init_type;
627
628       /* Make sure we mark the catch param as used, otherwise we'll get
629          a warning about an unused ((anonymous)).  */
630       TREE_USED (decl) = 1;
631
632       /* Figure out the type that the initializer is.  */
633       init_type = TREE_TYPE (decl);
634       if (TREE_CODE (init_type) != REFERENCE_TYPE
635           && TREE_CODE (init_type) != POINTER_TYPE)
636         init_type = build_reference_type (init_type);
637
638       exp = get_eh_value ();
639
640       /* Since pointers are passed by value, initialize a reference to
641          pointer catch parm with the address of the value slot.  */
642       if (TREE_CODE (init_type) == REFERENCE_TYPE
643           && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
644         exp = build_unary_op (ADDR_EXPR, exp, 1);
645
646       exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
647
648       push_eh_cleanup ();
649
650       /* Create a binding level for the parm.  */
651       pushlevel (0);
652       expand_start_bindings (0);
653
654       init = convert_from_reference (exp);
655
656       /* If the constructor for the catch parm exits via an exception, we
657          must call terminate.  See eh23.C.  */
658       if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
659         {
660           /* Generate the copy constructor call directly so we can wrap it.
661              See also expand_default_init.  */
662           init = ocp_convert (TREE_TYPE (decl), init,
663                               CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
664           init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
665                         build_terminate_handler ());
666         }
667
668       /* Let `cp_finish_decl' know that this initializer is ok.  */
669       DECL_INITIAL (decl) = init;
670       decl = pushdecl (decl);
671
672       start_decl_1 (decl);
673       cp_finish_decl (decl, init, NULL_TREE, 0,
674                       LOOKUP_ONLYCONVERTING|DIRECT_BIND);
675     }
676   else
677     {
678       push_eh_cleanup ();
679
680       /* Create a binding level for the parm.  */
681       pushlevel (0);
682       expand_start_bindings (0);
683
684       /* Fall into the catch all section.  */
685     }
686
687   emit_line_note (input_filename, lineno);
688 }
689
690
691 /* Call this to end a catch block.  Its responsible for emitting the
692    code to handle jumping back to the correct place, and for emitting
693    the label to jump to if this catch block didn't match.  */
694
695 void
696 expand_end_catch_block ()
697 {
698   if (! doing_eh (1))
699     return;
700
701   /* Cleanup the EH parameter.  */
702   expand_end_bindings (getdecls (), kept_level_p (), 0);
703   poplevel (kept_level_p (), 1, 0);
704       
705   /* Cleanup the EH object.  */
706   expand_end_bindings (getdecls (), kept_level_p (), 0);
707   poplevel (kept_level_p (), 1, 0);
708
709   /* Fall to outside the try statement when done executing handler and
710      we fall off end of handler.  This is jump Lresume in the
711      documentation.  */
712   expand_goto (top_label_entry (&caught_return_label_stack));
713
714   end_catch_handler ();
715 }
716
717 /* An exception spec is implemented more or less like:
718
719    try {
720      function body;
721    } catch (...) {
722      void *p[] = { typeid(raises) };
723      __check_eh_spec (p, count);
724    }
725
726    __check_eh_spec in exception.cc handles all the details.  */
727
728 void
729 expand_start_eh_spec ()
730 {
731   expand_start_try_stmts ();
732 }
733
734 static void
735 expand_end_eh_spec (raises)
736      tree raises;
737 {
738   tree tmp, fn, decl, types = NULL_TREE;
739   int count = 0;
740
741   expand_start_all_catch ();
742   expand_start_catch_block (NULL_TREE, NULL_TREE);
743
744   /* Build up an array of type_infos.  */
745   for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
746     {
747       types = expr_tree_cons
748         (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
749       ++count;
750     }
751
752   types = build_nt (CONSTRUCTOR, NULL_TREE, types);
753   TREE_HAS_CONSTRUCTOR (types) = 1;
754
755   /* We can't pass the CONSTRUCTOR directly, so stick it in a variable.  */
756   tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
757   decl = build_decl (VAR_DECL, NULL_TREE, tmp);
758   DECL_ARTIFICIAL (decl) = 1;
759   DECL_INITIAL (decl) = types;
760   cp_finish_decl (decl, types, NULL_TREE, 0, 0);
761
762   decl = decay_conversion (decl);
763
764   fn = get_identifier ("__check_eh_spec");
765   if (IDENTIFIER_GLOBAL_VALUE (fn))
766     fn = IDENTIFIER_GLOBAL_VALUE (fn);
767   else
768     {
769       push_obstacks_nochange ();
770       end_temporary_allocation ();
771
772       tmp = tree_cons
773         (NULL_TREE, integer_type_node, tree_cons
774          (NULL_TREE, TREE_TYPE (decl), void_list_node));
775       tmp = build_function_type (void_type_node, tmp);
776   
777       fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
778       DECL_EXTERNAL (fn) = 1;
779       TREE_PUBLIC (fn) = 1;
780       DECL_ARTIFICIAL (fn) = 1;
781       TREE_THIS_VOLATILE (fn) = 1;
782       pushdecl_top_level (fn);
783       make_function_rtl (fn);
784       pop_obstacks ();
785     }
786
787   mark_used (fn);
788   tmp = expr_tree_cons (NULL_TREE, build_int_2 (count, 0), expr_tree_cons
789                         (NULL_TREE, decl, NULL_TREE));
790   tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
791   expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
792
793   expand_end_catch_block ();
794   expand_end_all_catch ();
795 }
796
797 /* This is called to expand all the toplevel exception handling
798    finalization for a function.  It should only be called once per
799    function.  */
800
801 void
802 expand_exception_blocks ()
803 {
804   do_pending_stack_adjust ();
805   push_to_sequence (catch_clauses);
806   expand_leftover_cleanups ();
807   do_pending_stack_adjust ();
808   catch_clauses = get_insns ();
809   end_sequence ();
810
811   /* Do this after we expand leftover cleanups, so that the
812      expand_eh_region_end that expand_end_eh_spec does will match the
813      right expand_eh_region_start, and make sure it comes out before
814      the terminate protected region.  */
815   if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
816     {
817      expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
818      do_pending_stack_adjust ();
819      push_to_sequence (catch_clauses);
820      expand_leftover_cleanups ();
821      do_pending_stack_adjust ();
822      catch_clauses = get_insns ();
823      end_sequence ();
824     }
825
826   if (catch_clauses)
827     {
828       rtx funcend = gen_label_rtx ();
829       emit_jump (funcend);
830
831       /* We cannot protect n regions this way if we must flow into the
832          EH region through the top of the region, as we have to with
833          the setjmp/longjmp approach.  */
834       if (exceptions_via_longjmp == 0)
835         expand_eh_region_start ();
836
837       emit_insns (catch_clauses);
838       catch_clauses = NULL_RTX;
839
840       if (exceptions_via_longjmp == 0)
841         expand_eh_region_end (build_terminate_handler ());
842
843       expand_leftover_cleanups ();
844
845       emit_label (funcend);
846     }
847 }
848
849 tree
850 start_anon_func ()
851 {
852   static int counter = 0;
853   int old_interface_unknown = interface_unknown;
854   char name[32];
855   tree params;
856   tree t;
857
858   push_cp_function_context (NULL_TREE);
859   push_to_top_level ();
860
861   /* No need to mangle this.  */
862   push_lang_context (lang_name_c);
863
864   interface_unknown = 1;
865
866   params = void_list_node;
867   /* tcf stands for throw clean function.  */
868   sprintf (name, "__tcf_%d", counter++);
869   t = make_call_declarator (get_identifier (name), params, NULL_TREE,
870                             NULL_TREE);
871   start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
872                                   void_list_node),
873                   t, NULL_TREE, 0);
874   store_parm_decls ();
875   pushlevel (0);
876   clear_last_expr ();
877   push_momentary ();
878   expand_start_bindings (0);
879   emit_line_note (input_filename, lineno);
880
881   interface_unknown = old_interface_unknown;
882
883   pop_lang_context ();
884
885   return current_function_decl;
886 }
887
888 void
889 end_anon_func ()
890 {
891   expand_end_bindings (getdecls (), 1, 0);
892   poplevel (1, 0, 0);
893   pop_momentary ();
894
895   finish_function (lineno, 0, 0);
896
897   pop_from_top_level ();
898   pop_cp_function_context (NULL_TREE);
899 }
900
901 /* Return a pointer to a buffer for an exception object of type TYPE.  */
902
903 static tree
904 alloc_eh_object (type)
905      tree type;
906 {
907   tree fn, exp;
908
909   fn = get_identifier ("__eh_alloc");
910   if (IDENTIFIER_GLOBAL_VALUE (fn))
911     fn = IDENTIFIER_GLOBAL_VALUE (fn);
912   else
913     {
914       /* Declare __eh_alloc (size_t), as defined in exception.cc.  */
915       tree tmp;
916       push_obstacks_nochange ();
917       end_temporary_allocation ();
918       tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
919       fn = build_lang_decl (FUNCTION_DECL, fn,
920                             build_function_type (ptr_type_node, tmp));
921       DECL_EXTERNAL (fn) = 1;
922       TREE_PUBLIC (fn) = 1;
923       DECL_ARTIFICIAL (fn) = 1;
924       pushdecl_top_level (fn);
925       make_function_rtl (fn);
926       pop_obstacks ();
927     }
928
929   mark_used (fn);
930   exp = build_function_call (fn, expr_tree_cons
931                              (NULL_TREE, size_in_bytes (type), NULL_TREE));
932   exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
933   return exp;
934 }
935
936 /* Expand a throw statement.  This follows the following
937    algorithm:
938
939         1. Allocate space to save the current PC onto the stack.
940         2. Generate and emit a label and save its address into the
941                 newly allocated stack space since we can't save the pc directly.
942         3. If this is the first call to throw in this function:
943                 generate a label for the throw block
944         4. jump to the throw block label.  */
945
946 void
947 expand_throw (exp)
948      tree exp;
949 {
950   tree fn;
951   static tree cleanup_type;
952
953   if (! doing_eh (1))
954     return;
955
956   if (exp)
957     {
958       tree throw_type;
959       tree cleanup = NULL_TREE, e;
960
961       /* throw expression */
962       /* First, decay it.  */
963       exp = decay_conversion (exp);
964
965       /* cleanup_type is void (*)(void *, int),
966          the internal type of a destructor. */
967       if (cleanup_type == NULL_TREE)
968         {
969           push_obstacks_nochange ();
970           end_temporary_allocation ();
971           cleanup_type = build_pointer_type
972             (build_function_type
973              (void_type_node, tree_cons
974               (NULL_TREE, ptr_type_node, tree_cons
975                (NULL_TREE, integer_type_node, void_list_node))));
976           pop_obstacks ();
977         }
978
979       if (TYPE_PTR_P (TREE_TYPE (exp)))
980         throw_type = build_eh_type (exp);
981       else
982         {
983           tree object, ptr;
984
985           /* OK, this is kind of wacky.  The WP says that we call
986              terminate
987
988              when the exception handling mechanism, after completing
989              evaluation of the expression to be thrown but before the
990              exception is caught (_except.throw_), calls a user function
991              that exits via an uncaught exception.
992
993              So we have to protect the actual initialization of the
994              exception object with terminate(), but evaluate the expression
995              first.  We also expand the call to __eh_alloc
996              first.  Since there could be temps in the expression, we need
997              to handle that, too.  */
998
999           expand_start_target_temps ();
1000
1001 #if 0
1002           /* Unfortunately, this doesn't work.  */
1003           preexpand_calls (exp);
1004 #else
1005           /* Store the throw expression into a temp.  This can be less
1006              efficient than storing it into the allocated space directly, but
1007              oh well.  To do this efficiently we would need to insinuate
1008              ourselves into expand_call.  */
1009           if (TREE_SIDE_EFFECTS (exp))
1010             {
1011               tree temp = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp));
1012               DECL_ARTIFICIAL (temp) = 1;
1013               DECL_RTL (temp) = assign_temp (TREE_TYPE (exp), 2, 0, 1);
1014               DECL_INITIAL (temp) = exp;
1015               cp_finish_decl (temp, exp, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
1016               exp = temp;
1017             }
1018 #endif
1019
1020           /* Allocate the space for the exception.  */
1021           ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
1022           expand_expr (ptr, const0_rtx, VOIDmode, 0);
1023
1024           expand_eh_region_start ();
1025
1026           object = build_indirect_ref (ptr, NULL_PTR);
1027           exp = build_modify_expr (object, INIT_EXPR, exp);
1028
1029           if (exp == error_mark_node)
1030             error ("  in thrown expression");
1031
1032           expand_expr (exp, const0_rtx, VOIDmode, 0);
1033           expand_eh_region_end (build_terminate_handler ());
1034           expand_end_target_temps ();
1035
1036           throw_type = build_eh_type (object);
1037
1038           if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
1039             {
1040               cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
1041                                          dtor_identifier, 0);
1042               cleanup = TREE_VALUE (cleanup);
1043               mark_used (cleanup);
1044               mark_addressable (cleanup);
1045               /* Pretend it's a normal function.  */
1046               cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
1047             }
1048
1049           exp = ptr;
1050         }
1051
1052       /* Cast EXP to `void *' so that it will match the prototype for
1053          __cp_push_exception.  */
1054       exp = convert (ptr_type_node, exp);
1055
1056       if (cleanup == NULL_TREE)
1057         {
1058           cleanup = build_int_2 (0, 0);
1059           TREE_TYPE (cleanup) = cleanup_type;
1060         }
1061
1062       fn = get_identifier ("__cp_push_exception");
1063       if (IDENTIFIER_GLOBAL_VALUE (fn))
1064         fn = IDENTIFIER_GLOBAL_VALUE (fn);
1065       else
1066         {
1067           /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1068              as defined in exception.cc.  */
1069           tree tmp;
1070           push_obstacks_nochange ();
1071           end_temporary_allocation ();
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_obstacks_nochange ();
1105           end_temporary_allocation ();
1106           fn = build_lang_decl (FUNCTION_DECL, fn,
1107                                 build_function_type (void_type_node,
1108                                                      void_list_node));
1109           DECL_EXTERNAL (fn) = 1;
1110           TREE_PUBLIC (fn) = 1;
1111           DECL_ARTIFICIAL (fn) = 1;
1112           pushdecl_top_level (fn);
1113           make_function_rtl (fn);
1114           pop_obstacks ();
1115         }
1116
1117       mark_used (fn);
1118       exp = build_function_call (fn, NULL_TREE);
1119       expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
1120     }
1121
1122   expand_internal_throw ();
1123 }
1124
1125 /* Build a throw expression.  */
1126
1127 tree
1128 build_throw (e)
1129      tree e;
1130 {
1131   if (e == error_mark_node)
1132     return e;
1133
1134   if (processing_template_decl)
1135     return build_min (THROW_EXPR, void_type_node, e);
1136
1137   if (e == null_node)
1138     cp_warning ("throwing NULL, which has integral, not pointer type");
1139   
1140   if (e != NULL_TREE)
1141     {
1142       if (!complete_ptr_ref_or_void_ptr_p (TREE_TYPE (e), e))
1143         return error_mark_node;
1144     }
1145
1146   e = build1 (THROW_EXPR, void_type_node, e);
1147   TREE_SIDE_EFFECTS (e) = 1;
1148   TREE_USED (e) = 1;
1149
1150   return e;
1151 }
1152
1153 /* Make sure TYPE is complete, pointer to complete, reference to
1154    complete, or pointer to cv void. Issue diagnostic on failure.
1155    Return the zero on failure and non-zero on success. FROM can be
1156    the expr or decl from whence TYPE came, if available.  */
1157
1158 static int
1159 complete_ptr_ref_or_void_ptr_p (type, from)
1160      tree type;
1161      tree from;
1162 {
1163   int is_ptr;
1164   
1165   /* Check complete.  */
1166   type = complete_type_or_else (type, from);
1167   if (!type)
1168     return 0;
1169   
1170   /* Or a pointer or ref to one, or cv void *.  */
1171   is_ptr = TREE_CODE (type) == POINTER_TYPE;
1172   if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE)
1173     {
1174       tree core = TREE_TYPE (type);
1175   
1176       if (is_ptr && same_type_p (TYPE_MAIN_VARIANT (core), void_type_node))
1177         /* OK */;
1178       else if (!complete_type_or_else (core, from))
1179         return 0;
1180     }
1181   return 1;
1182 }
1183