OSDN Git Service

Fri Oct 31 01:45:31 1997 Jason Merrill <jason@yorick.cygnus.com>
[pf3gnuchains/gcc-fork.git] / gcc / cp / except.c
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.
6
7 This file is part of GNU CC.
8
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.
13
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.
18
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.  */
23
24
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"
37
38 rtx expand_builtin_return_addr  PROTO((enum built_in_function, int, rtx));
39
40 /* Holds the fndecl for __builtin_return_address.  */
41 tree builtin_return_address_fndecl;
42
43 /* A couple of backend routines from m88k.c */
44
45 /* Used to cache a call to __builtin_return_address.  */
46 static tree BuiltinReturnAddress;
47      
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));
55
56 static void
57 easy_expand_asm (str)
58      char *str;
59 {
60   expand_asm (build_string (strlen (str)+1, str));
61 }
62
63
64 #if 0
65 /* This is the startup, and finish stuff per exception table.  */
66
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
71
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 */
79
80 #ifdef EXCEPT_SECTION_ASM_OP
81
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);
88
89 #endif /* EXCEPT_SECTION_ASM_OP */
90
91 #ifdef EXCEPT_SECTION_ASM_OP
92
93  /* we need to know where the end of the exception table is... so this
94     is how we do it! */
95
96 asm (EXCEPT_SECTION_ASM_OP);
97 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
98 asm (TEXT_SECTION_ASM_OP);
99
100 #endif /* EXCEPT_SECTION_ASM_OP */
101
102 #endif
103
104 #include "decl.h"
105 #include "insn-flags.h"
106 #include "obstack.h"
107
108 /* ======================================================================
109    Briefly the algorithm works like this:
110
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.
115
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).
128
129         +---------------------------------------------------------------+
130         |XXX: Will need modification to deal with partially             |
131         |                       constructed arrays of objects           |
132         |                                                               |
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         +---------------------------------------------------------------+
138
139      When a catch block is encountered, there is a lot of work to be
140      done.
141
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.
148
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.
164      
165      ===================================================================== */
166
167 /* local globals for function calls
168    ====================================================================== */
169
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;
173
174 /* Used to cache __find_first_exception_table_match for throw.  */
175 static tree FirstExceptionMatch;
176
177 /* Used to cache a call to __unwind_function.  */
178 static tree Unwind;
179
180 /* Holds a ready to emit call to "terminate".  */
181 static tree TerminateFunctionCall;
182
183 /* ====================================================================== */
184
185
186 /* ========================================================================= */
187
188
189
190 /* local globals - these local globals are for storing data necessary for
191    generating the exception table and code in the correct order.
192
193    ========================================================================= */
194
195 /* Holds the pc for doing "throw" */
196 static tree saved_pc;
197
198 extern int throw_used;
199 extern rtx catch_clauses;
200
201 /* ========================================================================= */
202
203 /* Cheesyness to save some typing.  Returns the return value rtx.  */
204
205 static rtx
206 do_function_call (func, params, return_type)
207      tree func, params, return_type;
208 {
209   tree func_call;
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);
214   return NULL_RTX;
215 }
216
217 /* ========================================================================= */
218
219 /* sets up all the global eh stuff that needs to be initialized at the
220    start of compilation.
221
222    This includes:
223                 - Setting up all the function call trees.  */
224
225 void
226 init_exception_processing ()
227 {
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;
232   tree unwind_fndecl;
233   tree declspecs;
234   tree d;
235
236   /* void vtype () */
237   tree vtype = build_function_type (void_type_node, void_list_node);
238   
239   /* void (*)() */
240   tree PFV = build_pointer_type (vtype);
241
242   /* Arg list for the build_function_type call for set_terminate and
243      set_unexpected.  */
244   tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
245
246   /* void (*pfvtype (void (*) ()))() */
247   tree pfvtype = build_function_type (PFV, pfvlist);
248
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;
258
259   push_lang_context (lang_name_c);
260
261   catch_match_fndecl
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,
269                                                                               void_list_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,
275                                                         void_list_node)),
276                         NOT_BUILT_IN, NULL_PTR);
277   unwind_fndecl
278     = builtin_function ("__unwind_function",
279                         build_function_type (void_type_node,
280                                              tree_cons (NULL_TREE, ptr_type_node,
281                                                         void_list_node)),
282                         NOT_BUILT_IN, NULL_PTR);
283
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);
292
293   TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
294
295   pop_lang_context ();
296
297   d = build_decl (VAR_DECL, get_identifier ("__eh_pc"), ptr_type_node);
298   TREE_PUBLIC (d) = 1;
299   DECL_EXTERNAL (d) = 1;
300   DECL_ARTIFICIAL (d) = 1;
301   cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
302   saved_pc = d;
303
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;
307 }
308
309 /* Retrieve a pointer to the cp_eh_info node for the current exception
310    and save it in the current binding level.  */
311
312 static void
313 push_eh_info ()
314 {
315   tree decl, fn;
316
317   fn = get_identifier ("__cp_exception_info");
318   if (IDENTIFIER_GLOBAL_VALUE (fn))
319     fn = IDENTIFIER_GLOBAL_VALUE (fn);
320   else
321     {
322       tree t, fields[5];
323
324       /* Declare cp_eh_info * __cp_exception_info (void),
325          as defined in exception.cc. */
326       push_obstacks_nochange ();
327       end_temporary_allocation ();
328
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"),
333                                          ptr_type_node);
334       fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
335                                          ptr_type_node);
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"),
342                                          boolean_type_node);
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);
347
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);
357       pop_obstacks ();
358     }
359   fn = build_function_call (fn, NULL_TREE);
360
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"),
364                      TREE_TYPE (fn));
365   DECL_ARTIFICIAL (decl) = 1;
366   DECL_INITIAL (decl) = fn;
367   decl = pushdecl (decl);
368   cp_finish_decl (decl, fn, NULL_TREE, 0, 0);
369 }
370
371 /* Returns a reference to the cp_eh_info node for the current exception.  */
372
373 static tree
374 get_eh_info ()
375 {
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);
379 }
380
381 /* Returns a reference to the current exception object.  */
382
383 static tree
384 get_eh_value ()
385 {
386   return build_component_ref (get_eh_info (), get_identifier ("value"),
387                               NULL_TREE, 0);
388 }
389
390 /* Returns a reference to the current exception type.  */
391
392 static tree
393 get_eh_type ()
394 {
395   return build_component_ref (get_eh_info (), get_identifier ("type"),
396                               NULL_TREE, 0);
397 }
398
399 /* Returns a reference to whether or not the current exception
400    has been caught.  */
401
402 static tree
403 get_eh_caught ()
404 {
405   return build_component_ref (get_eh_info (), get_identifier ("caught"),
406                               NULL_TREE, 0);
407 }
408
409 /* Build a type value for use at runtime for a type that is matched
410    against by the exception handling system.  */
411
412 static tree
413 build_eh_type_type (type)
414      tree type;
415 {
416   char *typestring;
417   tree exp;
418
419   if (type == error_mark_node)
420     return error_mark_node;
421
422   /* peel back references, so they match.  */
423   if (TREE_CODE (type) == REFERENCE_TYPE)
424     type = TREE_TYPE (type);
425
426   /* Peel off cv qualifiers.  */
427   type = TYPE_MAIN_VARIANT (type);
428
429   if (flag_rtti)
430     {
431       return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
432     }
433
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);
437 }
438
439 /* Build a type value for use at runtime for a exp that is thrown or
440    matched against by the exception handling system.  */
441
442 static tree
443 build_eh_type (exp)
444      tree exp;
445 {
446   if (flag_rtti)
447     {
448       exp = build_typeid (exp);
449       return build1 (ADDR_EXPR, ptr_type_node, exp);
450     }
451   return build_eh_type_type (TREE_TYPE (exp));
452 }
453
454 /* This routine creates the cleanup for the current exception.  */
455
456 static void
457 push_eh_cleanup ()
458 {
459   /* All cleanups must last longer than normal.  */
460   int yes = suspend_momentary ();
461   tree fn, cleanup;
462
463   fn = get_identifier ("__cp_pop_exception");
464   if (IDENTIFIER_GLOBAL_VALUE (fn))
465     fn = IDENTIFIER_GLOBAL_VALUE (fn);
466   else
467     {
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,
473                                                  void_list_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);
480       pop_obstacks ();
481     }
482
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);
486
487   resume_momentary (yes);
488 }
489
490
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) */
496
497 void
498 expand_start_catch_block (declspecs, declarator)
499      tree declspecs, declarator;
500 {
501   rtx false_label_rtx;
502   tree decl = NULL_TREE;
503   tree init;
504
505   if (processing_template_decl)
506     {
507       if (declspecs)
508         {
509           decl = grokdeclarator (declarator, declspecs, CATCHPARM,
510                                  1, NULL_TREE);
511           pushdecl (decl);
512           decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
513                                copy_to_permanent (declspecs),
514                                NULL_TREE);
515           add_tree (decl);
516         }
517       return;
518     }
519
520   if (! doing_eh (1))
521     return;
522
523   /* Create a binding level for the parm.  */
524   pushlevel (0);
525   expand_start_bindings (0);
526
527   false_label_rtx = gen_label_rtx ();
528   push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
529
530   emit_line_note (input_filename, lineno);
531
532   push_eh_info ();
533
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.
538
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
542      multiple EH objects.
543
544      Matches the end in expand_end_catch_block.  */
545   expand_eh_region_start ();
546
547   push_eh_cleanup ();
548
549   if (declspecs)
550     {
551       tree exp;
552       rtx call_rtx, return_value_rtx;
553       tree init_type;
554
555       decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
556
557       if (decl == NULL_TREE)
558         {
559           error ("invalid catch parameter");
560           return;
561         }
562
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;
566
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);
572
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,
577                                   get_eh_type (),
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));
582
583       return_value_rtx = hard_function_value (ptr_type_node, exp);
584
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);
588
589       /* if it returned FALSE, jump over the catch block, else fall into it */
590       emit_jump_insn (gen_beq (false_label_rtx));
591
592       init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
593
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);
599     }
600
601   init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node);
602   expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL);
603
604   emit_line_note (input_filename, lineno);
605 }
606
607
608
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.  */
612
613 void
614 expand_end_catch_block ()
615 {
616   rtx start_region_label_rtx;
617   rtx end_region_label_rtx;
618   tree decls, t;
619
620   if (! doing_eh (1))
621     return;
622
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);
629
630   if (exceptions_via_longjmp)
631     {
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.  */
636
637       emit_library_call (sjpopnthrow_libfunc, 0, VOIDmode, 0);
638       emit_barrier ();
639     }
640   else
641     {
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.  */
645
646       expand_internal_throw (DECL_RTL (top_label_entry (&caught_return_label_stack)));
647     }
648
649   do_pending_stack_adjust ();
650   RTL_EXPR_SEQUENCE (t) = get_insns ();
651   end_sequence ();
652
653   /* Matches the start in expand_start_catch_block.  */
654   expand_eh_region_end (t);
655
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
658      documentation.  */
659   expand_goto (top_label_entry (&caught_return_label_stack));
660
661   expand_leftover_cleanups ();
662
663   /* Cleanup the EH parameter.  */
664   expand_end_bindings (getdecls (), kept_level_p (), 0);
665   poplevel (kept_level_p (), 1, 0);
666       
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));
670 }
671
672 /* unwind the stack.  */
673
674 static void
675 do_unwind (inner_throw_label)
676      rtx inner_throw_label;
677 {
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.  */
681   tree fcall;
682   tree params;
683   rtx next_pc;
684   rtx temp;
685
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");
698   emit_barrier ();
699 #endif
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");
703
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)));
708 #endif
709 #if defined (TARGET_88000) /* was m88k */
710   rtx temp_frame = frame_pointer_rtx;
711
712   temp_frame = memory_address (Pmode, temp_frame);
713   temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
714
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))));
721
722 #if 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))));
725
726   emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
727
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))));
730 #endif
731 #endif
732 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
733   tree fcall;
734   tree params;
735   rtx next_pc;
736
737 #if 0
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);
743
744   emit_move_insn (next_pc, inner_throw_label);
745   /* So, for now, just pass throw label to stack unwinder.  */
746 #endif
747   params = expr_tree_cons (NULL_TREE, make_tree (ptr_type_node,
748                                             inner_throw_label), NULL_TREE);
749   
750   do_function_call (Unwind, params, NULL_TREE);
751   assemble_external (TREE_OPERAND (Unwind, 0));
752   emit_barrier ();
753 #endif
754 }
755
756
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.
759
760    expands "throw" as the following pseudo code:
761
762         throw:
763                 eh = find_first_exception_match (saved_pc);
764             if (!eh) goto gotta_rethrow_it;
765                 goto eh;
766
767         gotta_rethrow_it:
768                 saved_pc = __builtin_return_address (0);
769                 pop_to_previous_level ();
770                 goto throw;  */
771
772 void
773 expand_builtin_throw ()
774 {
775 #ifndef DWARF2_UNWIND_INFO
776   tree fcall;
777   tree params;
778   rtx handler;
779   rtx saved_pcnthrow;
780   rtx next_pc;
781   rtx gotta_rethrow_it;
782   rtx gotta_call_terminate;
783   rtx after_unwind;
784   rtx top_of_loop;
785   tree t;
786   rtx x;
787
788   if (! doing_eh (0))
789     return;
790
791   if (! throw_used)
792     return;
793
794   params = void_list_node;
795   t = make_call_declarator (get_identifier ("__throw"), params, NULL_TREE,
796                             NULL_TREE);
797   start_function (decl_tree_cons (NULL_TREE,
798                                   get_identifier ("void"),
799                                   decl_tree_cons (NULL_TREE,
800                                                   get_identifier ("static"),
801                                                   NULL_TREE)),
802                   t, NULL_TREE, 0);
803   store_parm_decls ();
804   pushlevel (0);
805   clear_last_expr ();
806   push_momentary ();
807   expand_start_bindings (0);
808
809   gotta_rethrow_it = gen_label_rtx ();
810   gotta_call_terminate = gen_label_rtx ();
811
812   /* These two can be frontend specific.  If wanted, they can go in
813      expand_throw.  */
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));
818
819   /* search for an exception handler for the saved_pc */
820   handler = do_function_call (FirstExceptionMatch,
821                               expr_tree_cons (NULL_TREE, saved_pc,
822                                          NULL_TREE),
823                               ptr_type_node);
824   assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
825
826   /* did we find one? */
827   emit_cmp_insn (handler, const0_rtx, EQ, NULL_RTX,
828                  GET_MODE (handler), 0, 0);
829
830   /* if not, jump to gotta_rethrow_it */
831   emit_jump_insn (gen_beq (gotta_rethrow_it));
832
833   {
834     rtx ret_val, x;
835     ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
836                                           0, hard_frame_pointer_rtx);
837
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);
842     if (x != ret_val)
843       emit_move_insn (ret_val, x);
844 #endif
845
846     expand_null_return ();
847   }
848
849   top_of_loop = gen_label_rtx ();
850   emit_label (top_of_loop);
851   
852 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
853   if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
854     {
855       saved_pcnthrow = gen_reg_rtx (Pmode);
856       emit_move_insn (saved_pcnthrow, hard_function_value (ptr_type_node,
857                                                            NULL_TREE));
858     }
859 #endif
860       
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)));
868 #else
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);
872 #endif
873
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);
877
878   emit_jump_insn (gen_beq (gotta_call_terminate));
879
880   next_pc = eh_outer_context (next_pc);
881
882   /* Yes it did.  */
883 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
884   if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
885     {
886       rtx x;
887
888       x = validize_mem (gen_rtx (MEM, Pmode, saved_pcnthrow));
889       emit_move_insn (validize_mem (gen_rtx (MEM, Pmode, x)),
890                       next_pc);
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)));
898 #endif
899     }
900   else
901 #endif
902     emit_move_insn (eh_saved_pc_rtx, next_pc);
903
904   after_unwind = gen_label_rtx ();
905   do_unwind (gen_rtx (LABEL_REF, Pmode, after_unwind));
906
907   emit_label (after_unwind);
908
909 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
910   if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
911     {
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,
915                                           NULL_TREE));
916       t = build_function_call (t, NULL_TREE);
917       expand_expr (t, const0_rtx, VOIDmode, 0);
918     }
919   else
920 #endif
921     emit_throw ();
922
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));
927
928   {
929     rtx ret_val, x;
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);
934
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);
939     if (x != ret_val)
940       emit_move_insn (ret_val, x);
941 #endif
942
943 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
944     if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
945       {
946         rtx x = emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode,
947                                                   "__eh_pcnthrow"),
948                                          NULL_RTX, 1,
949                                          Pmode, 0);
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)))),
953                         throw_libfunc);
954 #ifdef FUNCTION_OUTGOING_VALUE  
955         emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
956                         x);
957         emit_insn (gen_rtx (USE, VOIDmode, FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
958 #endif
959       }
960 #endif
961
962     /* Fall into epilogue to unwind prologue.  */
963   }
964
965   expand_end_bindings (getdecls (), 1, 0);
966   poplevel (1, 0, 0);
967   pop_momentary ();
968
969   finish_function (lineno, 0, 0);
970 #endif /* DWARF2_UNWIND_INFO */
971 }
972
973
974 void
975 expand_start_eh_spec ()
976 {
977   expand_eh_region_start ();
978 }
979
980 static void
981 expand_end_eh_spec (raises)
982      tree raises;
983 {
984   tree expr, second_try;
985   rtx check = gen_label_rtx ();
986   rtx cont;
987   rtx ret = gen_reg_rtx (Pmode);
988   rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
989   rtx end = gen_label_rtx ();
990
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));
999   emit_jump (check);
1000   emit_label (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));
1004   emit_barrier ();
1005   do_pending_stack_adjust ();
1006   RTL_EXPR_SEQUENCE (expr) = get_insns ();
1007   end_sequence ();
1008   
1009   second_try = expr;
1010
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);
1017
1018   cont = gen_label_rtx ();
1019   emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1020   emit_jump (check);
1021   emit_label (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));
1026   emit_barrier ();
1027
1028   expand_eh_region_end (second_try);
1029   
1030   emit_label (check);
1031   emit_move_insn (flag, const1_rtx);
1032   cont = gen_label_rtx ();
1033
1034   push_eh_info ();
1035
1036   while (raises)
1037     {
1038       tree exp;
1039       tree match_type = TREE_VALUE (raises);
1040       
1041       if (match_type)
1042         {
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,
1048                                       get_eh_type (),
1049                                       expr_tree_cons (NULL_TREE, exp, NULL_TREE)));
1050           exp = build_function_call (CatchMatch, exp);
1051           assemble_external (TREE_OPERAND (CatchMatch, 0));
1052
1053           jumpif (exp, cont);
1054         }
1055
1056       raises = TREE_CHAIN (raises);
1057     }
1058   emit_move_insn (flag, const0_rtx);
1059   emit_label (cont);
1060   emit_indirect_jump (ret);
1061   emit_label (end);
1062   
1063   do_pending_stack_adjust ();
1064   RTL_EXPR_SEQUENCE (expr) = get_insns ();
1065   end_sequence ();
1066   
1067   expand_eh_region_end (expr);
1068 }
1069
1070 /* This is called to expand all the toplevel exception handling
1071    finalization for a function.  It should only be called once per
1072    function.  */
1073
1074 void
1075 expand_exception_blocks ()
1076 {
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 ();
1082   end_sequence ();
1083
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)))
1089     {
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 ();
1096      end_sequence ();
1097     }
1098
1099   if (catch_clauses)
1100     {
1101       rtx funcend = gen_label_rtx ();
1102       emit_jump (funcend);
1103
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)
1108         {
1109           /* Is this necessary?  */
1110           assemble_external (TREE_OPERAND (Terminate, 0));
1111
1112           expand_eh_region_start ();
1113         }
1114
1115       emit_insns (catch_clauses);
1116       catch_clauses = NULL_RTX;
1117
1118       if (exceptions_via_longjmp == 0)
1119         expand_eh_region_end (TerminateFunctionCall);
1120
1121       expand_leftover_cleanups ();
1122
1123       emit_label (funcend);
1124     }
1125 }
1126
1127 tree
1128 start_anon_func ()
1129 {
1130   static int counter = 0;
1131   int old_interface_unknown = interface_unknown;
1132   char name[32];
1133   tree params;
1134   tree t;
1135
1136   push_cp_function_context (NULL_TREE);
1137   push_to_top_level ();
1138
1139   /* No need to mangle this.  */
1140   push_lang_context (lang_name_c);
1141
1142   interface_unknown = 1;
1143
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,
1148                             NULL_TREE);
1149   start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1150                                   void_list_node),
1151                   t, NULL_TREE, 0);
1152   store_parm_decls ();
1153   pushlevel (0);
1154   clear_last_expr ();
1155   push_momentary ();
1156   expand_start_bindings (0);
1157   emit_line_note (input_filename, lineno);
1158
1159   interface_unknown = old_interface_unknown;
1160
1161   pop_lang_context ();
1162
1163   return current_function_decl;
1164 }
1165
1166 void
1167 end_anon_func ()
1168 {
1169   expand_end_bindings (getdecls (), 1, 0);
1170   poplevel (1, 0, 0);
1171   pop_momentary ();
1172
1173   finish_function (lineno, 0, 0);
1174
1175   pop_from_top_level ();
1176   pop_cp_function_context (NULL_TREE);
1177 }
1178
1179 /* Expand a throw statement.  This follows the following
1180    algorithm:
1181
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.  */
1188
1189 void
1190 expand_throw (exp)
1191      tree exp;
1192 {
1193   rtx label;
1194   tree fn;
1195   static tree cleanup_type;
1196
1197   if (! doing_eh (1))
1198     return;
1199
1200   if (exp)
1201     {
1202       tree throw_type;
1203       tree cleanup = NULL_TREE, e;
1204
1205       /* throw expression */
1206       /* First, decay it.  */
1207       exp = decay_conversion (exp);
1208
1209       /* cleanup_type is void (*)(void *, int),
1210          the internal type of a destructor. */
1211       if (cleanup_type == NULL_TREE)
1212         {
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))));
1220           pop_obstacks ();
1221         }
1222
1223       if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1224         {
1225           throw_type = build_eh_type (exp);
1226           exp = build_reinterpret_cast (ptr_type_node, exp);
1227         }
1228       else
1229         {
1230           tree object;
1231
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),
1235                            0);
1236
1237           if (exp == error_mark_node)
1238             error ("  in thrown expression");
1239
1240           object = build_indirect_ref (exp, NULL_PTR);
1241           throw_type = build_eh_type (object);
1242
1243           if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
1244             {
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);
1251             }
1252         }
1253
1254       if (cleanup == NULL_TREE)
1255         {
1256           cleanup = build_int_2 (0, 0);
1257           TREE_TYPE (cleanup) = cleanup_type;
1258         }
1259
1260       fn = get_identifier ("__cp_push_exception");
1261       if (IDENTIFIER_GLOBAL_VALUE (fn))
1262         fn = IDENTIFIER_GLOBAL_VALUE (fn);
1263       else
1264         {
1265           /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1266              as defined in exception.cc.  */
1267           tree tmp;
1268           push_obstacks_nochange ();
1269           end_temporary_allocation ();
1270           tmp = tree_cons
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);
1282           pop_obstacks ();
1283         }
1284
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);
1292     }
1293   else
1294     {
1295       /* rethrow current exception; note that it's no longer caught.  */
1296
1297       tree fn = get_identifier ("__uncatch_exception");
1298       if (IDENTIFIER_GLOBAL_VALUE (fn))
1299         fn = IDENTIFIER_GLOBAL_VALUE (fn);
1300       else
1301         {
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,
1308                                                      void_list_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);
1315           pop_obstacks ();
1316         }
1317
1318       exp = build_function_call (fn, NULL_TREE);
1319       expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
1320     }
1321
1322   if (exceptions_via_longjmp)
1323     emit_throw ();
1324   else
1325     {
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 ();
1330       emit_label (label);
1331
1332       expand_internal_throw (label);
1333     }
1334 }
1335
1336 /* Build a throw expression.  */
1337
1338 tree
1339 build_throw (e)
1340      tree e;
1341 {
1342   if (e != error_mark_node)
1343     {
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;
1348       TREE_USED (e) = 1;
1349     }
1350   return e;
1351 }