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 /* Used to cache a call to __builtin_return_address. */
46 static tree BuiltinReturnAddress;
48 static void easy_expand_asm PROTO((char *));
49 static void push_eh_cleanup PROTO((void));
50 static void do_unwind PROTO((rtx));
51 static rtx do_function_call PROTO((tree, tree, tree));
52 static tree build_eh_type_type PROTO((tree));
53 static tree build_eh_type PROTO((tree));
54 static void expand_end_eh_spec PROTO((tree));
60 expand_asm (build_string (strlen (str)+1, str));
65 /* This is the startup, and finish stuff per exception table. */
67 /* XXX - Tad: exception handling section */
68 #ifndef EXCEPT_SECTION_ASM_OP
69 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
72 #ifdef EXCEPT_SECTION_ASM_OP
76 void *exception_handler;
78 #endif /* EXCEPT_SECTION_ASM_OP */
80 #ifdef EXCEPT_SECTION_ASM_OP
82 /* on machines which support it, the exception table lives in another section,
83 but it needs a label so we can reference it... This sets up that
85 asm (EXCEPT_SECTION_ASM_OP);
86 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
87 asm (TEXT_SECTION_ASM_OP);
89 #endif /* EXCEPT_SECTION_ASM_OP */
91 #ifdef EXCEPT_SECTION_ASM_OP
93 /* we need to know where the end of the exception table is... so this
96 asm (EXCEPT_SECTION_ASM_OP);
97 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
98 asm (TEXT_SECTION_ASM_OP);
100 #endif /* EXCEPT_SECTION_ASM_OP */
105 #include "insn-flags.h"
108 /* ======================================================================
109 Briefly the algorithm works like this:
111 When a constructor or start of a try block is encountered,
112 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
113 new entry in the unwind protection stack and returns a label to
114 output to start the protection for that block.
116 When a destructor or end try block is encountered, pop_eh_entry
117 (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it
118 created when push_eh_entry () was called. The eh_entry structure
119 contains three things at this point. The start protect label,
120 the end protect label, and the exception handler label. The end
121 protect label should be output before the call to the destructor
122 (if any). If it was a destructor, then its parse tree is stored
123 in the finalization variable in the eh_entry structure. Otherwise
124 the finalization variable is set to NULL to reflect the fact that
125 is the the end of a try block. Next, this modified eh_entry node
126 is enqueued in the finalizations queue by calling
127 enqueue_eh_entry (&queue,entry).
129 +---------------------------------------------------------------+
130 |XXX: Will need modification to deal with partially |
131 | constructed arrays of objects |
133 | Basically, this consists of keeping track of how many |
134 | of the objects have been constructed already (this |
135 | should be in a register though, so that shouldn't be a |
137 +---------------------------------------------------------------+
139 When a catch block is encountered, there is a lot of work to be
142 Since we don't want to generate the catch block inline with the
143 regular flow of the function, we need to have some way of doing
144 so. Luckily, we can use sequences to defer the catch sections.
145 When the start of a catch block is encountered, we start the
146 sequence. After the catch block is generated, we end the
149 Next we must insure that when the catch block is executed, all
150 finalizations for the matching try block have been completed. If
151 any of those finalizations throw an exception, we must call
152 terminate according to the ARM (section r.15.6.1). What this
153 means is that we need to dequeue and emit finalizations for each
154 entry in the eh_queue until we get to an entry with a NULL
155 finalization field. For any of the finalization entries, if it
156 is not a call to terminate (), we must protect it by giving it
157 another start label, end label, and exception handler label,
158 setting its finalization tree to be a call to terminate (), and
159 enqueue'ing this new eh_entry to be output at an outer level.
160 Finally, after all that is done, we can get around to outputting
161 the catch block which basically wraps all the "catch (...) {...}"
162 statements in a big if/then/else construct that matches the
163 correct block to call.
165 ===================================================================== */
167 /* local globals for function calls
168 ====================================================================== */
170 /* Used to cache "terminate", "unexpected", "set_terminate", and
171 "set_unexpected" after default_conversion. (lib-except.c) */
172 static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
174 /* Used to cache __find_first_exception_table_match for throw. */
175 static tree FirstExceptionMatch;
177 /* Used to cache a call to __unwind_function. */
180 /* Holds a ready to emit call to "terminate". */
181 static tree TerminateFunctionCall;
183 /* ====================================================================== */
186 /* ========================================================================= */
190 /* local globals - these local globals are for storing data necessary for
191 generating the exception table and code in the correct order.
193 ========================================================================= */
195 /* Holds the pc for doing "throw" */
196 static tree saved_pc;
198 extern int throw_used;
199 extern rtx catch_clauses;
201 /* ========================================================================= */
203 /* Cheesyness to save some typing. Returns the return value rtx. */
206 do_function_call (func, params, return_type)
207 tree func, params, return_type;
210 func_call = build_function_call (func, params);
211 expand_call (func_call, NULL_RTX, 0);
212 if (return_type != NULL_TREE)
213 return hard_function_value (return_type, func_call);
217 /* ========================================================================= */
219 /* sets up all the global eh stuff that needs to be initialized at the
220 start of compilation.
223 - Setting up all the function call trees. */
226 init_exception_processing ()
228 tree unexpected_fndecl, terminate_fndecl;
229 tree set_unexpected_fndecl, set_terminate_fndecl;
230 tree catch_match_fndecl;
231 tree find_first_exception_match_fndecl;
237 tree vtype = build_function_type (void_type_node, void_list_node);
240 tree PFV = build_pointer_type (vtype);
242 /* Arg list for the build_function_type call for set_terminate and
244 tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
246 /* void (*pfvtype (void (*) ()))() */
247 tree pfvtype = build_function_type (PFV, pfvlist);
249 set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
250 pfvtype, NOT_BUILT_IN);
251 set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
252 pfvtype, NOT_BUILT_IN);
253 unexpected_fndecl = auto_function (get_identifier ("unexpected"),
254 vtype, NOT_BUILT_IN);
255 terminate_fndecl = auto_function (get_identifier ("terminate"),
256 vtype, NOT_BUILT_IN);
257 TREE_THIS_VOLATILE (terminate_fndecl) = 1;
259 push_lang_context (lang_name_c);
262 = builtin_function (flag_rtti
263 ? "__throw_type_match_rtti"
264 : "__throw_type_match",
265 build_function_type (ptr_type_node,
266 tree_cons (NULL_TREE, ptr_type_node,
267 tree_cons (NULL_TREE, ptr_type_node,
268 tree_cons (NULL_TREE, ptr_type_node,
270 NOT_BUILT_IN, NULL_PTR);
271 find_first_exception_match_fndecl
272 = builtin_function ("__find_first_exception_table_match",
273 build_function_type (ptr_type_node,
274 tree_cons (NULL_TREE, ptr_type_node,
276 NOT_BUILT_IN, NULL_PTR);
278 = builtin_function ("__unwind_function",
279 build_function_type (void_type_node,
280 tree_cons (NULL_TREE, ptr_type_node,
282 NOT_BUILT_IN, NULL_PTR);
284 Unexpected = default_conversion (unexpected_fndecl);
285 Terminate = default_conversion (terminate_fndecl);
286 SetTerminate = default_conversion (set_terminate_fndecl);
287 SetUnexpected = default_conversion (set_unexpected_fndecl);
288 CatchMatch = default_conversion (catch_match_fndecl);
289 FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
290 Unwind = default_conversion (unwind_fndecl);
291 BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
293 TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
297 d = build_decl (VAR_DECL, get_identifier ("__eh_pc"), ptr_type_node);
299 DECL_EXTERNAL (d) = 1;
300 DECL_ARTIFICIAL (d) = 1;
301 cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
304 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
305 be protected with __terminate. */
306 protect_cleanup_actions_with_terminate = 1;
309 /* Retrieve a pointer to the cp_eh_info node for the current exception
310 and save it in the current binding level. */
317 fn = get_identifier ("__cp_exception_info");
318 if (IDENTIFIER_GLOBAL_VALUE (fn))
319 fn = IDENTIFIER_GLOBAL_VALUE (fn);
324 /* Declare cp_eh_info * __cp_exception_info (void),
325 as defined in exception.cc. */
326 push_obstacks_nochange ();
327 end_temporary_allocation ();
329 /* struct cp_eh_info. This must match exception.cc. Note that this
330 type is not pushed anywhere. */
331 t = make_lang_type (RECORD_TYPE);
332 fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
334 fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
336 fields[2] = build_lang_field_decl
337 (FIELD_DECL, get_identifier ("cleanup"),
338 build_pointer_type (build_function_type
339 (ptr_type_node, tree_cons
340 (NULL_TREE, ptr_type_node, void_list_node))));
341 fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
343 fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
344 build_pointer_type (t));
345 finish_builtin_type (t, "cp_eh_info", fields, 5, ptr_type_node);
346 t = build_pointer_type (t);
348 /* And now the function. */
349 fn = build_lang_decl (FUNCTION_DECL, fn,
350 build_function_type (t, void_list_node));
351 DECL_EXTERNAL (fn) = 1;
352 TREE_PUBLIC (fn) = 1;
353 DECL_ARTIFICIAL (fn) = 1;
354 pushdecl_top_level (fn);
355 make_function_rtl (fn);
356 assemble_external (fn);
359 fn = build_function_call (fn, NULL_TREE);
361 /* Remember the pointer to the current exception info; it won't change
362 during this catch block. */
363 decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
365 DECL_ARTIFICIAL (decl) = 1;
366 DECL_INITIAL (decl) = fn;
367 decl = pushdecl (decl);
368 cp_finish_decl (decl, fn, NULL_TREE, 0, 0);
371 /* Returns a reference to the cp_eh_info node for the current exception. */
376 /* Look for the pointer pushed in push_eh_info. */
377 tree t = lookup_name (get_identifier ("__exception_info"), 0);
378 return build_indirect_ref (t, NULL_PTR);
381 /* Returns a reference to the current exception object. */
386 return build_component_ref (get_eh_info (), get_identifier ("value"),
390 /* Returns a reference to the current exception type. */
395 return build_component_ref (get_eh_info (), get_identifier ("type"),
399 /* Returns a reference to whether or not the current exception
405 return build_component_ref (get_eh_info (), get_identifier ("caught"),
409 /* Build a type value for use at runtime for a type that is matched
410 against by the exception handling system. */
413 build_eh_type_type (type)
419 if (type == error_mark_node)
420 return error_mark_node;
422 /* peel back references, so they match. */
423 if (TREE_CODE (type) == REFERENCE_TYPE)
424 type = TREE_TYPE (type);
426 /* Peel off cv qualifiers. */
427 type = TYPE_MAIN_VARIANT (type);
431 return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
434 typestring = build_overload_name (type, 1, 1);
435 exp = combine_strings (build_string (strlen (typestring)+1, typestring));
436 return build1 (ADDR_EXPR, ptr_type_node, exp);
439 /* Build a type value for use at runtime for a exp that is thrown or
440 matched against by the exception handling system. */
448 exp = build_typeid (exp);
449 return build1 (ADDR_EXPR, ptr_type_node, exp);
451 return build_eh_type_type (TREE_TYPE (exp));
454 /* This routine creates the cleanup for the current exception. */
459 /* All cleanups must last longer than normal. */
460 int yes = suspend_momentary ();
463 fn = get_identifier ("__cp_pop_exception");
464 if (IDENTIFIER_GLOBAL_VALUE (fn))
465 fn = IDENTIFIER_GLOBAL_VALUE (fn);
468 /* Declare void __cp_pop_exception (void), as defined in exception.cc. */
469 push_obstacks_nochange ();
470 end_temporary_allocation ();
471 fn = build_lang_decl (FUNCTION_DECL, fn,
472 build_function_type (void_type_node,
474 DECL_EXTERNAL (fn) = 1;
475 TREE_PUBLIC (fn) = 1;
476 DECL_ARTIFICIAL (fn) = 1;
477 pushdecl_top_level (fn);
478 make_function_rtl (fn);
479 assemble_external (fn);
483 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
484 cleanup = build_function_call (fn, NULL_TREE);
485 expand_decl_cleanup (NULL_TREE, cleanup);
487 resume_momentary (yes);
491 /* call this to start a catch block. Typename is the typename, and identifier
492 is the variable to place the object in or NULL if the variable doesn't
493 matter. If typename is NULL, that means its a "catch (...)" or catch
494 everything. In that case we don't need to do any type checking.
495 (ie: it ends up as the "else" clause rather than an "else if" clause) */
498 expand_start_catch_block (declspecs, declarator)
499 tree declspecs, declarator;
502 tree decl = NULL_TREE;
505 if (processing_template_decl)
509 decl = grokdeclarator (declarator, declspecs, CATCHPARM,
512 decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
513 copy_to_permanent (declspecs),
523 /* Create a binding level for the parm. */
525 expand_start_bindings (0);
527 false_label_rtx = gen_label_rtx ();
528 push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
530 emit_line_note (input_filename, lineno);
534 /* If we are not doing setjmp/longjmp EH, because we are reordered
535 out of line, we arrange to rethrow in the outer context so as to
536 skip through the terminate region we are nested in, should we
537 encounter an exception in the catch handler.
539 If we are doing setjmp/longjmp EH, we need to skip through the EH
540 object cleanup region. This isn't quite right, as we really need
541 to clean the object up, but we cannot do that until we track
544 Matches the end in expand_end_catch_block. */
545 expand_eh_region_start ();
552 rtx call_rtx, return_value_rtx;
555 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
557 if (decl == NULL_TREE)
559 error ("invalid catch parameter");
563 /* Make sure we mark the catch param as used, otherwise we'll get
564 a warning about an unused ((anonymous)). */
565 TREE_USED (decl) = 1;
567 /* Figure out the type that the initializer is. */
568 init_type = TREE_TYPE (decl);
569 if (TREE_CODE (init_type) != REFERENCE_TYPE
570 && TREE_CODE (init_type) != POINTER_TYPE)
571 init_type = build_reference_type (init_type);
573 exp = get_eh_value ();
574 exp = expr_tree_cons (NULL_TREE,
575 build_eh_type_type (TREE_TYPE (decl)),
576 expr_tree_cons (NULL_TREE,
578 expr_tree_cons (NULL_TREE, exp, NULL_TREE)));
579 exp = build_function_call (CatchMatch, exp);
580 call_rtx = expand_call (exp, NULL_RTX, 0);
581 assemble_external (TREE_OPERAND (CatchMatch, 0));
583 return_value_rtx = hard_function_value (ptr_type_node, exp);
585 /* did the throw type match function return TRUE? */
586 emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
587 GET_MODE (return_value_rtx), 0, 0);
589 /* if it returned FALSE, jump over the catch block, else fall into it */
590 emit_jump_insn (gen_beq (false_label_rtx));
592 init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
594 /* Do we need the below two lines? */
595 /* Let `cp_finish_decl' know that this initializer is ok. */
596 DECL_INITIAL (decl) = init;
597 decl = pushdecl (decl);
598 cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
601 init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node);
602 expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL);
604 emit_line_note (input_filename, lineno);
609 /* Call this to end a catch block. Its responsible for emitting the
610 code to handle jumping back to the correct place, and for emitting
611 the label to jump to if this catch block didn't match. */
614 expand_end_catch_block ()
616 rtx start_region_label_rtx;
617 rtx end_region_label_rtx;
623 t = make_node (RTL_EXPR);
624 TREE_TYPE (t) = void_type_node;
625 RTL_EXPR_RTL (t) = const0_rtx;
626 TREE_SIDE_EFFECTS (t) = 1;
627 do_pending_stack_adjust ();
628 start_sequence_for_rtl_expr (t);
630 if (exceptions_via_longjmp)
632 /* If we are doing setjmp/longjmp EH, we need to skip through
633 the EH object cleanup region. This isn't quite right, as we
634 really need to clean the object up, but we cannot do that
635 until we track multiple EH objects. */
637 emit_library_call (sjpopnthrow_libfunc, 0, VOIDmode, 0);
642 /* If we are not doing setjmp/longjmp EH, we need an extra
643 region around the whole catch block to skip through the
644 terminate region we are nested in. */
646 expand_internal_throw (DECL_RTL (top_label_entry (&caught_return_label_stack)));
649 do_pending_stack_adjust ();
650 RTL_EXPR_SEQUENCE (t) = get_insns ();
653 /* Matches the start in expand_start_catch_block. */
654 expand_eh_region_end (t);
656 /* Fall to outside the try statement when done executing handler and
657 we fall off end of handler. This is jump Lresume in the
659 expand_goto (top_label_entry (&caught_return_label_stack));
661 expand_leftover_cleanups ();
663 /* Cleanup the EH parameter. */
664 expand_end_bindings (getdecls (), kept_level_p (), 0);
665 poplevel (kept_level_p (), 1, 0);
667 /* label we emit to jump to if this catch block didn't match. */
668 /* This the closing } in the `if (eq) {' of the documentation. */
669 emit_label (pop_label_entry (&false_label_stack));
672 /* unwind the stack. */
675 do_unwind (inner_throw_label)
676 rtx inner_throw_label;
678 #if defined (SPARC_STACK_ALIGN) /* was sparc */
679 /* This doesn't work for the flat model sparc, nor does it need to
680 as the default unwinder is only used to unwind non-flat frames. */
686 /* Call to __builtin_return_address. */
687 params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
688 fcall = build_function_call (BuiltinReturnAddress, params);
689 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
690 /* In the return, the new pc is pc+8, as the value coming in is
691 really the address of the call insn, not the next insn. */
692 temp = gen_reg_rtx (Pmode);
693 emit_move_insn (temp, inner_throw_label);
694 emit_move_insn (next_pc, plus_constant (temp, -8));
695 emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31)));
696 easy_expand_asm ("ret");
697 easy_expand_asm ("restore");
700 #if defined (ARM_FRAME_RTX) /* was __arm */
701 if (flag_omit_frame_pointer)
702 sorry ("this implementation of exception handling requires a frame pointer");
704 emit_move_insn (stack_pointer_rtx,
705 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
706 emit_move_insn (hard_frame_pointer_rtx,
707 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
709 #if defined (TARGET_88000) /* was m88k */
710 rtx temp_frame = frame_pointer_rtx;
712 temp_frame = memory_address (Pmode, temp_frame);
713 temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
715 /* hopefully this will successfully pop the frame! */
716 emit_move_insn (frame_pointer_rtx, temp_frame);
717 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
718 emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
719 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
720 (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
723 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
724 -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
726 emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
728 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
729 (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
732 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
738 /* I would like to do this here, but the move below doesn't seem to work. */
739 /* Call to __builtin_return_address. */
740 params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
741 fcall = build_function_call (BuiltinReturnAddress, params);
742 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
744 emit_move_insn (next_pc, inner_throw_label);
745 /* So, for now, just pass throw label to stack unwinder. */
747 params = expr_tree_cons (NULL_TREE, make_tree (ptr_type_node,
748 inner_throw_label), NULL_TREE);
750 do_function_call (Unwind, params, NULL_TREE);
751 assemble_external (TREE_OPERAND (Unwind, 0));
757 /* Is called from expand_exception_blocks to generate the code in a function
758 to "throw" if anything in the function needs to perform a throw.
760 expands "throw" as the following pseudo code:
763 eh = find_first_exception_match (saved_pc);
764 if (!eh) goto gotta_rethrow_it;
768 saved_pc = __builtin_return_address (0);
769 pop_to_previous_level ();
773 expand_builtin_throw ()
775 #ifndef DWARF2_UNWIND_INFO
781 rtx gotta_rethrow_it;
782 rtx gotta_call_terminate;
794 params = void_list_node;
795 t = make_call_declarator (get_identifier ("__throw"), params, NULL_TREE,
797 start_function (decl_tree_cons (NULL_TREE,
798 get_identifier ("void"),
799 decl_tree_cons (NULL_TREE,
800 get_identifier ("static"),
807 expand_start_bindings (0);
809 gotta_rethrow_it = gen_label_rtx ();
810 gotta_call_terminate = gen_label_rtx ();
812 /* These two can be frontend specific. If wanted, they can go in
814 /* Do we have a valid object we are throwing? */
815 emit_cmp_insn (DECL_RTL (saved_throw_type), const0_rtx, EQ, NULL_RTX,
816 GET_MODE (DECL_RTL (saved_throw_type)), 0, 0);
817 emit_jump_insn (gen_beq (gotta_call_terminate));
819 /* search for an exception handler for the saved_pc */
820 handler = do_function_call (FirstExceptionMatch,
821 expr_tree_cons (NULL_TREE, saved_pc,
824 assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
826 /* did we find one? */
827 emit_cmp_insn (handler, const0_rtx, EQ, NULL_RTX,
828 GET_MODE (handler), 0, 0);
830 /* if not, jump to gotta_rethrow_it */
831 emit_jump_insn (gen_beq (gotta_rethrow_it));
835 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
836 0, hard_frame_pointer_rtx);
838 /* Set it up so that we continue at the handler. */
839 emit_move_insn (ret_val, handler);
840 #ifdef RETURN_ADDR_OFFSET
841 x = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
843 emit_move_insn (ret_val, x);
846 expand_null_return ();
849 top_of_loop = gen_label_rtx ();
850 emit_label (top_of_loop);
852 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
853 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
855 saved_pcnthrow = gen_reg_rtx (Pmode);
856 emit_move_insn (saved_pcnthrow, hard_function_value (ptr_type_node,
861 /* Call to __builtin_return_address. */
862 #if defined (ARM_FRAME_RTX) /* was __arm */
863 /* This should be moved into arm.h:RETURN_ADDR_RTX */
864 /* This replaces a 'call' to __builtin_return_address */
865 next_pc = gen_reg_rtx (Pmode);
866 emit_move_insn (next_pc,
867 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
869 params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
870 fcall = build_function_call (BuiltinReturnAddress, params);
871 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
874 /* Did __builtin_return_address return a valid address? */
875 emit_cmp_insn (next_pc, const0_rtx, EQ, NULL_RTX,
876 GET_MODE (next_pc), 0, 0);
878 emit_jump_insn (gen_beq (gotta_call_terminate));
880 next_pc = eh_outer_context (next_pc);
883 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
884 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
888 x = validize_mem (gen_rtx (MEM, Pmode, saved_pcnthrow));
889 emit_move_insn (validize_mem (gen_rtx (MEM, Pmode, x)),
891 #ifdef FUNCTION_OUTGOING_VALUE
892 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
893 validize_mem (gen_rtx (MEM, Pmode,
894 plus_constant (saved_pcnthrow,
895 GET_MODE_SIZE (Pmode)))));
896 emit_insn (gen_rtx (USE, VOIDmode,
897 FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
902 emit_move_insn (eh_saved_pc_rtx, next_pc);
904 after_unwind = gen_label_rtx ();
905 do_unwind (gen_rtx (LABEL_REF, Pmode, after_unwind));
907 emit_label (after_unwind);
909 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
910 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
912 t = build_function_type (void_type_node, void_list_node);
913 t = make_tree (build_pointer_type (t),
914 hard_function_value (ptr_type_node,
916 t = build_function_call (t, NULL_TREE);
917 expand_expr (t, const0_rtx, VOIDmode, 0);
923 /* no it didn't --> therefore we need to call terminate */
924 emit_label (gotta_call_terminate);
925 do_function_call (Terminate, NULL_TREE, NULL_TREE);
926 assemble_external (TREE_OPERAND (Terminate, 0));
930 /* code to deal with unwinding and looking for it again */
931 emit_label (gotta_rethrow_it);
932 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
933 0, hard_frame_pointer_rtx);
935 /* Set it up so that we continue inside, at the top of the loop. */
936 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
937 #ifdef RETURN_ADDR_OFFSET
938 x = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
940 emit_move_insn (ret_val, x);
943 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
944 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
946 rtx x = emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode,
950 /* This is to get a version of throw that will throw properly. */
951 emit_move_insn (validize_mem (gen_rtx (MEM, Pmode,
952 plus_constant (x, GET_MODE_SIZE (Pmode)))),
954 #ifdef FUNCTION_OUTGOING_VALUE
955 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
957 emit_insn (gen_rtx (USE, VOIDmode, FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
962 /* Fall into epilogue to unwind prologue. */
965 expand_end_bindings (getdecls (), 1, 0);
969 finish_function (lineno, 0, 0);
970 #endif /* DWARF2_UNWIND_INFO */
975 expand_start_eh_spec ()
977 expand_eh_region_start ();
981 expand_end_eh_spec (raises)
984 tree expr, second_try;
985 rtx check = gen_label_rtx ();
987 rtx ret = gen_reg_rtx (Pmode);
988 rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
989 rtx end = gen_label_rtx ();
991 expr = make_node (RTL_EXPR);
992 TREE_TYPE (expr) = void_type_node;
993 RTL_EXPR_RTL (expr) = const0_rtx;
994 TREE_SIDE_EFFECTS (expr) = 1;
995 do_pending_stack_adjust ();
996 start_sequence_for_rtl_expr (expr);
997 cont = gen_label_rtx ();
998 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1001 jumpif (make_tree (integer_type_node, flag), end);
1002 do_function_call (Terminate, NULL_TREE, NULL_TREE);
1003 assemble_external (TREE_OPERAND (Terminate, 0));
1005 do_pending_stack_adjust ();
1006 RTL_EXPR_SEQUENCE (expr) = get_insns ();
1011 expr = make_node (RTL_EXPR);
1012 TREE_TYPE (expr) = void_type_node;
1013 RTL_EXPR_RTL (expr) = const0_rtx;
1014 TREE_SIDE_EFFECTS (expr) = 1;
1015 do_pending_stack_adjust ();
1016 start_sequence_for_rtl_expr (expr);
1018 cont = gen_label_rtx ();
1019 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1022 jumpif (make_tree (integer_type_node, flag), end);
1023 expand_eh_region_start ();
1024 do_function_call (Unexpected, NULL_TREE, NULL_TREE);
1025 assemble_external (TREE_OPERAND (Unexpected, 0));
1028 expand_eh_region_end (second_try);
1031 emit_move_insn (flag, const1_rtx);
1032 cont = gen_label_rtx ();
1039 tree match_type = TREE_VALUE (raises);
1043 /* check TREE_VALUE (raises) here */
1044 exp = get_eh_value ();
1045 exp = expr_tree_cons (NULL_TREE,
1046 build_eh_type_type (match_type),
1047 expr_tree_cons (NULL_TREE,
1049 expr_tree_cons (NULL_TREE, exp, NULL_TREE)));
1050 exp = build_function_call (CatchMatch, exp);
1051 assemble_external (TREE_OPERAND (CatchMatch, 0));
1056 raises = TREE_CHAIN (raises);
1058 emit_move_insn (flag, const0_rtx);
1060 emit_indirect_jump (ret);
1063 do_pending_stack_adjust ();
1064 RTL_EXPR_SEQUENCE (expr) = get_insns ();
1067 expand_eh_region_end (expr);
1070 /* This is called to expand all the toplevel exception handling
1071 finalization for a function. It should only be called once per
1075 expand_exception_blocks ()
1077 do_pending_stack_adjust ();
1078 push_to_sequence (catch_clauses);
1079 expand_leftover_cleanups ();
1080 do_pending_stack_adjust ();
1081 catch_clauses = get_insns ();
1084 /* Do this after we expand leftover cleanups, so that the
1085 expand_eh_region_end that expand_end_eh_spec does will match the
1086 right expand_eh_region_start, and make sure it comes out before
1087 the terminate protected region. */
1088 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
1090 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
1091 do_pending_stack_adjust ();
1092 push_to_sequence (catch_clauses);
1093 expand_leftover_cleanups ();
1094 do_pending_stack_adjust ();
1095 catch_clauses = get_insns ();
1101 rtx funcend = gen_label_rtx ();
1102 emit_jump (funcend);
1104 /* We cannot protect n regions this way if we must flow into the
1105 EH region through the top of the region, as we have to with
1106 the setjmp/longjmp approach. */
1107 if (exceptions_via_longjmp == 0)
1109 /* Is this necessary? */
1110 assemble_external (TREE_OPERAND (Terminate, 0));
1112 expand_eh_region_start ();
1115 emit_insns (catch_clauses);
1116 catch_clauses = NULL_RTX;
1118 if (exceptions_via_longjmp == 0)
1119 expand_eh_region_end (TerminateFunctionCall);
1121 expand_leftover_cleanups ();
1123 emit_label (funcend);
1130 static int counter = 0;
1131 int old_interface_unknown = interface_unknown;
1136 push_cp_function_context (NULL_TREE);
1137 push_to_top_level ();
1139 /* No need to mangle this. */
1140 push_lang_context (lang_name_c);
1142 interface_unknown = 1;
1144 params = void_list_node;
1145 /* tcf stands for throw clean funciton. */
1146 sprintf (name, "__tcf_%d", counter++);
1147 t = make_call_declarator (get_identifier (name), params, NULL_TREE,
1149 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1152 store_parm_decls ();
1156 expand_start_bindings (0);
1157 emit_line_note (input_filename, lineno);
1159 interface_unknown = old_interface_unknown;
1161 pop_lang_context ();
1163 return current_function_decl;
1169 expand_end_bindings (getdecls (), 1, 0);
1173 finish_function (lineno, 0, 0);
1175 pop_from_top_level ();
1176 pop_cp_function_context (NULL_TREE);
1179 /* Expand a throw statement. This follows the following
1182 1. Allocate space to save the current PC onto the stack.
1183 2. Generate and emit a label and save its address into the
1184 newly allocated stack space since we can't save the pc directly.
1185 3. If this is the first call to throw in this function:
1186 generate a label for the throw block
1187 4. jump to the throw block label. */
1195 static tree cleanup_type;
1203 tree cleanup = NULL_TREE, e;
1205 /* throw expression */
1206 /* First, decay it. */
1207 exp = decay_conversion (exp);
1209 /* cleanup_type is void (*)(void *, int),
1210 the internal type of a destructor. */
1211 if (cleanup_type == NULL_TREE)
1213 push_obstacks_nochange ();
1214 end_temporary_allocation ();
1215 cleanup_type = build_pointer_type
1216 (build_function_type
1217 (void_type_node, tree_cons
1218 (NULL_TREE, ptr_type_node, tree_cons
1219 (NULL_TREE, integer_type_node, void_list_node))));
1223 if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1225 throw_type = build_eh_type (exp);
1226 exp = build_reinterpret_cast (ptr_type_node, exp);
1232 /* Make a copy of the thrown object. WP 15.1.5 */
1233 exp = build_new (NULL_TREE, TREE_TYPE (exp),
1234 build_expr_list (NULL_TREE, exp),
1237 if (exp == error_mark_node)
1238 error (" in thrown expression");
1240 object = build_indirect_ref (exp, NULL_PTR);
1241 throw_type = build_eh_type (object);
1243 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
1245 cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
1246 dtor_identifier, 0);
1247 cleanup = TREE_VALUE (cleanup);
1248 mark_addressable (cleanup);
1249 /* Pretend it's a normal function. */
1250 cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
1254 if (cleanup == NULL_TREE)
1256 cleanup = build_int_2 (0, 0);
1257 TREE_TYPE (cleanup) = cleanup_type;
1260 fn = get_identifier ("__cp_push_exception");
1261 if (IDENTIFIER_GLOBAL_VALUE (fn))
1262 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1265 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1266 as defined in exception.cc. */
1268 push_obstacks_nochange ();
1269 end_temporary_allocation ();
1271 (NULL_TREE, ptr_type_node, tree_cons
1272 (NULL_TREE, ptr_type_node, tree_cons
1273 (NULL_TREE, cleanup_type, void_list_node)));
1274 fn = build_lang_decl (FUNCTION_DECL, fn,
1275 build_function_type (void_type_node, tmp));
1276 DECL_EXTERNAL (fn) = 1;
1277 TREE_PUBLIC (fn) = 1;
1278 DECL_ARTIFICIAL (fn) = 1;
1279 pushdecl_top_level (fn);
1280 make_function_rtl (fn);
1281 assemble_external (fn);
1285 /* The throw expression is a full-expression. */
1286 exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
1287 e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons
1288 (NULL_TREE, throw_type, expr_tree_cons
1289 (NULL_TREE, cleanup, NULL_TREE)));
1290 e = build_function_call (fn, e);
1291 expand_expr (e, const0_rtx, VOIDmode, 0);
1295 /* rethrow current exception; note that it's no longer caught. */
1297 tree fn = get_identifier ("__uncatch_exception");
1298 if (IDENTIFIER_GLOBAL_VALUE (fn))
1299 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1302 /* Declare void __uncatch_exception (void)
1303 as defined in exception.cc. */
1304 push_obstacks_nochange ();
1305 end_temporary_allocation ();
1306 fn = build_lang_decl (FUNCTION_DECL, fn,
1307 build_function_type (void_type_node,
1309 DECL_EXTERNAL (fn) = 1;
1310 TREE_PUBLIC (fn) = 1;
1311 DECL_ARTIFICIAL (fn) = 1;
1312 pushdecl_top_level (fn);
1313 make_function_rtl (fn);
1314 assemble_external (fn);
1318 exp = build_function_call (fn, NULL_TREE);
1319 expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
1322 if (exceptions_via_longjmp)
1326 /* This is the label that represents where in the code we were, when
1327 we got an exception. This needs to be updated when we rethrow an
1328 exception, so that the matching routine knows to search out. */
1329 label = gen_label_rtx ();
1332 expand_internal_throw (label);
1336 /* Build a throw expression. */
1342 if (e != error_mark_node)
1344 if (processing_template_decl)
1345 return build_min (THROW_EXPR, void_type_node, e);
1346 e = build1 (THROW_EXPR, void_type_node, e);
1347 TREE_SIDE_EFFECTS (e) = 1;