OSDN Git Service

* cp-tree.def (THUNK_DECL): Remove.
[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 ((tree));
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 int dtor_nothrow PARAMS ((tree));
52 static tree do_pop_exception PARAMS ((tree));
53 static tree build_eh_type_type_ref PARAMS ((tree));
54 static tree build_terminate_handler PARAMS ((void));
55 static tree alloc_eh_object PARAMS ((tree));
56 static int complete_ptr_ref_or_void_ptr_p PARAMS ((tree, tree));
57 static void initialize_handler_parm PARAMS ((tree));
58 static tree expand_throw PARAMS ((tree));
59 static int decl_is_java_type PARAMS ((tree decl, int err));
60
61 #if 0
62 /* This is the startup, and finish stuff per exception table.  */
63
64 /* XXX - Tad: exception handling section */
65 #ifndef EXCEPT_SECTION_ASM_OP
66 #define EXCEPT_SECTION_ASM_OP   "section\t.gcc_except_table,\"a\",@progbits"
67 #endif
68
69 #ifdef EXCEPT_SECTION_ASM_OP
70
71  /* on machines which support it, the exception table lives in another section,
72         but it needs a label so we can reference it...  This sets up that
73     label! */
74 asm (EXCEPT_SECTION_ASM_OP);
75 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
76 asm (TEXT_SECTION_ASM_OP);
77
78 #endif /* EXCEPT_SECTION_ASM_OP */
79
80 #ifdef EXCEPT_SECTION_ASM_OP
81
82  /* we need to know where the end of the exception table is... so this
83     is how we do it! */
84
85 asm (EXCEPT_SECTION_ASM_OP);
86 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
87 asm (TEXT_SECTION_ASM_OP);
88
89 #endif /* EXCEPT_SECTION_ASM_OP */
90
91 #endif
92
93 #include "decl.h"
94 #include "insn-flags.h"
95 #include "obstack.h"
96
97 /* In a given translation unit we are constrained to catch only C++
98    types or only Java types.  `catch_language' holds the current type,
99    and `catch_language_init' registers whether `catch_language' has
100    been set.  */
101
102 static int catch_language_init = 0;
103 static int catch_language;
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 /* ====================================================================== */
165
166 /* sets up all the global eh stuff that needs to be initialized at the
167    start of compilation.  */
168
169 void
170 init_exception_processing ()
171 {
172   /* void vtype () */
173   tree vtype = build_function_type (void_type_node, void_list_node);
174   
175   if (flag_honor_std)
176     push_namespace (get_identifier ("std"));
177   terminate_node = build_cp_library_fn_ptr ("terminate", vtype);
178   TREE_THIS_VOLATILE (terminate_node) = 1;
179   TREE_NOTHROW (terminate_node) = 1;
180   if (flag_honor_std)
181     pop_namespace ();
182
183   set_exception_lang_code (EH_LANG_C_plus_plus);
184   set_exception_version_code (1);
185
186   /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
187      be protected with __terminate.  */
188   protect_cleanup_actions_with_terminate = 1;
189 }
190
191 /* Retrieve a pointer to the cp_eh_info node for the current exception.  */
192
193 static tree
194 call_eh_info ()
195 {
196   tree fn;
197
198   fn = get_identifier ("__start_cp_handler");
199   if (IDENTIFIER_GLOBAL_VALUE (fn))
200     fn = IDENTIFIER_GLOBAL_VALUE (fn);
201   else
202     {
203       tree t1, t, fields[7];
204
205       /* Declare cp_eh_info * __start_cp_handler (void),
206          as defined in exception.cc. */
207
208       /* struct cp_eh_info.  This must match exception.cc.  Note that this
209          type is not pushed anywhere.  */
210       t1= make_aggr_type (RECORD_TYPE);
211       fields[0] = build_lang_decl (FIELD_DECL, 
212                     get_identifier ("handler_label"), ptr_type_node);
213       fields[1] = build_lang_decl (FIELD_DECL, 
214                     get_identifier ("dynamic_handler_chain"), ptr_type_node);
215       fields[2] = build_lang_decl (FIELD_DECL, 
216                     get_identifier ("info"), ptr_type_node);
217       fields[3] = build_lang_decl (FIELD_DECL, 
218                     get_identifier ("table_index"), ptr_type_node);
219       /* N.B.: The fourth field LEN is expected to be
220          the number of fields - 1, not the total number of fields.  */
221       finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
222       t1 = build_pointer_type (t1);
223
224       t1= make_aggr_type (RECORD_TYPE);
225       fields[0] = build_lang_decl (FIELD_DECL, 
226                     get_identifier ("match_function"), ptr_type_node);
227       fields[1] = build_lang_decl (FIELD_DECL, 
228                     get_identifier ("language"), short_integer_type_node);
229       fields[2] = build_lang_decl (FIELD_DECL, 
230                     get_identifier ("version"), short_integer_type_node);
231       /* N.B.: The fourth field LEN is expected to be
232          the number of fields - 1, not the total number of fields.  */
233       finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node);
234       t = make_aggr_type (RECORD_TYPE);
235       fields[0] = build_lang_decl (FIELD_DECL, 
236                                    get_identifier ("eh_info"), t1);
237       fields[1] = build_lang_decl (FIELD_DECL, get_identifier ("value"),
238                                    ptr_type_node);
239       fields[2] = build_lang_decl (FIELD_DECL, get_identifier ("type"),
240                                    ptr_type_node);
241       fields[3] = build_lang_decl
242         (FIELD_DECL, get_identifier ("cleanup"),
243          build_pointer_type (build_function_type
244                              (ptr_type_node, tree_cons
245                               (NULL_TREE, ptr_type_node, void_list_node))));
246       fields[4] = build_lang_decl (FIELD_DECL, get_identifier ("caught"),
247                                    boolean_type_node);
248       fields[5] = build_lang_decl (FIELD_DECL, get_identifier ("next"),
249                                    build_pointer_type (t));
250       fields[6] = build_lang_decl
251         (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
252       /* N.B.: The fourth field LEN is expected to be
253          the number of fields - 1, not the total number of fields.  */
254       finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node);
255       t = build_pointer_type (t);
256
257       /* And now the function.  */
258       fn = push_library_fn (fn, build_function_type (t, void_list_node));
259     }
260   return build_function_call (fn, NULL_TREE);
261 }
262
263 /* Retrieve a pointer to the cp_eh_info node for the current exception
264    and save it in the current binding level.  */
265
266 static void
267 push_eh_info ()
268 {
269   tree decl, fn = call_eh_info ();
270
271   /* Remember the pointer to the current exception info; it won't change
272      during this catch block.  */
273   decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
274                      TREE_TYPE (fn));
275   DECL_ARTIFICIAL (decl) = 1;
276   DECL_INITIAL (decl) = fn;
277   decl = pushdecl (decl);
278   cp_finish_decl (decl, fn, NULL_TREE, 0);
279 }
280
281 /* Returns a reference to the cp_eh_info node for the current exception.  */
282
283 static tree
284 get_eh_info ()
285 {
286   /* Look for the pointer pushed in push_eh_info.  */
287   tree t = lookup_name (get_identifier ("__exception_info"), 0);
288   return build_indirect_ref (t, NULL_PTR);
289 }
290
291 /* Returns a reference to the current exception object.  */
292
293 static tree
294 get_eh_value ()
295 {
296   return build_component_ref (get_eh_info (), get_identifier ("value"),
297                               NULL_TREE, 0);
298 }
299
300 /* Returns a reference to the current exception type.  */
301
302 #if 0
303 static tree
304 get_eh_type ()
305 {
306   return build_component_ref (get_eh_info (), get_identifier ("type"),
307                               NULL_TREE, 0);
308 }
309
310 /* Returns a reference to whether or not the current exception
311    has been caught.  */
312
313 static tree
314 get_eh_caught ()
315 {
316   return build_component_ref (get_eh_info (), get_identifier ("caught"),
317                               NULL_TREE, 0);
318 }
319
320 /* Returns a reference to whether or not the current exception
321    has been caught.  */
322
323 static tree
324 get_eh_handlers ()
325 {
326   return build_component_ref (get_eh_info (), get_identifier ("handlers"),
327                               NULL_TREE, 0);
328 }
329 #endif
330
331 /* Build a type value for use at runtime for a type that is matched
332    against by the exception handling system.  */
333
334 static tree
335 build_eh_type_type (type)
336      tree type;
337 {
338   if (type == error_mark_node)
339     return error_mark_node;
340
341   /* peel back references, so they match.  */
342   if (TREE_CODE (type) == REFERENCE_TYPE)
343     type = TREE_TYPE (type);
344
345   /* Peel off cv qualifiers.  */
346   type = TYPE_MAIN_VARIANT (type);
347
348   return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
349 }
350
351 /* Build the address of a typeinfo decl for use in the runtime
352    matching field of the new exception model */
353
354 static tree
355 build_eh_type_type_ref (type)
356      tree type;
357 {
358   tree exp;
359
360   if (type == NULL_TREE || type == error_mark_node)
361     return type;
362
363   /* peel back references, so they match.  */
364   if (TREE_CODE (type) == REFERENCE_TYPE)
365     type = TREE_TYPE (type);
366
367   /* Peel off cv qualifiers.  */
368   type = TYPE_MAIN_VARIANT (type);
369
370   exp = get_tinfo_decl (type);
371   mark_used (exp);
372   exp = build1 (ADDR_EXPR, ptr_type_node, exp);
373
374   return (exp);
375 }
376
377 /* This routine is called to mark all the symbols representing runtime
378    type functions in the exception table as having been referenced.
379    This will make sure code is emitted for them. Called from finish_file. */
380
381 void 
382 mark_all_runtime_matches () 
383 {
384   int x,num;
385   void **ptr;
386   tree exp;
387   
388   num = find_all_handler_type_matches (&ptr);
389   if (num == 0 || ptr == NULL)
390     return;
391   
392   for (x=0; x <num; x++)
393     {
394       exp = (tree) ptr[x];
395       if (TREE_CODE (exp) == ADDR_EXPR)
396         {
397           exp = TREE_OPERAND (exp, 0);
398           if (TREE_CODE (exp) == FUNCTION_DECL)
399             TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
400         }
401     }
402   
403   free (ptr);
404 }
405
406 /* Returns nonzero if cleaning up an exception of type TYPE (which can be
407    NULL_TREE for a ... handler) will not throw an exception.  */
408
409 static int
410 dtor_nothrow (type)
411      tree type;
412 {
413   tree fn;
414
415   if (type == NULL_TREE)
416     return 0;
417
418   if (! TYPE_HAS_DESTRUCTOR (type))
419     return 1;
420
421   fn = lookup_member (type, dtor_identifier, 0, 0);
422   fn = TREE_VALUE (fn);
423   return TREE_NOTHROW (fn);
424 }
425
426 /* Build up a call to __cp_pop_exception, to destroy the exception object
427    for the current catch block if no others are currently using it.  */
428
429 static tree
430 do_pop_exception (type)
431      tree type;
432 {
433   tree fn, cleanup;
434   fn = get_identifier ("__cp_pop_exception");
435   if (IDENTIFIER_GLOBAL_VALUE (fn))
436     fn = IDENTIFIER_GLOBAL_VALUE (fn);
437   else
438     {
439       /* Declare void __cp_pop_exception (void *),
440          as defined in exception.cc. */
441       fn = push_void_library_fn
442         (fn, tree_cons (NULL_TREE, ptr_type_node, void_list_node));
443       /* This can throw if the destructor for the exception throws.  */
444       TREE_NOTHROW (fn) = 0;
445     }
446
447   /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
448   cleanup = lookup_name (get_identifier ("__exception_info"), 0);
449   cleanup = build_function_call (fn, tree_cons
450                                  (NULL_TREE, cleanup, NULL_TREE));
451   TREE_NOTHROW (cleanup) = dtor_nothrow (type);
452   return cleanup;
453 }
454
455 /* This routine creates the cleanup for the current exception.  */
456
457 static void
458 push_eh_cleanup (type)
459      tree type;
460 {
461   finish_decl_cleanup (NULL_TREE, do_pop_exception (type));
462 }
463
464 /* Build up a call to terminate on the function obstack, for use as an
465    exception handler.  */
466
467 static tree
468 build_terminate_handler ()
469 {
470   return build_function_call (terminate_node, NULL_TREE);
471 }
472
473 /* Return nonzero value if DECL is a Java type suitable for catch or
474    throw.  */
475
476 static int
477 decl_is_java_type (decl, err)
478      tree decl;
479      int err;
480 {
481   int r = (TREE_CODE (decl) == POINTER_TYPE
482            && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
483            && TYPE_FOR_JAVA (TREE_TYPE (decl)));
484
485   if (err)
486     {
487       if (TREE_CODE (decl) == REFERENCE_TYPE
488           && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
489           && TYPE_FOR_JAVA (TREE_TYPE (decl)))
490         {
491           /* Can't throw a reference.  */
492           cp_error ("type `%T' is disallowed in Java `throw' or `catch'",
493                     decl);
494         }
495
496       if (r)
497         {
498           tree jthrow_node
499             = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jthrowable"));
500           if (jthrow_node == NULL_TREE)
501             fatal ("call to Java `catch' or `throw', while `jthrowable' undefined");
502           jthrow_node = TREE_TYPE (TREE_TYPE (jthrow_node));
503
504           if (! DERIVED_FROM_P (jthrow_node, TREE_TYPE (decl)))
505             {
506               /* Thrown object must be a Throwable.  */
507               cp_error ("type `%T' is not derived from `java::lang::Throwable'",
508                         TREE_TYPE (decl));
509             }
510         }
511     }
512
513   return r;
514 }
515
516 /* Initialize the catch parameter DECL.  */
517
518 static void 
519 initialize_handler_parm (decl)
520      tree decl;
521 {
522   tree exp;
523   tree init;
524   tree init_type;
525   int lang;
526
527   /* Make sure we mark the catch param as used, otherwise we'll get a
528      warning about an unused ((anonymous)).  */
529   TREE_USED (decl) = 1;
530
531   /* Figure out the type that the initializer is.  */
532   init_type = TREE_TYPE (decl);
533   if (TREE_CODE (init_type) != REFERENCE_TYPE
534       && TREE_CODE (init_type) != POINTER_TYPE)
535     init_type = build_reference_type (init_type);
536
537   if (decl_is_java_type (init_type, 0))
538     {
539       tree fn
540         = builtin_function ("_Jv_exception_info", 
541                             build_function_type (ptr_type_node,
542                                                  tree_cons (NULL_TREE,
543                                                             void_type_node,
544                                                             NULL_TREE)),
545                             0, NOT_BUILT_IN, NULL_PTR);
546
547       exp = build (CALL_EXPR, ptr_type_node,
548                    build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)),
549                            fn),
550                    NULL_TREE, NULL_TREE);
551       TREE_SIDE_EFFECTS (exp) = 1;
552       lang = EH_LANG_Java;
553
554       set_exception_lang_code (EH_LANG_Java);
555       set_exception_version_code (1);
556     }
557   else
558     {
559       exp = get_eh_value ();
560       lang = EH_LANG_C_plus_plus;
561     }
562
563   if (catch_language_init)
564     {
565       if (lang != catch_language)
566         error ("mixing C++ and Java `catch'es in single translation unit");
567     }
568   else
569     {
570       catch_language_init = 1;
571       catch_language = lang;
572     }
573
574   /* Since pointers are passed by value, initialize a reference to
575      pointer catch parm with the address of the value slot.  */ 
576   if (TREE_CODE (init_type) == REFERENCE_TYPE 
577       && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
578     exp = build_unary_op (ADDR_EXPR, exp, 1);
579
580   exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
581
582   init = convert_from_reference (exp);
583
584   /* If the constructor for the catch parm exits via an exception, we
585      must call terminate.  See eh23.C.  */
586   if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
587     {
588       /* Generate the copy constructor call directly so we can wrap it.
589          See also expand_default_init.  */
590       init = ocp_convert (TREE_TYPE (decl), init,
591                           CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
592       init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
593                     build_terminate_handler ());
594     }
595
596   /* Let `cp_finish_decl' know that this initializer is ok.  */
597   DECL_INITIAL (decl) = error_mark_node;
598   decl = pushdecl (decl);
599
600   start_decl_1 (decl);
601   cp_finish_decl (decl, init, NULL_TREE,
602                   LOOKUP_ONLYCONVERTING|DIRECT_BIND);
603 }
604
605 /* Call this to start a catch block.  DECL is the catch parameter.  */
606
607 tree
608 expand_start_catch_block (decl)
609      tree decl;
610 {
611   tree compound_stmt_1;
612   tree compound_stmt_2;
613
614   if (! doing_eh (1))
615     return NULL_TREE;
616
617   /* Make sure this declaration is reasonable.  */
618   if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE))
619     decl = NULL_TREE;
620
621   /* Create a binding level for the eh_info and the exception object
622      cleanup.  */
623   compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
624
625   if (! decl || ! decl_is_java_type (TREE_TYPE (decl), 1))
626     {
627       /* The ordinary C++ case.  */
628       tree type;
629
630       if (decl)
631         type = TREE_TYPE (decl);
632       else
633         type = NULL_TREE;
634       begin_catch_block (build_eh_type_type_ref (type));
635
636       push_eh_info ();
637       push_eh_cleanup (type);
638     }
639   else
640     {
641       /* The Java case.  In this case, the match_info is a pointer to
642          the Java class object.  We assume that the class is a
643          compiled class.  */
644       tree ref = build_java_class_ref (TREE_TYPE (TREE_TYPE (decl)));
645       begin_catch_block (build1 (ADDR_EXPR, jclass_node, ref));
646     }
647
648   /* Create a binding level for the parm.  */
649   compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
650
651   if (decl)
652     initialize_handler_parm (decl);
653
654   return build_tree_list (compound_stmt_1, compound_stmt_2);
655 }
656
657
658 /* Call this to end a catch block.  Its responsible for emitting the
659    code to handle jumping back to the correct place, and for emitting
660    the label to jump to if this catch block didn't match.  */
661
662 void
663 expand_end_catch_block (blocks)
664      tree blocks;
665 {
666   tree compound_stmt_1 = blocks ? TREE_PURPOSE (blocks): NULL_TREE;
667   tree compound_stmt_2 = blocks ? TREE_VALUE (blocks): NULL_TREE;
668
669   if (! doing_eh (1))
670     return;
671
672   /* The exception being handled is rethrown if control reaches the end of
673      a handler of the function-try-block of a constructor or destructor.  */
674   if (in_function_try_handler
675       && (DECL_CONSTRUCTOR_P (current_function_decl)
676           || DECL_DESTRUCTOR_P (current_function_decl)))
677     finish_expr_stmt (build_throw (NULL_TREE));
678
679   /* Cleanup the EH parameter.  */
680   finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2);
681   /* Cleanup the EH object.  */
682   finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
683 }
684
685 /* An exception spec is implemented more or less like:
686
687    try {
688      function body;
689    } catch (...) {
690      void *p[] = { typeid(raises) };
691      __check_eh_spec (p, count);
692    }
693
694    __check_eh_spec in exception.cc handles all the details.  */
695
696 tree
697 expand_start_eh_spec ()
698 {
699   return begin_try_block ();
700 }
701
702 void
703 expand_end_eh_spec (raises, try_block)
704      tree raises;
705      tree try_block;
706 {
707   tree tmp, fn, decl, types = NULL_TREE;
708   tree blocks;
709   tree handler;
710   int count = 0;
711
712   finish_try_block (try_block);
713   handler = begin_handler ();
714   blocks = finish_handler_parms (NULL_TREE, handler);
715
716   if (TREE_VALUE (raises) == NULL_TREE)
717     {
718       fn = get_identifier ("__check_null_eh_spec");
719       if (IDENTIFIER_GLOBAL_VALUE (fn))
720         fn = IDENTIFIER_GLOBAL_VALUE (fn);
721       else
722         {
723           tmp = build_function_type (void_type_node, void_list_node);
724           fn = push_throw_library_fn (fn, tmp);
725           /* Since the spec doesn't allow any exceptions, this call
726              will never throw.  */
727           TREE_NOTHROW (fn) = 1;
728         }
729       tmp = NULL_TREE;
730     }
731   else
732     {
733       /* Build up an array of type_infos.  */
734       for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
735         {
736           types = tree_cons
737             (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
738           ++count;
739         }
740
741       types = build_nt (CONSTRUCTOR, NULL_TREE, types);
742       TREE_HAS_CONSTRUCTOR (types) = 1;
743
744       /* We can't pass the CONSTRUCTOR directly, so stick it in a variable.  */
745       tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
746       decl = build_decl (VAR_DECL, NULL_TREE, tmp);
747       DECL_ARTIFICIAL (decl) = 1;
748       DECL_INITIAL (decl) = types;
749       DECL_CONTEXT (decl) = current_function_decl;
750       cp_finish_decl (decl, types, NULL_TREE, 0);
751
752       decl = decay_conversion (decl);
753
754       fn = get_identifier ("__check_eh_spec");
755       if (IDENTIFIER_GLOBAL_VALUE (fn))
756         fn = IDENTIFIER_GLOBAL_VALUE (fn);
757       else
758         {
759           tmp = tree_cons
760             (NULL_TREE, integer_type_node, tree_cons
761              (NULL_TREE, TREE_TYPE (decl), void_list_node));
762           tmp = build_function_type (void_type_node, tmp);
763
764           fn = push_throw_library_fn (fn, tmp);
765         }
766
767       tmp = tree_cons (NULL_TREE, build_int_2 (count, 0), 
768                        tree_cons (NULL_TREE, decl, NULL_TREE));
769     }
770
771   tmp = build_call (fn, tmp);
772   finish_expr_stmt (tmp);
773
774   finish_handler (blocks, handler);
775   finish_handler_sequence (try_block);
776 }
777
778 /* This is called to expand all the toplevel exception handling
779    finalization for a function.  It should only be called once per
780    function.  */
781
782 void
783 expand_exception_blocks ()
784 {
785   do_pending_stack_adjust ();
786
787   if (catch_clauses)
788     {
789       rtx funcend = gen_label_rtx ();
790       emit_jump (funcend);
791
792       /* We cannot protect n regions this way if we must flow into the
793          EH region through the top of the region, as we have to with
794          the setjmp/longjmp approach.  */
795       if (exceptions_via_longjmp == 0)
796         expand_eh_region_start ();
797
798       emit_insns (catch_clauses);
799       catch_clauses = catch_clauses_last = NULL_RTX;
800
801       if (exceptions_via_longjmp == 0)
802         expand_eh_region_end (build_terminate_handler ());
803
804       emit_insns (catch_clauses);
805       catch_clauses = catch_clauses_last = NULL_RTX;
806       emit_label (funcend);
807     }
808 }
809
810 /* Return a pointer to a buffer for an exception object of type TYPE.  */
811
812 static tree
813 alloc_eh_object (type)
814      tree type;
815 {
816   tree fn, exp;
817
818   fn = get_identifier ("__eh_alloc");
819   if (IDENTIFIER_GLOBAL_VALUE (fn))
820     fn = IDENTIFIER_GLOBAL_VALUE (fn);
821   else
822     {
823       /* Declare __eh_alloc (size_t), as defined in exception.cc.  */
824       tree tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
825       fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
826     }
827
828   exp = build_function_call (fn, tree_cons
829                              (NULL_TREE, size_in_bytes (type), NULL_TREE));
830   exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
831   return exp;
832 }
833
834 /* Expand a throw statement.  This follows the following
835    algorithm:
836
837         1. Allocate space to save the current PC onto the stack.
838         2. Generate and emit a label and save its address into the
839                 newly allocated stack space since we can't save the pc directly.
840         3. If this is the first call to throw in this function:
841                 generate a label for the throw block
842         4. jump to the throw block label.  */
843
844 static tree
845 expand_throw (exp)
846      tree exp;
847 {
848   tree fn;
849
850   if (! doing_eh (1))
851     return error_mark_node;
852
853   if (exp
854       && decl_is_java_type (TREE_TYPE (exp), 1))
855     {
856       /* A Java `throw' statement.  */
857       tree args = tree_cons (NULL_TREE, exp, NULL);
858
859       fn = get_identifier (exceptions_via_longjmp
860                            ? "_Jv_Sjlj_Throw"
861                            : "_Jv_Throw");
862       if (IDENTIFIER_GLOBAL_VALUE (fn))
863         fn = IDENTIFIER_GLOBAL_VALUE (fn);
864       else
865         {
866           /* Declare _Jv_Throw (void *), as defined in Java's
867              exception.cc.  */
868           tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
869           tmp = build_function_type (ptr_type_node, tmp);
870           fn = push_library_fn (fn, tmp);
871           TREE_THIS_VOLATILE (fn) = 1;
872           TREE_NOTHROW (fn) = 0;
873         }
874
875       exp = build_function_call (fn, args);
876     }
877   else if (exp)
878     {
879       tree throw_type;
880       tree cleanup = NULL_TREE, e;
881       tree stmt_expr;
882       tree compound_stmt;
883       tree try_block;
884
885       begin_init_stmts (&stmt_expr, &compound_stmt);
886
887       /* throw expression */
888       /* First, decay it.  */
889       exp = decay_conversion (exp);
890
891       /* The CLEANUP_TYPE is the internal type of a destructor.  Under
892          the old ABI, destructors are two-argument functions; under
893          the new ABI they take only one argument.  */
894       if (cleanup_type == NULL_TREE)
895         {
896           tree arg_types;
897           
898           arg_types = void_list_node;
899           if (!flag_new_abi)
900             arg_types = tree_cons (NULL_TREE, integer_type_node, arg_types);
901           arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types);
902           cleanup_type = (build_pointer_type 
903                           (build_function_type (void_type_node, arg_types)));
904         }
905
906       if (TYPE_PTR_P (TREE_TYPE (exp)))
907         throw_type = build_eh_type_type (TREE_TYPE (exp));
908       else
909         {
910           tree object, ptr;
911
912           /* OK, this is kind of wacky.  The standard says that we call
913              terminate when the exception handling mechanism, after
914              completing evaluation of the expression to be thrown but
915              before the exception is caught (_except.throw_), calls a
916              user function that exits via an uncaught exception.
917
918              So we have to protect the actual initialization of the
919              exception object with terminate(), but evaluate the expression
920              first.  We also expand the call to __eh_alloc
921              first.  Since there could be temps in the expression, we need
922              to handle that, too.  */
923
924           my_friendly_assert (stmts_are_full_exprs_p == 1, 19990926);
925
926           /* Store the throw expression into a temp.  This can be less
927              efficient than storing it into the allocated space directly, but
928              oh well.  To do this efficiently we would need to insinuate
929              ourselves into expand_call.  */
930           if (TREE_SIDE_EFFECTS (exp))
931             {
932               tree temp = create_temporary_var (TREE_TYPE (exp));
933               DECL_INITIAL (temp) = exp;
934               cp_finish_decl (temp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
935               exp = temp;
936             }
937
938           /* Allocate the space for the exception.  */
939           ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
940           finish_expr_stmt (ptr);
941
942           try_block = begin_try_block ();
943           object = build_indirect_ref (ptr, NULL_PTR);
944           exp = build_modify_expr (object, INIT_EXPR, exp);
945
946           if (exp == error_mark_node)
947             error ("  in thrown expression");
948
949           finish_expr_stmt (exp);
950           finish_cleanup_try_block (try_block);
951           finish_cleanup (build_terminate_handler (), try_block);
952
953           throw_type = build_eh_type_type (TREE_TYPE (object));
954
955           if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
956             {
957               cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
958                                          (flag_new_abi
959                                           ? complete_dtor_identifier
960                                           : dtor_identifier),
961                                          0);
962               cleanup = TREE_VALUE (cleanup);
963               mark_used (cleanup);
964               mark_addressable (cleanup);
965               /* Pretend it's a normal function.  */
966               cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
967             }
968
969           exp = ptr;
970         }
971
972       /* Cast EXP to `void *' so that it will match the prototype for
973          __cp_push_exception.  */
974       exp = convert (ptr_type_node, exp);
975
976       if (cleanup == NULL_TREE)
977         {
978           cleanup = build_int_2 (0, 0);
979           TREE_TYPE (cleanup) = cleanup_type;
980         }
981
982       fn = cp_push_exception_identifier;
983       if (IDENTIFIER_GLOBAL_VALUE (fn))
984         fn = IDENTIFIER_GLOBAL_VALUE (fn);
985       else
986         {
987           /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
988              as defined in exception.cc.  */
989           tree tmp;
990           tmp = tree_cons
991             (NULL_TREE, ptr_type_node, tree_cons
992              (NULL_TREE, ptr_type_node, tree_cons
993               (NULL_TREE, cleanup_type, void_list_node)));
994           fn = push_void_library_fn (fn, tmp);
995         }
996
997       e = tree_cons (NULL_TREE, exp, tree_cons
998                      (NULL_TREE, throw_type, tree_cons
999                       (NULL_TREE, cleanup, NULL_TREE)));
1000       finish_expr_stmt (build_function_call (fn, e));
1001
1002       exp = finish_init_stmts (stmt_expr, compound_stmt);
1003     }
1004   else
1005     {
1006       /* rethrow current exception; note that it's no longer caught.  */
1007
1008       tree fn = get_identifier ("__uncatch_exception");
1009       if (IDENTIFIER_GLOBAL_VALUE (fn))
1010         fn = IDENTIFIER_GLOBAL_VALUE (fn);
1011       else
1012         /* Declare void __uncatch_exception (void)
1013            as defined in exception.cc. */
1014         fn = push_void_library_fn (fn, void_list_node);
1015
1016       exp = build_function_call (fn, NULL_TREE);
1017     }
1018
1019   return exp;
1020 }
1021
1022 /* Build a throw expression.  */
1023
1024 tree
1025 build_throw (e)
1026      tree e;
1027 {
1028   if (e == error_mark_node)
1029     return e;
1030
1031   if (processing_template_decl)
1032     return build_min (THROW_EXPR, void_type_node, e);
1033
1034   if (e == null_node)
1035     cp_warning ("throwing NULL, which has integral, not pointer type");
1036   
1037   if (e != NULL_TREE)
1038     {
1039       if (!complete_ptr_ref_or_void_ptr_p (TREE_TYPE (e), e))
1040         return error_mark_node;
1041     }
1042
1043   e = expand_throw (e);
1044   e = build1 (THROW_EXPR, void_type_node, e);
1045   TREE_SIDE_EFFECTS (e) = 1;
1046   TREE_USED (e) = 1;
1047
1048   return e;
1049 }
1050
1051 /* Make sure TYPE is complete, pointer to complete, reference to
1052    complete, or pointer to cv void. Issue diagnostic on failure.
1053    Return the zero on failure and non-zero on success. FROM can be
1054    the expr or decl from whence TYPE came, if available.  */
1055
1056 static int
1057 complete_ptr_ref_or_void_ptr_p (type, from)
1058      tree type;
1059      tree from;
1060 {
1061   int is_ptr;
1062   
1063   /* Check complete.  */
1064   type = complete_type_or_else (type, from);
1065   if (!type)
1066     return 0;
1067   
1068   /* Or a pointer or ref to one, or cv void *.  */
1069   is_ptr = TREE_CODE (type) == POINTER_TYPE;
1070   if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE)
1071     {
1072       tree core = TREE_TYPE (type);
1073   
1074       if (is_ptr && same_type_p (TYPE_MAIN_VARIANT (core), void_type_node))
1075         /* OK */;
1076       else if (!complete_type_or_else (core, from))
1077         return 0;
1078     }
1079   return 1;
1080 }
1081
1082 /* Returns nonzero if FN is a declaration of a standard C library
1083    function which is known not to throw.
1084
1085    [lib.res.on.exception.handling]: None of the functions from the
1086    Standard C library shall report an error by throwing an
1087    exception, unless it calls a program-supplied function that
1088    throws an exception.  */
1089
1090 #include "cfns.h"
1091
1092 int
1093 nothrow_libfn_p (fn)
1094      tree fn;
1095 {
1096   tree id;
1097
1098   if (TREE_PUBLIC (fn)
1099       && DECL_EXTERNAL (fn)
1100       && DECL_EXTERN_C_P (fn))
1101     /* OK */;
1102   else
1103     /* Can't be a C library function.  */
1104     return 0;
1105
1106   id = DECL_ASSEMBLER_NAME (fn);
1107   return !!libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
1108 }