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 static tree empty_fndecl;
185 /* ====================================================================== */
188 /* ========================================================================= */
192 /* local globals - these local globals are for storing data necessary for
193 generating the exception table and code in the correct order.
195 ========================================================================= */
197 /* Holds the pc for doing "throw" */
198 static tree saved_pc;
199 /* Holds the type of the thing being thrown. */
200 static tree saved_throw_type;
201 /* Holds the value being thrown. */
202 static tree saved_throw_value;
203 /* Holds the cleanup for the value being thrown. */
204 static tree saved_cleanup;
205 /* Indicates if we are in a catch clause. */
206 static tree saved_in_catch;
208 extern int throw_used;
209 extern rtx catch_clauses;
211 /* ========================================================================= */
213 /* Cheesyness to save some typing. Returns the return value rtx. */
216 do_function_call (func, params, return_type)
217 tree func, params, return_type;
220 func_call = build_function_call (func, params);
221 expand_call (func_call, NULL_RTX, 0);
222 if (return_type != NULL_TREE)
223 return hard_function_value (return_type, func_call);
227 /* ========================================================================= */
229 /* sets up all the global eh stuff that needs to be initialized at the
230 start of compilation.
233 - Setting up all the function call trees. */
236 init_exception_processing ()
238 tree unexpected_fndecl, terminate_fndecl;
239 tree set_unexpected_fndecl, set_terminate_fndecl;
240 tree catch_match_fndecl;
241 tree find_first_exception_match_fndecl;
247 tree vtype = build_function_type (void_type_node, void_list_node);
250 tree PFV = build_pointer_type (vtype);
252 /* Arg list for the build_function_type call for set_terminate and
254 tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
256 /* void (*pfvtype (void (*) ()))() */
257 tree pfvtype = build_function_type (PFV, pfvlist);
259 set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
260 pfvtype, NOT_BUILT_IN);
261 set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
262 pfvtype, NOT_BUILT_IN);
263 unexpected_fndecl = auto_function (get_identifier ("unexpected"),
264 vtype, NOT_BUILT_IN);
265 terminate_fndecl = auto_function (get_identifier ("terminate"),
266 vtype, NOT_BUILT_IN);
267 TREE_THIS_VOLATILE (terminate_fndecl) = 1;
269 push_lang_context (lang_name_c);
272 = builtin_function (flag_rtti
273 ? "__throw_type_match_rtti"
274 : "__throw_type_match",
275 build_function_type (ptr_type_node,
276 tree_cons (NULL_TREE, ptr_type_node,
277 tree_cons (NULL_TREE, ptr_type_node,
278 tree_cons (NULL_TREE, ptr_type_node,
280 NOT_BUILT_IN, NULL_PTR);
281 find_first_exception_match_fndecl
282 = builtin_function ("__find_first_exception_table_match",
283 build_function_type (ptr_type_node,
284 tree_cons (NULL_TREE, ptr_type_node,
286 NOT_BUILT_IN, NULL_PTR);
288 = builtin_function ("__unwind_function",
289 build_function_type (void_type_node,
290 tree_cons (NULL_TREE, ptr_type_node,
292 NOT_BUILT_IN, NULL_PTR);
294 = builtin_function ("__empty",
296 NOT_BUILT_IN, NULL_PTR);
297 DECL_EXTERNAL (empty_fndecl) = 1;
298 TREE_PUBLIC (empty_fndecl) = 1;
300 Unexpected = default_conversion (unexpected_fndecl);
301 Terminate = default_conversion (terminate_fndecl);
302 SetTerminate = default_conversion (set_terminate_fndecl);
303 SetUnexpected = default_conversion (set_unexpected_fndecl);
304 CatchMatch = default_conversion (catch_match_fndecl);
305 FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
306 Unwind = default_conversion (unwind_fndecl);
307 BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
309 TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
313 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
314 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
315 d = start_decl (d, declspecs, 0);
317 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
318 saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
320 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
321 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
322 d = start_decl (d, declspecs, 0);
324 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
325 saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
327 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
328 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
329 d = start_decl (d, declspecs, 0);
331 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
332 saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
334 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
335 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
336 d = make_call_declarator (d, void_list_node, NULL_TREE, NULL_TREE);
337 d = start_decl (d, declspecs, 0);
339 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
340 saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
342 declspecs = tree_cons (NULL_TREE, get_identifier ("bool"), NULL_TREE);
343 d = get_identifier ("__eh_in_catch");
344 d = start_decl (d, declspecs, 0);
346 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
347 saved_in_catch = lookup_name (get_identifier ("__eh_in_catch"), 0);
349 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
350 be protected with __terminate. */
351 protect_cleanup_actions_with_terminate = 1;
354 /* Build a type value for use at runtime for a type that is matched
355 against by the exception handling system. */
358 build_eh_type_type (type)
364 if (type == error_mark_node)
365 return error_mark_node;
367 /* peel back references, so they match. */
368 if (TREE_CODE (type) == REFERENCE_TYPE)
369 type = TREE_TYPE (type);
371 /* Peel off cv qualifiers. */
372 type = TYPE_MAIN_VARIANT (type);
376 return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
379 typestring = build_overload_name (type, 1, 1);
380 exp = combine_strings (build_string (strlen (typestring)+1, typestring));
381 return build1 (ADDR_EXPR, ptr_type_node, exp);
384 /* Build a type value for use at runtime for a exp that is thrown or
385 matched against by the exception handling system. */
393 exp = build_typeid (exp);
394 return build1 (ADDR_EXPR, ptr_type_node, exp);
396 return build_eh_type_type (TREE_TYPE (exp));
399 /* This routine creates the cleanup for the exception handling object. */
404 /* All cleanups must last longer than normal. */
405 int yes = suspend_momentary ();
407 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
408 tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
409 cleanup = build (COMPOUND_EXPR, void_type_node, cleanup,
410 build_modify_expr (saved_in_catch, NOP_EXPR,
411 build_modify_expr (saved_throw_type, NOP_EXPR, integer_zero_node)));
412 expand_decl_cleanup (NULL_TREE, cleanup);
414 resume_momentary (yes);
418 /* call this to start a catch block. Typename is the typename, and identifier
419 is the variable to place the object in or NULL if the variable doesn't
420 matter. If typename is NULL, that means its a "catch (...)" or catch
421 everything. In that case we don't need to do any type checking.
422 (ie: it ends up as the "else" clause rather than an "else if" clause) */
425 expand_start_catch_block (declspecs, declarator)
426 tree declspecs, declarator;
429 tree decl = NULL_TREE;
432 if (processing_template_decl)
436 decl = grokdeclarator (declarator, declspecs, CATCHPARM,
439 decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
440 copy_to_permanent (declspecs),
450 /* Create a binding level for the parm. */
452 expand_start_bindings (0);
454 false_label_rtx = gen_label_rtx ();
455 push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
457 emit_line_note (input_filename, lineno);
462 rtx call_rtx, return_value_rtx;
465 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
467 if (decl == NULL_TREE)
469 error ("invalid catch parameter");
471 /* This is cheap, but we want to maintain the data
474 expand_eh_region_start ();
479 /* Make sure we mark the catch param as used, otherwise we'll get
480 a warning about an unused ((anonymous)). */
481 TREE_USED (decl) = 1;
483 /* Figure out the type that the initializer is. */
484 init_type = TREE_TYPE (decl);
485 if (TREE_CODE (init_type) != REFERENCE_TYPE
486 && TREE_CODE (init_type) != POINTER_TYPE)
487 init_type = build_reference_type (init_type);
489 exp = saved_throw_value;
490 exp = tree_cons (NULL_TREE,
491 build_eh_type_type (TREE_TYPE (decl)),
492 tree_cons (NULL_TREE,
494 tree_cons (NULL_TREE, exp, NULL_TREE)));
495 exp = build_function_call (CatchMatch, exp);
496 call_rtx = expand_call (exp, NULL_RTX, 0);
497 assemble_external (TREE_OPERAND (CatchMatch, 0));
499 return_value_rtx = hard_function_value (ptr_type_node, exp);
501 /* did the throw type match function return TRUE? */
502 emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
503 GET_MODE (return_value_rtx), 0, 0);
505 /* if it returned FALSE, jump over the catch block, else fall into it */
506 emit_jump_insn (gen_beq (false_label_rtx));
510 init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
512 /* Do we need the below two lines? */
513 /* Let `cp_finish_decl' know that this initializer is ok. */
514 DECL_INITIAL (decl) = init;
515 decl = pushdecl (decl);
516 cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
522 /* Fall into the catch all section. */
525 emit_move_insn (DECL_RTL (saved_in_catch), const1_rtx);
527 /* If we are not doing setjmp/longjmp EH, because we are reordered
528 out of line, we arrange to rethrow in the outer context so as to
529 skip through the terminate region we are nested in, should we
530 encounter an exception in the catch handler.
532 If we are doing setjmp/longjmp EH, we need to skip through the EH
533 object cleanup region. This isn't quite right, as we really need
534 to clean the object up, but we cannot do that until we track
537 Matches the end in expand_end_catch_block. */
538 expand_eh_region_start ();
540 emit_line_note (input_filename, lineno);
545 /* Call this to end a catch block. Its responsible for emitting the
546 code to handle jumping back to the correct place, and for emitting
547 the label to jump to if this catch block didn't match. */
550 expand_end_catch_block ()
552 rtx start_region_label_rtx;
553 rtx end_region_label_rtx;
559 t = make_node (RTL_EXPR);
560 TREE_TYPE (t) = void_type_node;
561 RTL_EXPR_RTL (t) = const0_rtx;
562 TREE_SIDE_EFFECTS (t) = 1;
563 start_sequence_for_rtl_expr (t);
565 if (exceptions_via_longjmp)
567 /* If we are doing setjmp/longjmp EH, we need to skip through
568 the EH object cleanup region. This isn't quite right, as we
569 really need to clean the object up, but we cannot do that
570 until we track multiple EH objects. */
572 emit_library_call (sjpopnthrow_libfunc, 0, VOIDmode, 0);
577 /* If we are not doing setjmp/longjmp EH, we need an extra
578 region around the whole catch block to skip through the
579 terminate region we are nested in. */
581 expand_internal_throw (DECL_RTL (top_label_entry (&caught_return_label_stack)));
584 RTL_EXPR_SEQUENCE (t) = get_insns ();
587 /* Matches the start in expand_start_catch_block. */
588 expand_eh_region_end (t);
590 /* Fall to outside the try statement when done executing handler and
591 we fall off end of handler. This is jump Lresume in the
593 expand_goto (top_label_entry (&caught_return_label_stack));
595 expand_leftover_cleanups ();
597 /* Cleanup the EH parameter. */
598 expand_end_bindings (getdecls (), kept_level_p (), 0);
599 poplevel (kept_level_p (), 1, 0);
601 /* label we emit to jump to if this catch block didn't match. */
602 /* This the closing } in the `if (eq) {' of the documentation. */
603 emit_label (pop_label_entry (&false_label_stack));
606 /* unwind the stack. */
609 do_unwind (inner_throw_label)
610 rtx inner_throw_label;
612 #if defined (SPARC_STACK_ALIGN) /* was sparc */
613 /* This doesn't work for the flat model sparc, nor does it need to
614 as the default unwinder is only used to unwind non-flat frames. */
620 /* Call to __builtin_return_address. */
621 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
622 fcall = build_function_call (BuiltinReturnAddress, params);
623 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
624 /* In the return, the new pc is pc+8, as the value coming in is
625 really the address of the call insn, not the next insn. */
626 temp = gen_reg_rtx (Pmode);
627 emit_move_insn (temp, inner_throw_label);
628 emit_move_insn (next_pc, plus_constant (temp, -8));
629 emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31)));
630 easy_expand_asm ("ret");
631 easy_expand_asm ("restore");
634 #if defined (ARM_FRAME_RTX) /* was __arm */
635 if (flag_omit_frame_pointer)
636 sorry ("this implementation of exception handling requires a frame pointer");
638 emit_move_insn (stack_pointer_rtx,
639 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
640 emit_move_insn (hard_frame_pointer_rtx,
641 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
643 #if defined (TARGET_88000) /* was m88k */
644 rtx temp_frame = frame_pointer_rtx;
646 temp_frame = memory_address (Pmode, temp_frame);
647 temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
649 /* hopefully this will successfully pop the frame! */
650 emit_move_insn (frame_pointer_rtx, temp_frame);
651 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
652 emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
653 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
654 (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
657 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
658 -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
660 emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
662 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
663 (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
666 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
672 /* I would like to do this here, but the move below doesn't seem to work. */
673 /* Call to __builtin_return_address. */
674 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
675 fcall = build_function_call (BuiltinReturnAddress, params);
676 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
678 emit_move_insn (next_pc, inner_throw_label);
679 /* So, for now, just pass throw label to stack unwinder. */
681 params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
682 inner_throw_label), NULL_TREE);
684 do_function_call (Unwind, params, NULL_TREE);
685 assemble_external (TREE_OPERAND (Unwind, 0));
691 /* Is called from expand_exception_blocks to generate the code in a function
692 to "throw" if anything in the function needs to perform a throw.
694 expands "throw" as the following pseudo code:
697 eh = find_first_exception_match (saved_pc);
698 if (!eh) goto gotta_rethrow_it;
702 saved_pc = __builtin_return_address (0);
703 pop_to_previous_level ();
707 expand_builtin_throw ()
709 #ifndef DWARF2_UNWIND_INFO
715 rtx gotta_rethrow_it;
716 rtx gotta_call_terminate;
728 params = void_list_node;
729 t = make_call_declarator (get_identifier ("__throw"), params, NULL_TREE,
731 start_function (decl_tree_cons (NULL_TREE,
732 get_identifier ("void"),
733 decl_tree_cons (NULL_TREE,
734 get_identifier ("static"),
741 expand_start_bindings (0);
743 gotta_rethrow_it = gen_label_rtx ();
744 gotta_call_terminate = gen_label_rtx ();
746 /* These two can be frontend specific. If wanted, they can go in
748 /* Do we have a valid object we are throwing? */
749 emit_cmp_insn (DECL_RTL (saved_throw_type), const0_rtx, EQ, NULL_RTX,
750 GET_MODE (DECL_RTL (saved_throw_type)), 0, 0);
751 emit_jump_insn (gen_beq (gotta_call_terminate));
753 /* search for an exception handler for the saved_pc */
754 handler = do_function_call (FirstExceptionMatch,
755 tree_cons (NULL_TREE, saved_pc,
758 assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
760 /* did we find one? */
761 emit_cmp_insn (handler, const0_rtx, EQ, NULL_RTX,
762 GET_MODE (handler), 0, 0);
764 /* if not, jump to gotta_rethrow_it */
765 emit_jump_insn (gen_beq (gotta_rethrow_it));
769 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
770 0, hard_frame_pointer_rtx);
772 /* Set it up so that we continue at the handler. */
773 emit_move_insn (ret_val, handler);
774 #ifdef RETURN_ADDR_OFFSET
775 x = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
777 emit_move_insn (ret_val, x);
780 expand_null_return ();
783 top_of_loop = gen_label_rtx ();
784 emit_label (top_of_loop);
786 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
787 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
789 saved_pcnthrow = gen_reg_rtx (Pmode);
790 emit_move_insn (saved_pcnthrow, hard_function_value (ptr_type_node,
795 /* Call to __builtin_return_address. */
796 #if defined (ARM_FRAME_RTX) /* was __arm */
797 /* This should be moved into arm.h:RETURN_ADDR_RTX */
798 /* This replaces a 'call' to __builtin_return_address */
799 next_pc = gen_reg_rtx (Pmode);
800 emit_move_insn (next_pc,
801 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
803 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
804 fcall = build_function_call (BuiltinReturnAddress, params);
805 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
808 /* Did __builtin_return_address return a valid address? */
809 emit_cmp_insn (next_pc, const0_rtx, EQ, NULL_RTX,
810 GET_MODE (next_pc), 0, 0);
812 emit_jump_insn (gen_beq (gotta_call_terminate));
814 next_pc = eh_outer_context (next_pc);
817 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
818 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
822 x = validize_mem (gen_rtx (MEM, Pmode, saved_pcnthrow));
823 emit_move_insn (validize_mem (gen_rtx (MEM, Pmode, x)),
825 #ifdef FUNCTION_OUTGOING_VALUE
826 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
827 validize_mem (gen_rtx (MEM, Pmode,
828 plus_constant (saved_pcnthrow,
829 GET_MODE_SIZE (Pmode)))));
830 emit_insn (gen_rtx (USE, VOIDmode,
831 FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
836 emit_move_insn (eh_saved_pc_rtx, next_pc);
838 after_unwind = gen_label_rtx ();
839 do_unwind (gen_rtx (LABEL_REF, Pmode, after_unwind));
841 emit_label (after_unwind);
843 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
844 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
846 t = make_tree (build_pointer_type (TREE_TYPE (empty_fndecl)),
847 hard_function_value (ptr_type_node,
849 t = build_function_call (t, NULL_TREE);
850 expand_expr (t, const0_rtx, VOIDmode, 0);
856 /* no it didn't --> therefore we need to call terminate */
857 emit_label (gotta_call_terminate);
858 do_function_call (Terminate, NULL_TREE, NULL_TREE);
859 assemble_external (TREE_OPERAND (Terminate, 0));
863 /* code to deal with unwinding and looking for it again */
864 emit_label (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 inside, at the top of the loop. */
869 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
870 #ifdef RETURN_ADDR_OFFSET
871 x = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
873 emit_move_insn (ret_val, x);
876 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
877 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
879 rtx x = emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode,
883 /* This is to get a version of throw that will throw properly. */
884 emit_move_insn (validize_mem (gen_rtx (MEM, Pmode,
885 plus_constant (x, GET_MODE_SIZE (Pmode)))),
887 #ifdef FUNCTION_OUTGOING_VALUE
888 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
890 emit_insn (gen_rtx (USE, VOIDmode, FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
895 /* Fall into epilogue to unwind prologue. */
898 expand_end_bindings (getdecls (), 1, 0);
902 finish_function (lineno, 0, 0);
903 #endif /* DWARF2_UNWIND_INFO */
908 expand_start_eh_spec ()
910 expand_eh_region_start ();
914 expand_end_eh_spec (raises)
917 tree expr, second_try;
918 rtx check = gen_label_rtx ();
920 rtx ret = gen_reg_rtx (Pmode);
921 rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
922 rtx end = gen_label_rtx ();
924 expr = make_node (RTL_EXPR);
925 TREE_TYPE (expr) = void_type_node;
926 RTL_EXPR_RTL (expr) = const0_rtx;
927 TREE_SIDE_EFFECTS (expr) = 1;
928 start_sequence_for_rtl_expr (expr);
929 cont = gen_label_rtx ();
930 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
933 jumpif (make_tree (integer_type_node, flag), end);
934 do_function_call (Terminate, NULL_TREE, NULL_TREE);
935 assemble_external (TREE_OPERAND (Terminate, 0));
937 RTL_EXPR_SEQUENCE (expr) = get_insns ();
942 expr = make_node (RTL_EXPR);
943 TREE_TYPE (expr) = void_type_node;
944 RTL_EXPR_RTL (expr) = const0_rtx;
945 TREE_SIDE_EFFECTS (expr) = 1;
946 start_sequence_for_rtl_expr (expr);
948 cont = gen_label_rtx ();
949 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
952 jumpif (make_tree (integer_type_node, flag), end);
953 expand_eh_region_start ();
954 do_function_call (Unexpected, NULL_TREE, NULL_TREE);
955 assemble_external (TREE_OPERAND (Unexpected, 0));
958 expand_eh_region_end (second_try);
961 emit_move_insn (flag, const1_rtx);
962 cont = gen_label_rtx ();
966 tree match_type = TREE_VALUE (raises);
970 /* check TREE_VALUE (raises) here */
971 exp = saved_throw_value;
972 exp = tree_cons (NULL_TREE,
973 build_eh_type_type (match_type),
974 tree_cons (NULL_TREE,
976 tree_cons (NULL_TREE, exp, NULL_TREE)));
977 exp = build_function_call (CatchMatch, exp);
978 assemble_external (TREE_OPERAND (CatchMatch, 0));
983 raises = TREE_CHAIN (raises);
985 emit_move_insn (flag, const0_rtx);
987 emit_indirect_jump (ret);
990 RTL_EXPR_SEQUENCE (expr) = get_insns ();
993 expand_eh_region_end (expr);
996 /* This is called to expand all the toplevel exception handling
997 finalization for a function. It should only be called once per
1001 expand_exception_blocks ()
1003 push_to_sequence (catch_clauses);
1004 expand_leftover_cleanups ();
1005 catch_clauses = get_insns ();
1008 /* Do this after we expand leftover cleanups, so that the
1009 expand_eh_region_end that expand_end_eh_spec does will match the
1010 right expand_eh_region_start, and make sure it comes out before
1011 the terminate protected region. */
1012 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
1014 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
1015 push_to_sequence (catch_clauses);
1016 expand_leftover_cleanups ();
1017 catch_clauses = get_insns ();
1023 rtx funcend = gen_label_rtx ();
1024 emit_jump (funcend);
1026 /* We cannot protect n regions this way if we must flow into the
1027 EH region through the top of the region, as we have to with
1028 the setjmp/longjmp approach. */
1029 if (exceptions_via_longjmp == 0)
1031 /* Is this necessary? */
1032 assemble_external (TREE_OPERAND (Terminate, 0));
1034 expand_eh_region_start ();
1037 emit_insns (catch_clauses);
1038 catch_clauses = NULL_RTX;
1040 if (exceptions_via_longjmp == 0)
1041 expand_eh_region_end (TerminateFunctionCall);
1043 expand_leftover_cleanups ();
1045 emit_label (funcend);
1052 static int counter = 0;
1053 int old_interface_unknown = interface_unknown;
1058 push_cp_function_context (NULL_TREE);
1059 push_to_top_level ();
1061 /* No need to mangle this. */
1062 push_lang_context (lang_name_c);
1064 interface_unknown = 1;
1066 params = void_list_node;
1067 /* tcf stands for throw clean funciton. */
1068 sprintf (name, "__tcf_%d", counter++);
1069 t = make_call_declarator (get_identifier (name), params, NULL_TREE,
1071 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1074 store_parm_decls ();
1078 expand_start_bindings (0);
1079 emit_line_note (input_filename, lineno);
1081 interface_unknown = old_interface_unknown;
1083 pop_lang_context ();
1085 return current_function_decl;
1091 expand_end_bindings (getdecls (), 1, 0);
1095 finish_function (lineno, 0, 0);
1097 pop_from_top_level ();
1098 pop_cp_function_context (NULL_TREE);
1101 /* Expand a throw statement. This follows the following
1104 1. Allocate space to save the current PC onto the stack.
1105 2. Generate and emit a label and save its address into the
1106 newly allocated stack space since we can't save the pc directly.
1107 3. If this is the first call to throw in this function:
1108 generate a label for the throw block
1109 4. jump to the throw block label. */
1123 tree cleanup = empty_fndecl, e;
1125 /* throw expression */
1126 /* First, decay it. */
1127 exp = decay_conversion (exp);
1129 if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1131 throw_type = build_eh_type (exp);
1132 exp = build_reinterpret_cast (ptr_type_node, exp);
1138 /* Make a copy of the thrown object. WP 15.1.5 */
1139 exp = build_new (NULL_TREE, TREE_TYPE (exp),
1140 build_tree_list (NULL_TREE, exp),
1143 if (exp == error_mark_node)
1144 error (" in thrown expression");
1146 object = build_indirect_ref (exp, NULL_PTR);
1147 throw_type = build_eh_type (object);
1149 /* Build __tcf_ function. */
1150 cleanup = start_anon_func ();
1151 object = build_delete (TREE_TYPE (exp), saved_throw_value,
1152 integer_three_node, LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
1153 expand_expr (object, const0_rtx, VOIDmode, 0);
1155 mark_addressable (cleanup);
1158 if (cleanup == empty_fndecl)
1159 assemble_external (empty_fndecl);
1161 e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
1162 expand_expr (e, const0_rtx, VOIDmode, 0);
1164 e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
1165 e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
1166 expand_expr (e, const0_rtx, VOIDmode, 0);
1168 cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
1169 cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
1170 expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1174 /* rethrow current exception */
1175 /* This part is easy, as we don't have to do anything else. */
1178 if (exceptions_via_longjmp)
1182 /* This is the label that represents where in the code we were, when
1183 we got an exception. This needs to be updated when we rethrow an
1184 exception, so that the matching routine knows to search out. */
1185 label = gen_label_rtx ();
1188 expand_internal_throw (label);
1192 /* Build a throw expression. */
1198 if (e != error_mark_node)
1200 if (processing_template_decl)
1201 return build_min (THROW_EXPR, void_type_node, e);
1202 e = build1 (THROW_EXPR, void_type_node, e);
1203 TREE_SIDE_EFFECTS (e) = 1;