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