OSDN Git Service

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