1 /* Handle exceptional things in C++.
2 Copyright (C) 1989, 92-97, 1998, 1999 Free Software Foundation, Inc.
3 Contributed by Michael Tiemann <tiemann@cygnus.com>
4 Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
5 initial re-implementation courtesy Tad Hunt.
7 This file is part of GNU CC.
9 GNU CC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
14 GNU CC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU CC; see the file COPYING. If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 /* $FreeBSD: src/contrib/gcc/cp/except.c,v 1.5 1999/10/16 07:53:19 obrien Exp $ */
40 #include "eh-common.h"
42 rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
44 /* Holds the fndecl for __builtin_return_address. */
45 tree builtin_return_address_fndecl;
47 /* A couple of backend routines from m88k.c */
49 static void push_eh_cleanup PROTO((void));
50 static tree build_eh_type_type PROTO((tree));
51 static tree build_eh_type PROTO((tree));
52 static void expand_end_eh_spec PROTO((tree));
53 static tree call_eh_info PROTO((void));
54 static void push_eh_info PROTO((void));
55 static tree get_eh_info PROTO((void));
56 static tree get_eh_value PROTO((void));
58 static tree get_eh_type PROTO((void));
59 static tree get_eh_caught PROTO((void));
60 static tree get_eh_handlers PROTO((void));
62 static tree do_pop_exception PROTO((void));
63 static void process_start_catch_block PROTO((tree, tree));
64 static tree build_eh_type_type_ref PROTO((tree));
65 static tree build_terminate_handler PROTO((void));
66 static tree alloc_eh_object PROTO((tree));
69 /* This is the startup, and finish stuff per exception table. */
71 /* XXX - Tad: exception handling section */
72 #ifndef EXCEPT_SECTION_ASM_OP
73 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
76 #ifdef EXCEPT_SECTION_ASM_OP
78 /* on machines which support it, the exception table lives in another section,
79 but it needs a label so we can reference it... This sets up that
81 asm (EXCEPT_SECTION_ASM_OP);
82 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
83 asm (TEXT_SECTION_ASM_OP);
85 #endif /* EXCEPT_SECTION_ASM_OP */
87 #ifdef EXCEPT_SECTION_ASM_OP
89 /* we need to know where the end of the exception table is... so this
92 asm (EXCEPT_SECTION_ASM_OP);
93 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
94 asm (TEXT_SECTION_ASM_OP);
96 #endif /* EXCEPT_SECTION_ASM_OP */
101 #include "insn-flags.h"
104 /* ======================================================================
105 Briefly the algorithm works like this:
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.
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).
125 +---------------------------------------------------------------+
126 |XXX: Will need modification to deal with partially |
127 | constructed arrays of objects |
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 |
133 +---------------------------------------------------------------+
135 When a catch block is encountered, there is a lot of work to be
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
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.
161 ===================================================================== */
163 /* local globals for function calls
164 ====================================================================== */
166 /* Used to cache "terminate" and "__throw_type_match*". */
167 static tree Terminate, CatchMatch;
169 /* Used to cache __find_first_exception_table_match for throw. */
170 static tree FirstExceptionMatch;
172 /* Used to cache a call to __unwind_function. */
175 /* ====================================================================== */
178 /* ========================================================================= */
182 /* local globals - these local globals are for storing data necessary for
183 generating the exception table and code in the correct order.
185 ========================================================================= */
187 extern rtx catch_clauses;
188 extern tree const_ptr_type_node;
190 /* ========================================================================= */
192 /* sets up all the global eh stuff that needs to be initialized at the
193 start of compilation.
196 - Setting up all the function call trees. */
199 init_exception_processing ()
202 tree vtype = build_function_type (void_type_node, void_list_node);
205 push_namespace (get_identifier ("std"));
206 Terminate = auto_function (get_identifier ("terminate"),
207 vtype, NOT_BUILT_IN);
208 TREE_THIS_VOLATILE (Terminate) = 1;
212 push_lang_context (lang_name_c);
214 set_exception_lang_code (EH_LANG_C_plus_plus);
215 set_exception_version_code (1);
218 = builtin_function (flag_rtti
219 ? "__throw_type_match_rtti"
220 : "__throw_type_match",
221 build_function_type (ptr_type_node,
222 tree_cons (NULL_TREE, const_ptr_type_node,
223 tree_cons (NULL_TREE, const_ptr_type_node,
224 tree_cons (NULL_TREE, ptr_type_node,
226 NOT_BUILT_IN, NULL_PTR);
228 = builtin_function ("__find_first_exception_table_match",
229 build_function_type (ptr_type_node,
230 tree_cons (NULL_TREE, ptr_type_node,
232 NOT_BUILT_IN, NULL_PTR);
234 = builtin_function ("__unwind_function",
235 build_function_type (void_type_node,
236 tree_cons (NULL_TREE, ptr_type_node,
238 NOT_BUILT_IN, NULL_PTR);
242 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
243 be protected with __terminate. */
244 protect_cleanup_actions_with_terminate = 1;
247 /* Retrieve a pointer to the cp_eh_info node for the current exception. */
254 fn = get_identifier ("__start_cp_handler");
255 if (IDENTIFIER_GLOBAL_VALUE (fn))
256 fn = IDENTIFIER_GLOBAL_VALUE (fn);
259 tree t1, t, fields[7];
261 /* Declare cp_eh_info * __start_cp_handler (void),
262 as defined in exception.cc. */
263 push_obstacks_nochange ();
264 end_temporary_allocation ();
266 /* struct cp_eh_info. This must match exception.cc. Note that this
267 type is not pushed anywhere. */
268 t1= make_lang_type (RECORD_TYPE);
269 fields[0] = build_lang_field_decl (FIELD_DECL,
270 get_identifier ("handler_label"), ptr_type_node);
271 fields[1] = build_lang_field_decl (FIELD_DECL,
272 get_identifier ("dynamic_handler_chain"), ptr_type_node);
273 fields[2] = build_lang_field_decl (FIELD_DECL,
274 get_identifier ("info"), ptr_type_node);
275 fields[3] = build_lang_field_decl (FIELD_DECL,
276 get_identifier ("table_index"), ptr_type_node);
277 /* N.B.: The fourth field LEN is expected to be
278 the number of fields - 1, not the total number of fields. */
279 finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
280 t1 = build_pointer_type (t1);
282 t1= make_lang_type (RECORD_TYPE);
283 fields[0] = build_lang_field_decl (FIELD_DECL,
284 get_identifier ("match_function"), ptr_type_node);
285 fields[1] = build_lang_field_decl (FIELD_DECL,
286 get_identifier ("language"), short_integer_type_node);
287 fields[2] = build_lang_field_decl (FIELD_DECL,
288 get_identifier ("version"), short_integer_type_node);
289 /* N.B.: The fourth field LEN is expected to be
290 the number of fields - 1, not the total number of fields. */
291 finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node);
292 t = make_lang_type (RECORD_TYPE);
293 fields[0] = build_lang_field_decl (FIELD_DECL,
294 get_identifier ("eh_info"), t1);
295 fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
297 fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
299 fields[3] = build_lang_field_decl
300 (FIELD_DECL, get_identifier ("cleanup"),
301 build_pointer_type (build_function_type
302 (ptr_type_node, tree_cons
303 (NULL_TREE, ptr_type_node, void_list_node))));
304 fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
306 fields[5] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
307 build_pointer_type (t));
308 fields[6] = build_lang_field_decl
309 (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
310 /* N.B.: The fourth field LEN is expected to be
311 the number of fields - 1, not the total number of fields. */
312 finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node);
313 t = build_pointer_type (t);
315 /* And now the function. */
316 fn = build_lang_decl (FUNCTION_DECL, fn,
317 build_function_type (t, void_list_node));
318 DECL_EXTERNAL (fn) = 1;
319 TREE_PUBLIC (fn) = 1;
320 DECL_ARTIFICIAL (fn) = 1;
321 pushdecl_top_level (fn);
322 make_function_rtl (fn);
326 return build_function_call (fn, NULL_TREE);
329 /* Retrieve a pointer to the cp_eh_info node for the current exception
330 and save it in the current binding level. */
335 tree decl, fn = call_eh_info ();
337 /* Remember the pointer to the current exception info; it won't change
338 during this catch block. */
339 decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
341 DECL_ARTIFICIAL (decl) = 1;
342 DECL_INITIAL (decl) = fn;
343 decl = pushdecl (decl);
344 cp_finish_decl (decl, fn, NULL_TREE, 0, 0);
347 /* Returns a reference to the cp_eh_info node for the current exception. */
352 /* Look for the pointer pushed in push_eh_info. */
353 tree t = lookup_name (get_identifier ("__exception_info"), 0);
354 return build_indirect_ref (t, NULL_PTR);
357 /* Returns a reference to the current exception object. */
362 return build_component_ref (get_eh_info (), get_identifier ("value"),
366 /* Returns a reference to the current exception type. */
372 return build_component_ref (get_eh_info (), get_identifier ("type"),
376 /* Returns a reference to whether or not the current exception
382 return build_component_ref (get_eh_info (), get_identifier ("caught"),
386 /* Returns a reference to whether or not the current exception
392 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
397 /* Build a type value for use at runtime for a type that is matched
398 against by the exception handling system. */
401 build_eh_type_type (type)
404 const char *typestring;
407 if (type == error_mark_node)
408 return error_mark_node;
410 /* peel back references, so they match. */
411 if (TREE_CODE (type) == REFERENCE_TYPE)
412 type = TREE_TYPE (type);
414 /* Peel off cv qualifiers. */
415 type = TYPE_MAIN_VARIANT (type);
418 return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
420 typestring = build_overload_name (type, 1, 1);
421 exp = combine_strings (build_string (strlen (typestring)+1, typestring));
422 return build1 (ADDR_EXPR, ptr_type_node, exp);
425 /* Build the address of a runtime type for use in the runtime matching
426 field of the new exception model */
429 build_eh_type_type_ref (type)
432 const char *typestring;
435 if (type == error_mark_node)
436 return error_mark_node;
438 /* peel back references, so they match. */
439 if (TREE_CODE (type) == REFERENCE_TYPE)
440 type = TREE_TYPE (type);
442 /* Peel off cv qualifiers. */
443 type = TYPE_MAIN_VARIANT (type);
445 push_obstacks_nochange ();
446 end_temporary_allocation ();
450 exp = get_tinfo_fn (type);
452 mark_inline_for_output (exp);
453 exp = build1 (ADDR_EXPR, ptr_type_node, exp);
457 typestring = build_overload_name (type, 1, 1);
458 exp = combine_strings (build_string (strlen (typestring)+1, typestring));
459 exp = build1 (ADDR_EXPR, ptr_type_node, exp);
466 /* Build a type value for use at runtime for a exp that is thrown or
467 matched against by the exception handling system. */
475 exp = build_typeid (exp);
476 return build1 (ADDR_EXPR, ptr_type_node, exp);
478 return build_eh_type_type (TREE_TYPE (exp));
481 /* This routine is called to mark all the symbols representing runtime
482 type functions in the exception table as haveing been referenced.
483 This will make sure code is emitted for them. Called from finish_file. */
485 mark_all_runtime_matches ()
491 num = find_all_handler_type_matches (&ptr);
492 if (num == 0 || ptr == NULL)
495 for (x=0; x <num; x++)
498 if (TREE_CODE (exp) == ADDR_EXPR)
500 exp = TREE_OPERAND (exp, 0);
501 if (TREE_CODE (exp) == FUNCTION_DECL)
502 TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
509 /* Build up a call to __cp_pop_exception, to destroy the exception object
510 for the current catch block. HANDLER is either true or false, telling
511 the library whether or not it is being called from an exception handler;
512 if it is, it avoids destroying the object on rethrow. */
518 fn = get_identifier ("__cp_pop_exception");
519 if (IDENTIFIER_GLOBAL_VALUE (fn))
520 fn = IDENTIFIER_GLOBAL_VALUE (fn);
523 /* Declare void __cp_pop_exception (void *),
524 as defined in exception.cc. */
525 push_obstacks_nochange ();
526 end_temporary_allocation ();
529 build_function_type (void_type_node, tree_cons
530 (NULL_TREE, ptr_type_node, void_list_node)));
531 DECL_EXTERNAL (fn) = 1;
532 TREE_PUBLIC (fn) = 1;
533 DECL_ARTIFICIAL (fn) = 1;
534 pushdecl_top_level (fn);
535 make_function_rtl (fn);
540 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
541 cleanup = lookup_name (get_identifier ("__exception_info"), 0);
542 cleanup = build_function_call (fn, expr_tree_cons
543 (NULL_TREE, cleanup, NULL_TREE));
547 /* This routine creates the cleanup for the current exception. */
554 yes = suspend_momentary ();
555 /* All cleanups must last longer than normal. */
556 expand_decl_cleanup (NULL_TREE, do_pop_exception ());
557 resume_momentary (yes);
560 /* Build up a call to terminate on the function obstack, for use as an
561 exception handler. */
564 build_terminate_handler ()
566 int yes = suspend_momentary ();
567 tree term = build_function_call (Terminate, NULL_TREE);
568 resume_momentary (yes);
572 /* Call this to start a catch block. Typename is the typename, and identifier
573 is the variable to place the object in or NULL if the variable doesn't
574 matter. If typename is NULL, that means its a "catch (...)" or catch
575 everything. In that case we don't need to do any type checking.
576 (ie: it ends up as the "else" clause rather than an "else if" clause) */
579 expand_start_catch_block (declspecs, declarator)
580 tree declspecs, declarator;
584 if (processing_template_decl)
588 decl = grokdeclarator (declarator, declspecs, CATCHPARM,
591 decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
592 copy_to_permanent (declspecs),
602 process_start_catch_block (declspecs, declarator);
606 /* This function performs the expand_start_catch_block functionality for
607 exceptions implemented in the new style. __throw determines whether
608 a handler needs to be called or not, so the handler itself has to do
609 nothing additional. */
612 process_start_catch_block (declspecs, declarator)
613 tree declspecs, declarator;
615 tree decl = NULL_TREE;
618 /* Create a binding level for the eh_info and the exception object
621 expand_start_bindings (0);
626 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
628 if (decl == NULL_TREE)
629 error ("invalid catch parameter");
633 start_catch_handler (build_eh_type_type_ref (TREE_TYPE (decl)));
635 start_catch_handler (CATCH_ALL_TYPE);
637 emit_line_note (input_filename, lineno);
646 /* Make sure we mark the catch param as used, otherwise we'll get
647 a warning about an unused ((anonymous)). */
648 TREE_USED (decl) = 1;
650 /* Figure out the type that the initializer is. */
651 init_type = TREE_TYPE (decl);
652 if (TREE_CODE (init_type) != REFERENCE_TYPE
653 && TREE_CODE (init_type) != POINTER_TYPE)
654 init_type = build_reference_type (init_type);
656 exp = get_eh_value ();
658 /* Since pointers are passed by value, initialize a reference to
659 pointer catch parm with the address of the value slot. */
660 if (TREE_CODE (init_type) == REFERENCE_TYPE
661 && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
662 exp = build_unary_op (ADDR_EXPR, exp, 1);
664 exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
668 /* Create a binding level for the parm. */
670 expand_start_bindings (0);
672 init = convert_from_reference (exp);
674 /* If the constructor for the catch parm exits via an exception, we
675 must call terminate. See eh23.C. */
676 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
678 /* Generate the copy constructor call directly so we can wrap it.
679 See also expand_default_init. */
680 init = ocp_convert (TREE_TYPE (decl), init,
681 CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
682 init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
683 build_terminate_handler ());
686 /* Let `cp_finish_decl' know that this initializer is ok. */
687 DECL_INITIAL (decl) = init;
688 decl = pushdecl (decl);
691 cp_finish_decl (decl, init, NULL_TREE, 0,
692 LOOKUP_ONLYCONVERTING|DIRECT_BIND);
698 /* Create a binding level for the parm. */
700 expand_start_bindings (0);
702 /* Fall into the catch all section. */
705 emit_line_note (input_filename, lineno);
709 /* Call this to end a catch block. Its responsible for emitting the
710 code to handle jumping back to the correct place, and for emitting
711 the label to jump to if this catch block didn't match. */
714 expand_end_catch_block ()
719 /* Cleanup the EH parameter. */
720 expand_end_bindings (getdecls (), kept_level_p (), 0);
721 poplevel (kept_level_p (), 1, 0);
723 /* Cleanup the EH object. */
724 expand_end_bindings (getdecls (), kept_level_p (), 0);
725 poplevel (kept_level_p (), 1, 0);
727 /* Fall to outside the try statement when done executing handler and
728 we fall off end of handler. This is jump Lresume in the
730 expand_goto (top_label_entry (&caught_return_label_stack));
732 end_catch_handler ();
735 /* An exception spec is implemented more or less like:
740 void *p[] = { typeid(raises) };
741 __check_eh_spec (p, count);
744 __check_eh_spec in exception.cc handles all the details. */
747 expand_start_eh_spec ()
749 expand_start_try_stmts ();
753 expand_end_eh_spec (raises)
756 tree tmp, fn, decl, types = NULL_TREE;
759 expand_start_all_catch ();
760 expand_start_catch_block (NULL_TREE, NULL_TREE);
762 /* Build up an array of type_infos. */
763 for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
765 types = expr_tree_cons
766 (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
770 types = build_nt (CONSTRUCTOR, NULL_TREE, types);
771 TREE_HAS_CONSTRUCTOR (types) = 1;
773 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
774 tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
775 decl = build_decl (VAR_DECL, NULL_TREE, tmp);
776 DECL_ARTIFICIAL (decl) = 1;
777 DECL_INITIAL (decl) = types;
778 cp_finish_decl (decl, types, NULL_TREE, 0, 0);
780 decl = decay_conversion (decl);
782 fn = get_identifier ("__check_eh_spec");
783 if (IDENTIFIER_GLOBAL_VALUE (fn))
784 fn = IDENTIFIER_GLOBAL_VALUE (fn);
787 push_obstacks_nochange ();
788 end_temporary_allocation ();
791 (NULL_TREE, integer_type_node, tree_cons
792 (NULL_TREE, TREE_TYPE (decl), void_list_node));
793 tmp = build_function_type (void_type_node, tmp);
795 fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
796 DECL_EXTERNAL (fn) = 1;
797 TREE_PUBLIC (fn) = 1;
798 DECL_ARTIFICIAL (fn) = 1;
799 TREE_THIS_VOLATILE (fn) = 1;
800 pushdecl_top_level (fn);
801 make_function_rtl (fn);
806 tmp = expr_tree_cons (NULL_TREE, build_int_2 (count, 0), expr_tree_cons
807 (NULL_TREE, decl, NULL_TREE));
808 tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
809 expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
811 expand_end_catch_block ();
812 expand_end_all_catch ();
815 /* This is called to expand all the toplevel exception handling
816 finalization for a function. It should only be called once per
820 expand_exception_blocks ()
822 do_pending_stack_adjust ();
823 push_to_sequence (catch_clauses);
824 expand_leftover_cleanups ();
825 do_pending_stack_adjust ();
826 catch_clauses = get_insns ();
829 /* Do this after we expand leftover cleanups, so that the
830 expand_eh_region_end that expand_end_eh_spec does will match the
831 right expand_eh_region_start, and make sure it comes out before
832 the terminate protected region. */
833 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
835 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
836 do_pending_stack_adjust ();
837 push_to_sequence (catch_clauses);
838 expand_leftover_cleanups ();
839 do_pending_stack_adjust ();
840 catch_clauses = get_insns ();
846 rtx funcend = gen_label_rtx ();
849 /* We cannot protect n regions this way if we must flow into the
850 EH region through the top of the region, as we have to with
851 the setjmp/longjmp approach. */
852 if (exceptions_via_longjmp == 0)
853 expand_eh_region_start ();
855 emit_insns (catch_clauses);
856 catch_clauses = NULL_RTX;
858 if (exceptions_via_longjmp == 0)
859 expand_eh_region_end (build_terminate_handler ());
861 expand_leftover_cleanups ();
863 emit_label (funcend);
870 static int counter = 0;
871 int old_interface_unknown = interface_unknown;
876 push_cp_function_context (NULL_TREE);
877 push_to_top_level ();
879 /* No need to mangle this. */
880 push_lang_context (lang_name_c);
882 interface_unknown = 1;
884 params = void_list_node;
885 /* tcf stands for throw clean function. */
886 sprintf (name, "__tcf_%d", counter++);
887 t = make_call_declarator (get_identifier (name), params, NULL_TREE,
889 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
896 expand_start_bindings (0);
897 emit_line_note (input_filename, lineno);
899 interface_unknown = old_interface_unknown;
903 return current_function_decl;
909 expand_end_bindings (getdecls (), 1, 0);
913 finish_function (lineno, 0, 0);
915 pop_from_top_level ();
916 pop_cp_function_context (NULL_TREE);
919 /* Return a pointer to a buffer for an exception object of type TYPE. */
922 alloc_eh_object (type)
927 fn = get_identifier ("__eh_alloc");
928 if (IDENTIFIER_GLOBAL_VALUE (fn))
929 fn = IDENTIFIER_GLOBAL_VALUE (fn);
932 /* Declare __eh_alloc (size_t), as defined in exception.cc. */
934 push_obstacks_nochange ();
935 end_temporary_allocation ();
936 tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
937 fn = build_lang_decl (FUNCTION_DECL, fn,
938 build_function_type (ptr_type_node, tmp));
939 DECL_EXTERNAL (fn) = 1;
940 TREE_PUBLIC (fn) = 1;
941 DECL_ARTIFICIAL (fn) = 1;
942 pushdecl_top_level (fn);
943 make_function_rtl (fn);
948 exp = build_function_call (fn, expr_tree_cons
949 (NULL_TREE, size_in_bytes (type), NULL_TREE));
950 exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
954 /* Expand a throw statement. This follows the following
957 1. Allocate space to save the current PC onto the stack.
958 2. Generate and emit a label and save its address into the
959 newly allocated stack space since we can't save the pc directly.
960 3. If this is the first call to throw in this function:
961 generate a label for the throw block
962 4. jump to the throw block label. */
969 static tree cleanup_type;
977 tree cleanup = NULL_TREE, e;
979 /* throw expression */
980 /* First, decay it. */
981 exp = decay_conversion (exp);
983 /* cleanup_type is void (*)(void *, int),
984 the internal type of a destructor. */
985 if (cleanup_type == NULL_TREE)
987 push_obstacks_nochange ();
988 end_temporary_allocation ();
989 cleanup_type = build_pointer_type
991 (void_type_node, tree_cons
992 (NULL_TREE, ptr_type_node, tree_cons
993 (NULL_TREE, integer_type_node, void_list_node))));
997 if (TYPE_PTR_P (TREE_TYPE (exp)))
998 throw_type = build_eh_type (exp);
1003 /* OK, this is kind of wacky. The WP says that we call
1006 when the exception handling mechanism, after completing
1007 evaluation of the expression to be thrown but before the
1008 exception is caught (_except.throw_), calls a user function
1009 that exits via an uncaught exception.
1011 So we have to protect the actual initialization of the
1012 exception object with terminate(), but evaluate the expression
1013 first. We also expand the call to __eh_alloc
1014 first. Since there could be temps in the expression, we need
1015 to handle that, too. */
1017 expand_start_target_temps ();
1020 /* Unfortunately, this doesn't work. */
1021 preexpand_calls (exp);
1023 /* Store the throw expression into a temp. This can be less
1024 efficient than storing it into the allocated space directly, but
1025 oh well. To do this efficiently we would need to insinuate
1026 ourselves into expand_call. */
1027 if (TREE_SIDE_EFFECTS (exp))
1029 tree temp = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp));
1030 DECL_ARTIFICIAL (temp) = 1;
1031 DECL_RTL (temp) = assign_temp (TREE_TYPE (exp), 2, 0, 1);
1032 DECL_INITIAL (temp) = exp;
1033 cp_finish_decl (temp, exp, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
1038 /* Allocate the space for the exception. */
1039 ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
1040 expand_expr (ptr, const0_rtx, VOIDmode, 0);
1042 expand_eh_region_start ();
1044 object = build_indirect_ref (ptr, NULL_PTR);
1045 exp = build_modify_expr (object, INIT_EXPR, exp);
1047 if (exp == error_mark_node)
1048 error (" in thrown expression");
1050 expand_expr (exp, const0_rtx, VOIDmode, 0);
1051 expand_eh_region_end (build_terminate_handler ());
1052 expand_end_target_temps ();
1054 throw_type = build_eh_type (object);
1056 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
1058 cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
1059 dtor_identifier, 0);
1060 cleanup = TREE_VALUE (cleanup);
1061 mark_used (cleanup);
1062 mark_addressable (cleanup);
1063 /* Pretend it's a normal function. */
1064 cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
1070 /* Cast EXP to `void *' so that it will match the prototype for
1071 __cp_push_exception. */
1072 exp = convert (ptr_type_node, exp);
1074 if (cleanup == NULL_TREE)
1076 cleanup = build_int_2 (0, 0);
1077 TREE_TYPE (cleanup) = cleanup_type;
1080 fn = get_identifier ("__cp_push_exception");
1081 if (IDENTIFIER_GLOBAL_VALUE (fn))
1082 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1085 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1086 as defined in exception.cc. */
1088 push_obstacks_nochange ();
1089 end_temporary_allocation ();
1091 (NULL_TREE, ptr_type_node, tree_cons
1092 (NULL_TREE, ptr_type_node, tree_cons
1093 (NULL_TREE, cleanup_type, void_list_node)));
1094 fn = build_lang_decl (FUNCTION_DECL, fn,
1095 build_function_type (void_type_node, tmp));
1096 DECL_EXTERNAL (fn) = 1;
1097 TREE_PUBLIC (fn) = 1;
1098 DECL_ARTIFICIAL (fn) = 1;
1099 pushdecl_top_level (fn);
1100 make_function_rtl (fn);
1105 e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons
1106 (NULL_TREE, throw_type, expr_tree_cons
1107 (NULL_TREE, cleanup, NULL_TREE)));
1108 e = build_function_call (fn, e);
1109 expand_expr (e, const0_rtx, VOIDmode, 0);
1113 /* rethrow current exception; note that it's no longer caught. */
1115 tree fn = get_identifier ("__uncatch_exception");
1116 if (IDENTIFIER_GLOBAL_VALUE (fn))
1117 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1120 /* Declare void __uncatch_exception (void)
1121 as defined in exception.cc. */
1122 push_obstacks_nochange ();
1123 end_temporary_allocation ();
1124 fn = build_lang_decl (FUNCTION_DECL, fn,
1125 build_function_type (void_type_node,
1127 DECL_EXTERNAL (fn) = 1;
1128 TREE_PUBLIC (fn) = 1;
1129 DECL_ARTIFICIAL (fn) = 1;
1130 pushdecl_top_level (fn);
1131 make_function_rtl (fn);
1136 exp = build_function_call (fn, NULL_TREE);
1137 expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
1140 expand_internal_throw ();
1143 /* Build a throw expression. */
1149 if (e == error_mark_node)
1152 if (processing_template_decl)
1153 return build_min (THROW_EXPR, void_type_node, e);
1156 cp_warning ("throwing NULL, which has integral, not pointer type");
1158 e = build1 (THROW_EXPR, void_type_node, e);
1159 TREE_SIDE_EFFECTS (e) = 1;