Import final gcc2 snapshot (990109)
[official-gcc.git] / gcc / cp / except.c
blobc59cf71bbf9287fba3ee01a2d68c6193c03382bf
1 /* Handle exceptional things in C++.
2 Copyright (C) 1989, 92-97, 1998 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)
12 any later version.
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. */
25 #include "config.h"
26 #include <stdio.h>
27 #include "tree.h"
28 #include "rtl.h"
29 #include "cp-tree.h"
30 #include "flags.h"
31 #include "obstack.h"
32 #include "expr.h"
33 #include "output.h"
34 #include "except.h"
35 #include "function.h"
36 #include "defaults.h"
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));
56 static void
57 easy_expand_asm (str)
58 char *str;
60 expand_asm (build_string (strlen (str)+1, str));
64 #if 0
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"
70 #endif
72 #ifdef EXCEPT_SECTION_ASM_OP
73 typedef struct {
74 void *start_region;
75 void *end_region;
76 void *exception_handler;
77 } exception_table;
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
84 label! */
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
94 is how we do it! */
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 */
102 #endif
104 #include "decl.h"
105 #include "insn-flags.h"
106 #include "obstack.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 |
136 | problem. |
137 +---------------------------------------------------------------+
139 When a catch block is encountered, there is a lot of work to be
140 done.
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
147 sequence.
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. */
178 static tree Unwind;
180 /* ====================================================================== */
183 /* ========================================================================= */
187 /* local globals - these local globals are for storing data necessary for
188 generating the exception table and code in the correct order.
190 ========================================================================= */
192 /* Holds the pc for doing "throw" */
193 static tree saved_pc;
195 extern int throw_used;
196 extern rtx catch_clauses;
198 /* ========================================================================= */
200 /* Cheesyness to save some typing. Returns the return value rtx. */
202 static rtx
203 do_function_call (func, params, return_type)
204 tree func, params, return_type;
206 tree func_call;
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);
211 return NULL_RTX;
214 /* ========================================================================= */
216 /* sets up all the global eh stuff that needs to be initialized at the
217 start of compilation.
219 This includes:
220 - Setting up all the function call trees. */
222 void
223 init_exception_processing ()
225 tree unexpected_fndecl, terminate_fndecl;
226 tree set_unexpected_fndecl, set_terminate_fndecl;
227 tree catch_match_fndecl;
228 tree find_first_exception_match_fndecl;
229 tree unwind_fndecl;
230 tree declspecs;
231 tree d;
233 /* void vtype () */
234 tree vtype = build_function_type (void_type_node, void_list_node);
236 /* void (*)() */
237 tree PFV = build_pointer_type (vtype);
239 /* Arg list for the build_function_type call for set_terminate and
240 set_unexpected. */
241 tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
243 /* void (*pfvtype (void (*) ()))() */
244 tree pfvtype = build_function_type (PFV, pfvlist);
246 set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
247 pfvtype, NOT_BUILT_IN);
248 set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
249 pfvtype, NOT_BUILT_IN);
250 unexpected_fndecl = auto_function (get_identifier ("unexpected"),
251 vtype, NOT_BUILT_IN);
252 terminate_fndecl = auto_function (get_identifier ("terminate"),
253 vtype, NOT_BUILT_IN);
254 TREE_THIS_VOLATILE (terminate_fndecl) = 1;
256 push_lang_context (lang_name_c);
258 catch_match_fndecl
259 = builtin_function (flag_rtti
260 ? "__throw_type_match_rtti"
261 : "__throw_type_match",
262 build_function_type (ptr_type_node,
263 tree_cons (NULL_TREE, ptr_type_node,
264 tree_cons (NULL_TREE, ptr_type_node,
265 tree_cons (NULL_TREE, ptr_type_node,
266 void_list_node)))),
267 NOT_BUILT_IN, NULL_PTR);
268 find_first_exception_match_fndecl
269 = builtin_function ("__find_first_exception_table_match",
270 build_function_type (ptr_type_node,
271 tree_cons (NULL_TREE, ptr_type_node,
272 void_list_node)),
273 NOT_BUILT_IN, NULL_PTR);
274 unwind_fndecl
275 = builtin_function ("__unwind_function",
276 build_function_type (void_type_node,
277 tree_cons (NULL_TREE, ptr_type_node,
278 void_list_node)),
279 NOT_BUILT_IN, NULL_PTR);
281 Unexpected = default_conversion (unexpected_fndecl);
282 Terminate = terminate_fndecl;
283 SetTerminate = default_conversion (set_terminate_fndecl);
284 SetUnexpected = default_conversion (set_unexpected_fndecl);
285 CatchMatch = default_conversion (catch_match_fndecl);
286 FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
287 Unwind = default_conversion (unwind_fndecl);
288 BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
290 pop_lang_context ();
292 d = build_decl (VAR_DECL, get_identifier ("__eh_pc"), ptr_type_node);
293 TREE_PUBLIC (d) = 1;
294 DECL_EXTERNAL (d) = 1;
295 DECL_ARTIFICIAL (d) = 1;
296 cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
297 saved_pc = d;
299 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
300 be protected with __terminate. */
301 protect_cleanup_actions_with_terminate = 1;
304 /* Retrieve a pointer to the cp_eh_info node for the current exception. */
306 static tree
307 call_eh_info ()
309 tree fn;
311 fn = get_identifier ("__cp_exception_info");
312 if (IDENTIFIER_GLOBAL_VALUE (fn))
313 fn = IDENTIFIER_GLOBAL_VALUE (fn);
314 else
316 tree t, fields[6];
318 /* Declare cp_eh_info * __cp_exception_info (void),
319 as defined in exception.cc. */
320 push_obstacks_nochange ();
321 end_temporary_allocation ();
323 /* struct cp_eh_info. This must match exception.cc. Note that this
324 type is not pushed anywhere. */
325 t = make_lang_type (RECORD_TYPE);
326 fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
327 ptr_type_node);
328 fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
329 ptr_type_node);
330 fields[2] = build_lang_field_decl
331 (FIELD_DECL, get_identifier ("cleanup"),
332 build_pointer_type (build_function_type
333 (ptr_type_node, tree_cons
334 (NULL_TREE, ptr_type_node, void_list_node))));
335 fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
336 boolean_type_node);
337 fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
338 build_pointer_type (t));
339 fields[5] = build_lang_field_decl
340 (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
341 /* N.B.: The fourth field LEN is expected to be
342 the number of fields - 1, not the total number of fields. */
343 finish_builtin_type (t, "cp_eh_info", fields, 5, ptr_type_node);
344 t = build_pointer_type (t);
346 /* And now the function. */
347 fn = build_lang_decl (FUNCTION_DECL, fn,
348 build_function_type (t, void_list_node));
349 DECL_EXTERNAL (fn) = 1;
350 TREE_PUBLIC (fn) = 1;
351 DECL_ARTIFICIAL (fn) = 1;
352 pushdecl_top_level (fn);
353 make_function_rtl (fn);
354 assemble_external (fn);
355 pop_obstacks ();
357 return build_function_call (fn, NULL_TREE);
360 /* Retrieve a pointer to the cp_eh_info node for the current exception
361 and save it in the current binding level. */
363 static void
364 push_eh_info ()
366 tree decl, fn = call_eh_info ();
368 /* Remember the pointer to the current exception info; it won't change
369 during this catch block. */
370 decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
371 TREE_TYPE (fn));
372 DECL_ARTIFICIAL (decl) = 1;
373 DECL_INITIAL (decl) = fn;
374 decl = pushdecl (decl);
375 cp_finish_decl (decl, fn, NULL_TREE, 0, 0);
378 /* Returns a reference to the cp_eh_info node for the current exception. */
380 static tree
381 get_eh_info ()
383 /* Look for the pointer pushed in push_eh_info. */
384 tree t = lookup_name (get_identifier ("__exception_info"), 0);
385 return build_indirect_ref (t, NULL_PTR);
388 /* Returns a reference to the current exception object. */
390 static tree
391 get_eh_value ()
393 return build_component_ref (get_eh_info (), get_identifier ("value"),
394 NULL_TREE, 0);
397 /* Returns a reference to the current exception type. */
399 static tree
400 get_eh_type ()
402 return build_component_ref (get_eh_info (), get_identifier ("type"),
403 NULL_TREE, 0);
406 /* Returns a reference to whether or not the current exception
407 has been caught. */
409 static tree
410 get_eh_caught ()
412 return build_component_ref (get_eh_info (), get_identifier ("caught"),
413 NULL_TREE, 0);
416 /* Returns a reference to whether or not the current exception
417 has been caught. */
419 static tree
420 get_eh_handlers ()
422 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
423 NULL_TREE, 0);
426 /* Build a type value for use at runtime for a type that is matched
427 against by the exception handling system. */
429 static tree
430 build_eh_type_type (type)
431 tree type;
433 char *typestring;
434 tree exp;
436 if (type == error_mark_node)
437 return error_mark_node;
439 /* peel back references, so they match. */
440 if (TREE_CODE (type) == REFERENCE_TYPE)
441 type = TREE_TYPE (type);
443 /* Peel off cv qualifiers. */
444 type = TYPE_MAIN_VARIANT (type);
446 if (flag_rtti)
448 return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
451 typestring = build_overload_name (type, 1, 1);
452 exp = combine_strings (build_string (strlen (typestring)+1, typestring));
453 return build1 (ADDR_EXPR, ptr_type_node, exp);
456 /* Build a type value for use at runtime for a exp that is thrown or
457 matched against by the exception handling system. */
459 static tree
460 build_eh_type (exp)
461 tree exp;
463 if (flag_rtti)
465 exp = build_typeid (exp);
466 return build1 (ADDR_EXPR, ptr_type_node, exp);
468 return build_eh_type_type (TREE_TYPE (exp));
471 /* Build up a call to __cp_pop_exception, to destroy the exception object
472 for the current catch block. HANDLER is either true or false, telling
473 the library whether or not it is being called from an exception handler;
474 if it is, it avoids destroying the object on rethrow. */
476 static tree
477 do_pop_exception ()
479 tree fn, cleanup;
480 fn = get_identifier ("__cp_pop_exception");
481 if (IDENTIFIER_GLOBAL_VALUE (fn))
482 fn = IDENTIFIER_GLOBAL_VALUE (fn);
483 else
485 /* Declare void __cp_pop_exception (void *),
486 as defined in exception.cc. */
487 push_obstacks_nochange ();
488 end_temporary_allocation ();
489 fn = build_lang_decl
490 (FUNCTION_DECL, fn,
491 build_function_type (void_type_node, tree_cons
492 (NULL_TREE, ptr_type_node, void_list_node)));
493 DECL_EXTERNAL (fn) = 1;
494 TREE_PUBLIC (fn) = 1;
495 DECL_ARTIFICIAL (fn) = 1;
496 pushdecl_top_level (fn);
497 make_function_rtl (fn);
498 assemble_external (fn);
499 pop_obstacks ();
502 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
503 cleanup = lookup_name (get_identifier ("__exception_info"), 0);
504 cleanup = build_function_call (fn, expr_tree_cons
505 (NULL_TREE, cleanup, NULL_TREE));
506 return cleanup;
509 /* This routine creates the cleanup for the current exception. */
511 static void
512 push_eh_cleanup ()
514 int yes;
516 expand_expr (build_unary_op (PREINCREMENT_EXPR, get_eh_handlers (), 1),
517 const0_rtx, VOIDmode, EXPAND_NORMAL);
519 yes = suspend_momentary ();
520 /* All cleanups must last longer than normal. */
521 expand_decl_cleanup (NULL_TREE, do_pop_exception ());
522 resume_momentary (yes);
525 /* call this to start a catch block. Typename is the typename, and identifier
526 is the variable to place the object in or NULL if the variable doesn't
527 matter. If typename is NULL, that means its a "catch (...)" or catch
528 everything. In that case we don't need to do any type checking.
529 (ie: it ends up as the "else" clause rather than an "else if" clause) */
531 void
532 expand_start_catch_block (declspecs, declarator)
533 tree declspecs, declarator;
535 rtx false_label_rtx;
536 tree decl = NULL_TREE;
537 tree init;
539 if (processing_template_decl)
541 if (declspecs)
543 decl = grokdeclarator (declarator, declspecs, CATCHPARM,
544 1, NULL_TREE);
545 pushdecl (decl);
546 decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
547 copy_to_permanent (declspecs),
548 NULL_TREE);
549 add_tree (decl);
551 return;
554 if (! doing_eh (1))
555 return;
557 /* If we are not doing setjmp/longjmp EH, because we are reordered
558 out of line, we arrange to rethrow in the outer context so as to
559 skip through the terminate region we are nested in, should we
560 encounter an exception in the catch handler. We also need to do
561 this because we are not physically within the try block, if any,
562 that contains this catch block.
564 Matches the end in expand_end_catch_block. */
565 if (! exceptions_via_longjmp)
566 expand_eh_region_start ();
568 /* Create a binding level for the eh_info and the exception object
569 cleanup. */
570 pushlevel (0);
571 expand_start_bindings (0);
573 false_label_rtx = gen_label_rtx ();
574 push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
576 emit_line_note (input_filename, lineno);
578 push_eh_info ();
580 if (declspecs)
582 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
584 if (decl == NULL_TREE)
585 error ("invalid catch parameter");
588 if (decl)
590 tree exp;
591 rtx call_rtx, return_value_rtx;
592 tree init_type;
594 /* Make sure we mark the catch param as used, otherwise we'll get
595 a warning about an unused ((anonymous)). */
596 TREE_USED (decl) = 1;
598 /* Figure out the type that the initializer is. */
599 init_type = TREE_TYPE (decl);
600 if (TREE_CODE (init_type) != REFERENCE_TYPE
601 && TREE_CODE (init_type) != POINTER_TYPE)
602 init_type = build_reference_type (init_type);
604 exp = get_eh_value ();
606 /* Since pointers are passed by value, initialize a reference to
607 pointer catch parm with the address of the value slot. */
608 if (TREE_CODE (init_type) == REFERENCE_TYPE
609 && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
610 exp = build_unary_op (ADDR_EXPR, exp, 1);
612 exp = expr_tree_cons (NULL_TREE,
613 build_eh_type_type (TREE_TYPE (decl)),
614 expr_tree_cons (NULL_TREE,
615 get_eh_type (),
616 expr_tree_cons (NULL_TREE, exp, NULL_TREE)));
617 exp = build_function_call (CatchMatch, exp);
618 call_rtx = expand_call (exp, NULL_RTX, 0);
619 assemble_external (TREE_OPERAND (CatchMatch, 0));
621 return_value_rtx = hard_function_value (ptr_type_node, exp);
623 /* did the throw type match function return TRUE? */
624 emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
625 GET_MODE (return_value_rtx), 0, 0);
627 /* if it returned FALSE, jump over the catch block, else fall into it */
628 emit_jump_insn (gen_beq (false_label_rtx));
630 push_eh_cleanup ();
632 /* Create a binding level for the parm. */
633 pushlevel (0);
634 expand_start_bindings (0);
636 init = convert_from_reference (make_tree (init_type, call_rtx));
638 /* If the constructor for the catch parm exits via an exception, we
639 must call terminate. See eh23.C. */
640 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
642 int yes = suspend_momentary ();
643 tree term = build_function_call (Terminate, NULL_TREE);
644 resume_momentary (yes);
646 /* Generate the copy constructor call directly so we can wrap it.
647 See also expand_default_init. */
648 init = ocp_convert (TREE_TYPE (decl), init,
649 CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
650 init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init, term);
653 /* Let `cp_finish_decl' know that this initializer is ok. */
654 DECL_INITIAL (decl) = init;
655 decl = pushdecl (decl);
657 cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
659 else
661 push_eh_cleanup ();
663 /* Create a binding level for the parm. */
664 pushlevel (0);
665 expand_start_bindings (0);
667 /* Fall into the catch all section. */
670 init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node);
671 expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL);
673 emit_line_note (input_filename, lineno);
678 /* Call this to end a catch block. Its responsible for emitting the
679 code to handle jumping back to the correct place, and for emitting
680 the label to jump to if this catch block didn't match. */
682 void
683 expand_end_catch_block ()
685 if (! doing_eh (1))
686 return;
688 /* Cleanup the EH parameter. */
689 expand_end_bindings (getdecls (), kept_level_p (), 0);
690 poplevel (kept_level_p (), 1, 0);
692 /* Cleanup the EH object. */
693 expand_end_bindings (getdecls (), kept_level_p (), 0);
694 poplevel (kept_level_p (), 1, 0);
696 if (! exceptions_via_longjmp)
698 /* If we are not doing setjmp/longjmp EH, we need an extra
699 region around the whole catch block to skip through the
700 terminate region we are nested in. */
702 tree t = make_node (RTL_EXPR);
703 TREE_TYPE (t) = void_type_node;
704 RTL_EXPR_RTL (t) = const0_rtx;
705 TREE_SIDE_EFFECTS (t) = 1;
706 do_pending_stack_adjust ();
707 start_sequence_for_rtl_expr (t);
709 expand_internal_throw (outer_context_label_stack->u.rlabel);
711 do_pending_stack_adjust ();
712 RTL_EXPR_SEQUENCE (t) = get_insns ();
713 end_sequence ();
715 /* For the rethrow region. */
716 expand_eh_region_end (t);
719 /* Fall to outside the try statement when done executing handler and
720 we fall off end of handler. This is jump Lresume in the
721 documentation. */
722 expand_goto (top_label_entry (&caught_return_label_stack));
724 expand_leftover_cleanups ();
726 /* label we emit to jump to if this catch block didn't match. */
727 /* This the closing } in the `if (eq) {' of the documentation. */
728 emit_label (pop_label_entry (&false_label_stack));
731 /* unwind the stack. */
733 static void
734 do_unwind (inner_throw_label)
735 rtx inner_throw_label;
737 #if defined (SPARC_STACK_ALIGN) /* was sparc */
738 /* This doesn't work for the flat model sparc, nor does it need to
739 as the default unwinder is only used to unwind non-flat frames. */
740 tree fcall;
741 tree params;
742 rtx next_pc;
743 rtx temp;
745 /* Call to __builtin_return_address. */
746 params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
747 fcall = build_function_call (BuiltinReturnAddress, params);
748 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
749 /* In the return, the new pc is pc+8, as the value coming in is
750 really the address of the call insn, not the next insn. */
751 temp = gen_reg_rtx (Pmode);
752 emit_move_insn (temp, inner_throw_label);
753 emit_move_insn (next_pc, plus_constant (temp, -8));
754 emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31)));
755 easy_expand_asm ("ret");
756 easy_expand_asm ("restore");
757 emit_barrier ();
758 #endif
759 #if defined (ARM_FRAME_RTX) /* was __arm */
760 if (flag_omit_frame_pointer)
761 sorry ("this implementation of exception handling requires a frame pointer");
763 emit_move_insn (stack_pointer_rtx,
764 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
765 emit_move_insn (hard_frame_pointer_rtx,
766 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
767 #endif
768 #if defined (TARGET_88000) /* was m88k */
769 rtx temp_frame = frame_pointer_rtx;
771 temp_frame = memory_address (Pmode, temp_frame);
772 temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
774 /* hopefully this will successfully pop the frame! */
775 emit_move_insn (frame_pointer_rtx, temp_frame);
776 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
777 emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
778 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
779 (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
781 #if 0
782 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
783 -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
785 emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
787 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
788 (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
789 #endif
790 #endif
791 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
792 tree fcall;
793 tree params;
794 rtx next_pc;
796 #if 0
797 /* I would like to do this here, but the move below doesn't seem to work. */
798 /* Call to __builtin_return_address. */
799 params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
800 fcall = build_function_call (BuiltinReturnAddress, params);
801 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
803 emit_move_insn (next_pc, inner_throw_label);
804 /* So, for now, just pass throw label to stack unwinder. */
805 #endif
806 params = expr_tree_cons (NULL_TREE, make_tree (ptr_type_node,
807 inner_throw_label), NULL_TREE);
809 do_function_call (Unwind, params, NULL_TREE);
810 assemble_external (TREE_OPERAND (Unwind, 0));
811 emit_barrier ();
812 #endif
816 /* Is called from expand_exception_blocks to generate the code in a function
817 to "throw" if anything in the function needs to perform a throw.
819 expands "throw" as the following pseudo code:
821 throw:
822 eh = find_first_exception_match (saved_pc);
823 if (!eh) goto gotta_rethrow_it;
824 goto eh;
826 gotta_rethrow_it:
827 saved_pc = __builtin_return_address (0);
828 pop_to_previous_level ();
829 goto throw; */
831 void
832 expand_builtin_throw ()
834 #ifndef DWARF2_UNWIND_INFO
835 tree fcall;
836 tree params;
837 rtx handler;
838 rtx saved_pcnthrow;
839 rtx next_pc;
840 rtx gotta_rethrow_it;
841 rtx gotta_call_terminate;
842 rtx after_unwind;
843 rtx top_of_loop;
844 tree t;
845 rtx x;
847 if (! doing_eh (0))
848 return;
850 if (! throw_used)
851 return;
853 params = void_list_node;
854 t = make_call_declarator (get_identifier ("__throw"), params, NULL_TREE,
855 NULL_TREE);
856 start_function (decl_tree_cons (NULL_TREE,
857 get_identifier ("void"),
858 decl_tree_cons (NULL_TREE,
859 get_identifier ("static"),
860 NULL_TREE)),
861 t, NULL_TREE, 0);
862 store_parm_decls ();
863 pushlevel (0);
864 clear_last_expr ();
865 push_momentary ();
866 expand_start_bindings (0);
868 gotta_rethrow_it = gen_label_rtx ();
869 gotta_call_terminate = gen_label_rtx ();
871 /* These two can be frontend specific. If wanted, they can go in
872 expand_throw. */
873 /* Do we have a valid object we are throwing? */
874 t = call_eh_info ();
875 emit_cmp_insn (expand_expr (t, NULL_RTX, Pmode, 0),
876 const0_rtx, EQ, NULL_RTX,
877 GET_MODE (DECL_RTL (t)), 0, 0);
878 emit_jump_insn (gen_beq (gotta_call_terminate));
880 /* search for an exception handler for the saved_pc */
881 handler = do_function_call (FirstExceptionMatch,
882 expr_tree_cons (NULL_TREE, saved_pc,
883 NULL_TREE),
884 ptr_type_node);
885 assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
887 /* did we find one? */
888 emit_cmp_insn (handler, const0_rtx, EQ, NULL_RTX,
889 GET_MODE (handler), 0, 0);
891 /* if not, jump to gotta_rethrow_it */
892 emit_jump_insn (gen_beq (gotta_rethrow_it));
895 rtx ret_val, x;
896 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
897 0, hard_frame_pointer_rtx);
899 /* Set it up so that we continue at the handler. */
900 emit_move_insn (ret_val, handler);
901 #ifdef RETURN_ADDR_OFFSET
902 x = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
903 if (x != ret_val)
904 emit_move_insn (ret_val, x);
905 #endif
907 expand_null_return ();
910 top_of_loop = gen_label_rtx ();
911 emit_label (top_of_loop);
913 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
914 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
916 saved_pcnthrow = gen_reg_rtx (Pmode);
917 emit_move_insn (saved_pcnthrow, hard_function_value (ptr_type_node,
918 NULL_TREE));
920 #endif
922 /* Call to __builtin_return_address. */
923 #if defined (ARM_FRAME_RTX) /* was __arm */
924 /* This should be moved into arm.h:RETURN_ADDR_RTX */
925 /* This replaces a 'call' to __builtin_return_address */
926 next_pc = gen_reg_rtx (Pmode);
927 emit_move_insn (next_pc,
928 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
929 #else
930 params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
931 fcall = build_function_call (BuiltinReturnAddress, params);
932 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
933 #endif
935 /* Did __builtin_return_address return a valid address? */
936 emit_cmp_insn (next_pc, const0_rtx, EQ, NULL_RTX,
937 GET_MODE (next_pc), 0, 0);
939 emit_jump_insn (gen_beq (gotta_call_terminate));
941 next_pc = eh_outer_context (next_pc);
943 /* Yes it did. */
944 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
945 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
947 rtx x;
949 x = validize_mem (gen_rtx (MEM, Pmode, saved_pcnthrow));
950 emit_move_insn (validize_mem (gen_rtx (MEM, Pmode, x)),
951 next_pc);
952 #ifdef FUNCTION_OUTGOING_VALUE
953 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
954 validize_mem (gen_rtx (MEM, Pmode,
955 plus_constant (saved_pcnthrow,
956 GET_MODE_SIZE (Pmode)))));
957 emit_insn (gen_rtx (USE, VOIDmode,
958 FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
959 #endif
961 else
962 #endif
963 emit_move_insn (eh_saved_pc_rtx, next_pc);
965 after_unwind = gen_label_rtx ();
966 do_unwind (gen_rtx (LABEL_REF, Pmode, after_unwind));
968 emit_label (after_unwind);
970 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
971 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
973 t = build_function_type (void_type_node, void_list_node);
974 t = make_tree (build_pointer_type (t),
975 hard_function_value (ptr_type_node,
976 NULL_TREE));
977 t = build_function_call (t, NULL_TREE);
978 expand_expr (t, const0_rtx, VOIDmode, 0);
980 else
981 #endif
982 emit_throw ();
984 /* no it didn't --> therefore we need to call terminate */
985 emit_label (gotta_call_terminate);
986 do_function_call (Terminate, NULL_TREE, NULL_TREE);
989 rtx ret_val, x;
990 /* code to deal with unwinding and looking for it again */
991 emit_label (gotta_rethrow_it);
992 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
993 0, hard_frame_pointer_rtx);
995 /* Set it up so that we continue inside, at the top of the loop. */
996 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
997 #ifdef RETURN_ADDR_OFFSET
998 x = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
999 if (x != ret_val)
1000 emit_move_insn (ret_val, x);
1001 #endif
1003 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
1004 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
1006 rtx x = emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode,
1007 "__eh_pcnthrow"),
1008 NULL_RTX, 1,
1009 Pmode, 0);
1010 /* This is to get a version of throw that will throw properly. */
1011 emit_move_insn (validize_mem (gen_rtx (MEM, Pmode,
1012 plus_constant (x, GET_MODE_SIZE (Pmode)))),
1013 throw_libfunc);
1014 #ifdef FUNCTION_OUTGOING_VALUE
1015 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
1017 emit_insn (gen_rtx (USE, VOIDmode, FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
1018 #endif
1020 #endif
1022 /* Fall into epilogue to unwind prologue. */
1025 expand_end_bindings (getdecls (), 1, 0);
1026 poplevel (1, 0, 0);
1027 pop_momentary ();
1029 finish_function (lineno, 0, 0);
1030 #endif /* DWARF2_UNWIND_INFO */
1034 void
1035 expand_start_eh_spec ()
1037 expand_eh_region_start ();
1040 static void
1041 expand_end_eh_spec (raises)
1042 tree raises;
1044 tree expr, second_try;
1045 rtx check = gen_label_rtx ();
1046 rtx cont;
1047 rtx ret = gen_reg_rtx (Pmode);
1048 rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
1049 rtx end = gen_label_rtx ();
1051 expr = make_node (RTL_EXPR);
1052 TREE_TYPE (expr) = void_type_node;
1053 RTL_EXPR_RTL (expr) = const0_rtx;
1054 TREE_SIDE_EFFECTS (expr) = 1;
1055 do_pending_stack_adjust ();
1056 start_sequence_for_rtl_expr (expr);
1057 cont = gen_label_rtx ();
1058 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1059 emit_jump (check);
1060 emit_label (cont);
1061 jumpif (make_tree (integer_type_node, flag), end);
1062 do_function_call (Terminate, NULL_TREE, NULL_TREE);
1063 emit_barrier ();
1064 do_pending_stack_adjust ();
1065 RTL_EXPR_SEQUENCE (expr) = get_insns ();
1066 end_sequence ();
1068 second_try = expr;
1070 expr = make_node (RTL_EXPR);
1071 TREE_TYPE (expr) = void_type_node;
1072 RTL_EXPR_RTL (expr) = const0_rtx;
1073 TREE_SIDE_EFFECTS (expr) = 1;
1074 do_pending_stack_adjust ();
1075 start_sequence_for_rtl_expr (expr);
1077 cont = gen_label_rtx ();
1078 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1079 emit_jump (check);
1080 emit_label (cont);
1081 jumpif (make_tree (integer_type_node, flag), end);
1082 expand_eh_region_start ();
1083 do_function_call (Unexpected, NULL_TREE, NULL_TREE);
1084 assemble_external (TREE_OPERAND (Unexpected, 0));
1085 emit_barrier ();
1087 expand_eh_region_end (second_try);
1089 emit_label (check);
1090 emit_move_insn (flag, const1_rtx);
1091 cont = gen_label_rtx ();
1093 push_eh_info ();
1095 while (raises)
1097 tree exp;
1098 tree match_type = TREE_VALUE (raises);
1100 if (match_type)
1102 /* check TREE_VALUE (raises) here */
1103 exp = get_eh_value ();
1104 exp = expr_tree_cons (NULL_TREE,
1105 build_eh_type_type (match_type),
1106 expr_tree_cons (NULL_TREE,
1107 get_eh_type (),
1108 expr_tree_cons (NULL_TREE, exp, NULL_TREE)));
1109 exp = build_function_call (CatchMatch, exp);
1110 assemble_external (TREE_OPERAND (CatchMatch, 0));
1112 jumpif (exp, cont);
1115 raises = TREE_CHAIN (raises);
1117 emit_move_insn (flag, const0_rtx);
1118 emit_label (cont);
1119 emit_indirect_jump (ret);
1120 emit_label (end);
1122 do_pending_stack_adjust ();
1123 RTL_EXPR_SEQUENCE (expr) = get_insns ();
1124 end_sequence ();
1126 expand_eh_region_end (expr);
1129 /* This is called to expand all the toplevel exception handling
1130 finalization for a function. It should only be called once per
1131 function. */
1133 void
1134 expand_exception_blocks ()
1136 do_pending_stack_adjust ();
1137 push_to_sequence (catch_clauses);
1138 expand_leftover_cleanups ();
1139 do_pending_stack_adjust ();
1140 catch_clauses = get_insns ();
1141 end_sequence ();
1143 /* Do this after we expand leftover cleanups, so that the
1144 expand_eh_region_end that expand_end_eh_spec does will match the
1145 right expand_eh_region_start, and make sure it comes out before
1146 the terminate protected region. */
1147 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
1149 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
1150 do_pending_stack_adjust ();
1151 push_to_sequence (catch_clauses);
1152 expand_leftover_cleanups ();
1153 do_pending_stack_adjust ();
1154 catch_clauses = get_insns ();
1155 end_sequence ();
1158 if (catch_clauses)
1160 rtx funcend = gen_label_rtx ();
1161 emit_jump (funcend);
1163 /* We cannot protect n regions this way if we must flow into the
1164 EH region through the top of the region, as we have to with
1165 the setjmp/longjmp approach. */
1166 if (exceptions_via_longjmp == 0)
1168 expand_eh_region_start ();
1171 emit_insns (catch_clauses);
1172 catch_clauses = NULL_RTX;
1174 if (exceptions_via_longjmp == 0)
1175 expand_eh_region_end (build_function_call (Terminate, NULL_TREE));
1177 expand_leftover_cleanups ();
1179 emit_label (funcend);
1183 tree
1184 start_anon_func ()
1186 static int counter = 0;
1187 int old_interface_unknown = interface_unknown;
1188 char name[32];
1189 tree params;
1190 tree t;
1192 push_cp_function_context (NULL_TREE);
1193 push_to_top_level ();
1195 /* No need to mangle this. */
1196 push_lang_context (lang_name_c);
1198 interface_unknown = 1;
1200 params = void_list_node;
1201 /* tcf stands for throw clean function. */
1202 sprintf (name, "__tcf_%d", counter++);
1203 t = make_call_declarator (get_identifier (name), params, NULL_TREE,
1204 NULL_TREE);
1205 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1206 void_list_node),
1207 t, NULL_TREE, 0);
1208 store_parm_decls ();
1209 pushlevel (0);
1210 clear_last_expr ();
1211 push_momentary ();
1212 expand_start_bindings (0);
1213 emit_line_note (input_filename, lineno);
1215 interface_unknown = old_interface_unknown;
1217 pop_lang_context ();
1219 return current_function_decl;
1222 void
1223 end_anon_func ()
1225 expand_end_bindings (getdecls (), 1, 0);
1226 poplevel (1, 0, 0);
1227 pop_momentary ();
1229 finish_function (lineno, 0, 0);
1231 pop_from_top_level ();
1232 pop_cp_function_context (NULL_TREE);
1235 /* Expand a throw statement. This follows the following
1236 algorithm:
1238 1. Allocate space to save the current PC onto the stack.
1239 2. Generate and emit a label and save its address into the
1240 newly allocated stack space since we can't save the pc directly.
1241 3. If this is the first call to throw in this function:
1242 generate a label for the throw block
1243 4. jump to the throw block label. */
1245 void
1246 expand_throw (exp)
1247 tree exp;
1249 rtx label;
1250 tree fn;
1251 static tree cleanup_type;
1253 if (! doing_eh (1))
1254 return;
1256 if (exp)
1258 tree throw_type;
1259 tree cleanup = NULL_TREE, e;
1261 /* throw expression */
1262 /* First, decay it. */
1263 exp = decay_conversion (exp);
1265 /* cleanup_type is void (*)(void *, int),
1266 the internal type of a destructor. */
1267 if (cleanup_type == NULL_TREE)
1269 push_obstacks_nochange ();
1270 end_temporary_allocation ();
1271 cleanup_type = build_pointer_type
1272 (build_function_type
1273 (void_type_node, tree_cons
1274 (NULL_TREE, ptr_type_node, tree_cons
1275 (NULL_TREE, integer_type_node, void_list_node))));
1276 pop_obstacks ();
1279 if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1281 throw_type = build_eh_type (exp);
1282 exp = build_reinterpret_cast (ptr_type_node, exp);
1284 else
1286 tree object;
1288 /* Make a copy of the thrown object. WP 15.1.5 */
1289 exp = build_new (NULL_TREE, TREE_TYPE (exp),
1290 build_expr_list (NULL_TREE, exp),
1293 if (exp == error_mark_node)
1294 error (" in thrown expression");
1296 object = build_indirect_ref (exp, NULL_PTR);
1297 throw_type = build_eh_type (object);
1299 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
1301 cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
1302 dtor_identifier, 0);
1303 cleanup = TREE_VALUE (cleanup);
1304 mark_used (cleanup);
1305 mark_addressable (cleanup);
1306 /* Pretend it's a normal function. */
1307 cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
1311 if (cleanup == NULL_TREE)
1313 cleanup = build_int_2 (0, 0);
1314 TREE_TYPE (cleanup) = cleanup_type;
1317 fn = get_identifier ("__cp_push_exception");
1318 if (IDENTIFIER_GLOBAL_VALUE (fn))
1319 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1320 else
1322 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1323 as defined in exception.cc. */
1324 tree tmp;
1325 push_obstacks_nochange ();
1326 end_temporary_allocation ();
1327 tmp = tree_cons
1328 (NULL_TREE, ptr_type_node, tree_cons
1329 (NULL_TREE, ptr_type_node, tree_cons
1330 (NULL_TREE, cleanup_type, void_list_node)));
1331 fn = build_lang_decl (FUNCTION_DECL, fn,
1332 build_function_type (void_type_node, tmp));
1333 DECL_EXTERNAL (fn) = 1;
1334 TREE_PUBLIC (fn) = 1;
1335 DECL_ARTIFICIAL (fn) = 1;
1336 pushdecl_top_level (fn);
1337 make_function_rtl (fn);
1338 assemble_external (fn);
1339 pop_obstacks ();
1342 /* The throw expression is a full-expression. */
1343 exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
1344 e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons
1345 (NULL_TREE, throw_type, expr_tree_cons
1346 (NULL_TREE, cleanup, NULL_TREE)));
1347 e = build_function_call (fn, e);
1348 expand_expr (e, const0_rtx, VOIDmode, 0);
1350 else
1352 /* rethrow current exception; note that it's no longer caught. */
1354 tree fn = get_identifier ("__uncatch_exception");
1355 if (IDENTIFIER_GLOBAL_VALUE (fn))
1356 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1357 else
1359 /* Declare void __uncatch_exception (void)
1360 as defined in exception.cc. */
1361 push_obstacks_nochange ();
1362 end_temporary_allocation ();
1363 fn = build_lang_decl (FUNCTION_DECL, fn,
1364 build_function_type (void_type_node,
1365 void_list_node));
1366 DECL_EXTERNAL (fn) = 1;
1367 TREE_PUBLIC (fn) = 1;
1368 DECL_ARTIFICIAL (fn) = 1;
1369 pushdecl_top_level (fn);
1370 make_function_rtl (fn);
1371 assemble_external (fn);
1372 pop_obstacks ();
1375 exp = build_function_call (fn, NULL_TREE);
1376 expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
1379 if (exceptions_via_longjmp)
1380 emit_throw ();
1381 else
1383 /* This is the label that represents where in the code we were, when
1384 we got an exception. This needs to be updated when we rethrow an
1385 exception, so that the matching routine knows to search out. */
1386 label = gen_label_rtx ();
1387 emit_label (label);
1389 expand_internal_throw (label);
1393 /* Build a throw expression. */
1395 tree
1396 build_throw (e)
1397 tree e;
1399 if (e != error_mark_node)
1401 if (processing_template_decl)
1402 return build_min (THROW_EXPR, void_type_node, e);
1403 e = build1 (THROW_EXPR, void_type_node, e);
1404 TREE_SIDE_EFFECTS (e) = 1;
1405 TREE_USED (e) = 1;
1407 return e;