1 /* Handle exceptional things in C++.
2 Copyright (C) 1989, 92-97, 1998 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. */
38 rtx expand_builtin_return_addr
PROTO((enum built_in_function
, int, rtx
));
40 /* Holds the fndecl for __builtin_return_address. */
41 tree builtin_return_address_fndecl
;
43 /* A couple of backend routines from m88k.c */
45 static void push_eh_cleanup
PROTO((void));
46 static rtx do_function_call
PROTO((tree
, tree
, tree
));
47 static tree build_eh_type_type
PROTO((tree
));
48 static tree build_eh_type
PROTO((tree
));
49 static void expand_end_eh_spec
PROTO((tree
));
50 static tree call_eh_info
PROTO((void));
51 static void push_eh_info
PROTO((void));
52 static tree get_eh_info
PROTO((void));
53 static tree get_eh_value
PROTO((void));
54 static tree get_eh_type
PROTO((void));
55 static tree get_eh_caught
PROTO((void));
56 static tree get_eh_handlers
PROTO((void));
57 static tree do_pop_exception
PROTO((void));
60 /* This is the startup, and finish stuff per exception table. */
62 /* XXX - Tad: exception handling section */
63 #ifndef EXCEPT_SECTION_ASM_OP
64 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
67 #ifdef EXCEPT_SECTION_ASM_OP
71 void *exception_handler
;
73 #endif /* EXCEPT_SECTION_ASM_OP */
75 #ifdef EXCEPT_SECTION_ASM_OP
77 /* on machines which support it, the exception table lives in another section,
78 but it needs a label so we can reference it... This sets up that
80 asm (EXCEPT_SECTION_ASM_OP
);
81 exception_table __EXCEPTION_TABLE__
[1] = { (void*)0, (void*)0, (void*)0 };
82 asm (TEXT_SECTION_ASM_OP
);
84 #endif /* EXCEPT_SECTION_ASM_OP */
86 #ifdef EXCEPT_SECTION_ASM_OP
88 /* we need to know where the end of the exception table is... so this
91 asm (EXCEPT_SECTION_ASM_OP
);
92 exception_table __EXCEPTION_END__
[1] = { (void*)-1, (void*)-1, (void*)-1 };
93 asm (TEXT_SECTION_ASM_OP
);
95 #endif /* EXCEPT_SECTION_ASM_OP */
100 #include "insn-flags.h"
103 /* ======================================================================
104 Briefly the algorithm works like this:
106 When a constructor or start of a try block is encountered,
107 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
108 new entry in the unwind protection stack and returns a label to
109 output to start the protection for that block.
111 When a destructor or end try block is encountered, pop_eh_entry
112 (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it
113 created when push_eh_entry () was called. The eh_entry structure
114 contains three things at this point. The start protect label,
115 the end protect label, and the exception handler label. The end
116 protect label should be output before the call to the destructor
117 (if any). If it was a destructor, then its parse tree is stored
118 in the finalization variable in the eh_entry structure. Otherwise
119 the finalization variable is set to NULL to reflect the fact that
120 is the the end of a try block. Next, this modified eh_entry node
121 is enqueued in the finalizations queue by calling
122 enqueue_eh_entry (&queue,entry).
124 +---------------------------------------------------------------+
125 |XXX: Will need modification to deal with partially |
126 | constructed arrays of objects |
128 | Basically, this consists of keeping track of how many |
129 | of the objects have been constructed already (this |
130 | should be in a register though, so that shouldn't be a |
132 +---------------------------------------------------------------+
134 When a catch block is encountered, there is a lot of work to be
137 Since we don't want to generate the catch block inline with the
138 regular flow of the function, we need to have some way of doing
139 so. Luckily, we can use sequences to defer the catch sections.
140 When the start of a catch block is encountered, we start the
141 sequence. After the catch block is generated, we end the
144 Next we must insure that when the catch block is executed, all
145 finalizations for the matching try block have been completed. If
146 any of those finalizations throw an exception, we must call
147 terminate according to the ARM (section r.15.6.1). What this
148 means is that we need to dequeue and emit finalizations for each
149 entry in the eh_queue until we get to an entry with a NULL
150 finalization field. For any of the finalization entries, if it
151 is not a call to terminate (), we must protect it by giving it
152 another start label, end label, and exception handler label,
153 setting its finalization tree to be a call to terminate (), and
154 enqueue'ing this new eh_entry to be output at an outer level.
155 Finally, after all that is done, we can get around to outputting
156 the catch block which basically wraps all the "catch (...) {...}"
157 statements in a big if/then/else construct that matches the
158 correct block to call.
160 ===================================================================== */
162 /* local globals for function calls
163 ====================================================================== */
165 /* Used to cache "terminate" and "__throw_type_match*". */
166 static tree Terminate
, CatchMatch
;
168 /* Used to cache __find_first_exception_table_match for throw. */
169 static tree FirstExceptionMatch
;
171 /* Used to cache a call to __unwind_function. */
174 /* ====================================================================== */
177 /* ========================================================================= */
181 /* local globals - these local globals are for storing data necessary for
182 generating the exception table and code in the correct order.
184 ========================================================================= */
186 extern rtx catch_clauses
;
187 extern tree const_ptr_type_node
;
189 /* ========================================================================= */
191 /* Cheesyness to save some typing. Returns the return value rtx. */
194 do_function_call (func
, params
, return_type
)
195 tree func
, params
, return_type
;
198 func_call
= build_function_call (func
, params
);
199 expand_call (func_call
, NULL_RTX
, 0);
200 if (return_type
!= NULL_TREE
)
201 return hard_function_value (return_type
, func_call
);
205 /* ========================================================================= */
207 /* sets up all the global eh stuff that needs to be initialized at the
208 start of compilation.
211 - Setting up all the function call trees. */
214 init_exception_processing ()
217 tree vtype
= build_function_type (void_type_node
, void_list_node
);
219 Terminate
= auto_function (get_identifier ("terminate"),
220 vtype
, NOT_BUILT_IN
);
221 TREE_THIS_VOLATILE (Terminate
) = 1;
223 push_lang_context (lang_name_c
);
226 = builtin_function (flag_rtti
227 ? "__throw_type_match_rtti"
228 : "__throw_type_match",
229 build_function_type (ptr_type_node
,
230 tree_cons (NULL_TREE
, const_ptr_type_node
,
231 tree_cons (NULL_TREE
, const_ptr_type_node
,
232 tree_cons (NULL_TREE
, ptr_type_node
,
234 NOT_BUILT_IN
, NULL_PTR
);
236 = builtin_function ("__find_first_exception_table_match",
237 build_function_type (ptr_type_node
,
238 tree_cons (NULL_TREE
, ptr_type_node
,
240 NOT_BUILT_IN
, NULL_PTR
);
242 = builtin_function ("__unwind_function",
243 build_function_type (void_type_node
,
244 tree_cons (NULL_TREE
, ptr_type_node
,
246 NOT_BUILT_IN
, NULL_PTR
);
250 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
251 be protected with __terminate. */
252 protect_cleanup_actions_with_terminate
= 1;
255 /* Retrieve a pointer to the cp_eh_info node for the current exception. */
262 fn
= get_identifier ("__cp_exception_info");
263 if (IDENTIFIER_GLOBAL_VALUE (fn
))
264 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
269 /* Declare cp_eh_info * __cp_exception_info (void),
270 as defined in exception.cc. */
271 push_obstacks_nochange ();
272 end_temporary_allocation ();
274 /* struct cp_eh_info. This must match exception.cc. Note that this
275 type is not pushed anywhere. */
276 t
= make_lang_type (RECORD_TYPE
);
277 fields
[0] = build_lang_field_decl (FIELD_DECL
, get_identifier ("value"),
279 fields
[1] = build_lang_field_decl (FIELD_DECL
, get_identifier ("type"),
281 fields
[2] = build_lang_field_decl
282 (FIELD_DECL
, get_identifier ("cleanup"),
283 build_pointer_type (build_function_type
284 (ptr_type_node
, tree_cons
285 (NULL_TREE
, ptr_type_node
, void_list_node
))));
286 fields
[3] = build_lang_field_decl (FIELD_DECL
, get_identifier ("caught"),
288 fields
[4] = build_lang_field_decl (FIELD_DECL
, get_identifier ("next"),
289 build_pointer_type (t
));
290 fields
[5] = build_lang_field_decl
291 (FIELD_DECL
, get_identifier ("handlers"), long_integer_type_node
);
292 /* N.B.: The fourth field LEN is expected to be
293 the number of fields - 1, not the total number of fields. */
294 finish_builtin_type (t
, "cp_eh_info", fields
, 5, ptr_type_node
);
295 t
= build_pointer_type (t
);
297 /* And now the function. */
298 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
299 build_function_type (t
, void_list_node
));
300 DECL_EXTERNAL (fn
) = 1;
301 TREE_PUBLIC (fn
) = 1;
302 DECL_ARTIFICIAL (fn
) = 1;
303 pushdecl_top_level (fn
);
304 make_function_rtl (fn
);
305 assemble_external (fn
);
308 return build_function_call (fn
, NULL_TREE
);
311 /* Retrieve a pointer to the cp_eh_info node for the current exception
312 and save it in the current binding level. */
317 tree decl
, fn
= call_eh_info ();
319 /* Remember the pointer to the current exception info; it won't change
320 during this catch block. */
321 decl
= build_decl (VAR_DECL
, get_identifier ("__exception_info"),
323 DECL_ARTIFICIAL (decl
) = 1;
324 DECL_INITIAL (decl
) = fn
;
325 decl
= pushdecl (decl
);
326 cp_finish_decl (decl
, fn
, NULL_TREE
, 0, 0);
329 /* Returns a reference to the cp_eh_info node for the current exception. */
334 /* Look for the pointer pushed in push_eh_info. */
335 tree t
= lookup_name (get_identifier ("__exception_info"), 0);
336 return build_indirect_ref (t
, NULL_PTR
);
339 /* Returns a reference to the current exception object. */
344 return build_component_ref (get_eh_info (), get_identifier ("value"),
348 /* Returns a reference to the current exception type. */
353 return build_component_ref (get_eh_info (), get_identifier ("type"),
357 /* Returns a reference to whether or not the current exception
363 return build_component_ref (get_eh_info (), get_identifier ("caught"),
367 /* Returns a reference to whether or not the current exception
373 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
377 /* Build a type value for use at runtime for a type that is matched
378 against by the exception handling system. */
381 build_eh_type_type (type
)
387 if (type
== error_mark_node
)
388 return error_mark_node
;
390 /* peel back references, so they match. */
391 if (TREE_CODE (type
) == REFERENCE_TYPE
)
392 type
= TREE_TYPE (type
);
394 /* Peel off cv qualifiers. */
395 type
= TYPE_MAIN_VARIANT (type
);
399 return build1 (ADDR_EXPR
, ptr_type_node
, get_typeid (type
));
402 typestring
= build_overload_name (type
, 1, 1);
403 exp
= combine_strings (build_string (strlen (typestring
)+1, typestring
));
404 return build1 (ADDR_EXPR
, ptr_type_node
, exp
);
407 /* Build a type value for use at runtime for a exp that is thrown or
408 matched against by the exception handling system. */
416 exp
= build_typeid (exp
);
417 return build1 (ADDR_EXPR
, ptr_type_node
, exp
);
419 return build_eh_type_type (TREE_TYPE (exp
));
422 /* Build up a call to __cp_pop_exception, to destroy the exception object
423 for the current catch block. HANDLER is either true or false, telling
424 the library whether or not it is being called from an exception handler;
425 if it is, it avoids destroying the object on rethrow. */
431 fn
= get_identifier ("__cp_pop_exception");
432 if (IDENTIFIER_GLOBAL_VALUE (fn
))
433 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
436 /* Declare void __cp_pop_exception (void *),
437 as defined in exception.cc. */
438 push_obstacks_nochange ();
439 end_temporary_allocation ();
442 build_function_type (void_type_node
, tree_cons
443 (NULL_TREE
, ptr_type_node
, void_list_node
)));
444 DECL_EXTERNAL (fn
) = 1;
445 TREE_PUBLIC (fn
) = 1;
446 DECL_ARTIFICIAL (fn
) = 1;
447 pushdecl_top_level (fn
);
448 make_function_rtl (fn
);
449 assemble_external (fn
);
453 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
454 cleanup
= lookup_name (get_identifier ("__exception_info"), 0);
455 cleanup
= build_function_call (fn
, expr_tree_cons
456 (NULL_TREE
, cleanup
, NULL_TREE
));
460 /* This routine creates the cleanup for the current exception. */
467 expand_expr (build_unary_op (PREINCREMENT_EXPR
, get_eh_handlers (), 1),
468 const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
470 yes
= suspend_momentary ();
471 /* All cleanups must last longer than normal. */
472 expand_decl_cleanup (NULL_TREE
, do_pop_exception ());
473 resume_momentary (yes
);
476 /* Build up a call to terminate on the function obstack, for use as an
477 exception handler. */
480 build_terminate_handler ()
482 int yes
= suspend_momentary ();
483 tree term
= build_function_call (Terminate
, NULL_TREE
);
484 resume_momentary (yes
);
488 /* call this to start a catch block. Typename is the typename, and identifier
489 is the variable to place the object in or NULL if the variable doesn't
490 matter. If typename is NULL, that means its a "catch (...)" or catch
491 everything. In that case we don't need to do any type checking.
492 (ie: it ends up as the "else" clause rather than an "else if" clause) */
495 expand_start_catch_block (declspecs
, declarator
)
496 tree declspecs
, declarator
;
499 tree decl
= NULL_TREE
;
502 if (processing_template_decl
)
506 decl
= grokdeclarator (declarator
, declspecs
, CATCHPARM
,
509 decl
= build_min_nt (DECL_STMT
, copy_to_permanent (declarator
),
510 copy_to_permanent (declspecs
),
520 /* Create a binding level for the eh_info and the exception object
523 expand_start_bindings (0);
525 false_label_rtx
= gen_label_rtx ();
526 push_label_entry (&false_label_stack
, false_label_rtx
, NULL_TREE
);
528 emit_line_note (input_filename
, lineno
);
534 decl
= grokdeclarator (declarator
, declspecs
, CATCHPARM
, 1, NULL_TREE
);
536 if (decl
== NULL_TREE
)
537 error ("invalid catch parameter");
543 rtx call_rtx
, return_value_rtx
;
546 /* Make sure we mark the catch param as used, otherwise we'll get
547 a warning about an unused ((anonymous)). */
548 TREE_USED (decl
) = 1;
550 /* Figure out the type that the initializer is. */
551 init_type
= TREE_TYPE (decl
);
552 if (TREE_CODE (init_type
) != REFERENCE_TYPE
553 && TREE_CODE (init_type
) != POINTER_TYPE
)
554 init_type
= build_reference_type (init_type
);
556 exp
= get_eh_value ();
558 /* Since pointers are passed by value, initialize a reference to
559 pointer catch parm with the address of the value slot. */
560 if (TREE_CODE (init_type
) == REFERENCE_TYPE
561 && TREE_CODE (TREE_TYPE (init_type
)) == POINTER_TYPE
)
562 exp
= build_unary_op (ADDR_EXPR
, exp
, 1);
564 exp
= expr_tree_cons (NULL_TREE
,
565 build_eh_type_type (TREE_TYPE (decl
)),
566 expr_tree_cons (NULL_TREE
,
568 expr_tree_cons (NULL_TREE
, exp
, NULL_TREE
)));
569 exp
= build_function_call (CatchMatch
, exp
);
570 call_rtx
= expand_call (exp
, NULL_RTX
, 0);
572 return_value_rtx
= hard_function_value (ptr_type_node
, exp
);
574 /* did the throw type match function return TRUE? */
575 emit_cmp_insn (return_value_rtx
, const0_rtx
, EQ
, NULL_RTX
,
576 GET_MODE (return_value_rtx
), 0, 0);
578 /* if it returned FALSE, jump over the catch block, else fall into it */
579 emit_jump_insn (gen_beq (false_label_rtx
));
583 /* Create a binding level for the parm. */
585 expand_start_bindings (0);
587 init
= convert_from_reference (make_tree (init_type
, call_rtx
));
589 /* If the constructor for the catch parm exits via an exception, we
590 must call terminate. See eh23.C. */
591 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl
)))
593 /* Generate the copy constructor call directly so we can wrap it.
594 See also expand_default_init. */
595 init
= ocp_convert (TREE_TYPE (decl
), init
,
596 CONV_IMPLICIT
|CONV_FORCE_TEMP
, 0);
597 init
= build (TRY_CATCH_EXPR
, TREE_TYPE (init
), init
,
598 build_terminate_handler ());
601 /* Let `cp_finish_decl' know that this initializer is ok. */
602 DECL_INITIAL (decl
) = init
;
603 decl
= pushdecl (decl
);
605 cp_finish_decl (decl
, init
, NULL_TREE
, 0, LOOKUP_ONLYCONVERTING
);
611 /* Create a binding level for the parm. */
613 expand_start_bindings (0);
615 /* Fall into the catch all section. */
618 init
= build_modify_expr (get_eh_caught (), NOP_EXPR
, integer_one_node
);
619 expand_expr (init
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
621 emit_line_note (input_filename
, lineno
);
626 /* Call this to end a catch block. Its responsible for emitting the
627 code to handle jumping back to the correct place, and for emitting
628 the label to jump to if this catch block didn't match. */
631 expand_end_catch_block ()
636 /* Cleanup the EH parameter. */
637 expand_end_bindings (getdecls (), kept_level_p (), 0);
638 poplevel (kept_level_p (), 1, 0);
640 /* Cleanup the EH object. */
641 expand_end_bindings (getdecls (), kept_level_p (), 0);
642 poplevel (kept_level_p (), 1, 0);
644 /* Fall to outside the try statement when done executing handler and
645 we fall off end of handler. This is jump Lresume in the
647 expand_goto (top_label_entry (&caught_return_label_stack
));
649 /* label we emit to jump to if this catch block didn't match. */
650 /* This the closing } in the `if (eq) {' of the documentation. */
651 emit_label (pop_label_entry (&false_label_stack
));
654 /* An exception spec is implemented more or less like:
659 void *p[] = { typeid(raises) };
660 __check_eh_spec (p, count);
663 __check_eh_spec in exception.cc handles all the details. */
666 expand_start_eh_spec ()
668 expand_start_try_stmts ();
672 expand_end_eh_spec (raises
)
675 tree tmp
, fn
, decl
, types
= NULL_TREE
;
678 expand_start_all_catch ();
679 expand_start_catch_block (NULL_TREE
, NULL_TREE
);
681 /* Build up an array of type_infos. */
682 for (; raises
&& TREE_VALUE (raises
); raises
= TREE_CHAIN (raises
))
684 types
= expr_tree_cons
685 (NULL_TREE
, build_eh_type_type (TREE_VALUE (raises
)), types
);
689 types
= build_nt (CONSTRUCTOR
, NULL_TREE
, types
);
690 TREE_HAS_CONSTRUCTOR (types
) = 1;
692 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
693 tmp
= build_array_type (const_ptr_type_node
, NULL_TREE
);
694 decl
= build_decl (VAR_DECL
, NULL_TREE
, tmp
);
695 DECL_ARTIFICIAL (decl
) = 1;
696 DECL_INITIAL (decl
) = types
;
697 cp_finish_decl (decl
, types
, NULL_TREE
, 0, 0);
699 decl
= decay_conversion (decl
);
701 fn
= get_identifier ("__check_eh_spec");
702 if (IDENTIFIER_GLOBAL_VALUE (fn
))
703 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
706 push_obstacks_nochange ();
707 end_temporary_allocation ();
710 (NULL_TREE
, integer_type_node
, tree_cons
711 (NULL_TREE
, TREE_TYPE (decl
), void_list_node
));
712 tmp
= build_function_type (void_type_node
, tmp
);
714 fn
= build_lang_decl (FUNCTION_DECL
, fn
, tmp
);
715 DECL_EXTERNAL (fn
) = 1;
716 TREE_PUBLIC (fn
) = 1;
717 DECL_ARTIFICIAL (fn
) = 1;
718 TREE_THIS_VOLATILE (fn
) = 1;
719 pushdecl_top_level (fn
);
720 make_function_rtl (fn
);
721 assemble_external (fn
);
725 tmp
= expr_tree_cons (NULL_TREE
, build_int_2 (count
, 0), expr_tree_cons
726 (NULL_TREE
, decl
, NULL_TREE
));
727 tmp
= build_call (fn
, TREE_TYPE (TREE_TYPE (fn
)), tmp
);
728 expand_expr (tmp
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
730 expand_end_catch_block ();
731 expand_end_all_catch ();
734 /* This is called to expand all the toplevel exception handling
735 finalization for a function. It should only be called once per
739 expand_exception_blocks ()
741 do_pending_stack_adjust ();
742 push_to_sequence (catch_clauses
);
743 expand_leftover_cleanups ();
744 do_pending_stack_adjust ();
745 catch_clauses
= get_insns ();
748 /* Do this after we expand leftover cleanups, so that the
749 expand_eh_region_end that expand_end_eh_spec does will match the
750 right expand_eh_region_start, and make sure it comes out before
751 the terminate protected region. */
752 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl
)))
754 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl
)));
755 do_pending_stack_adjust ();
756 push_to_sequence (catch_clauses
);
757 expand_leftover_cleanups ();
758 do_pending_stack_adjust ();
759 catch_clauses
= get_insns ();
765 rtx funcend
= gen_label_rtx ();
768 /* We cannot protect n regions this way if we must flow into the
769 EH region through the top of the region, as we have to with
770 the setjmp/longjmp approach. */
771 if (exceptions_via_longjmp
== 0)
772 expand_eh_region_start ();
774 emit_insns (catch_clauses
);
775 catch_clauses
= NULL_RTX
;
777 if (exceptions_via_longjmp
== 0)
778 expand_eh_region_end (build_terminate_handler ());
780 expand_leftover_cleanups ();
782 emit_label (funcend
);
789 static int counter
= 0;
790 int old_interface_unknown
= interface_unknown
;
795 push_cp_function_context (NULL_TREE
);
796 push_to_top_level ();
798 /* No need to mangle this. */
799 push_lang_context (lang_name_c
);
801 interface_unknown
= 1;
803 params
= void_list_node
;
804 /* tcf stands for throw clean function. */
805 sprintf (name
, "__tcf_%d", counter
++);
806 t
= make_call_declarator (get_identifier (name
), params
, NULL_TREE
,
808 start_function (decl_tree_cons (NULL_TREE
, get_identifier ("static"),
815 expand_start_bindings (0);
816 emit_line_note (input_filename
, lineno
);
818 interface_unknown
= old_interface_unknown
;
822 return current_function_decl
;
828 expand_end_bindings (getdecls (), 1, 0);
832 finish_function (lineno
, 0, 0);
834 pop_from_top_level ();
835 pop_cp_function_context (NULL_TREE
);
838 /* Return a pointer to a buffer for an exception object of type TYPE. */
841 alloc_eh_object (type
)
846 fn
= get_identifier ("__eh_alloc");
847 if (IDENTIFIER_GLOBAL_VALUE (fn
))
848 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
851 /* Declare __eh_alloc (size_t), as defined in exception.cc. */
853 push_obstacks_nochange ();
854 end_temporary_allocation ();
855 tmp
= tree_cons (NULL_TREE
, sizetype
, void_list_node
);
856 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
857 build_function_type (ptr_type_node
, tmp
));
858 DECL_EXTERNAL (fn
) = 1;
859 TREE_PUBLIC (fn
) = 1;
860 DECL_ARTIFICIAL (fn
) = 1;
861 pushdecl_top_level (fn
);
862 make_function_rtl (fn
);
863 assemble_external (fn
);
867 exp
= build_function_call (fn
, expr_tree_cons
868 (NULL_TREE
, size_in_bytes (type
), NULL_TREE
));
869 exp
= build1 (NOP_EXPR
, build_pointer_type (type
), exp
);
873 /* Expand a throw statement. This follows the following
876 1. Allocate space to save the current PC onto the stack.
877 2. Generate and emit a label and save its address into the
878 newly allocated stack space since we can't save the pc directly.
879 3. If this is the first call to throw in this function:
880 generate a label for the throw block
881 4. jump to the throw block label. */
888 static tree cleanup_type
;
896 tree cleanup
= NULL_TREE
, e
;
898 /* throw expression */
899 /* First, decay it. */
900 exp
= decay_conversion (exp
);
902 /* cleanup_type is void (*)(void *, int),
903 the internal type of a destructor. */
904 if (cleanup_type
== NULL_TREE
)
906 push_obstacks_nochange ();
907 end_temporary_allocation ();
908 cleanup_type
= build_pointer_type
910 (void_type_node
, tree_cons
911 (NULL_TREE
, ptr_type_node
, tree_cons
912 (NULL_TREE
, integer_type_node
, void_list_node
))));
916 if (TREE_CODE (TREE_TYPE (exp
)) == POINTER_TYPE
)
918 throw_type
= build_eh_type (exp
);
919 exp
= build_reinterpret_cast (ptr_type_node
, exp
);
925 /* OK, this is kind of wacky. The WP says that we call
928 when the exception handling mechanism, after completing
929 evaluation of the expression to be thrown but before the
930 exception is caught (_except.throw_), calls a user function
931 that exits via an uncaught exception.
933 So we have to protect the actual initialization of the
934 exception object with terminate(), but evaluate the expression
935 first. We also expand the call to __eh_alloc
936 first. Since there could be temps in the expression, we need
937 to handle that, too. */
939 expand_start_target_temps ();
942 /* Unfortunately, this doesn't work. */
943 preexpand_calls (exp
);
945 /* Store the throw expression into a temp. This can be less
946 efficient than storing it into the allocated space directly, but
947 oh well. To do this efficiently we would need to insinuate
948 ourselves into expand_call. */
949 if (TREE_SIDE_EFFECTS (exp
))
951 tree temp
= build (VAR_DECL
, TREE_TYPE (exp
));
952 DECL_ARTIFICIAL (temp
) = 1;
953 layout_decl (temp
, 0);
954 DECL_RTL (temp
) = assign_temp (TREE_TYPE (exp
), 2, 0, 1);
955 expand_expr (build (INIT_EXPR
, TREE_TYPE (exp
), temp
, exp
),
956 NULL_RTX
, VOIDmode
, 0);
957 expand_decl_cleanup (NULL_TREE
, maybe_build_cleanup (temp
));
962 /* Allocate the space for the exception. */
963 ptr
= save_expr (alloc_eh_object (TREE_TYPE (exp
)));
964 expand_expr (ptr
, const0_rtx
, VOIDmode
, 0);
966 expand_eh_region_start ();
968 object
= build_indirect_ref (ptr
, NULL_PTR
);
969 exp
= build_modify_expr (object
, INIT_EXPR
, exp
);
971 if (exp
== error_mark_node
)
972 error (" in thrown expression");
974 expand_expr (exp
, const0_rtx
, VOIDmode
, 0);
975 expand_eh_region_end (build_terminate_handler ());
976 expand_end_target_temps ();
978 throw_type
= build_eh_type (object
);
980 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object
)))
982 cleanup
= lookup_fnfields (TYPE_BINFO (TREE_TYPE (object
)),
984 cleanup
= TREE_VALUE (cleanup
);
986 mark_addressable (cleanup
);
987 /* Pretend it's a normal function. */
988 cleanup
= build1 (ADDR_EXPR
, cleanup_type
, cleanup
);
994 if (cleanup
== NULL_TREE
)
996 cleanup
= build_int_2 (0, 0);
997 TREE_TYPE (cleanup
) = cleanup_type
;
1000 fn
= get_identifier ("__cp_push_exception");
1001 if (IDENTIFIER_GLOBAL_VALUE (fn
))
1002 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
1005 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1006 as defined in exception.cc. */
1008 push_obstacks_nochange ();
1009 end_temporary_allocation ();
1011 (NULL_TREE
, ptr_type_node
, tree_cons
1012 (NULL_TREE
, ptr_type_node
, tree_cons
1013 (NULL_TREE
, cleanup_type
, void_list_node
)));
1014 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
1015 build_function_type (void_type_node
, tmp
));
1016 DECL_EXTERNAL (fn
) = 1;
1017 TREE_PUBLIC (fn
) = 1;
1018 DECL_ARTIFICIAL (fn
) = 1;
1019 pushdecl_top_level (fn
);
1020 make_function_rtl (fn
);
1021 assemble_external (fn
);
1025 e
= expr_tree_cons (NULL_TREE
, exp
, expr_tree_cons
1026 (NULL_TREE
, throw_type
, expr_tree_cons
1027 (NULL_TREE
, cleanup
, NULL_TREE
)));
1028 e
= build_function_call (fn
, e
);
1029 expand_expr (e
, const0_rtx
, VOIDmode
, 0);
1033 /* rethrow current exception; note that it's no longer caught. */
1035 tree fn
= get_identifier ("__uncatch_exception");
1036 if (IDENTIFIER_GLOBAL_VALUE (fn
))
1037 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
1040 /* Declare void __uncatch_exception (void)
1041 as defined in exception.cc. */
1042 push_obstacks_nochange ();
1043 end_temporary_allocation ();
1044 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
1045 build_function_type (void_type_node
,
1047 DECL_EXTERNAL (fn
) = 1;
1048 TREE_PUBLIC (fn
) = 1;
1049 DECL_ARTIFICIAL (fn
) = 1;
1050 pushdecl_top_level (fn
);
1051 make_function_rtl (fn
);
1052 assemble_external (fn
);
1056 exp
= build_function_call (fn
, NULL_TREE
);
1057 expand_expr (exp
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1060 expand_internal_throw ();
1063 /* Build a throw expression. */
1069 if (e
!= error_mark_node
)
1071 if (processing_template_decl
)
1072 return build_min (THROW_EXPR
, void_type_node
, e
);
1073 e
= build1 (THROW_EXPR
, void_type_node
, e
);
1074 TREE_SIDE_EFFECTS (e
) = 1;