1 /* Handle exceptional things in C++.
2 Copyright (C) 1989, 92-95, 1996 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 /* Holds the pc for doing "throw" */
189 static tree saved_pc
;
191 extern int throw_used
;
192 extern rtx catch_clauses
;
193 extern tree const_ptr_type_node
;
195 /* ========================================================================= */
197 /* Cheesyness to save some typing. Returns the return value rtx. */
200 do_function_call (func
, params
, return_type
)
201 tree func
, params
, return_type
;
204 func_call
= build_function_call (func
, params
);
205 expand_call (func_call
, NULL_RTX
, 0);
206 if (return_type
!= NULL_TREE
)
207 return hard_function_value (return_type
, func_call
);
211 /* ========================================================================= */
213 /* sets up all the global eh stuff that needs to be initialized at the
214 start of compilation.
217 - Setting up all the function call trees. */
220 init_exception_processing ()
225 tree vtype
= build_function_type (void_type_node
, void_list_node
);
227 Terminate
= auto_function (get_identifier ("terminate"),
228 vtype
, NOT_BUILT_IN
);
229 TREE_THIS_VOLATILE (Terminate
) = 1;
231 push_lang_context (lang_name_c
);
234 = builtin_function (flag_rtti
235 ? "__throw_type_match_rtti"
236 : "__throw_type_match",
237 build_function_type (ptr_type_node
,
238 tree_cons (NULL_TREE
, const_ptr_type_node
,
239 tree_cons (NULL_TREE
, const_ptr_type_node
,
240 tree_cons (NULL_TREE
, ptr_type_node
,
242 NOT_BUILT_IN
, NULL_PTR
);
244 = builtin_function ("__find_first_exception_table_match",
245 build_function_type (ptr_type_node
,
246 tree_cons (NULL_TREE
, ptr_type_node
,
248 NOT_BUILT_IN
, NULL_PTR
);
250 = builtin_function ("__unwind_function",
251 build_function_type (void_type_node
,
252 tree_cons (NULL_TREE
, ptr_type_node
,
254 NOT_BUILT_IN
, NULL_PTR
);
258 d
= build_decl (VAR_DECL
, get_identifier ("__eh_pc"), ptr_type_node
);
260 DECL_EXTERNAL (d
) = 1;
261 DECL_ARTIFICIAL (d
) = 1;
262 cp_finish_decl (d
, NULL_TREE
, NULL_TREE
, 0, 0);
265 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
266 be protected with __terminate. */
267 protect_cleanup_actions_with_terminate
= 1;
270 /* Retrieve a pointer to the cp_eh_info node for the current exception. */
277 fn
= get_identifier ("__cp_exception_info");
278 if (IDENTIFIER_GLOBAL_VALUE (fn
))
279 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
284 /* Declare cp_eh_info * __cp_exception_info (void),
285 as defined in exception.cc. */
286 push_obstacks_nochange ();
287 end_temporary_allocation ();
289 /* struct cp_eh_info. This must match exception.cc. Note that this
290 type is not pushed anywhere. */
291 t
= make_lang_type (RECORD_TYPE
);
292 fields
[0] = build_lang_field_decl (FIELD_DECL
, get_identifier ("value"),
294 fields
[1] = build_lang_field_decl (FIELD_DECL
, get_identifier ("type"),
296 fields
[2] = build_lang_field_decl
297 (FIELD_DECL
, get_identifier ("cleanup"),
298 build_pointer_type (build_function_type
299 (ptr_type_node
, tree_cons
300 (NULL_TREE
, ptr_type_node
, void_list_node
))));
301 fields
[3] = build_lang_field_decl (FIELD_DECL
, get_identifier ("caught"),
303 fields
[4] = build_lang_field_decl (FIELD_DECL
, get_identifier ("next"),
304 build_pointer_type (t
));
305 fields
[5] = build_lang_field_decl
306 (FIELD_DECL
, get_identifier ("handlers"), long_integer_type_node
);
307 /* N.B.: The fourth field LEN is expected to be
308 the number of fields - 1, not the total number of fields. */
309 finish_builtin_type (t
, "cp_eh_info", fields
, 5, ptr_type_node
);
310 t
= build_pointer_type (t
);
312 /* And now the function. */
313 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
314 build_function_type (t
, void_list_node
));
315 DECL_EXTERNAL (fn
) = 1;
316 TREE_PUBLIC (fn
) = 1;
317 DECL_ARTIFICIAL (fn
) = 1;
318 pushdecl_top_level (fn
);
319 make_function_rtl (fn
);
320 assemble_external (fn
);
323 return build_function_call (fn
, NULL_TREE
);
326 /* Retrieve a pointer to the cp_eh_info node for the current exception
327 and save it in the current binding level. */
332 tree decl
, fn
= call_eh_info ();
334 /* Remember the pointer to the current exception info; it won't change
335 during this catch block. */
336 decl
= build_decl (VAR_DECL
, get_identifier ("__exception_info"),
338 DECL_ARTIFICIAL (decl
) = 1;
339 DECL_INITIAL (decl
) = fn
;
340 decl
= pushdecl (decl
);
341 cp_finish_decl (decl
, fn
, NULL_TREE
, 0, 0);
344 /* Returns a reference to the cp_eh_info node for the current exception. */
349 /* Look for the pointer pushed in push_eh_info. */
350 tree t
= lookup_name (get_identifier ("__exception_info"), 0);
351 return build_indirect_ref (t
, NULL_PTR
);
354 /* Returns a reference to the current exception object. */
359 return build_component_ref (get_eh_info (), get_identifier ("value"),
363 /* Returns a reference to the current exception type. */
368 return build_component_ref (get_eh_info (), get_identifier ("type"),
372 /* Returns a reference to whether or not the current exception
378 return build_component_ref (get_eh_info (), get_identifier ("caught"),
382 /* Returns a reference to whether or not the current exception
388 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
392 /* Build a type value for use at runtime for a type that is matched
393 against by the exception handling system. */
396 build_eh_type_type (type
)
402 if (type
== error_mark_node
)
403 return error_mark_node
;
405 /* peel back references, so they match. */
406 if (TREE_CODE (type
) == REFERENCE_TYPE
)
407 type
= TREE_TYPE (type
);
409 /* Peel off cv qualifiers. */
410 type
= TYPE_MAIN_VARIANT (type
);
414 return build1 (ADDR_EXPR
, ptr_type_node
, get_typeid (type
));
417 typestring
= build_overload_name (type
, 1, 1);
418 exp
= combine_strings (build_string (strlen (typestring
)+1, typestring
));
419 return build1 (ADDR_EXPR
, ptr_type_node
, exp
);
422 /* Build a type value for use at runtime for a exp that is thrown or
423 matched against by the exception handling system. */
431 exp
= build_typeid (exp
);
432 return build1 (ADDR_EXPR
, ptr_type_node
, exp
);
434 return build_eh_type_type (TREE_TYPE (exp
));
437 /* Build up a call to __cp_pop_exception, to destroy the exception object
438 for the current catch block. HANDLER is either true or false, telling
439 the library whether or not it is being called from an exception handler;
440 if it is, it avoids destroying the object on rethrow. */
443 do_pop_exception (handler
)
447 fn
= get_identifier ("__cp_pop_exception");
448 if (IDENTIFIER_GLOBAL_VALUE (fn
))
449 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
452 /* Declare void __cp_pop_exception (void *),
453 as defined in exception.cc. */
454 push_obstacks_nochange ();
455 end_temporary_allocation ();
458 build_function_type (void_type_node
, tree_cons
459 (NULL_TREE
, ptr_type_node
, tree_cons
460 (NULL_TREE
, boolean_type_node
,
462 DECL_EXTERNAL (fn
) = 1;
463 TREE_PUBLIC (fn
) = 1;
464 DECL_ARTIFICIAL (fn
) = 1;
465 pushdecl_top_level (fn
);
466 make_function_rtl (fn
);
467 assemble_external (fn
);
471 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
472 cleanup
= lookup_name (get_identifier ("__exception_info"), 0);
473 cleanup
= build_function_call (fn
, expr_tree_cons
474 (NULL_TREE
, cleanup
, expr_tree_cons
475 (NULL_TREE
, handler
, NULL_TREE
)));
479 /* This routine creates the cleanup for the current exception. */
484 /* All cleanups must last longer than normal. */
485 int yes
= suspend_momentary ();
486 expand_decl_cleanup_no_eh (NULL_TREE
, do_pop_exception (boolean_false_node
));
487 resume_momentary (yes
);
489 expand_expr (build_unary_op (PREINCREMENT_EXPR
, get_eh_handlers (), 1),
490 const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
492 /* We don't destroy the exception object on rethrow, so we can't use
493 the normal cleanup mechanism for it. */
494 expand_eh_region_start ();
497 /* call this to start a catch block. Typename is the typename, and identifier
498 is the variable to place the object in or NULL if the variable doesn't
499 matter. If typename is NULL, that means its a "catch (...)" or catch
500 everything. In that case we don't need to do any type checking.
501 (ie: it ends up as the "else" clause rather than an "else if" clause) */
504 expand_start_catch_block (declspecs
, declarator
)
505 tree declspecs
, declarator
;
508 tree decl
= NULL_TREE
;
511 if (processing_template_decl
)
515 decl
= grokdeclarator (declarator
, declspecs
, CATCHPARM
,
518 decl
= build_min_nt (DECL_STMT
, copy_to_permanent (declarator
),
519 copy_to_permanent (declspecs
),
529 /* If we are not doing setjmp/longjmp EH, because we are reordered
530 out of line, we arrange to rethrow in the outer context so as to
531 skip through the terminate region we are nested in, should we
532 encounter an exception in the catch handler. We also need to do
533 this because we are not physically within the try block, if any,
534 that contains this catch block.
536 Matches the end in expand_end_catch_block. */
537 if (! exceptions_via_longjmp
)
538 expand_eh_region_start ();
540 /* Create a binding level for the eh_info and the exception object
543 expand_start_bindings (0);
545 false_label_rtx
= gen_label_rtx ();
546 push_label_entry (&false_label_stack
, false_label_rtx
, NULL_TREE
);
548 emit_line_note (input_filename
, lineno
);
554 decl
= grokdeclarator (declarator
, declspecs
, CATCHPARM
, 1, NULL_TREE
);
556 if (decl
== NULL_TREE
)
557 error ("invalid catch parameter");
563 rtx call_rtx
, return_value_rtx
;
566 /* Make sure we mark the catch param as used, otherwise we'll get
567 a warning about an unused ((anonymous)). */
568 TREE_USED (decl
) = 1;
570 /* Figure out the type that the initializer is. */
571 init_type
= TREE_TYPE (decl
);
572 if (TREE_CODE (init_type
) != REFERENCE_TYPE
573 && TREE_CODE (init_type
) != POINTER_TYPE
)
574 init_type
= build_reference_type (init_type
);
576 exp
= get_eh_value ();
578 /* Since pointers are passed by value, initialize a reference to
579 pointer catch parm with the address of the value slot. */
580 if (TREE_CODE (init_type
) == REFERENCE_TYPE
581 && TREE_CODE (TREE_TYPE (init_type
)) == POINTER_TYPE
)
582 exp
= build_unary_op (ADDR_EXPR
, exp
, 1);
584 exp
= expr_tree_cons (NULL_TREE
,
585 build_eh_type_type (TREE_TYPE (decl
)),
586 expr_tree_cons (NULL_TREE
,
588 expr_tree_cons (NULL_TREE
, exp
, NULL_TREE
)));
589 exp
= build_function_call (CatchMatch
, exp
);
590 call_rtx
= expand_call (exp
, NULL_RTX
, 0);
592 return_value_rtx
= hard_function_value (ptr_type_node
, exp
);
594 /* did the throw type match function return TRUE? */
595 emit_cmp_insn (return_value_rtx
, const0_rtx
, EQ
, NULL_RTX
,
596 GET_MODE (return_value_rtx
), 0, 0);
598 /* if it returned FALSE, jump over the catch block, else fall into it */
599 emit_jump_insn (gen_beq (false_label_rtx
));
603 /* Create a binding level for the parm. */
605 expand_start_bindings (0);
607 init
= convert_from_reference (make_tree (init_type
, call_rtx
));
609 /* If the constructor for the catch parm exits via an exception, we
610 must call terminate. See eh23.C. */
611 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl
)))
613 /* Generate the copy constructor call directly so we can wrap it.
614 See also expand_default_init. */
615 init
= ocp_convert (TREE_TYPE (decl
), init
,
616 CONV_IMPLICIT
|CONV_FORCE_TEMP
, 0);
617 init
= build (TRY_CATCH_EXPR
, TREE_TYPE (init
), init
,
618 build_function_call (Terminate
, NULL_TREE
));
621 /* Let `cp_finish_decl' know that this initializer is ok. */
622 DECL_INITIAL (decl
) = init
;
623 decl
= pushdecl (decl
);
625 cp_finish_decl (decl
, init
, NULL_TREE
, 0, LOOKUP_ONLYCONVERTING
);
631 /* Create a binding level for the parm. */
633 expand_start_bindings (0);
635 /* Fall into the catch all section. */
638 init
= build_modify_expr (get_eh_caught (), NOP_EXPR
, integer_one_node
);
639 expand_expr (init
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
641 emit_line_note (input_filename
, lineno
);
646 /* Call this to end a catch block. Its responsible for emitting the
647 code to handle jumping back to the correct place, and for emitting
648 the label to jump to if this catch block didn't match. */
651 expand_end_catch_block ()
656 /* Cleanup the EH parameter. */
657 expand_end_bindings (getdecls (), kept_level_p (), 0);
658 poplevel (kept_level_p (), 1, 0);
660 /* Matches push_eh_cleanup. */
661 expand_eh_region_end (do_pop_exception (boolean_true_node
));
663 /* Cleanup the EH object. */
664 expand_end_bindings (getdecls (), kept_level_p (), 0);
665 poplevel (kept_level_p (), 1, 0);
667 if (! exceptions_via_longjmp
)
669 /* If we are not doing setjmp/longjmp EH, we need an extra
670 region around the whole catch block to skip through the
671 terminate region we are nested in. */
673 tree t
= make_node (RTL_EXPR
);
674 TREE_TYPE (t
) = void_type_node
;
675 RTL_EXPR_RTL (t
) = const0_rtx
;
676 TREE_SIDE_EFFECTS (t
) = 1;
677 do_pending_stack_adjust ();
678 start_sequence_for_rtl_expr (t
);
680 expand_internal_throw (outer_context_label_stack
->u
.rlabel
);
682 do_pending_stack_adjust ();
683 RTL_EXPR_SEQUENCE (t
) = get_insns ();
686 /* For the rethrow region. */
687 expand_eh_region_end (t
);
690 /* Fall to outside the try statement when done executing handler and
691 we fall off end of handler. This is jump Lresume in the
693 expand_goto (top_label_entry (&caught_return_label_stack
));
695 expand_leftover_cleanups ();
697 /* label we emit to jump to if this catch block didn't match. */
698 /* This the closing } in the `if (eq) {' of the documentation. */
699 emit_label (pop_label_entry (&false_label_stack
));
702 /* unwind the stack. */
705 do_unwind (inner_throw_label
)
706 rtx inner_throw_label
;
708 #if defined (SPARC_STACK_ALIGN) /* was sparc */
709 /* This doesn't work for the flat model sparc, nor does it need to
710 as the default unwinder is only used to unwind non-flat frames. */
716 /* Call to __builtin_return_address. */
717 params
= expr_tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
718 fcall
= build_function_call (builtin_return_address_fndecl
, params
);
719 next_pc
= expand_expr (fcall
, NULL_RTX
, Pmode
, 0);
720 /* In the return, the new pc is pc+8, as the value coming in is
721 really the address of the call insn, not the next insn. */
722 temp
= gen_reg_rtx (Pmode
);
723 emit_move_insn (temp
, inner_throw_label
);
724 emit_move_insn (next_pc
, plus_constant (temp
, -8));
725 emit_insn (gen_rtx (USE
, VOIDmode
, gen_rtx (REG
, SImode
, 31)));
726 easy_expand_asm ("ret");
727 easy_expand_asm ("restore");
730 #if defined (ARM_FRAME_RTX) /* was __arm */
731 if (flag_omit_frame_pointer
)
732 sorry ("this implementation of exception handling requires a frame pointer");
734 emit_move_insn (stack_pointer_rtx
,
735 gen_rtx (MEM
, Pmode
, plus_constant (hard_frame_pointer_rtx
, -8)));
736 emit_move_insn (hard_frame_pointer_rtx
,
737 gen_rtx (MEM
, Pmode
, plus_constant (hard_frame_pointer_rtx
, -12)));
739 #if defined (TARGET_88000) /* was m88k */
740 rtx temp_frame
= frame_pointer_rtx
;
742 temp_frame
= memory_address (Pmode
, temp_frame
);
743 temp_frame
= copy_to_reg (gen_rtx (MEM
, Pmode
, temp_frame
));
745 /* hopefully this will successfully pop the frame! */
746 emit_move_insn (frame_pointer_rtx
, temp_frame
);
747 emit_move_insn (stack_pointer_rtx
, frame_pointer_rtx
);
748 emit_move_insn (arg_pointer_rtx
, frame_pointer_rtx
);
749 emit_insn (gen_add2_insn (stack_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
750 (HOST_WIDE_INT
)m88k_debugger_offset (stack_pointer_rtx
, 0))));
753 emit_insn (gen_add2_insn (arg_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
754 -(HOST_WIDE_INT
)m88k_debugger_offset (arg_pointer_rtx
, 0))));
756 emit_move_insn (stack_pointer_rtx
, arg_pointer_rtx
);
758 emit_insn (gen_add2_insn (stack_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
759 (HOST_WIDE_INT
)m88k_debugger_offset (arg_pointer_rtx
, 0))));
762 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
768 /* I would like to do this here, but the move below doesn't seem to work. */
769 /* Call to __builtin_return_address. */
770 params
= expr_tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
771 fcall
= build_function_call (builtin_return_address_fndecl
, params
);
772 next_pc
= expand_expr (fcall
, NULL_RTX
, Pmode
, 0);
774 emit_move_insn (next_pc
, inner_throw_label
);
775 /* So, for now, just pass throw label to stack unwinder. */
777 params
= expr_tree_cons (NULL_TREE
, make_tree (ptr_type_node
,
778 inner_throw_label
), NULL_TREE
);
780 do_function_call (Unwind
, params
, NULL_TREE
);
786 /* Is called from expand_exception_blocks to generate the code in a function
787 to "throw" if anything in the function needs to perform a throw.
789 expands "throw" as the following pseudo code:
792 eh = find_first_exception_match (saved_pc);
793 if (!eh) goto gotta_rethrow_it;
797 saved_pc = __builtin_return_address (0);
798 pop_to_previous_level ();
802 expand_builtin_throw ()
804 #ifndef DWARF2_UNWIND_INFO
810 rtx gotta_rethrow_it
;
811 rtx gotta_call_terminate
;
823 params
= void_list_node
;
824 t
= make_call_declarator (get_identifier ("__throw"), params
, NULL_TREE
,
826 start_function (decl_tree_cons (NULL_TREE
,
827 get_identifier ("void"),
828 decl_tree_cons (NULL_TREE
,
829 get_identifier ("static"),
836 expand_start_bindings (0);
838 gotta_rethrow_it
= gen_label_rtx ();
839 gotta_call_terminate
= gen_label_rtx ();
841 /* These two can be frontend specific. If wanted, they can go in
843 /* Do we have a valid object we are throwing? */
845 emit_cmp_insn (expand_expr (t
, NULL_RTX
, Pmode
, 0),
846 const0_rtx
, EQ
, NULL_RTX
,
847 GET_MODE (DECL_RTL (t
)), 0, 0);
848 emit_jump_insn (gen_beq (gotta_call_terminate
));
850 /* search for an exception handler for the saved_pc */
851 handler
= do_function_call (FirstExceptionMatch
,
852 expr_tree_cons (NULL_TREE
, saved_pc
,
856 /* did we find one? */
857 emit_cmp_insn (handler
, const0_rtx
, EQ
, NULL_RTX
,
858 GET_MODE (handler
), 0, 0);
860 /* if not, jump to gotta_rethrow_it */
861 emit_jump_insn (gen_beq (gotta_rethrow_it
));
865 ret_val
= expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS
,
866 0, hard_frame_pointer_rtx
);
868 /* Set it up so that we continue at the handler. */
869 emit_move_insn (ret_val
, handler
);
870 #ifdef RETURN_ADDR_OFFSET
871 x
= plus_constant (ret_val
, -RETURN_ADDR_OFFSET
);
873 emit_move_insn (ret_val
, x
);
876 expand_null_return ();
879 top_of_loop
= gen_label_rtx ();
880 emit_label (top_of_loop
);
882 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
883 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE
)
885 saved_pcnthrow
= gen_reg_rtx (Pmode
);
886 emit_move_insn (saved_pcnthrow
, hard_function_value (ptr_type_node
,
891 /* Call to __builtin_return_address. */
892 #if defined (ARM_FRAME_RTX) /* was __arm */
893 /* This should be moved into arm.h:RETURN_ADDR_RTX */
894 /* This replaces a 'call' to __builtin_return_address */
895 next_pc
= gen_reg_rtx (Pmode
);
896 emit_move_insn (next_pc
,
897 gen_rtx (MEM
, Pmode
, plus_constant (hard_frame_pointer_rtx
, -4)));
899 params
= expr_tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
900 fcall
= build_function_call (builtin_return_address_fndecl
, params
);
901 next_pc
= expand_expr (fcall
, NULL_RTX
, Pmode
, 0);
904 /* Did __builtin_return_address return a valid address? */
905 emit_cmp_insn (next_pc
, const0_rtx
, EQ
, NULL_RTX
,
906 GET_MODE (next_pc
), 0, 0);
908 emit_jump_insn (gen_beq (gotta_call_terminate
));
910 next_pc
= eh_outer_context (next_pc
);
913 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
914 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE
)
918 x
= validize_mem (gen_rtx (MEM
, Pmode
, saved_pcnthrow
));
919 emit_move_insn (validize_mem (gen_rtx (MEM
, Pmode
, x
)),
921 #ifdef FUNCTION_OUTGOING_VALUE
922 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node
, NULL_TREE
),
923 validize_mem (gen_rtx (MEM
, Pmode
,
924 plus_constant (saved_pcnthrow
,
925 GET_MODE_SIZE (Pmode
)))));
926 emit_insn (gen_rtx (USE
, VOIDmode
,
927 FUNCTION_OUTGOING_VALUE (ptr_type_node
, NULL_TREE
)));
932 emit_move_insn (eh_saved_pc_rtx
, next_pc
);
934 after_unwind
= gen_label_rtx ();
935 do_unwind (gen_rtx (LABEL_REF
, Pmode
, after_unwind
));
937 emit_label (after_unwind
);
939 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
940 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE
)
942 t
= build_function_type (void_type_node
, void_list_node
);
943 t
= make_tree (build_pointer_type (t
),
944 hard_function_value (ptr_type_node
,
946 t
= build_function_call (t
, NULL_TREE
);
947 expand_expr (t
, const0_rtx
, VOIDmode
, 0);
953 /* no it didn't --> therefore we need to call terminate */
954 emit_label (gotta_call_terminate
);
955 do_function_call (Terminate
, NULL_TREE
, NULL_TREE
);
959 /* code to deal with unwinding and looking for it again */
960 emit_label (gotta_rethrow_it
);
961 ret_val
= expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS
,
962 0, hard_frame_pointer_rtx
);
964 /* Set it up so that we continue inside, at the top of the loop. */
965 emit_move_insn (ret_val
, gen_rtx (LABEL_REF
, Pmode
, top_of_loop
));
966 #ifdef RETURN_ADDR_OFFSET
967 x
= plus_constant (ret_val
, -RETURN_ADDR_OFFSET
);
969 emit_move_insn (ret_val
, x
);
972 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
973 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE
)
975 rtx x
= emit_library_call_value (gen_rtx (SYMBOL_REF
, Pmode
,
979 /* This is to get a version of throw that will throw properly. */
980 emit_move_insn (validize_mem (gen_rtx (MEM
, Pmode
,
981 plus_constant (x
, GET_MODE_SIZE (Pmode
)))),
983 #ifdef FUNCTION_OUTGOING_VALUE
984 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node
, NULL_TREE
),
986 emit_insn (gen_rtx (USE
, VOIDmode
, FUNCTION_OUTGOING_VALUE (ptr_type_node
, NULL_TREE
)));
991 /* Fall into epilogue to unwind prologue. */
994 expand_end_bindings (getdecls (), 1, 0);
998 finish_function (lineno
, 0, 0);
999 #endif /* DWARF2_UNWIND_INFO */
1002 /* An exception spec is implemented more or less like:
1007 void *p[] = { typeid(raises) };
1008 __check_eh_spec (p, count);
1011 __check_eh_spec in exception.cc handles all the details. */
1014 expand_start_eh_spec ()
1016 expand_start_try_stmts ();
1020 expand_end_eh_spec (raises
)
1023 tree tmp
, fn
, decl
, types
= NULL_TREE
;
1026 expand_start_all_catch ();
1027 expand_start_catch_block (NULL_TREE
, NULL_TREE
);
1029 /* Build up an array of type_infos. */
1030 for (; raises
&& TREE_VALUE (raises
); raises
= TREE_CHAIN (raises
))
1032 types
= expr_tree_cons
1033 (NULL_TREE
, build_eh_type_type (TREE_VALUE (raises
)), types
);
1037 types
= build_nt (CONSTRUCTOR
, NULL_TREE
, types
);
1038 TREE_HAS_CONSTRUCTOR (types
) = 1;
1040 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
1041 tmp
= build_array_type (const_ptr_type_node
, NULL_TREE
);
1042 decl
= build_decl (VAR_DECL
, NULL_TREE
, tmp
);
1043 DECL_ARTIFICIAL (decl
) = 1;
1044 DECL_INITIAL (decl
) = types
;
1045 cp_finish_decl (decl
, types
, NULL_TREE
, 0, 0);
1047 decl
= decay_conversion (decl
);
1049 fn
= get_identifier ("__check_eh_spec");
1050 if (IDENTIFIER_GLOBAL_VALUE (fn
))
1051 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
1054 push_obstacks_nochange ();
1055 end_temporary_allocation ();
1058 (NULL_TREE
, integer_type_node
, tree_cons
1059 (NULL_TREE
, TREE_TYPE (decl
), void_list_node
));
1060 tmp
= build_function_type (void_type_node
, tmp
);
1062 fn
= build_lang_decl (FUNCTION_DECL
, fn
, tmp
);
1063 DECL_EXTERNAL (fn
) = 1;
1064 TREE_PUBLIC (fn
) = 1;
1065 DECL_ARTIFICIAL (fn
) = 1;
1066 TREE_THIS_VOLATILE (fn
) = 1;
1067 pushdecl_top_level (fn
);
1068 make_function_rtl (fn
);
1069 assemble_external (fn
);
1073 tmp
= expr_tree_cons (NULL_TREE
, build_int_2 (count
, 0), expr_tree_cons
1074 (NULL_TREE
, decl
, NULL_TREE
));
1075 tmp
= build_call (fn
, TREE_TYPE (TREE_TYPE (fn
)), tmp
);
1076 expand_expr (tmp
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1078 expand_end_catch_block ();
1079 expand_end_all_catch ();
1082 /* This is called to expand all the toplevel exception handling
1083 finalization for a function. It should only be called once per
1087 expand_exception_blocks ()
1089 do_pending_stack_adjust ();
1090 push_to_sequence (catch_clauses
);
1091 expand_leftover_cleanups ();
1092 do_pending_stack_adjust ();
1093 catch_clauses
= get_insns ();
1096 /* Do this after we expand leftover cleanups, so that the
1097 expand_eh_region_end that expand_end_eh_spec does will match the
1098 right expand_eh_region_start, and make sure it comes out before
1099 the terminate protected region. */
1100 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl
)))
1102 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl
)));
1103 do_pending_stack_adjust ();
1104 push_to_sequence (catch_clauses
);
1105 expand_leftover_cleanups ();
1106 do_pending_stack_adjust ();
1107 catch_clauses
= get_insns ();
1113 rtx funcend
= gen_label_rtx ();
1114 emit_jump (funcend
);
1116 /* We cannot protect n regions this way if we must flow into the
1117 EH region through the top of the region, as we have to with
1118 the setjmp/longjmp approach. */
1119 if (exceptions_via_longjmp
== 0)
1120 expand_eh_region_start ();
1122 emit_insns (catch_clauses
);
1123 catch_clauses
= NULL_RTX
;
1125 if (exceptions_via_longjmp
== 0)
1126 expand_eh_region_end (build_function_call (Terminate
, NULL_TREE
));
1128 expand_leftover_cleanups ();
1130 emit_label (funcend
);
1137 static int counter
= 0;
1138 int old_interface_unknown
= interface_unknown
;
1143 push_cp_function_context (NULL_TREE
);
1144 push_to_top_level ();
1146 /* No need to mangle this. */
1147 push_lang_context (lang_name_c
);
1149 interface_unknown
= 1;
1151 params
= void_list_node
;
1152 /* tcf stands for throw clean funciton. */
1153 sprintf (name
, "__tcf_%d", counter
++);
1154 t
= make_call_declarator (get_identifier (name
), params
, NULL_TREE
,
1156 start_function (decl_tree_cons (NULL_TREE
, get_identifier ("static"),
1159 store_parm_decls ();
1163 expand_start_bindings (0);
1164 emit_line_note (input_filename
, lineno
);
1166 interface_unknown
= old_interface_unknown
;
1168 pop_lang_context ();
1170 return current_function_decl
;
1176 expand_end_bindings (getdecls (), 1, 0);
1180 finish_function (lineno
, 0, 0);
1182 pop_from_top_level ();
1183 pop_cp_function_context (NULL_TREE
);
1186 /* Expand a throw statement. This follows the following
1189 1. Allocate space to save the current PC onto the stack.
1190 2. Generate and emit a label and save its address into the
1191 newly allocated stack space since we can't save the pc directly.
1192 3. If this is the first call to throw in this function:
1193 generate a label for the throw block
1194 4. jump to the throw block label. */
1202 static tree cleanup_type
;
1210 tree cleanup
= NULL_TREE
, e
;
1212 /* throw expression */
1213 /* First, decay it. */
1214 exp
= decay_conversion (exp
);
1216 /* cleanup_type is void (*)(void *, int),
1217 the internal type of a destructor. */
1218 if (cleanup_type
== NULL_TREE
)
1220 push_obstacks_nochange ();
1221 end_temporary_allocation ();
1222 cleanup_type
= build_pointer_type
1223 (build_function_type
1224 (void_type_node
, tree_cons
1225 (NULL_TREE
, ptr_type_node
, tree_cons
1226 (NULL_TREE
, integer_type_node
, void_list_node
))));
1230 if (TREE_CODE (TREE_TYPE (exp
)) == POINTER_TYPE
)
1232 throw_type
= build_eh_type (exp
);
1233 exp
= build_reinterpret_cast (ptr_type_node
, exp
);
1239 /* Make a copy of the thrown object. WP 15.1.5 */
1240 exp
= build_new (NULL_TREE
, TREE_TYPE (exp
),
1241 build_expr_list (NULL_TREE
, exp
),
1244 if (exp
== error_mark_node
)
1245 error (" in thrown expression");
1247 object
= build_indirect_ref (exp
, NULL_PTR
);
1248 throw_type
= build_eh_type (object
);
1250 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object
)))
1252 cleanup
= lookup_fnfields (TYPE_BINFO (TREE_TYPE (object
)),
1253 dtor_identifier
, 0);
1254 cleanup
= TREE_VALUE (cleanup
);
1255 mark_used (cleanup
);
1256 mark_addressable (cleanup
);
1257 /* Pretend it's a normal function. */
1258 cleanup
= build1 (ADDR_EXPR
, cleanup_type
, cleanup
);
1262 if (cleanup
== NULL_TREE
)
1264 cleanup
= build_int_2 (0, 0);
1265 TREE_TYPE (cleanup
) = cleanup_type
;
1268 fn
= get_identifier ("__cp_push_exception");
1269 if (IDENTIFIER_GLOBAL_VALUE (fn
))
1270 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
1273 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1274 as defined in exception.cc. */
1276 push_obstacks_nochange ();
1277 end_temporary_allocation ();
1279 (NULL_TREE
, ptr_type_node
, tree_cons
1280 (NULL_TREE
, ptr_type_node
, tree_cons
1281 (NULL_TREE
, cleanup_type
, void_list_node
)));
1282 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
1283 build_function_type (void_type_node
, tmp
));
1284 DECL_EXTERNAL (fn
) = 1;
1285 TREE_PUBLIC (fn
) = 1;
1286 DECL_ARTIFICIAL (fn
) = 1;
1287 pushdecl_top_level (fn
);
1288 make_function_rtl (fn
);
1289 assemble_external (fn
);
1293 /* The throw expression is a full-expression. */
1294 exp
= build1 (CLEANUP_POINT_EXPR
, TREE_TYPE (exp
), exp
);
1295 e
= expr_tree_cons (NULL_TREE
, exp
, expr_tree_cons
1296 (NULL_TREE
, throw_type
, expr_tree_cons
1297 (NULL_TREE
, cleanup
, NULL_TREE
)));
1298 e
= build_function_call (fn
, e
);
1299 expand_expr (e
, const0_rtx
, VOIDmode
, 0);
1303 /* rethrow current exception; note that it's no longer caught. */
1305 tree fn
= get_identifier ("__uncatch_exception");
1306 if (IDENTIFIER_GLOBAL_VALUE (fn
))
1307 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
1310 /* Declare void __uncatch_exception (void)
1311 as defined in exception.cc. */
1312 push_obstacks_nochange ();
1313 end_temporary_allocation ();
1314 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
1315 build_function_type (void_type_node
,
1317 DECL_EXTERNAL (fn
) = 1;
1318 TREE_PUBLIC (fn
) = 1;
1319 DECL_ARTIFICIAL (fn
) = 1;
1320 pushdecl_top_level (fn
);
1321 make_function_rtl (fn
);
1322 assemble_external (fn
);
1326 exp
= build_function_call (fn
, NULL_TREE
);
1327 expand_expr (exp
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1330 if (exceptions_via_longjmp
)
1334 /* This is the label that represents where in the code we were, when
1335 we got an exception. This needs to be updated when we rethrow an
1336 exception, so that the matching routine knows to search out. */
1337 label
= gen_label_rtx ();
1340 expand_internal_throw (label
);
1344 /* Build a throw expression. */
1350 if (e
!= error_mark_node
)
1352 if (processing_template_decl
)
1353 return build_min (THROW_EXPR
, void_type_node
, e
);
1354 e
= build1 (THROW_EXPR
, void_type_node
, e
);
1355 TREE_SIDE_EFFECTS (e
) = 1;