OSDN Git Service

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