1 /* Handle exceptional things in C++.
2 Copyright (C) 1989, 92-96, 1997 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 easy_expand_asm
PROTO((char *));
46 static void push_eh_cleanup
PROTO((void));
47 static void do_unwind
PROTO((rtx
));
48 static rtx do_function_call
PROTO((tree
, tree
, tree
));
49 static tree build_eh_type_type
PROTO((tree
));
50 static tree build_eh_type
PROTO((tree
));
51 static void expand_end_eh_spec
PROTO((tree
));
57 expand_asm (build_string (strlen (str
)+1, str
));
62 /* This is the startup, and finish stuff per exception table. */
64 /* XXX - Tad: exception handling section */
65 #ifndef EXCEPT_SECTION_ASM_OP
66 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
69 #ifdef EXCEPT_SECTION_ASM_OP
73 void *exception_handler
;
75 #endif /* EXCEPT_SECTION_ASM_OP */
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 is the 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 /* Cheesyness to save some typing. Returns the return value rtx. */
196 do_function_call (func
, params
, return_type
)
197 tree func
, params
, return_type
;
200 func_call
= build_function_call (func
, params
);
201 expand_call (func_call
, NULL_RTX
, 0);
202 if (return_type
!= NULL_TREE
)
203 return hard_function_value (return_type
, func_call
);
207 /* ========================================================================= */
209 /* sets up all the global eh stuff that needs to be initialized at the
210 start of compilation.
213 - Setting up all the function call trees. */
216 init_exception_processing ()
221 tree vtype
= build_function_type (void_type_node
, void_list_node
);
223 Terminate
= auto_function (get_identifier ("terminate"),
224 vtype
, NOT_BUILT_IN
);
225 TREE_THIS_VOLATILE (Terminate
) = 1;
227 push_lang_context (lang_name_c
);
230 = builtin_function (flag_rtti
231 ? "__throw_type_match_rtti"
232 : "__throw_type_match",
233 build_function_type (ptr_type_node
,
234 tree_cons (NULL_TREE
, const_ptr_type_node
,
235 tree_cons (NULL_TREE
, const_ptr_type_node
,
236 tree_cons (NULL_TREE
, ptr_type_node
,
238 NOT_BUILT_IN
, NULL_PTR
);
240 = builtin_function ("__find_first_exception_table_match",
241 build_function_type (ptr_type_node
,
242 tree_cons (NULL_TREE
, ptr_type_node
,
244 NOT_BUILT_IN
, NULL_PTR
);
246 = builtin_function ("__unwind_function",
247 build_function_type (void_type_node
,
248 tree_cons (NULL_TREE
, ptr_type_node
,
250 NOT_BUILT_IN
, NULL_PTR
);
254 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
255 be protected with __terminate. */
256 protect_cleanup_actions_with_terminate
= 1;
259 /* Retrieve a pointer to the cp_eh_info node for the current exception. */
266 fn
= get_identifier ("__cp_exception_info");
267 if (IDENTIFIER_GLOBAL_VALUE (fn
))
268 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
273 /* Declare cp_eh_info * __cp_exception_info (void),
274 as defined in exception.cc. */
275 push_obstacks_nochange ();
276 end_temporary_allocation ();
278 /* struct cp_eh_info. This must match exception.cc. Note that this
279 type is not pushed anywhere. */
280 t
= make_lang_type (RECORD_TYPE
);
281 fields
[0] = build_lang_field_decl (FIELD_DECL
, get_identifier ("value"),
283 fields
[1] = build_lang_field_decl (FIELD_DECL
, get_identifier ("type"),
285 fields
[2] = build_lang_field_decl
286 (FIELD_DECL
, get_identifier ("cleanup"),
287 build_pointer_type (build_function_type
288 (ptr_type_node
, tree_cons
289 (NULL_TREE
, ptr_type_node
, void_list_node
))));
290 fields
[3] = build_lang_field_decl (FIELD_DECL
, get_identifier ("caught"),
292 fields
[4] = build_lang_field_decl (FIELD_DECL
, get_identifier ("next"),
293 build_pointer_type (t
));
294 fields
[5] = build_lang_field_decl
295 (FIELD_DECL
, get_identifier ("handlers"), long_integer_type_node
);
296 /* N.B.: The fourth field LEN is expected to be
297 the number of fields - 1, not the total number of fields. */
298 finish_builtin_type (t
, "cp_eh_info", fields
, 5, ptr_type_node
);
299 t
= build_pointer_type (t
);
301 /* And now the function. */
302 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
303 build_function_type (t
, void_list_node
));
304 DECL_EXTERNAL (fn
) = 1;
305 TREE_PUBLIC (fn
) = 1;
306 DECL_ARTIFICIAL (fn
) = 1;
307 pushdecl_top_level (fn
);
308 make_function_rtl (fn
);
309 assemble_external (fn
);
312 return build_function_call (fn
, NULL_TREE
);
315 /* Retrieve a pointer to the cp_eh_info node for the current exception
316 and save it in the current binding level. */
321 tree decl
, fn
= call_eh_info ();
323 /* Remember the pointer to the current exception info; it won't change
324 during this catch block. */
325 decl
= build_decl (VAR_DECL
, get_identifier ("__exception_info"),
327 DECL_ARTIFICIAL (decl
) = 1;
328 DECL_INITIAL (decl
) = fn
;
329 decl
= pushdecl (decl
);
330 cp_finish_decl (decl
, fn
, NULL_TREE
, 0, 0);
333 /* Returns a reference to the cp_eh_info node for the current exception. */
338 /* Look for the pointer pushed in push_eh_info. */
339 tree t
= lookup_name (get_identifier ("__exception_info"), 0);
340 return build_indirect_ref (t
, NULL_PTR
);
343 /* Returns a reference to the current exception object. */
348 return build_component_ref (get_eh_info (), get_identifier ("value"),
352 /* Returns a reference to the current exception type. */
357 return build_component_ref (get_eh_info (), get_identifier ("type"),
361 /* Returns a reference to whether or not the current exception
367 return build_component_ref (get_eh_info (), get_identifier ("caught"),
371 /* Returns a reference to whether or not the current exception
377 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
381 /* Build a type value for use at runtime for a type that is matched
382 against by the exception handling system. */
385 build_eh_type_type (type
)
391 if (type
== error_mark_node
)
392 return error_mark_node
;
394 /* peel back references, so they match. */
395 if (TREE_CODE (type
) == REFERENCE_TYPE
)
396 type
= TREE_TYPE (type
);
398 /* Peel off cv qualifiers. */
399 type
= TYPE_MAIN_VARIANT (type
);
403 return build1 (ADDR_EXPR
, ptr_type_node
, get_typeid (type
));
406 typestring
= build_overload_name (type
, 1, 1);
407 exp
= combine_strings (build_string (strlen (typestring
)+1, typestring
));
408 return build1 (ADDR_EXPR
, ptr_type_node
, exp
);
411 /* Build a type value for use at runtime for a exp that is thrown or
412 matched against by the exception handling system. */
420 exp
= build_typeid (exp
);
421 return build1 (ADDR_EXPR
, ptr_type_node
, exp
);
423 return build_eh_type_type (TREE_TYPE (exp
));
426 /* Build up a call to __cp_pop_exception, to destroy the exception object
427 for the current catch block. HANDLER is either true or false, telling
428 the library whether or not it is being called from an exception handler;
429 if it is, it avoids destroying the object on rethrow. */
435 fn
= get_identifier ("__cp_pop_exception");
436 if (IDENTIFIER_GLOBAL_VALUE (fn
))
437 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
440 /* Declare void __cp_pop_exception (void *),
441 as defined in exception.cc. */
442 push_obstacks_nochange ();
443 end_temporary_allocation ();
446 build_function_type (void_type_node
, tree_cons
447 (NULL_TREE
, ptr_type_node
, void_list_node
)));
448 DECL_EXTERNAL (fn
) = 1;
449 TREE_PUBLIC (fn
) = 1;
450 DECL_ARTIFICIAL (fn
) = 1;
451 pushdecl_top_level (fn
);
452 make_function_rtl (fn
);
453 assemble_external (fn
);
457 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
458 cleanup
= lookup_name (get_identifier ("__exception_info"), 0);
459 cleanup
= build_function_call (fn
, expr_tree_cons
460 (NULL_TREE
, cleanup
, NULL_TREE
));
464 /* This routine creates the cleanup for the current exception. */
471 expand_expr (build_unary_op (PREINCREMENT_EXPR
, get_eh_handlers (), 1),
472 const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
474 yes
= suspend_momentary ();
475 /* All cleanups must last longer than normal. */
476 expand_decl_cleanup (NULL_TREE
, do_pop_exception ());
477 resume_momentary (yes
);
480 /* Build up a call to terminate on the function obstack, for use as an
481 exception handler. */
484 build_terminate_handler ()
486 int yes
= suspend_momentary ();
487 tree term
= build_function_call (Terminate
, NULL_TREE
);
488 resume_momentary (yes
);
492 /* call this to start a catch block. Typename is the typename, and identifier
493 is the variable to place the object in or NULL if the variable doesn't
494 matter. If typename is NULL, that means its a "catch (...)" or catch
495 everything. In that case we don't need to do any type checking.
496 (ie: it ends up as the "else" clause rather than an "else if" clause) */
499 expand_start_catch_block (declspecs
, declarator
)
500 tree declspecs
, declarator
;
503 tree decl
= NULL_TREE
;
506 if (processing_template_decl
)
510 decl
= grokdeclarator (declarator
, declspecs
, CATCHPARM
,
513 decl
= build_min_nt (DECL_STMT
, copy_to_permanent (declarator
),
514 copy_to_permanent (declspecs
),
524 /* Create a binding level for the eh_info and the exception object
527 expand_start_bindings (0);
529 false_label_rtx
= gen_label_rtx ();
530 push_label_entry (&false_label_stack
, false_label_rtx
, NULL_TREE
);
532 emit_line_note (input_filename
, lineno
);
538 decl
= grokdeclarator (declarator
, declspecs
, CATCHPARM
, 1, NULL_TREE
);
540 if (decl
== NULL_TREE
)
541 error ("invalid catch parameter");
547 rtx call_rtx
, return_value_rtx
;
550 /* Make sure we mark the catch param as used, otherwise we'll get
551 a warning about an unused ((anonymous)). */
552 TREE_USED (decl
) = 1;
554 /* Figure out the type that the initializer is. */
555 init_type
= TREE_TYPE (decl
);
556 if (TREE_CODE (init_type
) != REFERENCE_TYPE
557 && TREE_CODE (init_type
) != POINTER_TYPE
)
558 init_type
= build_reference_type (init_type
);
560 exp
= get_eh_value ();
562 /* Since pointers are passed by value, initialize a reference to
563 pointer catch parm with the address of the value slot. */
564 if (TREE_CODE (init_type
) == REFERENCE_TYPE
565 && TREE_CODE (TREE_TYPE (init_type
)) == POINTER_TYPE
)
566 exp
= build_unary_op (ADDR_EXPR
, exp
, 1);
568 exp
= expr_tree_cons (NULL_TREE
,
569 build_eh_type_type (TREE_TYPE (decl
)),
570 expr_tree_cons (NULL_TREE
,
572 expr_tree_cons (NULL_TREE
, exp
, NULL_TREE
)));
573 exp
= build_function_call (CatchMatch
, exp
);
574 call_rtx
= expand_call (exp
, NULL_RTX
, 0);
576 return_value_rtx
= hard_function_value (ptr_type_node
, exp
);
578 /* did the throw type match function return TRUE? */
579 emit_cmp_insn (return_value_rtx
, const0_rtx
, EQ
, NULL_RTX
,
580 GET_MODE (return_value_rtx
), 0, 0);
582 /* if it returned FALSE, jump over the catch block, else fall into it */
583 emit_jump_insn (gen_beq (false_label_rtx
));
587 /* Create a binding level for the parm. */
589 expand_start_bindings (0);
591 init
= convert_from_reference (make_tree (init_type
, call_rtx
));
593 /* If the constructor for the catch parm exits via an exception, we
594 must call terminate. See eh23.C. */
595 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl
)))
597 /* Generate the copy constructor call directly so we can wrap it.
598 See also expand_default_init. */
599 init
= ocp_convert (TREE_TYPE (decl
), init
,
600 CONV_IMPLICIT
|CONV_FORCE_TEMP
, 0);
601 init
= build (TRY_CATCH_EXPR
, TREE_TYPE (init
), init
,
602 build_terminate_handler ());
605 /* Let `cp_finish_decl' know that this initializer is ok. */
606 DECL_INITIAL (decl
) = init
;
607 decl
= pushdecl (decl
);
609 cp_finish_decl (decl
, init
, NULL_TREE
, 0, LOOKUP_ONLYCONVERTING
);
615 /* Create a binding level for the parm. */
617 expand_start_bindings (0);
619 /* Fall into the catch all section. */
622 init
= build_modify_expr (get_eh_caught (), NOP_EXPR
, integer_one_node
);
623 expand_expr (init
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
625 emit_line_note (input_filename
, lineno
);
630 /* Call this to end a catch block. Its responsible for emitting the
631 code to handle jumping back to the correct place, and for emitting
632 the label to jump to if this catch block didn't match. */
635 expand_end_catch_block ()
640 /* Cleanup the EH parameter. */
641 expand_end_bindings (getdecls (), kept_level_p (), 0);
642 poplevel (kept_level_p (), 1, 0);
644 /* Cleanup the EH object. */
645 expand_end_bindings (getdecls (), kept_level_p (), 0);
646 poplevel (kept_level_p (), 1, 0);
648 /* Fall to outside the try statement when done executing handler and
649 we fall off end of handler. This is jump Lresume in the
651 expand_goto (top_label_entry (&caught_return_label_stack
));
653 /* label we emit to jump to if this catch block didn't match. */
654 /* This the closing } in the `if (eq) {' of the documentation. */
655 emit_label (pop_label_entry (&false_label_stack
));
658 /* unwind the stack. */
661 do_unwind (inner_throw_label
)
662 rtx inner_throw_label
;
664 #if defined (SPARC_STACK_ALIGN) /* was sparc */
665 /* This doesn't work for the flat model sparc, nor does it need to
666 as the default unwinder is only used to unwind non-flat frames. */
672 /* Call to __builtin_return_address. */
673 params
= expr_tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
674 fcall
= build_function_call (builtin_return_address_fndecl
, params
);
675 next_pc
= expand_expr (fcall
, NULL_RTX
, Pmode
, 0);
676 /* In the return, the new pc is pc+8, as the value coming in is
677 really the address of the call insn, not the next insn. */
678 temp
= gen_reg_rtx (Pmode
);
679 emit_move_insn (temp
, inner_throw_label
);
680 emit_move_insn (next_pc
, plus_constant (temp
, -8));
681 emit_insn (gen_rtx (USE
, VOIDmode
, gen_rtx (REG
, SImode
, 31)));
682 easy_expand_asm ("ret");
683 easy_expand_asm ("restore");
686 #if defined (ARM_FRAME_RTX) /* was __arm */
687 if (flag_omit_frame_pointer
)
688 sorry ("this implementation of exception handling requires a frame pointer");
690 emit_move_insn (stack_pointer_rtx
,
691 gen_rtx (MEM
, Pmode
, plus_constant (hard_frame_pointer_rtx
, -8)));
692 emit_move_insn (hard_frame_pointer_rtx
,
693 gen_rtx (MEM
, Pmode
, plus_constant (hard_frame_pointer_rtx
, -12)));
695 #if defined (TARGET_88000) /* was m88k */
696 rtx temp_frame
= frame_pointer_rtx
;
698 temp_frame
= memory_address (Pmode
, temp_frame
);
699 temp_frame
= copy_to_reg (gen_rtx (MEM
, Pmode
, temp_frame
));
701 /* hopefully this will successfully pop the frame! */
702 emit_move_insn (frame_pointer_rtx
, temp_frame
);
703 emit_move_insn (stack_pointer_rtx
, frame_pointer_rtx
);
704 emit_move_insn (arg_pointer_rtx
, frame_pointer_rtx
);
705 emit_insn (gen_add2_insn (stack_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
706 (HOST_WIDE_INT
)m88k_debugger_offset (stack_pointer_rtx
, 0))));
709 emit_insn (gen_add2_insn (arg_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
710 -(HOST_WIDE_INT
)m88k_debugger_offset (arg_pointer_rtx
, 0))));
712 emit_move_insn (stack_pointer_rtx
, arg_pointer_rtx
);
714 emit_insn (gen_add2_insn (stack_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
715 (HOST_WIDE_INT
)m88k_debugger_offset (arg_pointer_rtx
, 0))));
718 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
724 /* I would like to do this here, but the move below doesn't seem to work. */
725 /* Call to __builtin_return_address. */
726 params
= expr_tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
727 fcall
= build_function_call (builtin_return_address_fndecl
, params
);
728 next_pc
= expand_expr (fcall
, NULL_RTX
, Pmode
, 0);
730 emit_move_insn (next_pc
, inner_throw_label
);
731 /* So, for now, just pass throw label to stack unwinder. */
733 params
= expr_tree_cons (NULL_TREE
, make_tree (ptr_type_node
,
734 inner_throw_label
), NULL_TREE
);
736 do_function_call (Unwind
, params
, NULL_TREE
);
742 /* An exception spec is implemented more or less like:
747 void *p[] = { typeid(raises) };
748 __check_eh_spec (p, count);
751 __check_eh_spec in exception.cc handles all the details. */
754 expand_start_eh_spec ()
756 expand_start_try_stmts ();
760 expand_end_eh_spec (raises
)
763 tree tmp
, fn
, decl
, types
= NULL_TREE
;
766 expand_start_all_catch ();
767 expand_start_catch_block (NULL_TREE
, NULL_TREE
);
769 /* Build up an array of type_infos. */
770 for (; raises
&& TREE_VALUE (raises
); raises
= TREE_CHAIN (raises
))
772 types
= expr_tree_cons
773 (NULL_TREE
, build_eh_type_type (TREE_VALUE (raises
)), types
);
777 types
= build_nt (CONSTRUCTOR
, NULL_TREE
, types
);
778 TREE_HAS_CONSTRUCTOR (types
) = 1;
780 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
781 tmp
= build_array_type (const_ptr_type_node
, NULL_TREE
);
782 decl
= build_decl (VAR_DECL
, NULL_TREE
, tmp
);
783 DECL_ARTIFICIAL (decl
) = 1;
784 DECL_INITIAL (decl
) = types
;
785 cp_finish_decl (decl
, types
, NULL_TREE
, 0, 0);
787 decl
= decay_conversion (decl
);
789 fn
= get_identifier ("__check_eh_spec");
790 if (IDENTIFIER_GLOBAL_VALUE (fn
))
791 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
794 push_obstacks_nochange ();
795 end_temporary_allocation ();
798 (NULL_TREE
, integer_type_node
, tree_cons
799 (NULL_TREE
, TREE_TYPE (decl
), void_list_node
));
800 tmp
= build_function_type (void_type_node
, tmp
);
802 fn
= build_lang_decl (FUNCTION_DECL
, fn
, tmp
);
803 DECL_EXTERNAL (fn
) = 1;
804 TREE_PUBLIC (fn
) = 1;
805 DECL_ARTIFICIAL (fn
) = 1;
806 TREE_THIS_VOLATILE (fn
) = 1;
807 pushdecl_top_level (fn
);
808 make_function_rtl (fn
);
809 assemble_external (fn
);
813 tmp
= expr_tree_cons (NULL_TREE
, build_int_2 (count
, 0), expr_tree_cons
814 (NULL_TREE
, decl
, NULL_TREE
));
815 tmp
= build_call (fn
, TREE_TYPE (TREE_TYPE (fn
)), tmp
);
816 expand_expr (tmp
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
818 expand_end_catch_block ();
819 expand_end_all_catch ();
822 /* This is called to expand all the toplevel exception handling
823 finalization for a function. It should only be called once per
827 expand_exception_blocks ()
829 do_pending_stack_adjust ();
830 push_to_sequence (catch_clauses
);
831 expand_leftover_cleanups ();
832 do_pending_stack_adjust ();
833 catch_clauses
= get_insns ();
836 /* Do this after we expand leftover cleanups, so that the
837 expand_eh_region_end that expand_end_eh_spec does will match the
838 right expand_eh_region_start, and make sure it comes out before
839 the terminate protected region. */
840 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl
)))
842 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl
)));
843 do_pending_stack_adjust ();
844 push_to_sequence (catch_clauses
);
845 expand_leftover_cleanups ();
846 do_pending_stack_adjust ();
847 catch_clauses
= get_insns ();
853 rtx funcend
= gen_label_rtx ();
856 /* We cannot protect n regions this way if we must flow into the
857 EH region through the top of the region, as we have to with
858 the setjmp/longjmp approach. */
859 if (exceptions_via_longjmp
== 0)
860 expand_eh_region_start ();
862 emit_insns (catch_clauses
);
863 catch_clauses
= NULL_RTX
;
865 if (exceptions_via_longjmp
== 0)
866 expand_eh_region_end (build_terminate_handler ());
868 expand_leftover_cleanups ();
870 emit_label (funcend
);
877 static int counter
= 0;
878 int old_interface_unknown
= interface_unknown
;
883 push_cp_function_context (NULL_TREE
);
884 push_to_top_level ();
886 /* No need to mangle this. */
887 push_lang_context (lang_name_c
);
889 interface_unknown
= 1;
891 params
= void_list_node
;
892 /* tcf stands for throw clean function. */
893 sprintf (name
, "__tcf_%d", counter
++);
894 t
= make_call_declarator (get_identifier (name
), params
, NULL_TREE
,
896 start_function (decl_tree_cons (NULL_TREE
, get_identifier ("static"),
903 expand_start_bindings (0);
904 emit_line_note (input_filename
, lineno
);
906 interface_unknown
= old_interface_unknown
;
910 return current_function_decl
;
916 expand_end_bindings (getdecls (), 1, 0);
920 finish_function (lineno
, 0, 0);
922 pop_from_top_level ();
923 pop_cp_function_context (NULL_TREE
);
926 /* Return a pointer to a buffer for an exception object of type TYPE. */
929 alloc_eh_object (type
)
934 fn
= get_identifier ("__eh_alloc");
935 if (IDENTIFIER_GLOBAL_VALUE (fn
))
936 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
939 /* Declare __eh_alloc (size_t), as defined in exception.cc. */
941 push_obstacks_nochange ();
942 end_temporary_allocation ();
943 tmp
= tree_cons (NULL_TREE
, sizetype
, void_list_node
);
944 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
945 build_function_type (ptr_type_node
, tmp
));
946 DECL_EXTERNAL (fn
) = 1;
947 TREE_PUBLIC (fn
) = 1;
948 DECL_ARTIFICIAL (fn
) = 1;
949 pushdecl_top_level (fn
);
950 make_function_rtl (fn
);
951 assemble_external (fn
);
955 exp
= build_function_call (fn
, expr_tree_cons
956 (NULL_TREE
, size_in_bytes (type
), NULL_TREE
));
957 exp
= build1 (NOP_EXPR
, build_pointer_type (type
), exp
);
961 /* Expand a throw statement. This follows the following
964 1. Allocate space to save the current PC onto the stack.
965 2. Generate and emit a label and save its address into the
966 newly allocated stack space since we can't save the pc directly.
967 3. If this is the first call to throw in this function:
968 generate a label for the throw block
969 4. jump to the throw block label. */
977 static tree cleanup_type
;
985 tree cleanup
= NULL_TREE
, e
;
987 /* throw expression */
988 /* First, decay it. */
989 exp
= decay_conversion (exp
);
991 /* cleanup_type is void (*)(void *, int),
992 the internal type of a destructor. */
993 if (cleanup_type
== NULL_TREE
)
995 push_obstacks_nochange ();
996 end_temporary_allocation ();
997 cleanup_type
= build_pointer_type
999 (void_type_node
, tree_cons
1000 (NULL_TREE
, ptr_type_node
, tree_cons
1001 (NULL_TREE
, integer_type_node
, void_list_node
))));
1005 if (TREE_CODE (TREE_TYPE (exp
)) == POINTER_TYPE
)
1007 throw_type
= build_eh_type (exp
);
1008 exp
= build_reinterpret_cast (ptr_type_node
, exp
);
1014 /* OK, this is kind of wacky. The WP says that we call
1017 when the exception handling mechanism, after completing
1018 evaluation of the expression to be thrown but before the
1019 exception is caught (_except.throw_), calls a user function
1020 that exits via an uncaught exception.
1022 So we have to protect the actual initialization of the
1023 exception object with terminate(), but evaluate the expression
1024 first. We also expand the call to __eh_alloc
1025 first. Since there could be temps in the expression, we need
1026 to handle that, too. */
1028 expand_start_target_temps ();
1031 /* Unfortunately, this doesn't work. */
1032 preexpand_calls (exp
);
1034 /* Store the throw expression into a temp. This can be less
1035 efficient than storing it into the allocated space directly, but
1036 oh well. To do this efficiently we would need to insinuate
1037 ourselves into expand_call. */
1038 if (TREE_SIDE_EFFECTS (exp
))
1040 tree temp
= build (VAR_DECL
, TREE_TYPE (exp
));
1041 DECL_ARTIFICIAL (temp
) = 1;
1042 layout_decl (temp
, 0);
1043 DECL_RTL (temp
) = assign_temp (TREE_TYPE (exp
), 2, 0, 1);
1044 expand_expr (build (INIT_EXPR
, TREE_TYPE (exp
), temp
, exp
),
1045 NULL_RTX
, VOIDmode
, 0);
1046 expand_decl_cleanup (NULL_TREE
, maybe_build_cleanup (temp
));
1051 /* Allocate the space for the exception. */
1052 ptr
= save_expr (alloc_eh_object (TREE_TYPE (exp
)));
1053 expand_expr (ptr
, const0_rtx
, VOIDmode
, 0);
1055 expand_eh_region_start ();
1057 object
= build_indirect_ref (ptr
, NULL_PTR
);
1058 exp
= build_modify_expr (object
, INIT_EXPR
, exp
);
1060 if (exp
== error_mark_node
)
1061 error (" in thrown expression");
1063 expand_expr (exp
, const0_rtx
, VOIDmode
, 0);
1064 expand_eh_region_end (build_terminate_handler ());
1065 expand_end_target_temps ();
1067 throw_type
= build_eh_type (object
);
1069 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object
)))
1071 cleanup
= lookup_fnfields (TYPE_BINFO (TREE_TYPE (object
)),
1072 dtor_identifier
, 0);
1073 cleanup
= TREE_VALUE (cleanup
);
1074 mark_used (cleanup
);
1075 mark_addressable (cleanup
);
1076 /* Pretend it's a normal function. */
1077 cleanup
= build1 (ADDR_EXPR
, cleanup_type
, cleanup
);
1083 if (cleanup
== NULL_TREE
)
1085 cleanup
= build_int_2 (0, 0);
1086 TREE_TYPE (cleanup
) = cleanup_type
;
1089 fn
= get_identifier ("__cp_push_exception");
1090 if (IDENTIFIER_GLOBAL_VALUE (fn
))
1091 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
1094 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1095 as defined in exception.cc. */
1097 push_obstacks_nochange ();
1098 end_temporary_allocation ();
1100 (NULL_TREE
, ptr_type_node
, tree_cons
1101 (NULL_TREE
, ptr_type_node
, tree_cons
1102 (NULL_TREE
, cleanup_type
, void_list_node
)));
1103 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
1104 build_function_type (void_type_node
, tmp
));
1105 DECL_EXTERNAL (fn
) = 1;
1106 TREE_PUBLIC (fn
) = 1;
1107 DECL_ARTIFICIAL (fn
) = 1;
1108 pushdecl_top_level (fn
);
1109 make_function_rtl (fn
);
1110 assemble_external (fn
);
1114 e
= expr_tree_cons (NULL_TREE
, exp
, expr_tree_cons
1115 (NULL_TREE
, throw_type
, expr_tree_cons
1116 (NULL_TREE
, cleanup
, NULL_TREE
)));
1117 e
= build_function_call (fn
, e
);
1118 expand_expr (e
, const0_rtx
, VOIDmode
, 0);
1122 /* rethrow current exception; note that it's no longer caught. */
1124 tree fn
= get_identifier ("__uncatch_exception");
1125 if (IDENTIFIER_GLOBAL_VALUE (fn
))
1126 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
1129 /* Declare void __uncatch_exception (void)
1130 as defined in exception.cc. */
1131 push_obstacks_nochange ();
1132 end_temporary_allocation ();
1133 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
1134 build_function_type (void_type_node
,
1136 DECL_EXTERNAL (fn
) = 1;
1137 TREE_PUBLIC (fn
) = 1;
1138 DECL_ARTIFICIAL (fn
) = 1;
1139 pushdecl_top_level (fn
);
1140 make_function_rtl (fn
);
1141 assemble_external (fn
);
1145 exp
= build_function_call (fn
, NULL_TREE
);
1146 expand_expr (exp
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1149 expand_internal_throw ();
1152 /* Build a throw expression. */
1158 if (e
!= error_mark_node
)
1160 if (processing_template_decl
)
1161 return build_min (THROW_EXPR
, void_type_node
, e
);
1162 e
= build1 (THROW_EXPR
, void_type_node
, e
);
1163 TREE_SIDE_EFFECTS (e
) = 1;