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 #ifndef DWARF2_UNWIND_INFO
189 /* Holds the pc for doing "throw" */
190 static tree saved_pc
;
192 extern int throw_used
;
195 extern rtx catch_clauses
;
196 extern tree const_ptr_type_node
;
198 /* ========================================================================= */
200 /* Cheesyness to save some typing. Returns the return value rtx. */
203 do_function_call (func
, params
, return_type
)
204 tree func
, params
, return_type
;
207 func_call
= build_function_call (func
, params
);
208 expand_call (func_call
, NULL_RTX
, 0);
209 if (return_type
!= NULL_TREE
)
210 return hard_function_value (return_type
, func_call
);
214 /* ========================================================================= */
216 /* sets up all the global eh stuff that needs to be initialized at the
217 start of compilation.
220 - Setting up all the function call trees. */
223 init_exception_processing ()
228 tree vtype
= build_function_type (void_type_node
, void_list_node
);
230 Terminate
= auto_function (get_identifier ("terminate"),
231 vtype
, NOT_BUILT_IN
);
232 TREE_THIS_VOLATILE (Terminate
) = 1;
234 push_lang_context (lang_name_c
);
237 = builtin_function (flag_rtti
238 ? "__throw_type_match_rtti"
239 : "__throw_type_match",
240 build_function_type (ptr_type_node
,
241 tree_cons (NULL_TREE
, const_ptr_type_node
,
242 tree_cons (NULL_TREE
, const_ptr_type_node
,
243 tree_cons (NULL_TREE
, ptr_type_node
,
245 NOT_BUILT_IN
, NULL_PTR
);
247 = builtin_function ("__find_first_exception_table_match",
248 build_function_type (ptr_type_node
,
249 tree_cons (NULL_TREE
, ptr_type_node
,
251 NOT_BUILT_IN
, NULL_PTR
);
253 = builtin_function ("__unwind_function",
254 build_function_type (void_type_node
,
255 tree_cons (NULL_TREE
, ptr_type_node
,
257 NOT_BUILT_IN
, NULL_PTR
);
261 #ifndef DWARF2_UNWIND_INFO
262 d
= build_decl (VAR_DECL
, get_identifier ("__eh_pc"), ptr_type_node
);
264 DECL_EXTERNAL (d
) = 1;
265 DECL_ARTIFICIAL (d
) = 1;
266 cp_finish_decl (d
, NULL_TREE
, NULL_TREE
, 0, 0);
270 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
271 be protected with __terminate. */
272 protect_cleanup_actions_with_terminate
= 1;
275 /* Retrieve a pointer to the cp_eh_info node for the current exception. */
282 fn
= get_identifier ("__cp_exception_info");
283 if (IDENTIFIER_GLOBAL_VALUE (fn
))
284 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
289 /* Declare cp_eh_info * __cp_exception_info (void),
290 as defined in exception.cc. */
291 push_obstacks_nochange ();
292 end_temporary_allocation ();
294 /* struct cp_eh_info. This must match exception.cc. Note that this
295 type is not pushed anywhere. */
296 t
= make_lang_type (RECORD_TYPE
);
297 fields
[0] = build_lang_field_decl (FIELD_DECL
, get_identifier ("value"),
299 fields
[1] = build_lang_field_decl (FIELD_DECL
, get_identifier ("type"),
301 fields
[2] = build_lang_field_decl
302 (FIELD_DECL
, get_identifier ("cleanup"),
303 build_pointer_type (build_function_type
304 (ptr_type_node
, tree_cons
305 (NULL_TREE
, ptr_type_node
, void_list_node
))));
306 fields
[3] = build_lang_field_decl (FIELD_DECL
, get_identifier ("caught"),
308 fields
[4] = build_lang_field_decl (FIELD_DECL
, get_identifier ("next"),
309 build_pointer_type (t
));
310 fields
[5] = build_lang_field_decl
311 (FIELD_DECL
, get_identifier ("handlers"), long_integer_type_node
);
312 /* N.B.: The fourth field LEN is expected to be
313 the number of fields - 1, not the total number of fields. */
314 finish_builtin_type (t
, "cp_eh_info", fields
, 5, ptr_type_node
);
315 t
= build_pointer_type (t
);
317 /* And now the function. */
318 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
319 build_function_type (t
, void_list_node
));
320 DECL_EXTERNAL (fn
) = 1;
321 TREE_PUBLIC (fn
) = 1;
322 DECL_ARTIFICIAL (fn
) = 1;
323 pushdecl_top_level (fn
);
324 make_function_rtl (fn
);
325 assemble_external (fn
);
328 return build_function_call (fn
, NULL_TREE
);
331 /* Retrieve a pointer to the cp_eh_info node for the current exception
332 and save it in the current binding level. */
337 tree decl
, fn
= call_eh_info ();
339 /* Remember the pointer to the current exception info; it won't change
340 during this catch block. */
341 decl
= build_decl (VAR_DECL
, get_identifier ("__exception_info"),
343 DECL_ARTIFICIAL (decl
) = 1;
344 DECL_INITIAL (decl
) = fn
;
345 decl
= pushdecl (decl
);
346 cp_finish_decl (decl
, fn
, NULL_TREE
, 0, 0);
349 /* Returns a reference to the cp_eh_info node for the current exception. */
354 /* Look for the pointer pushed in push_eh_info. */
355 tree t
= lookup_name (get_identifier ("__exception_info"), 0);
356 return build_indirect_ref (t
, NULL_PTR
);
359 /* Returns a reference to the current exception object. */
364 return build_component_ref (get_eh_info (), get_identifier ("value"),
368 /* Returns a reference to the current exception type. */
373 return build_component_ref (get_eh_info (), get_identifier ("type"),
377 /* Returns a reference to whether or not the current exception
383 return build_component_ref (get_eh_info (), get_identifier ("caught"),
387 /* Returns a reference to whether or not the current exception
393 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
397 /* Build a type value for use at runtime for a type that is matched
398 against by the exception handling system. */
401 build_eh_type_type (type
)
407 if (type
== error_mark_node
)
408 return error_mark_node
;
410 /* peel back references, so they match. */
411 if (TREE_CODE (type
) == REFERENCE_TYPE
)
412 type
= TREE_TYPE (type
);
414 /* Peel off cv qualifiers. */
415 type
= TYPE_MAIN_VARIANT (type
);
419 return build1 (ADDR_EXPR
, ptr_type_node
, get_typeid (type
));
422 typestring
= build_overload_name (type
, 1, 1);
423 exp
= combine_strings (build_string (strlen (typestring
)+1, typestring
));
424 return build1 (ADDR_EXPR
, ptr_type_node
, exp
);
427 /* Build a type value for use at runtime for a exp that is thrown or
428 matched against by the exception handling system. */
436 exp
= build_typeid (exp
);
437 return build1 (ADDR_EXPR
, ptr_type_node
, exp
);
439 return build_eh_type_type (TREE_TYPE (exp
));
442 /* Build up a call to __cp_pop_exception, to destroy the exception object
443 for the current catch block. HANDLER is either true or false, telling
444 the library whether or not it is being called from an exception handler;
445 if it is, it avoids destroying the object on rethrow. */
451 fn
= get_identifier ("__cp_pop_exception");
452 if (IDENTIFIER_GLOBAL_VALUE (fn
))
453 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
456 /* Declare void __cp_pop_exception (void *),
457 as defined in exception.cc. */
458 push_obstacks_nochange ();
459 end_temporary_allocation ();
462 build_function_type (void_type_node
, tree_cons
463 (NULL_TREE
, ptr_type_node
, void_list_node
)));
464 DECL_EXTERNAL (fn
) = 1;
465 TREE_PUBLIC (fn
) = 1;
466 DECL_ARTIFICIAL (fn
) = 1;
467 pushdecl_top_level (fn
);
468 make_function_rtl (fn
);
469 assemble_external (fn
);
473 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
474 cleanup
= lookup_name (get_identifier ("__exception_info"), 0);
475 cleanup
= build_function_call (fn
, expr_tree_cons
476 (NULL_TREE
, cleanup
, NULL_TREE
));
480 /* This routine creates the cleanup for the current exception. */
487 expand_expr (build_unary_op (PREINCREMENT_EXPR
, get_eh_handlers (), 1),
488 const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
490 yes
= suspend_momentary ();
491 /* All cleanups must last longer than normal. */
492 expand_decl_cleanup (NULL_TREE
, do_pop_exception ());
493 resume_momentary (yes
);
496 /* call this to start a catch block. Typename is the typename, and identifier
497 is the variable to place the object in or NULL if the variable doesn't
498 matter. If typename is NULL, that means its a "catch (...)" or catch
499 everything. In that case we don't need to do any type checking.
500 (ie: it ends up as the "else" clause rather than an "else if" clause) */
503 expand_start_catch_block (declspecs
, declarator
)
504 tree declspecs
, declarator
;
507 tree decl
= NULL_TREE
;
510 if (processing_template_decl
)
514 decl
= grokdeclarator (declarator
, declspecs
, CATCHPARM
,
517 decl
= build_min_nt (DECL_STMT
, copy_to_permanent (declarator
),
518 copy_to_permanent (declspecs
),
528 /* Create a binding level for the eh_info and the exception object
531 expand_start_bindings (0);
533 false_label_rtx
= gen_label_rtx ();
534 push_label_entry (&false_label_stack
, false_label_rtx
, NULL_TREE
);
536 emit_line_note (input_filename
, lineno
);
542 decl
= grokdeclarator (declarator
, declspecs
, CATCHPARM
, 1, NULL_TREE
);
544 if (decl
== NULL_TREE
)
545 error ("invalid catch parameter");
551 rtx call_rtx
, return_value_rtx
;
554 /* Make sure we mark the catch param as used, otherwise we'll get
555 a warning about an unused ((anonymous)). */
556 TREE_USED (decl
) = 1;
558 /* Figure out the type that the initializer is. */
559 init_type
= TREE_TYPE (decl
);
560 if (TREE_CODE (init_type
) != REFERENCE_TYPE
561 && TREE_CODE (init_type
) != POINTER_TYPE
)
562 init_type
= build_reference_type (init_type
);
564 exp
= get_eh_value ();
566 /* Since pointers are passed by value, initialize a reference to
567 pointer catch parm with the address of the value slot. */
568 if (TREE_CODE (init_type
) == REFERENCE_TYPE
569 && TREE_CODE (TREE_TYPE (init_type
)) == POINTER_TYPE
)
570 exp
= build_unary_op (ADDR_EXPR
, exp
, 1);
572 exp
= expr_tree_cons (NULL_TREE
,
573 build_eh_type_type (TREE_TYPE (decl
)),
574 expr_tree_cons (NULL_TREE
,
576 expr_tree_cons (NULL_TREE
, exp
, NULL_TREE
)));
577 exp
= build_function_call (CatchMatch
, exp
);
578 call_rtx
= expand_call (exp
, NULL_RTX
, 0);
580 return_value_rtx
= hard_function_value (ptr_type_node
, exp
);
582 /* did the throw type match function return TRUE? */
583 emit_cmp_insn (return_value_rtx
, const0_rtx
, EQ
, NULL_RTX
,
584 GET_MODE (return_value_rtx
), 0, 0);
586 /* if it returned FALSE, jump over the catch block, else fall into it */
587 emit_jump_insn (gen_beq (false_label_rtx
));
591 /* Create a binding level for the parm. */
593 expand_start_bindings (0);
595 init
= convert_from_reference (make_tree (init_type
, call_rtx
));
597 /* If the constructor for the catch parm exits via an exception, we
598 must call terminate. See eh23.C. */
599 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl
)))
601 /* Generate the copy constructor call directly so we can wrap it.
602 See also expand_default_init. */
603 init
= ocp_convert (TREE_TYPE (decl
), init
,
604 CONV_IMPLICIT
|CONV_FORCE_TEMP
, 0);
605 init
= build (TRY_CATCH_EXPR
, TREE_TYPE (init
), init
,
606 build_function_call (Terminate
, NULL_TREE
));
609 /* Let `cp_finish_decl' know that this initializer is ok. */
610 DECL_INITIAL (decl
) = init
;
611 decl
= pushdecl (decl
);
613 cp_finish_decl (decl
, init
, NULL_TREE
, 0, LOOKUP_ONLYCONVERTING
);
619 /* Create a binding level for the parm. */
621 expand_start_bindings (0);
623 /* Fall into the catch all section. */
626 init
= build_modify_expr (get_eh_caught (), NOP_EXPR
, integer_one_node
);
627 expand_expr (init
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
629 emit_line_note (input_filename
, lineno
);
634 /* Call this to end a catch block. Its responsible for emitting the
635 code to handle jumping back to the correct place, and for emitting
636 the label to jump to if this catch block didn't match. */
639 expand_end_catch_block ()
644 /* Cleanup the EH parameter. */
645 expand_end_bindings (getdecls (), kept_level_p (), 0);
646 poplevel (kept_level_p (), 1, 0);
648 /* Cleanup the EH object. */
649 expand_end_bindings (getdecls (), kept_level_p (), 0);
650 poplevel (kept_level_p (), 1, 0);
652 /* Fall to outside the try statement when done executing handler and
653 we fall off end of handler. This is jump Lresume in the
655 expand_goto (top_label_entry (&caught_return_label_stack
));
657 /* label we emit to jump to if this catch block didn't match. */
658 /* This the closing } in the `if (eq) {' of the documentation. */
659 emit_label (pop_label_entry (&false_label_stack
));
662 /* unwind the stack. */
665 do_unwind (inner_throw_label
)
666 rtx inner_throw_label
;
668 #if defined (SPARC_STACK_ALIGN) /* was sparc */
669 /* This doesn't work for the flat model sparc, nor does it need to
670 as the default unwinder is only used to unwind non-flat frames. */
676 /* Call to __builtin_return_address. */
677 params
= expr_tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
678 fcall
= build_function_call (builtin_return_address_fndecl
, params
);
679 next_pc
= expand_expr (fcall
, NULL_RTX
, Pmode
, 0);
680 /* In the return, the new pc is pc+8, as the value coming in is
681 really the address of the call insn, not the next insn. */
682 temp
= gen_reg_rtx (Pmode
);
683 emit_move_insn (temp
, inner_throw_label
);
684 emit_move_insn (next_pc
, plus_constant (temp
, -8));
685 emit_insn (gen_rtx (USE
, VOIDmode
, gen_rtx (REG
, SImode
, 31)));
686 easy_expand_asm ("ret");
687 easy_expand_asm ("restore");
690 #if defined (ARM_FRAME_RTX) /* was __arm */
691 if (flag_omit_frame_pointer
)
692 sorry ("this implementation of exception handling requires a frame pointer");
694 emit_move_insn (stack_pointer_rtx
,
695 gen_rtx (MEM
, Pmode
, plus_constant (hard_frame_pointer_rtx
, -8)));
696 emit_move_insn (hard_frame_pointer_rtx
,
697 gen_rtx (MEM
, Pmode
, plus_constant (hard_frame_pointer_rtx
, -12)));
699 #if defined (TARGET_88000) /* was m88k */
700 rtx temp_frame
= frame_pointer_rtx
;
702 temp_frame
= memory_address (Pmode
, temp_frame
);
703 temp_frame
= copy_to_reg (gen_rtx (MEM
, Pmode
, temp_frame
));
705 /* hopefully this will successfully pop the frame! */
706 emit_move_insn (frame_pointer_rtx
, temp_frame
);
707 emit_move_insn (stack_pointer_rtx
, frame_pointer_rtx
);
708 emit_move_insn (arg_pointer_rtx
, frame_pointer_rtx
);
709 emit_insn (gen_add2_insn (stack_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
710 (HOST_WIDE_INT
)m88k_debugger_offset (stack_pointer_rtx
, 0))));
713 emit_insn (gen_add2_insn (arg_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
714 -(HOST_WIDE_INT
)m88k_debugger_offset (arg_pointer_rtx
, 0))));
716 emit_move_insn (stack_pointer_rtx
, arg_pointer_rtx
);
718 emit_insn (gen_add2_insn (stack_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
719 (HOST_WIDE_INT
)m88k_debugger_offset (arg_pointer_rtx
, 0))));
722 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
728 /* I would like to do this here, but the move below doesn't seem to work. */
729 /* Call to __builtin_return_address. */
730 params
= expr_tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
731 fcall
= build_function_call (builtin_return_address_fndecl
, params
);
732 next_pc
= expand_expr (fcall
, NULL_RTX
, Pmode
, 0);
734 emit_move_insn (next_pc
, inner_throw_label
);
735 /* So, for now, just pass throw label to stack unwinder. */
737 params
= expr_tree_cons (NULL_TREE
, make_tree (ptr_type_node
,
738 inner_throw_label
), NULL_TREE
);
740 do_function_call (Unwind
, params
, NULL_TREE
);
746 /* Is called from expand_exception_blocks to generate the code in a function
747 to "throw" if anything in the function needs to perform a throw.
749 expands "throw" as the following pseudo code:
752 eh = find_first_exception_match (saved_pc);
753 if (!eh) goto gotta_rethrow_it;
757 saved_pc = __builtin_return_address (0);
758 pop_to_previous_level ();
762 expand_builtin_throw ()
764 #ifndef DWARF2_UNWIND_INFO
770 rtx gotta_rethrow_it
;
771 rtx gotta_call_terminate
;
783 params
= void_list_node
;
784 t
= make_call_declarator (get_identifier ("__throw"), params
, NULL_TREE
,
786 start_function (decl_tree_cons (NULL_TREE
,
787 get_identifier ("void"),
788 decl_tree_cons (NULL_TREE
,
789 get_identifier ("static"),
796 expand_start_bindings (0);
798 gotta_rethrow_it
= gen_label_rtx ();
799 gotta_call_terminate
= gen_label_rtx ();
801 /* These two can be frontend specific. If wanted, they can go in
803 /* Do we have a valid object we are throwing? */
805 emit_cmp_insn (expand_expr (t
, NULL_RTX
, Pmode
, 0),
806 const0_rtx
, EQ
, NULL_RTX
,
807 GET_MODE (DECL_RTL (t
)), 0, 0);
808 emit_jump_insn (gen_beq (gotta_call_terminate
));
810 /* search for an exception handler for the saved_pc */
811 handler
= do_function_call (FirstExceptionMatch
,
812 expr_tree_cons (NULL_TREE
, saved_pc
,
816 /* did we find one? */
817 emit_cmp_insn (handler
, const0_rtx
, EQ
, NULL_RTX
,
818 GET_MODE (handler
), 0, 0);
820 /* if not, jump to gotta_rethrow_it */
821 emit_jump_insn (gen_beq (gotta_rethrow_it
));
825 ret_val
= expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS
,
826 0, hard_frame_pointer_rtx
);
828 /* Set it up so that we continue at the handler. */
829 emit_move_insn (ret_val
, handler
);
830 #ifdef RETURN_ADDR_OFFSET
831 x
= plus_constant (ret_val
, -RETURN_ADDR_OFFSET
);
833 emit_move_insn (ret_val
, x
);
836 expand_null_return ();
839 top_of_loop
= gen_label_rtx ();
840 emit_label (top_of_loop
);
842 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
843 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE
)
845 saved_pcnthrow
= gen_reg_rtx (Pmode
);
846 emit_move_insn (saved_pcnthrow
, hard_function_value (ptr_type_node
,
851 /* Call to __builtin_return_address. */
852 #if defined (ARM_FRAME_RTX) /* was __arm */
853 /* This should be moved into arm.h:RETURN_ADDR_RTX */
854 /* This replaces a 'call' to __builtin_return_address */
855 next_pc
= gen_reg_rtx (Pmode
);
856 emit_move_insn (next_pc
,
857 gen_rtx (MEM
, Pmode
, plus_constant (hard_frame_pointer_rtx
, -4)));
859 params
= expr_tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
860 fcall
= build_function_call (builtin_return_address_fndecl
, params
);
861 next_pc
= expand_expr (fcall
, NULL_RTX
, Pmode
, 0);
864 /* Did __builtin_return_address return a valid address? */
865 emit_cmp_insn (next_pc
, const0_rtx
, EQ
, NULL_RTX
,
866 GET_MODE (next_pc
), 0, 0);
868 emit_jump_insn (gen_beq (gotta_call_terminate
));
870 next_pc
= eh_outer_context (next_pc
);
873 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
874 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE
)
878 x
= validize_mem (gen_rtx (MEM
, Pmode
, saved_pcnthrow
));
879 emit_move_insn (validize_mem (gen_rtx (MEM
, Pmode
, x
)),
881 #ifdef FUNCTION_OUTGOING_VALUE
882 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node
, NULL_TREE
),
883 validize_mem (gen_rtx (MEM
, Pmode
,
884 plus_constant (saved_pcnthrow
,
885 GET_MODE_SIZE (Pmode
)))));
886 emit_insn (gen_rtx (USE
, VOIDmode
,
887 FUNCTION_OUTGOING_VALUE (ptr_type_node
, NULL_TREE
)));
892 emit_move_insn (eh_saved_pc_rtx
, next_pc
);
894 after_unwind
= gen_label_rtx ();
895 do_unwind (gen_rtx (LABEL_REF
, Pmode
, after_unwind
));
897 emit_label (after_unwind
);
899 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
900 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE
)
902 t
= build_function_type (void_type_node
, void_list_node
);
903 t
= make_tree (build_pointer_type (t
),
904 hard_function_value (ptr_type_node
,
906 t
= build_function_call (t
, NULL_TREE
);
907 expand_expr (t
, const0_rtx
, VOIDmode
, 0);
913 /* no it didn't --> therefore we need to call terminate */
914 emit_label (gotta_call_terminate
);
915 do_function_call (Terminate
, NULL_TREE
, NULL_TREE
);
919 /* code to deal with unwinding and looking for it again */
920 emit_label (gotta_rethrow_it
);
921 ret_val
= expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS
,
922 0, hard_frame_pointer_rtx
);
924 /* Set it up so that we continue inside, at the top of the loop. */
925 emit_move_insn (ret_val
, gen_rtx (LABEL_REF
, Pmode
, top_of_loop
));
926 #ifdef RETURN_ADDR_OFFSET
927 x
= plus_constant (ret_val
, -RETURN_ADDR_OFFSET
);
929 emit_move_insn (ret_val
, x
);
932 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
933 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE
)
935 rtx x
= emit_library_call_value (gen_rtx (SYMBOL_REF
, Pmode
,
939 /* This is to get a version of throw that will throw properly. */
940 emit_move_insn (validize_mem (gen_rtx (MEM
, Pmode
,
941 plus_constant (x
, GET_MODE_SIZE (Pmode
)))),
943 #ifdef FUNCTION_OUTGOING_VALUE
944 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node
, NULL_TREE
),
946 emit_insn (gen_rtx (USE
, VOIDmode
, FUNCTION_OUTGOING_VALUE (ptr_type_node
, NULL_TREE
)));
951 /* Fall into epilogue to unwind prologue. */
954 expand_end_bindings (getdecls (), 1, 0);
958 finish_function (lineno
, 0, 0);
959 #endif /* DWARF2_UNWIND_INFO */
962 /* An exception spec is implemented more or less like:
967 void *p[] = { typeid(raises) };
968 __check_eh_spec (p, count);
971 __check_eh_spec in exception.cc handles all the details. */
974 expand_start_eh_spec ()
976 expand_start_try_stmts ();
980 expand_end_eh_spec (raises
)
983 tree tmp
, fn
, decl
, types
= NULL_TREE
;
986 expand_start_all_catch ();
987 expand_start_catch_block (NULL_TREE
, NULL_TREE
);
989 /* Build up an array of type_infos. */
990 for (; raises
&& TREE_VALUE (raises
); raises
= TREE_CHAIN (raises
))
992 types
= expr_tree_cons
993 (NULL_TREE
, build_eh_type_type (TREE_VALUE (raises
)), types
);
997 types
= build_nt (CONSTRUCTOR
, NULL_TREE
, types
);
998 TREE_HAS_CONSTRUCTOR (types
) = 1;
1000 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
1001 tmp
= build_array_type (const_ptr_type_node
, NULL_TREE
);
1002 decl
= build_decl (VAR_DECL
, NULL_TREE
, tmp
);
1003 DECL_ARTIFICIAL (decl
) = 1;
1004 DECL_INITIAL (decl
) = types
;
1005 cp_finish_decl (decl
, types
, NULL_TREE
, 0, 0);
1007 decl
= decay_conversion (decl
);
1009 fn
= get_identifier ("__check_eh_spec");
1010 if (IDENTIFIER_GLOBAL_VALUE (fn
))
1011 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
1014 push_obstacks_nochange ();
1015 end_temporary_allocation ();
1018 (NULL_TREE
, integer_type_node
, tree_cons
1019 (NULL_TREE
, TREE_TYPE (decl
), void_list_node
));
1020 tmp
= build_function_type (void_type_node
, tmp
);
1022 fn
= build_lang_decl (FUNCTION_DECL
, fn
, tmp
);
1023 DECL_EXTERNAL (fn
) = 1;
1024 TREE_PUBLIC (fn
) = 1;
1025 DECL_ARTIFICIAL (fn
) = 1;
1026 TREE_THIS_VOLATILE (fn
) = 1;
1027 pushdecl_top_level (fn
);
1028 make_function_rtl (fn
);
1029 assemble_external (fn
);
1033 tmp
= expr_tree_cons (NULL_TREE
, build_int_2 (count
, 0), expr_tree_cons
1034 (NULL_TREE
, decl
, NULL_TREE
));
1035 tmp
= build_call (fn
, TREE_TYPE (TREE_TYPE (fn
)), tmp
);
1036 expand_expr (tmp
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1038 expand_end_catch_block ();
1039 expand_end_all_catch ();
1042 /* This is called to expand all the toplevel exception handling
1043 finalization for a function. It should only be called once per
1047 expand_exception_blocks ()
1049 do_pending_stack_adjust ();
1050 push_to_sequence (catch_clauses
);
1051 expand_leftover_cleanups ();
1052 do_pending_stack_adjust ();
1053 catch_clauses
= get_insns ();
1056 /* Do this after we expand leftover cleanups, so that the
1057 expand_eh_region_end that expand_end_eh_spec does will match the
1058 right expand_eh_region_start, and make sure it comes out before
1059 the terminate protected region. */
1060 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl
)))
1062 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl
)));
1063 do_pending_stack_adjust ();
1064 push_to_sequence (catch_clauses
);
1065 expand_leftover_cleanups ();
1066 do_pending_stack_adjust ();
1067 catch_clauses
= get_insns ();
1073 rtx funcend
= gen_label_rtx ();
1074 emit_jump (funcend
);
1076 /* We cannot protect n regions this way if we must flow into the
1077 EH region through the top of the region, as we have to with
1078 the setjmp/longjmp approach. */
1079 if (exceptions_via_longjmp
== 0)
1080 expand_eh_region_start ();
1082 emit_insns (catch_clauses
);
1083 catch_clauses
= NULL_RTX
;
1085 if (exceptions_via_longjmp
== 0)
1086 expand_eh_region_end (build_function_call (Terminate
, NULL_TREE
));
1088 expand_leftover_cleanups ();
1090 emit_label (funcend
);
1097 static int counter
= 0;
1098 int old_interface_unknown
= interface_unknown
;
1103 push_cp_function_context (NULL_TREE
);
1104 push_to_top_level ();
1106 /* No need to mangle this. */
1107 push_lang_context (lang_name_c
);
1109 interface_unknown
= 1;
1111 params
= void_list_node
;
1112 /* tcf stands for throw clean function. */
1113 sprintf (name
, "__tcf_%d", counter
++);
1114 t
= make_call_declarator (get_identifier (name
), params
, NULL_TREE
,
1116 start_function (decl_tree_cons (NULL_TREE
, get_identifier ("static"),
1119 store_parm_decls ();
1123 expand_start_bindings (0);
1124 emit_line_note (input_filename
, lineno
);
1126 interface_unknown
= old_interface_unknown
;
1128 pop_lang_context ();
1130 return current_function_decl
;
1136 expand_end_bindings (getdecls (), 1, 0);
1140 finish_function (lineno
, 0, 0);
1142 pop_from_top_level ();
1143 pop_cp_function_context (NULL_TREE
);
1146 /* Expand a throw statement. This follows the following
1149 1. Allocate space to save the current PC onto the stack.
1150 2. Generate and emit a label and save its address into the
1151 newly allocated stack space since we can't save the pc directly.
1152 3. If this is the first call to throw in this function:
1153 generate a label for the throw block
1154 4. jump to the throw block label. */
1162 static tree cleanup_type
;
1170 tree cleanup
= NULL_TREE
, e
;
1172 /* throw expression */
1173 /* First, decay it. */
1174 exp
= decay_conversion (exp
);
1176 /* cleanup_type is void (*)(void *, int),
1177 the internal type of a destructor. */
1178 if (cleanup_type
== NULL_TREE
)
1180 push_obstacks_nochange ();
1181 end_temporary_allocation ();
1182 cleanup_type
= build_pointer_type
1183 (build_function_type
1184 (void_type_node
, tree_cons
1185 (NULL_TREE
, ptr_type_node
, tree_cons
1186 (NULL_TREE
, integer_type_node
, void_list_node
))));
1190 if (TREE_CODE (TREE_TYPE (exp
)) == POINTER_TYPE
)
1192 throw_type
= build_eh_type (exp
);
1193 exp
= build_reinterpret_cast (ptr_type_node
, exp
);
1199 /* Make a copy of the thrown object. WP 15.1.5 */
1200 exp
= build_new (NULL_TREE
, TREE_TYPE (exp
),
1201 build_expr_list (NULL_TREE
, exp
),
1204 if (exp
== error_mark_node
)
1205 error (" in thrown expression");
1207 object
= build_indirect_ref (exp
, NULL_PTR
);
1208 throw_type
= build_eh_type (object
);
1210 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object
)))
1212 cleanup
= lookup_fnfields (TYPE_BINFO (TREE_TYPE (object
)),
1213 dtor_identifier
, 0);
1214 cleanup
= TREE_VALUE (cleanup
);
1215 mark_used (cleanup
);
1216 mark_addressable (cleanup
);
1217 /* Pretend it's a normal function. */
1218 cleanup
= build1 (ADDR_EXPR
, cleanup_type
, cleanup
);
1222 if (cleanup
== NULL_TREE
)
1224 cleanup
= build_int_2 (0, 0);
1225 TREE_TYPE (cleanup
) = cleanup_type
;
1228 fn
= get_identifier ("__cp_push_exception");
1229 if (IDENTIFIER_GLOBAL_VALUE (fn
))
1230 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
1233 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1234 as defined in exception.cc. */
1236 push_obstacks_nochange ();
1237 end_temporary_allocation ();
1239 (NULL_TREE
, ptr_type_node
, tree_cons
1240 (NULL_TREE
, ptr_type_node
, tree_cons
1241 (NULL_TREE
, cleanup_type
, void_list_node
)));
1242 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
1243 build_function_type (void_type_node
, tmp
));
1244 DECL_EXTERNAL (fn
) = 1;
1245 TREE_PUBLIC (fn
) = 1;
1246 DECL_ARTIFICIAL (fn
) = 1;
1247 pushdecl_top_level (fn
);
1248 make_function_rtl (fn
);
1249 assemble_external (fn
);
1253 /* The throw expression is a full-expression. */
1254 exp
= build1 (CLEANUP_POINT_EXPR
, TREE_TYPE (exp
), exp
);
1255 e
= expr_tree_cons (NULL_TREE
, exp
, expr_tree_cons
1256 (NULL_TREE
, throw_type
, expr_tree_cons
1257 (NULL_TREE
, cleanup
, NULL_TREE
)));
1258 e
= build_function_call (fn
, e
);
1259 expand_expr (e
, const0_rtx
, VOIDmode
, 0);
1263 /* rethrow current exception; note that it's no longer caught. */
1265 tree fn
= get_identifier ("__uncatch_exception");
1266 if (IDENTIFIER_GLOBAL_VALUE (fn
))
1267 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
1270 /* Declare void __uncatch_exception (void)
1271 as defined in exception.cc. */
1272 push_obstacks_nochange ();
1273 end_temporary_allocation ();
1274 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
1275 build_function_type (void_type_node
,
1277 DECL_EXTERNAL (fn
) = 1;
1278 TREE_PUBLIC (fn
) = 1;
1279 DECL_ARTIFICIAL (fn
) = 1;
1280 pushdecl_top_level (fn
);
1281 make_function_rtl (fn
);
1282 assemble_external (fn
);
1286 exp
= build_function_call (fn
, NULL_TREE
);
1287 expand_expr (exp
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1290 expand_internal_throw ();
1293 /* Build a throw expression. */
1299 if (e
!= error_mark_node
)
1301 if (processing_template_decl
)
1302 return build_min (THROW_EXPR
, void_type_node
, e
);
1303 e
= build1 (THROW_EXPR
, void_type_node
, e
);
1304 TREE_SIDE_EFFECTS (e
) = 1;