OSDN Git Service

* tree.h (struct tree_common): Rename raises_flag to nothrow_flag.
[pf3gnuchains/gcc-fork.git] / gcc / cp / except.c
1 /* Handle exceptional things in C++.
2    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
3    Free Software Foundation, Inc.
4    Contributed by Michael Tiemann <tiemann@cygnus.com>
5    Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
6    initial re-implementation courtesy Tad Hunt.
7
8 This file is part of GNU CC.
9
10 GNU CC is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 GNU CC is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with GNU CC; see the file COPYING.  If not, write to
22 the Free Software Foundation, 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA.  */
24
25
26 #include "config.h"
27 #include "system.h"
28 #include "tree.h"
29 #include "rtl.h"
30 #include "cp-tree.h"
31 #include "flags.h"
32 #include "obstack.h"
33 #include "expr.h"
34 #include "output.h"
35 #include "except.h"
36 #include "defaults.h"
37 #include "toplev.h"
38 #include "eh-common.h"
39
40 static void push_eh_cleanup PARAMS ((void));
41 static tree build_eh_type_type PARAMS ((tree));
42 static tree call_eh_info PARAMS ((void));
43 static void push_eh_info PARAMS ((void));
44 static tree get_eh_info PARAMS ((void));
45 static tree get_eh_value PARAMS ((void));
46 #if 0
47 static tree get_eh_type PARAMS ((void));
48 static tree get_eh_caught PARAMS ((void));
49 static tree get_eh_handlers PARAMS ((void));
50 #endif
51 static tree do_pop_exception PARAMS ((void));
52 static tree build_eh_type_type_ref PARAMS ((tree));
53 static tree build_terminate_handler PARAMS ((void));
54 static tree alloc_eh_object PARAMS ((tree));
55 static int complete_ptr_ref_or_void_ptr_p PARAMS ((tree, tree));
56 static void initialize_handler_parm PARAMS ((tree));
57 static tree expand_throw PARAMS ((tree));
58 static int decl_is_java_type PARAMS ((tree decl, int err));
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 /* In a given translation unit we are constrained to catch only C++
97    types or only Java types.  `catch_language' holds the current type,
98    and `catch_language_init' registers whether `catch_language' has
99    been set.  */
100
101 static int catch_language_init = 0;
102 static int catch_language;
103
104 /* ======================================================================
105    Briefly the algorithm works like this:
106
107      When a constructor or start of a try block is encountered,
108      push_eh_entry (&eh_stack) is called.  Push_eh_entry () creates a
109      new entry in the unwind protection stack and returns a label to
110      output to start the protection for that block.
111
112      When a destructor or end try block is encountered, pop_eh_entry
113      (&eh_stack) is called.  Pop_eh_entry () returns the eh_entry it
114      created when push_eh_entry () was called.  The eh_entry structure
115      contains three things at this point.  The start protect label,
116      the end protect label, and the exception handler label.  The end
117      protect label should be output before the call to the destructor
118      (if any). If it was a destructor, then its parse tree is stored
119      in the finalization variable in the eh_entry structure.  Otherwise
120      the finalization variable is set to NULL to reflect the fact that
121      it is the end of a try block.  Next, this modified eh_entry node
122      is enqueued in the finalizations queue by calling
123      enqueue_eh_entry (&queue,entry).
124
125         +---------------------------------------------------------------+
126         |XXX: Will need modification to deal with partially             |
127         |                       constructed arrays of objects           |
128         |                                                               |
129         |       Basically, this consists of keeping track of how many   |
130         |       of the objects have been constructed already (this      |
131         |       should be in a register though, so that shouldn't be a  |
132         |       problem.                                                |
133         +---------------------------------------------------------------+
134
135      When a catch block is encountered, there is a lot of work to be
136      done.
137
138      Since we don't want to generate the catch block inline with the
139      regular flow of the function, we need to have some way of doing
140      so.  Luckily, we can use sequences to defer the catch sections.
141      When the start of a catch block is encountered, we start the
142      sequence.  After the catch block is generated, we end the
143      sequence.
144
145      Next we must insure that when the catch block is executed, all
146      finalizations for the matching try block have been completed.  If
147      any of those finalizations throw an exception, we must call
148      terminate according to the ARM (section r.15.6.1).  What this
149      means is that we need to dequeue and emit finalizations for each
150      entry in the eh_queue until we get to an entry with a NULL
151      finalization field.  For any of the finalization entries, if it
152      is not a call to terminate (), we must protect it by giving it
153      another start label, end label, and exception handler label,
154      setting its finalization tree to be a call to terminate (), and
155      enqueue'ing this new eh_entry to be output at an outer level.
156      Finally, after all that is done, we can get around to outputting
157      the catch block which basically wraps all the "catch (...) {...}"
158      statements in a big if/then/else construct that matches the
159      correct block to call.
160      
161      ===================================================================== */
162
163 /* ====================================================================== */
164
165 /* sets up all the global eh stuff that needs to be initialized at the
166    start of compilation.  */
167
168 void
169 init_exception_processing ()
170 {
171   /* void vtype () */
172   tree vtype = build_function_type (void_type_node, void_list_node);
173   
174   if (flag_honor_std)
175     push_namespace (get_identifier ("std"));
176   terminate_node = auto_function (get_identifier ("terminate"), vtype);
177   TREE_THIS_VOLATILE (terminate_node) = 1;
178   if (flag_honor_std)
179     pop_namespace ();
180
181   set_exception_lang_code (EH_LANG_C_plus_plus);
182   set_exception_version_code (1);
183
184   /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
185      be protected with __terminate.  */
186   protect_cleanup_actions_with_terminate = 1;
187 }
188
189 /* Retrieve a pointer to the cp_eh_info node for the current exception.  */
190
191 static tree
192 call_eh_info ()
193 {
194   tree fn;
195
196   fn = get_identifier ("__start_cp_handler");
197   if (IDENTIFIER_GLOBAL_VALUE (fn))
198     fn = IDENTIFIER_GLOBAL_VALUE (fn);
199   else
200     {
201       tree t1, t, fields[7];
202
203       /* Declare cp_eh_info * __start_cp_handler (void),
204          as defined in exception.cc. */
205
206       /* struct cp_eh_info.  This must match exception.cc.  Note that this
207          type is not pushed anywhere.  */
208       t1= make_aggr_type (RECORD_TYPE);
209       fields[0] = build_lang_decl (FIELD_DECL, 
210                     get_identifier ("handler_label"), ptr_type_node);
211       fields[1] = build_lang_decl (FIELD_DECL, 
212                     get_identifier ("dynamic_handler_chain"), ptr_type_node);
213       fields[2] = build_lang_decl (FIELD_DECL, 
214                     get_identifier ("info"), ptr_type_node);
215       fields[3] = build_lang_decl (FIELD_DECL, 
216                     get_identifier ("table_index"), ptr_type_node);
217       /* N.B.: The fourth field LEN is expected to be
218          the number of fields - 1, not the total number of fields.  */
219       finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
220       t1 = build_pointer_type (t1);
221
222       t1= make_aggr_type (RECORD_TYPE);
223       fields[0] = build_lang_decl (FIELD_DECL, 
224                     get_identifier ("match_function"), ptr_type_node);
225       fields[1] = build_lang_decl (FIELD_DECL, 
226                     get_identifier ("language"), short_integer_type_node);
227       fields[2] = build_lang_decl (FIELD_DECL, 
228                     get_identifier ("version"), short_integer_type_node);
229       /* N.B.: The fourth field LEN is expected to be
230          the number of fields - 1, not the total number of fields.  */
231       finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node);
232       t = make_aggr_type (RECORD_TYPE);
233       fields[0] = build_lang_decl (FIELD_DECL, 
234                                    get_identifier ("eh_info"), t1);
235       fields[1] = build_lang_decl (FIELD_DECL, get_identifier ("value"),
236                                    ptr_type_node);
237       fields[2] = build_lang_decl (FIELD_DECL, get_identifier ("type"),
238                                    ptr_type_node);
239       fields[3] = build_lang_decl
240         (FIELD_DECL, get_identifier ("cleanup"),
241          build_pointer_type (build_function_type
242                              (ptr_type_node, tree_cons
243                               (NULL_TREE, ptr_type_node, void_list_node))));
244       fields[4] = build_lang_decl (FIELD_DECL, get_identifier ("caught"),
245                                    boolean_type_node);
246       fields[5] = build_lang_decl (FIELD_DECL, get_identifier ("next"),
247                                    build_pointer_type (t));
248       fields[6] = build_lang_decl
249         (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
250       /* N.B.: The fourth field LEN is expected to be
251          the number of fields - 1, not the total number of fields.  */
252       finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node);
253       t = build_pointer_type (t);
254
255       /* And now the function.  */
256       fn = build_lang_decl (FUNCTION_DECL, fn,
257                             build_function_type (t, void_list_node));
258       DECL_EXTERNAL (fn) = 1;
259       TREE_PUBLIC (fn) = 1;
260       DECL_ARTIFICIAL (fn) = 1;
261       TREE_NOTHROW (fn) = 1;
262       pushdecl_top_level (fn);
263       make_function_rtl (fn);
264     }
265   mark_used (fn);
266   return build_function_call (fn, NULL_TREE);
267 }
268
269 /* Retrieve a pointer to the cp_eh_info node for the current exception
270    and save it in the current binding level.  */
271
272 static void
273 push_eh_info ()
274 {
275   tree decl, fn = call_eh_info ();
276
277   /* Remember the pointer to the current exception info; it won't change
278      during this catch block.  */
279   decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
280                      TREE_TYPE (fn));
281   DECL_ARTIFICIAL (decl) = 1;
282   DECL_INITIAL (decl) = fn;
283   decl = pushdecl (decl);
284   cp_finish_decl (decl, fn, NULL_TREE, 0);
285 }
286
287 /* Returns a reference to the cp_eh_info node for the current exception.  */
288
289 static tree
290 get_eh_info ()
291 {
292   /* Look for the pointer pushed in push_eh_info.  */
293   tree t = lookup_name (get_identifier ("__exception_info"), 0);
294   return build_indirect_ref (t, NULL_PTR);
295 }
296
297 /* Returns a reference to the current exception object.  */
298
299 static tree
300 get_eh_value ()
301 {
302   return build_component_ref (get_eh_info (), get_identifier ("value"),
303                               NULL_TREE, 0);
304 }
305
306 /* Returns a reference to the current exception type.  */
307
308 #if 0
309 static tree
310 get_eh_type ()
311 {
312   return build_component_ref (get_eh_info (), get_identifier ("type"),
313                               NULL_TREE, 0);
314 }
315
316 /* Returns a reference to whether or not the current exception
317    has been caught.  */
318
319 static tree
320 get_eh_caught ()
321 {
322   return build_component_ref (get_eh_info (), get_identifier ("caught"),
323                               NULL_TREE, 0);
324 }
325
326 /* Returns a reference to whether or not the current exception
327    has been caught.  */
328
329 static tree
330 get_eh_handlers ()
331 {
332   return build_component_ref (get_eh_info (), get_identifier ("handlers"),
333                               NULL_TREE, 0);
334 }
335 #endif
336
337 /* Build a type value for use at runtime for a type that is matched
338    against by the exception handling system.  */
339
340 static tree
341 build_eh_type_type (type)
342      tree type;
343 {
344   if (type == error_mark_node)
345     return error_mark_node;
346
347   /* peel back references, so they match.  */
348   if (TREE_CODE (type) == REFERENCE_TYPE)
349     type = TREE_TYPE (type);
350
351   /* Peel off cv qualifiers.  */
352   type = TYPE_MAIN_VARIANT (type);
353
354   return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
355 }
356
357 /* Build the address of a typeinfo decl for use in the runtime
358    matching field of the new exception model */
359
360 static tree
361 build_eh_type_type_ref (type)
362      tree type;
363 {
364   tree exp;
365
366   if (type == error_mark_node)
367     return error_mark_node;
368
369   /* peel back references, so they match.  */
370   if (TREE_CODE (type) == REFERENCE_TYPE)
371     type = TREE_TYPE (type);
372
373   /* Peel off cv qualifiers.  */
374   type = TYPE_MAIN_VARIANT (type);
375
376   exp = get_tinfo_decl (type);
377   mark_used (exp);
378   exp = build1 (ADDR_EXPR, ptr_type_node, exp);
379
380   return (exp);
381 }
382
383 /* This routine is called to mark all the symbols representing runtime
384    type functions in the exception table as having been referenced.
385    This will make sure code is emitted for them. Called from finish_file. */
386 void 
387 mark_all_runtime_matches () 
388 {
389   int x,num;
390   void **ptr;
391   tree exp;
392   
393   num = find_all_handler_type_matches (&ptr);
394   if (num == 0 || ptr == NULL)
395     return;
396   
397   for (x=0; x <num; x++)
398     {
399       exp = (tree) ptr[x];
400       if (TREE_CODE (exp) == ADDR_EXPR)
401         {
402           exp = TREE_OPERAND (exp, 0);
403           if (TREE_CODE (exp) == FUNCTION_DECL)
404             TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
405         }
406     }
407   
408   free (ptr);
409 }
410
411 /* Build up a call to __cp_pop_exception, to destroy the exception object
412    for the current catch block.  HANDLER is either true or false, telling
413    the library whether or not it is being called from an exception handler;
414    if it is, it avoids destroying the object on rethrow.  */
415
416 static tree
417 do_pop_exception ()
418 {
419   tree fn, cleanup;
420   fn = get_identifier ("__cp_pop_exception");
421   if (IDENTIFIER_GLOBAL_VALUE (fn))
422     fn = IDENTIFIER_GLOBAL_VALUE (fn);
423   else
424     {
425       /* Declare void __cp_pop_exception (void *),
426          as defined in exception.cc. */
427       fn = build_lang_decl
428         (FUNCTION_DECL, fn,
429          build_function_type (void_type_node, tree_cons
430                               (NULL_TREE, ptr_type_node, void_list_node)));
431       DECL_EXTERNAL (fn) = 1;
432       TREE_PUBLIC (fn) = 1;
433       DECL_ARTIFICIAL (fn) = 1;
434       pushdecl_top_level (fn);
435       make_function_rtl (fn);
436     }
437
438   mark_used (fn);
439   /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
440   cleanup = lookup_name (get_identifier ("__exception_info"), 0);
441   cleanup = build_function_call (fn, tree_cons
442                                  (NULL_TREE, cleanup, NULL_TREE));
443   return cleanup;
444 }
445
446 /* This routine creates the cleanup for the current exception.  */
447
448 static void
449 push_eh_cleanup ()
450 {
451   finish_decl_cleanup (NULL_TREE, do_pop_exception ());
452 }
453
454 /* Build up a call to terminate on the function obstack, for use as an
455    exception handler.  */
456
457 static tree
458 build_terminate_handler ()
459 {
460   return build_function_call (terminate_node, NULL_TREE);
461 }
462
463 /* Return nonzero value if DECL is a Java type suitable for catch or
464    throw.  */
465
466 static int
467 decl_is_java_type (decl, err)
468      tree decl;
469      int err;
470 {
471   int r = (TREE_CODE (decl) == POINTER_TYPE
472            && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
473            && TYPE_FOR_JAVA (TREE_TYPE (decl)));
474
475   if (err)
476     {
477       if (TREE_CODE (decl) == REFERENCE_TYPE
478           && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
479           && TYPE_FOR_JAVA (TREE_TYPE (decl)))
480         {
481           /* Can't throw a reference.  */
482           cp_error ("type `%T' is disallowed in Java `throw' or `catch'",
483                     decl);
484         }
485
486       if (r)
487         {
488           tree jthrow_node
489             = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jthrowable"));
490           if (jthrow_node == NULL_TREE)
491             fatal ("call to Java `catch' or `throw', while `jthrowable' undefined");
492           jthrow_node = TREE_TYPE (TREE_TYPE (jthrow_node));
493
494           if (! DERIVED_FROM_P (jthrow_node, TREE_TYPE (decl)))
495             {
496               /* Thrown object must be a Throwable.  */
497               cp_error ("type `%T' is not derived from `java::lang::Throwable'",
498                         TREE_TYPE (decl));
499             }
500         }
501     }
502
503   return r;
504 }
505
506 /* Initialize the catch parameter DECL.  */
507
508 static void 
509 initialize_handler_parm (decl)
510      tree decl;
511 {
512   tree exp;
513   tree init;
514   tree init_type;
515   int lang;
516
517   /* Make sure we mark the catch param as used, otherwise we'll get a
518      warning about an unused ((anonymous)).  */
519   TREE_USED (decl) = 1;
520
521   /* Figure out the type that the initializer is.  */
522   init_type = TREE_TYPE (decl);
523   if (TREE_CODE (init_type) != REFERENCE_TYPE
524       && TREE_CODE (init_type) != POINTER_TYPE)
525     init_type = build_reference_type (init_type);
526
527   if (decl_is_java_type (init_type, 0))
528     {
529       tree fn
530         = builtin_function ("_Jv_exception_info", 
531                             build_function_type (ptr_type_node,
532                                                  tree_cons (NULL_TREE,
533                                                             void_type_node,
534                                                             NULL_TREE)),
535                             0, NOT_BUILT_IN, NULL_PTR);
536
537       exp = build (CALL_EXPR, ptr_type_node,
538                    build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)),
539                            fn),
540                    NULL_TREE, NULL_TREE);
541       TREE_SIDE_EFFECTS (exp) = 1;
542       lang = EH_LANG_Java;
543
544       set_exception_lang_code (EH_LANG_Java);
545       set_exception_version_code (1);
546     }
547   else
548     {
549       exp = get_eh_value ();
550       lang = EH_LANG_C_plus_plus;
551     }
552
553   if (catch_language_init)
554     {
555       if (lang != catch_language)
556         error ("mixing C++ and Java `catch'es in single translation unit");
557     }
558   else
559     {
560       catch_language_init = 1;
561       catch_language = lang;
562     }
563
564   /* Since pointers are passed by value, initialize a reference to
565      pointer catch parm with the address of the value slot.  */ 
566   if (TREE_CODE (init_type) == REFERENCE_TYPE 
567       && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
568     exp = build_unary_op (ADDR_EXPR, exp, 1);
569
570   exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
571
572   init = convert_from_reference (exp);
573
574   /* If the constructor for the catch parm exits via an exception, we
575      must call terminate.  See eh23.C.  */
576   if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
577     {
578       /* Generate the copy constructor call directly so we can wrap it.
579          See also expand_default_init.  */
580       init = ocp_convert (TREE_TYPE (decl), init,
581                           CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
582       init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
583                     build_terminate_handler ());
584     }
585
586   /* Let `cp_finish_decl' know that this initializer is ok.  */
587   DECL_INITIAL (decl) = error_mark_node;
588   decl = pushdecl (decl);
589
590   start_decl_1 (decl);
591   cp_finish_decl (decl, init, NULL_TREE,
592                   LOOKUP_ONLYCONVERTING|DIRECT_BIND);
593 }
594
595 /* Call this to start a catch block.  DECL is the catch parameter.  */
596
597 tree
598 expand_start_catch_block (decl)
599      tree decl;
600 {
601   tree compound_stmt_1;
602   tree compound_stmt_2;
603   tree type;
604
605   if (! doing_eh (1))
606     return NULL_TREE;
607
608   /* Make sure this declaration is reasonable.  */
609   if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE))
610     decl = NULL_TREE;
611
612   /* Create a binding level for the eh_info and the exception object
613      cleanup.  */
614   compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
615
616   if (! decl || ! decl_is_java_type (TREE_TYPE (decl), 1))
617     {
618       /* The ordinary C++ case.  */
619
620       if (decl)
621         type = build_eh_type_type_ref (TREE_TYPE (decl));
622       else
623         type = NULL_TREE;
624       begin_catch_block (type);
625
626       push_eh_info ();
627       push_eh_cleanup ();
628     }
629   else
630     {
631       /* The Java case.  In this case, the match_info is a pointer to
632          the Java class object.  We assume that the class is a
633          compiled class.  */
634       tree ref = build_java_class_ref (TREE_TYPE (TREE_TYPE (decl)));
635       begin_catch_block (build1 (ADDR_EXPR, jclass_node, ref));
636     }
637
638   /* Create a binding level for the parm.  */
639   compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
640
641   if (decl)
642     initialize_handler_parm (decl);
643
644   return build_tree_list (compound_stmt_1, compound_stmt_2);
645 }
646
647
648 /* Call this to end a catch block.  Its responsible for emitting the
649    code to handle jumping back to the correct place, and for emitting
650    the label to jump to if this catch block didn't match.  */
651
652 void
653 expand_end_catch_block (blocks)
654      tree blocks;
655 {
656   tree compound_stmt_1 = blocks ? TREE_PURPOSE (blocks): NULL_TREE;
657   tree compound_stmt_2 = blocks ? TREE_VALUE (blocks): NULL_TREE;
658
659   if (! doing_eh (1))
660     return;
661
662   /* The exception being handled is rethrown if control reaches the end of
663      a handler of the function-try-block of a constructor or destructor.  */
664   if (in_function_try_handler
665       && (DECL_CONSTRUCTOR_P (current_function_decl)
666           || DECL_DESTRUCTOR_P (current_function_decl)))
667     finish_expr_stmt (build_throw (NULL_TREE));
668
669   /* Cleanup the EH parameter.  */
670   finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2);
671   /* Cleanup the EH object.  */
672   finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
673 }
674
675 /* An exception spec is implemented more or less like:
676
677    try {
678      function body;
679    } catch (...) {
680      void *p[] = { typeid(raises) };
681      __check_eh_spec (p, count);
682    }
683
684    __check_eh_spec in exception.cc handles all the details.  */
685
686 tree
687 expand_start_eh_spec ()
688 {
689   return begin_try_block ();
690 }
691
692 void
693 expand_end_eh_spec (raises, try_block)
694      tree raises;
695      tree try_block;
696 {
697   tree tmp, fn, decl, types = NULL_TREE;
698   tree blocks;
699   tree handler;
700   int count = 0;
701
702   finish_try_block (try_block);
703   handler = begin_handler ();
704   blocks = finish_handler_parms (NULL_TREE, handler);
705
706   /* Build up an array of type_infos.  */
707   for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
708     {
709       types = tree_cons
710         (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
711       ++count;
712     }
713
714   types = build_nt (CONSTRUCTOR, NULL_TREE, types);
715   TREE_HAS_CONSTRUCTOR (types) = 1;
716
717   /* We can't pass the CONSTRUCTOR directly, so stick it in a variable.  */
718   tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
719   decl = build_decl (VAR_DECL, NULL_TREE, tmp);
720   DECL_ARTIFICIAL (decl) = 1;
721   DECL_INITIAL (decl) = types;
722   DECL_CONTEXT (decl) = current_function_decl;
723   cp_finish_decl (decl, types, NULL_TREE, 0);
724
725   decl = decay_conversion (decl);
726
727   fn = get_identifier ("__check_eh_spec");
728   if (IDENTIFIER_GLOBAL_VALUE (fn))
729     fn = IDENTIFIER_GLOBAL_VALUE (fn);
730   else
731     {
732       tmp = tree_cons
733         (NULL_TREE, integer_type_node, tree_cons
734          (NULL_TREE, TREE_TYPE (decl), void_list_node));
735       tmp = build_function_type (void_type_node, tmp);
736   
737       fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
738       DECL_EXTERNAL (fn) = 1;
739       TREE_PUBLIC (fn) = 1;
740       DECL_ARTIFICIAL (fn) = 1;
741       TREE_THIS_VOLATILE (fn) = 1;
742       pushdecl_top_level (fn);
743       make_function_rtl (fn);
744     }
745
746   mark_used (fn);
747   tmp = tree_cons (NULL_TREE, build_int_2 (count, 0), 
748                    tree_cons (NULL_TREE, decl, NULL_TREE));
749   tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
750   finish_expr_stmt (tmp);
751
752   finish_handler (blocks, handler);
753   finish_handler_sequence (try_block);
754 }
755
756 /* This is called to expand all the toplevel exception handling
757    finalization for a function.  It should only be called once per
758    function.  */
759
760 void
761 expand_exception_blocks ()
762 {
763   do_pending_stack_adjust ();
764
765   if (catch_clauses)
766     {
767       rtx funcend = gen_label_rtx ();
768       emit_jump (funcend);
769
770       /* We cannot protect n regions this way if we must flow into the
771          EH region through the top of the region, as we have to with
772          the setjmp/longjmp approach.  */
773       if (exceptions_via_longjmp == 0)
774         expand_eh_region_start ();
775
776       emit_insns (catch_clauses);
777       catch_clauses = NULL_RTX;
778
779       if (exceptions_via_longjmp == 0)
780         expand_eh_region_end (build_terminate_handler ());
781
782       emit_insns (catch_clauses);
783       catch_clauses = NULL_RTX;
784       emit_label (funcend);
785     }
786 }
787
788 /* Return a pointer to a buffer for an exception object of type TYPE.  */
789
790 static tree
791 alloc_eh_object (type)
792      tree type;
793 {
794   tree fn, exp;
795
796   fn = get_identifier ("__eh_alloc");
797   if (IDENTIFIER_GLOBAL_VALUE (fn))
798     fn = IDENTIFIER_GLOBAL_VALUE (fn);
799   else
800     {
801       /* Declare __eh_alloc (size_t), as defined in exception.cc.  */
802       tree tmp;
803       tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
804       fn = build_lang_decl (FUNCTION_DECL, fn,
805                             build_function_type (ptr_type_node, tmp));
806       DECL_EXTERNAL (fn) = 1;
807       TREE_PUBLIC (fn) = 1;
808       DECL_ARTIFICIAL (fn) = 1;
809       TREE_NOTHROW (fn) = 1;
810       pushdecl_top_level (fn);
811       make_function_rtl (fn);
812     }
813
814   mark_used (fn);
815   exp = build_function_call (fn, tree_cons
816                              (NULL_TREE, size_in_bytes (type), NULL_TREE));
817   exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
818   return exp;
819 }
820
821 /* Expand a throw statement.  This follows the following
822    algorithm:
823
824         1. Allocate space to save the current PC onto the stack.
825         2. Generate and emit a label and save its address into the
826                 newly allocated stack space since we can't save the pc directly.
827         3. If this is the first call to throw in this function:
828                 generate a label for the throw block
829         4. jump to the throw block label.  */
830
831 static tree
832 expand_throw (exp)
833      tree exp;
834 {
835   tree fn;
836
837   if (! doing_eh (1))
838     return error_mark_node;
839
840   if (exp
841       && decl_is_java_type (TREE_TYPE (exp), 1))
842     {
843       /* A Java `throw' statement.  */
844       tree args = tree_cons (NULL_TREE, exp, NULL);
845
846       fn = get_identifier (exceptions_via_longjmp
847                            ? "_Jv_Sjlj_throw"
848                            : "_Jv_Throw");
849       if (IDENTIFIER_GLOBAL_VALUE (fn))
850         fn = IDENTIFIER_GLOBAL_VALUE (fn);
851       else
852         {
853           /* Declare _Jv_Throw (void *), as defined in Java's
854              exception.cc.  */
855           tree tmp;
856           tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
857           fn = build_lang_decl (FUNCTION_DECL, fn,
858                                 build_function_type (ptr_type_node, tmp));
859           DECL_EXTERNAL (fn) = 1;
860           TREE_PUBLIC (fn) = 1;
861           DECL_ARTIFICIAL (fn) = 1;
862           TREE_THIS_VOLATILE (fn) = 1;
863           pushdecl_top_level (fn);
864           make_function_rtl (fn);
865         }
866
867       exp = build_function_call (fn, args);
868     }
869   else if (exp)
870     {
871       tree throw_type;
872       tree cleanup = NULL_TREE, e;
873       tree stmt_expr;
874       tree compound_stmt;
875       tree try_block;
876
877       begin_init_stmts (&stmt_expr, &compound_stmt);
878
879       /* throw expression */
880       /* First, decay it.  */
881       exp = decay_conversion (exp);
882
883       /* cleanup_type is void (*)(void *, int),
884          the internal type of a destructor. */
885       if (cleanup_type == NULL_TREE)
886         cleanup_type = build_pointer_type
887           (build_function_type
888            (void_type_node, tree_cons
889             (NULL_TREE, ptr_type_node, tree_cons
890              (NULL_TREE, integer_type_node, void_list_node))));
891
892       if (TYPE_PTR_P (TREE_TYPE (exp)))
893         throw_type = build_eh_type_type (TREE_TYPE (exp));
894       else
895         {
896           tree object, ptr;
897
898           /* OK, this is kind of wacky.  The standard says that we call
899              terminate when the exception handling mechanism, after
900              completing evaluation of the expression to be thrown but
901              before the exception is caught (_except.throw_), calls a
902              user function that exits via an uncaught exception.
903
904              So we have to protect the actual initialization of the
905              exception object with terminate(), but evaluate the expression
906              first.  We also expand the call to __eh_alloc
907              first.  Since there could be temps in the expression, we need
908              to handle that, too.  */
909
910           my_friendly_assert (stmts_are_full_exprs_p == 1, 19990926);
911
912           /* Store the throw expression into a temp.  This can be less
913              efficient than storing it into the allocated space directly, but
914              oh well.  To do this efficiently we would need to insinuate
915              ourselves into expand_call.  */
916           if (TREE_SIDE_EFFECTS (exp))
917             {
918               tree temp = create_temporary_var (TREE_TYPE (exp));
919               DECL_INITIAL (temp) = exp;
920               cp_finish_decl (temp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
921               exp = temp;
922             }
923
924           /* Allocate the space for the exception.  */
925           ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
926           finish_expr_stmt (ptr);
927
928           try_block = begin_try_block ();
929           object = build_indirect_ref (ptr, NULL_PTR);
930           exp = build_modify_expr (object, INIT_EXPR, exp);
931
932           if (exp == error_mark_node)
933             error ("  in thrown expression");
934
935           finish_expr_stmt (exp);
936           finish_cleanup_try_block (try_block);
937           finish_cleanup (build_terminate_handler (), try_block);
938
939           throw_type = build_eh_type_type (TREE_TYPE (object));
940
941           if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
942             {
943               cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
944                                          dtor_identifier, 0);
945               cleanup = TREE_VALUE (cleanup);
946               mark_used (cleanup);
947               mark_addressable (cleanup);
948               /* Pretend it's a normal function.  */
949               cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
950             }
951
952           exp = ptr;
953         }
954
955       /* Cast EXP to `void *' so that it will match the prototype for
956          __cp_push_exception.  */
957       exp = convert (ptr_type_node, exp);
958
959       if (cleanup == NULL_TREE)
960         {
961           cleanup = build_int_2 (0, 0);
962           TREE_TYPE (cleanup) = cleanup_type;
963         }
964
965       fn = get_identifier ("__cp_push_exception");
966       if (IDENTIFIER_GLOBAL_VALUE (fn))
967         fn = IDENTIFIER_GLOBAL_VALUE (fn);
968       else
969         {
970           /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
971              as defined in exception.cc.  */
972           tree tmp;
973           tmp = tree_cons
974             (NULL_TREE, ptr_type_node, tree_cons
975              (NULL_TREE, ptr_type_node, tree_cons
976               (NULL_TREE, cleanup_type, void_list_node)));
977           fn = build_lang_decl (FUNCTION_DECL, fn,
978                                 build_function_type (void_type_node, tmp));
979           DECL_EXTERNAL (fn) = 1;
980           TREE_PUBLIC (fn) = 1;
981           DECL_ARTIFICIAL (fn) = 1;
982           TREE_NOTHROW (fn) = 1;
983           pushdecl_top_level (fn);
984           make_function_rtl (fn);
985         }
986
987       mark_used (fn);
988       e = tree_cons (NULL_TREE, exp, tree_cons
989                      (NULL_TREE, throw_type, tree_cons
990                       (NULL_TREE, cleanup, NULL_TREE)));
991       finish_expr_stmt (build_function_call (fn, e));
992
993       exp = finish_init_stmts (stmt_expr, compound_stmt);
994     }
995   else
996     {
997       /* rethrow current exception; note that it's no longer caught.  */
998
999       tree fn = get_identifier ("__uncatch_exception");
1000       if (IDENTIFIER_GLOBAL_VALUE (fn))
1001         fn = IDENTIFIER_GLOBAL_VALUE (fn);
1002       else
1003         {
1004           /* Declare void __uncatch_exception (void)
1005              as defined in exception.cc. */
1006           fn = build_lang_decl (FUNCTION_DECL, fn,
1007                                 build_function_type (void_type_node,
1008                                                      void_list_node));
1009           DECL_EXTERNAL (fn) = 1;
1010           TREE_PUBLIC (fn) = 1;
1011           DECL_ARTIFICIAL (fn) = 1;
1012           TREE_NOTHROW (fn) = 1;
1013           pushdecl_top_level (fn);
1014           make_function_rtl (fn);
1015         }
1016
1017       mark_used (fn);
1018       exp = build_function_call (fn, NULL_TREE);
1019     }
1020
1021   return exp;
1022 }
1023
1024 /* Build a throw expression.  */
1025
1026 tree
1027 build_throw (e)
1028      tree e;
1029 {
1030   if (e == error_mark_node)
1031     return e;
1032
1033   if (processing_template_decl)
1034     return build_min (THROW_EXPR, void_type_node, e);
1035
1036   if (e == null_node)
1037     cp_warning ("throwing NULL, which has integral, not pointer type");
1038   
1039   if (e != NULL_TREE)
1040     {
1041       if (!complete_ptr_ref_or_void_ptr_p (TREE_TYPE (e), e))
1042         return error_mark_node;
1043     }
1044
1045   e = expand_throw (e);
1046   e = build1 (THROW_EXPR, void_type_node, e);
1047   TREE_SIDE_EFFECTS (e) = 1;
1048   TREE_USED (e) = 1;
1049
1050   return e;
1051 }
1052
1053 /* Make sure TYPE is complete, pointer to complete, reference to
1054    complete, or pointer to cv void. Issue diagnostic on failure.
1055    Return the zero on failure and non-zero on success. FROM can be
1056    the expr or decl from whence TYPE came, if available.  */
1057
1058 static int
1059 complete_ptr_ref_or_void_ptr_p (type, from)
1060      tree type;
1061      tree from;
1062 {
1063   int is_ptr;
1064   
1065   /* Check complete.  */
1066   type = complete_type_or_else (type, from);
1067   if (!type)
1068     return 0;
1069   
1070   /* Or a pointer or ref to one, or cv void *.  */
1071   is_ptr = TREE_CODE (type) == POINTER_TYPE;
1072   if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE)
1073     {
1074       tree core = TREE_TYPE (type);
1075   
1076       if (is_ptr && same_type_p (TYPE_MAIN_VARIANT (core), void_type_node))
1077         /* OK */;
1078       else if (!complete_type_or_else (core, from))
1079         return 0;
1080     }
1081   return 1;
1082 }
1083