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 $ */
25 /* $DragonFly: src/contrib/gcc/cp/Attic/except.c,v 1.2 2003/06/17 04:24:02 dillon Exp $ */
41 #include "eh-common.h"
43 rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
45 /* Holds the fndecl for __builtin_return_address. */
46 tree builtin_return_address_fndecl;
48 /* A couple of backend routines from m88k.c */
50 static void push_eh_cleanup PROTO((void));
51 static tree build_eh_type_type PROTO((tree));
52 static tree build_eh_type PROTO((tree));
53 static void expand_end_eh_spec PROTO((tree));
54 static tree call_eh_info PROTO((void));
55 static void push_eh_info PROTO((void));
56 static tree get_eh_info PROTO((void));
57 static tree get_eh_value PROTO((void));
59 static tree get_eh_type PROTO((void));
60 static tree get_eh_caught PROTO((void));
61 static tree get_eh_handlers PROTO((void));
63 static tree do_pop_exception PROTO((void));
64 static void process_start_catch_block PROTO((tree, tree));
65 static tree build_eh_type_type_ref PROTO((tree));
66 static tree build_terminate_handler PROTO((void));
67 static tree alloc_eh_object PROTO((tree));
70 /* This is the startup, and finish stuff per exception table. */
72 /* XXX - Tad: exception handling section */
73 #ifndef EXCEPT_SECTION_ASM_OP
74 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
77 #ifdef EXCEPT_SECTION_ASM_OP
79 /* on machines which support it, the exception table lives in another section,
80 but it needs a label so we can reference it... This sets up that
82 asm (EXCEPT_SECTION_ASM_OP);
83 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
84 asm (TEXT_SECTION_ASM_OP);
86 #endif /* EXCEPT_SECTION_ASM_OP */
88 #ifdef EXCEPT_SECTION_ASM_OP
90 /* we need to know where the end of the exception table is... so this
93 asm (EXCEPT_SECTION_ASM_OP);
94 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
95 asm (TEXT_SECTION_ASM_OP);
97 #endif /* EXCEPT_SECTION_ASM_OP */
102 #include "insn-flags.h"
105 /* ======================================================================
106 Briefly the algorithm works like this:
108 When a constructor or start of a try block is encountered,
109 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
110 new entry in the unwind protection stack and returns a label to
111 output to start the protection for that block.
113 When a destructor or end try block is encountered, pop_eh_entry
114 (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it
115 created when push_eh_entry () was called. The eh_entry structure
116 contains three things at this point. The start protect label,
117 the end protect label, and the exception handler label. The end
118 protect label should be output before the call to the destructor
119 (if any). If it was a destructor, then its parse tree is stored
120 in the finalization variable in the eh_entry structure. Otherwise
121 the finalization variable is set to NULL to reflect the fact that
122 it is the end of a try block. Next, this modified eh_entry node
123 is enqueued in the finalizations queue by calling
124 enqueue_eh_entry (&queue,entry).
126 +---------------------------------------------------------------+
127 |XXX: Will need modification to deal with partially |
128 | constructed arrays of objects |
130 | Basically, this consists of keeping track of how many |
131 | of the objects have been constructed already (this |
132 | should be in a register though, so that shouldn't be a |
134 +---------------------------------------------------------------+
136 When a catch block is encountered, there is a lot of work to be
139 Since we don't want to generate the catch block inline with the
140 regular flow of the function, we need to have some way of doing
141 so. Luckily, we can use sequences to defer the catch sections.
142 When the start of a catch block is encountered, we start the
143 sequence. After the catch block is generated, we end the
146 Next we must insure that when the catch block is executed, all
147 finalizations for the matching try block have been completed. If
148 any of those finalizations throw an exception, we must call
149 terminate according to the ARM (section r.15.6.1). What this
150 means is that we need to dequeue and emit finalizations for each
151 entry in the eh_queue until we get to an entry with a NULL
152 finalization field. For any of the finalization entries, if it
153 is not a call to terminate (), we must protect it by giving it
154 another start label, end label, and exception handler label,
155 setting its finalization tree to be a call to terminate (), and
156 enqueue'ing this new eh_entry to be output at an outer level.
157 Finally, after all that is done, we can get around to outputting
158 the catch block which basically wraps all the "catch (...) {...}"
159 statements in a big if/then/else construct that matches the
160 correct block to call.
162 ===================================================================== */
164 /* local globals for function calls
165 ====================================================================== */
167 /* Used to cache "terminate" and "__throw_type_match*". */
168 static tree Terminate, CatchMatch;
170 /* Used to cache __find_first_exception_table_match for throw. */
171 static tree FirstExceptionMatch;
173 /* Used to cache a call to __unwind_function. */
176 /* ====================================================================== */
179 /* ========================================================================= */
183 /* local globals - these local globals are for storing data necessary for
184 generating the exception table and code in the correct order.
186 ========================================================================= */
188 extern rtx catch_clauses;
189 extern tree const_ptr_type_node;
191 /* ========================================================================= */
193 /* sets up all the global eh stuff that needs to be initialized at the
194 start of compilation.
197 - Setting up all the function call trees. */
200 init_exception_processing ()
203 tree vtype = build_function_type (void_type_node, void_list_node);
206 push_namespace (get_identifier ("std"));
207 Terminate = auto_function (get_identifier ("terminate"),
208 vtype, NOT_BUILT_IN);
209 TREE_THIS_VOLATILE (Terminate) = 1;
213 push_lang_context (lang_name_c);
215 set_exception_lang_code (EH_LANG_C_plus_plus);
216 set_exception_version_code (1);
219 = builtin_function (flag_rtti
220 ? "__throw_type_match_rtti"
221 : "__throw_type_match",
222 build_function_type (ptr_type_node,
223 tree_cons (NULL_TREE, const_ptr_type_node,
224 tree_cons (NULL_TREE, const_ptr_type_node,
225 tree_cons (NULL_TREE, ptr_type_node,
227 NOT_BUILT_IN, NULL_PTR);
229 = builtin_function ("__find_first_exception_table_match",
230 build_function_type (ptr_type_node,
231 tree_cons (NULL_TREE, ptr_type_node,
233 NOT_BUILT_IN, NULL_PTR);
235 = builtin_function ("__unwind_function",
236 build_function_type (void_type_node,
237 tree_cons (NULL_TREE, ptr_type_node,
239 NOT_BUILT_IN, NULL_PTR);
243 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
244 be protected with __terminate. */
245 protect_cleanup_actions_with_terminate = 1;
248 /* Retrieve a pointer to the cp_eh_info node for the current exception. */
255 fn = get_identifier ("__start_cp_handler");
256 if (IDENTIFIER_GLOBAL_VALUE (fn))
257 fn = IDENTIFIER_GLOBAL_VALUE (fn);
260 tree t1, t, fields[7];
262 /* Declare cp_eh_info * __start_cp_handler (void),
263 as defined in exception.cc. */
264 push_obstacks_nochange ();
265 end_temporary_allocation ();
267 /* struct cp_eh_info. This must match exception.cc. Note that this
268 type is not pushed anywhere. */
269 t1= make_lang_type (RECORD_TYPE);
270 fields[0] = build_lang_field_decl (FIELD_DECL,
271 get_identifier ("handler_label"), ptr_type_node);
272 fields[1] = build_lang_field_decl (FIELD_DECL,
273 get_identifier ("dynamic_handler_chain"), ptr_type_node);
274 fields[2] = build_lang_field_decl (FIELD_DECL,
275 get_identifier ("info"), ptr_type_node);
276 fields[3] = build_lang_field_decl (FIELD_DECL,
277 get_identifier ("table_index"), ptr_type_node);
278 /* N.B.: The fourth field LEN is expected to be
279 the number of fields - 1, not the total number of fields. */
280 finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
281 t1 = build_pointer_type (t1);
283 t1= make_lang_type (RECORD_TYPE);
284 fields[0] = build_lang_field_decl (FIELD_DECL,
285 get_identifier ("match_function"), ptr_type_node);
286 fields[1] = build_lang_field_decl (FIELD_DECL,
287 get_identifier ("language"), short_integer_type_node);
288 fields[2] = build_lang_field_decl (FIELD_DECL,
289 get_identifier ("version"), short_integer_type_node);
290 /* N.B.: The fourth field LEN is expected to be
291 the number of fields - 1, not the total number of fields. */
292 finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node);
293 t = make_lang_type (RECORD_TYPE);
294 fields[0] = build_lang_field_decl (FIELD_DECL,
295 get_identifier ("eh_info"), t1);
296 fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
298 fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
300 fields[3] = build_lang_field_decl
301 (FIELD_DECL, get_identifier ("cleanup"),
302 build_pointer_type (build_function_type
303 (ptr_type_node, tree_cons
304 (NULL_TREE, ptr_type_node, void_list_node))));
305 fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
307 fields[5] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
308 build_pointer_type (t));
309 fields[6] = build_lang_field_decl
310 (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
311 /* N.B.: The fourth field LEN is expected to be
312 the number of fields - 1, not the total number of fields. */
313 finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node);
314 t = build_pointer_type (t);
316 /* And now the function. */
317 fn = build_lang_decl (FUNCTION_DECL, fn,
318 build_function_type (t, void_list_node));
319 DECL_EXTERNAL (fn) = 1;
320 TREE_PUBLIC (fn) = 1;
321 DECL_ARTIFICIAL (fn) = 1;
322 pushdecl_top_level (fn);
323 make_function_rtl (fn);
327 return build_function_call (fn, NULL_TREE);
330 /* Retrieve a pointer to the cp_eh_info node for the current exception
331 and save it in the current binding level. */
336 tree decl, fn = call_eh_info ();
338 /* Remember the pointer to the current exception info; it won't change
339 during this catch block. */
340 decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
342 DECL_ARTIFICIAL (decl) = 1;
343 DECL_INITIAL (decl) = fn;
344 decl = pushdecl (decl);
345 cp_finish_decl (decl, fn, NULL_TREE, 0, 0);
348 /* Returns a reference to the cp_eh_info node for the current exception. */
353 /* Look for the pointer pushed in push_eh_info. */
354 tree t = lookup_name (get_identifier ("__exception_info"), 0);
355 return build_indirect_ref (t, NULL_PTR);
358 /* Returns a reference to the current exception object. */
363 return build_component_ref (get_eh_info (), get_identifier ("value"),
367 /* Returns a reference to the current exception type. */
373 return build_component_ref (get_eh_info (), get_identifier ("type"),
377 /* Returns a reference to whether or not the current exception
383 return build_component_ref (get_eh_info (), get_identifier ("caught"),
387 /* Returns a reference to whether or not the current exception
393 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
398 /* Build a type value for use at runtime for a type that is matched
399 against by the exception handling system. */
402 build_eh_type_type (type)
405 const char *typestring;
408 if (type == error_mark_node)
409 return error_mark_node;
411 /* peel back references, so they match. */
412 if (TREE_CODE (type) == REFERENCE_TYPE)
413 type = TREE_TYPE (type);
415 /* Peel off cv qualifiers. */
416 type = TYPE_MAIN_VARIANT (type);
419 return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
421 typestring = build_overload_name (type, 1, 1);
422 exp = combine_strings (build_string (strlen (typestring)+1, typestring));
423 return build1 (ADDR_EXPR, ptr_type_node, exp);
426 /* Build the address of a runtime type for use in the runtime matching
427 field of the new exception model */
430 build_eh_type_type_ref (type)
433 const char *typestring;
436 if (type == error_mark_node)
437 return error_mark_node;
439 /* peel back references, so they match. */
440 if (TREE_CODE (type) == REFERENCE_TYPE)
441 type = TREE_TYPE (type);
443 /* Peel off cv qualifiers. */
444 type = TYPE_MAIN_VARIANT (type);
446 push_obstacks_nochange ();
447 end_temporary_allocation ();
451 exp = get_tinfo_fn (type);
453 mark_inline_for_output (exp);
454 exp = build1 (ADDR_EXPR, ptr_type_node, exp);
458 typestring = build_overload_name (type, 1, 1);
459 exp = combine_strings (build_string (strlen (typestring)+1, typestring));
460 exp = build1 (ADDR_EXPR, ptr_type_node, exp);
467 /* Build a type value for use at runtime for a exp that is thrown or
468 matched against by the exception handling system. */
476 exp = build_typeid (exp);
477 return build1 (ADDR_EXPR, ptr_type_node, exp);
479 return build_eh_type_type (TREE_TYPE (exp));
482 /* This routine is called to mark all the symbols representing runtime
483 type functions in the exception table as haveing been referenced.
484 This will make sure code is emitted for them. Called from finish_file. */
486 mark_all_runtime_matches ()
492 num = find_all_handler_type_matches (&ptr);
493 if (num == 0 || ptr == NULL)
496 for (x=0; x <num; x++)
499 if (TREE_CODE (exp) == ADDR_EXPR)
501 exp = TREE_OPERAND (exp, 0);
502 if (TREE_CODE (exp) == FUNCTION_DECL)
503 TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
510 /* Build up a call to __cp_pop_exception, to destroy the exception object
511 for the current catch block. HANDLER is either true or false, telling
512 the library whether or not it is being called from an exception handler;
513 if it is, it avoids destroying the object on rethrow. */
519 fn = get_identifier ("__cp_pop_exception");
520 if (IDENTIFIER_GLOBAL_VALUE (fn))
521 fn = IDENTIFIER_GLOBAL_VALUE (fn);
524 /* Declare void __cp_pop_exception (void *),
525 as defined in exception.cc. */
526 push_obstacks_nochange ();
527 end_temporary_allocation ();
530 build_function_type (void_type_node, tree_cons
531 (NULL_TREE, ptr_type_node, void_list_node)));
532 DECL_EXTERNAL (fn) = 1;
533 TREE_PUBLIC (fn) = 1;
534 DECL_ARTIFICIAL (fn) = 1;
535 pushdecl_top_level (fn);
536 make_function_rtl (fn);
541 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
542 cleanup = lookup_name (get_identifier ("__exception_info"), 0);
543 cleanup = build_function_call (fn, expr_tree_cons
544 (NULL_TREE, cleanup, NULL_TREE));
548 /* This routine creates the cleanup for the current exception. */
555 yes = suspend_momentary ();
556 /* All cleanups must last longer than normal. */
557 expand_decl_cleanup (NULL_TREE, do_pop_exception ());
558 resume_momentary (yes);
561 /* Build up a call to terminate on the function obstack, for use as an
562 exception handler. */
565 build_terminate_handler ()
567 int yes = suspend_momentary ();
568 tree term = build_function_call (Terminate, NULL_TREE);
569 resume_momentary (yes);
573 /* Call this to start a catch block. Typename is the typename, and identifier
574 is the variable to place the object in or NULL if the variable doesn't
575 matter. If typename is NULL, that means its a "catch (...)" or catch
576 everything. In that case we don't need to do any type checking.
577 (ie: it ends up as the "else" clause rather than an "else if" clause) */
580 expand_start_catch_block (declspecs, declarator)
581 tree declspecs, declarator;
585 if (processing_template_decl)
589 decl = grokdeclarator (declarator, declspecs, CATCHPARM,
592 decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
593 copy_to_permanent (declspecs),
603 process_start_catch_block (declspecs, declarator);
607 /* This function performs the expand_start_catch_block functionality for
608 exceptions implemented in the new style. __throw determines whether
609 a handler needs to be called or not, so the handler itself has to do
610 nothing additional. */
613 process_start_catch_block (declspecs, declarator)
614 tree declspecs, declarator;
616 tree decl = NULL_TREE;
619 /* Create a binding level for the eh_info and the exception object
622 expand_start_bindings (0);
627 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
629 if (decl == NULL_TREE)
630 error ("invalid catch parameter");
634 start_catch_handler (build_eh_type_type_ref (TREE_TYPE (decl)));
636 start_catch_handler (CATCH_ALL_TYPE);
638 emit_line_note (input_filename, lineno);
647 /* Make sure we mark the catch param as used, otherwise we'll get
648 a warning about an unused ((anonymous)). */
649 TREE_USED (decl) = 1;
651 /* Figure out the type that the initializer is. */
652 init_type = TREE_TYPE (decl);
653 if (TREE_CODE (init_type) != REFERENCE_TYPE
654 && TREE_CODE (init_type) != POINTER_TYPE)
655 init_type = build_reference_type (init_type);
657 exp = get_eh_value ();
659 /* Since pointers are passed by value, initialize a reference to
660 pointer catch parm with the address of the value slot. */
661 if (TREE_CODE (init_type) == REFERENCE_TYPE
662 && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
663 exp = build_unary_op (ADDR_EXPR, exp, 1);
665 exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
669 /* Create a binding level for the parm. */
671 expand_start_bindings (0);
673 init = convert_from_reference (exp);
675 /* If the constructor for the catch parm exits via an exception, we
676 must call terminate. See eh23.C. */
677 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
679 /* Generate the copy constructor call directly so we can wrap it.
680 See also expand_default_init. */
681 init = ocp_convert (TREE_TYPE (decl), init,
682 CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
683 init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
684 build_terminate_handler ());
687 /* Let `cp_finish_decl' know that this initializer is ok. */
688 DECL_INITIAL (decl) = init;
689 decl = pushdecl (decl);
692 cp_finish_decl (decl, init, NULL_TREE, 0,
693 LOOKUP_ONLYCONVERTING|DIRECT_BIND);
699 /* Create a binding level for the parm. */
701 expand_start_bindings (0);
703 /* Fall into the catch all section. */
706 emit_line_note (input_filename, lineno);
710 /* Call this to end a catch block. Its responsible for emitting the
711 code to handle jumping back to the correct place, and for emitting
712 the label to jump to if this catch block didn't match. */
715 expand_end_catch_block ()
720 /* Cleanup the EH parameter. */
721 expand_end_bindings (getdecls (), kept_level_p (), 0);
722 poplevel (kept_level_p (), 1, 0);
724 /* Cleanup the EH object. */
725 expand_end_bindings (getdecls (), kept_level_p (), 0);
726 poplevel (kept_level_p (), 1, 0);
728 /* Fall to outside the try statement when done executing handler and
729 we fall off end of handler. This is jump Lresume in the
731 expand_goto (top_label_entry (&caught_return_label_stack));
733 end_catch_handler ();
736 /* An exception spec is implemented more or less like:
741 void *p[] = { typeid(raises) };
742 __check_eh_spec (p, count);
745 __check_eh_spec in exception.cc handles all the details. */
748 expand_start_eh_spec ()
750 expand_start_try_stmts ();
754 expand_end_eh_spec (raises)
757 tree tmp, fn, decl, types = NULL_TREE;
760 expand_start_all_catch ();
761 expand_start_catch_block (NULL_TREE, NULL_TREE);
763 /* Build up an array of type_infos. */
764 for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
766 types = expr_tree_cons
767 (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
771 types = build_nt (CONSTRUCTOR, NULL_TREE, types);
772 TREE_HAS_CONSTRUCTOR (types) = 1;
774 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
775 tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
776 decl = build_decl (VAR_DECL, NULL_TREE, tmp);
777 DECL_ARTIFICIAL (decl) = 1;
778 DECL_INITIAL (decl) = types;
779 cp_finish_decl (decl, types, NULL_TREE, 0, 0);
781 decl = decay_conversion (decl);
783 fn = get_identifier ("__check_eh_spec");
784 if (IDENTIFIER_GLOBAL_VALUE (fn))
785 fn = IDENTIFIER_GLOBAL_VALUE (fn);
788 push_obstacks_nochange ();
789 end_temporary_allocation ();
792 (NULL_TREE, integer_type_node, tree_cons
793 (NULL_TREE, TREE_TYPE (decl), void_list_node));
794 tmp = build_function_type (void_type_node, tmp);
796 fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
797 DECL_EXTERNAL (fn) = 1;
798 TREE_PUBLIC (fn) = 1;
799 DECL_ARTIFICIAL (fn) = 1;
800 TREE_THIS_VOLATILE (fn) = 1;
801 pushdecl_top_level (fn);
802 make_function_rtl (fn);
807 tmp = expr_tree_cons (NULL_TREE, build_int_2 (count, 0), expr_tree_cons
808 (NULL_TREE, decl, NULL_TREE));
809 tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
810 expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
812 expand_end_catch_block ();
813 expand_end_all_catch ();
816 /* This is called to expand all the toplevel exception handling
817 finalization for a function. It should only be called once per
821 expand_exception_blocks ()
823 do_pending_stack_adjust ();
824 push_to_sequence (catch_clauses);
825 expand_leftover_cleanups ();
826 do_pending_stack_adjust ();
827 catch_clauses = get_insns ();
830 /* Do this after we expand leftover cleanups, so that the
831 expand_eh_region_end that expand_end_eh_spec does will match the
832 right expand_eh_region_start, and make sure it comes out before
833 the terminate protected region. */
834 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
836 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
837 do_pending_stack_adjust ();
838 push_to_sequence (catch_clauses);
839 expand_leftover_cleanups ();
840 do_pending_stack_adjust ();
841 catch_clauses = get_insns ();
847 rtx funcend = gen_label_rtx ();
850 /* We cannot protect n regions this way if we must flow into the
851 EH region through the top of the region, as we have to with
852 the setjmp/longjmp approach. */
853 if (exceptions_via_longjmp == 0)
854 expand_eh_region_start ();
856 emit_insns (catch_clauses);
857 catch_clauses = NULL_RTX;
859 if (exceptions_via_longjmp == 0)
860 expand_eh_region_end (build_terminate_handler ());
862 expand_leftover_cleanups ();
864 emit_label (funcend);
871 static int counter = 0;
872 int old_interface_unknown = interface_unknown;
877 push_cp_function_context (NULL_TREE);
878 push_to_top_level ();
880 /* No need to mangle this. */
881 push_lang_context (lang_name_c);
883 interface_unknown = 1;
885 params = void_list_node;
886 /* tcf stands for throw clean function. */
887 sprintf (name, "__tcf_%d", counter++);
888 t = make_call_declarator (get_identifier (name), params, NULL_TREE,
890 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
897 expand_start_bindings (0);
898 emit_line_note (input_filename, lineno);
900 interface_unknown = old_interface_unknown;
904 return current_function_decl;
910 expand_end_bindings (getdecls (), 1, 0);
914 finish_function (lineno, 0, 0);
916 pop_from_top_level ();
917 pop_cp_function_context (NULL_TREE);
920 /* Return a pointer to a buffer for an exception object of type TYPE. */
923 alloc_eh_object (type)
928 fn = get_identifier ("__eh_alloc");
929 if (IDENTIFIER_GLOBAL_VALUE (fn))
930 fn = IDENTIFIER_GLOBAL_VALUE (fn);
933 /* Declare __eh_alloc (size_t), as defined in exception.cc. */
935 push_obstacks_nochange ();
936 end_temporary_allocation ();
937 tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
938 fn = build_lang_decl (FUNCTION_DECL, fn,
939 build_function_type (ptr_type_node, tmp));
940 DECL_EXTERNAL (fn) = 1;
941 TREE_PUBLIC (fn) = 1;
942 DECL_ARTIFICIAL (fn) = 1;
943 pushdecl_top_level (fn);
944 make_function_rtl (fn);
949 exp = build_function_call (fn, expr_tree_cons
950 (NULL_TREE, size_in_bytes (type), NULL_TREE));
951 exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
955 /* Expand a throw statement. This follows the following
958 1. Allocate space to save the current PC onto the stack.
959 2. Generate and emit a label and save its address into the
960 newly allocated stack space since we can't save the pc directly.
961 3. If this is the first call to throw in this function:
962 generate a label for the throw block
963 4. jump to the throw block label. */
970 static tree cleanup_type;
978 tree cleanup = NULL_TREE, e;
980 /* throw expression */
981 /* First, decay it. */
982 exp = decay_conversion (exp);
984 /* cleanup_type is void (*)(void *, int),
985 the internal type of a destructor. */
986 if (cleanup_type == NULL_TREE)
988 push_obstacks_nochange ();
989 end_temporary_allocation ();
990 cleanup_type = build_pointer_type
992 (void_type_node, tree_cons
993 (NULL_TREE, ptr_type_node, tree_cons
994 (NULL_TREE, integer_type_node, void_list_node))));
998 if (TYPE_PTR_P (TREE_TYPE (exp)))
999 throw_type = build_eh_type (exp);
1004 /* OK, this is kind of wacky. The WP says that we call
1007 when the exception handling mechanism, after completing
1008 evaluation of the expression to be thrown but before the
1009 exception is caught (_except.throw_), calls a user function
1010 that exits via an uncaught exception.
1012 So we have to protect the actual initialization of the
1013 exception object with terminate(), but evaluate the expression
1014 first. We also expand the call to __eh_alloc
1015 first. Since there could be temps in the expression, we need
1016 to handle that, too. */
1018 expand_start_target_temps ();
1021 /* Unfortunately, this doesn't work. */
1022 preexpand_calls (exp);
1024 /* Store the throw expression into a temp. This can be less
1025 efficient than storing it into the allocated space directly, but
1026 oh well. To do this efficiently we would need to insinuate
1027 ourselves into expand_call. */
1028 if (TREE_SIDE_EFFECTS (exp))
1030 tree temp = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp));
1031 DECL_ARTIFICIAL (temp) = 1;
1032 DECL_RTL (temp) = assign_temp (TREE_TYPE (exp), 2, 0, 1);
1033 DECL_INITIAL (temp) = exp;
1034 cp_finish_decl (temp, exp, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
1039 /* Allocate the space for the exception. */
1040 ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
1041 expand_expr (ptr, const0_rtx, VOIDmode, 0);
1043 expand_eh_region_start ();
1045 object = build_indirect_ref (ptr, NULL_PTR);
1046 exp = build_modify_expr (object, INIT_EXPR, exp);
1048 if (exp == error_mark_node)
1049 error (" in thrown expression");
1051 expand_expr (exp, const0_rtx, VOIDmode, 0);
1052 expand_eh_region_end (build_terminate_handler ());
1053 expand_end_target_temps ();
1055 throw_type = build_eh_type (object);
1057 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
1059 cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
1060 dtor_identifier, 0);
1061 cleanup = TREE_VALUE (cleanup);
1062 mark_used (cleanup);
1063 mark_addressable (cleanup);
1064 /* Pretend it's a normal function. */
1065 cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
1071 /* Cast EXP to `void *' so that it will match the prototype for
1072 __cp_push_exception. */
1073 exp = convert (ptr_type_node, exp);
1075 if (cleanup == NULL_TREE)
1077 cleanup = build_int_2 (0, 0);
1078 TREE_TYPE (cleanup) = cleanup_type;
1081 fn = get_identifier ("__cp_push_exception");
1082 if (IDENTIFIER_GLOBAL_VALUE (fn))
1083 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1086 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1087 as defined in exception.cc. */
1089 push_obstacks_nochange ();
1090 end_temporary_allocation ();
1092 (NULL_TREE, ptr_type_node, tree_cons
1093 (NULL_TREE, ptr_type_node, tree_cons
1094 (NULL_TREE, cleanup_type, void_list_node)));
1095 fn = build_lang_decl (FUNCTION_DECL, fn,
1096 build_function_type (void_type_node, tmp));
1097 DECL_EXTERNAL (fn) = 1;
1098 TREE_PUBLIC (fn) = 1;
1099 DECL_ARTIFICIAL (fn) = 1;
1100 pushdecl_top_level (fn);
1101 make_function_rtl (fn);
1106 e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons
1107 (NULL_TREE, throw_type, expr_tree_cons
1108 (NULL_TREE, cleanup, NULL_TREE)));
1109 e = build_function_call (fn, e);
1110 expand_expr (e, const0_rtx, VOIDmode, 0);
1114 /* rethrow current exception; note that it's no longer caught. */
1116 tree fn = get_identifier ("__uncatch_exception");
1117 if (IDENTIFIER_GLOBAL_VALUE (fn))
1118 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1121 /* Declare void __uncatch_exception (void)
1122 as defined in exception.cc. */
1123 push_obstacks_nochange ();
1124 end_temporary_allocation ();
1125 fn = build_lang_decl (FUNCTION_DECL, fn,
1126 build_function_type (void_type_node,
1128 DECL_EXTERNAL (fn) = 1;
1129 TREE_PUBLIC (fn) = 1;
1130 DECL_ARTIFICIAL (fn) = 1;
1131 pushdecl_top_level (fn);
1132 make_function_rtl (fn);
1137 exp = build_function_call (fn, NULL_TREE);
1138 expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
1141 expand_internal_throw ();
1144 /* Build a throw expression. */
1150 if (e == error_mark_node)
1153 if (processing_template_decl)
1154 return build_min (THROW_EXPR, void_type_node, e);
1157 cp_warning ("throwing NULL, which has integral, not pointer type");
1159 e = build1 (THROW_EXPR, void_type_node, e);
1160 TREE_SIDE_EFFECTS (e) = 1;