OSDN Git Service

91th Cygnus<->FSF quick merge
[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 "tree.h"
27 #include "rtl.h"
28 #include "cp-tree.h"
29 #include "flags.h"
30 #include "obstack.h"
31 #include "expr.h"
32 #include "output.h"
33 #include "except.h"
34 #include "function.h"
35
36 rtx expand_builtin_return_addr  PROTO((enum built_in_function, int, rtx));
37
38 /* Holds the fndecl for __builtin_return_address.  */
39 tree builtin_return_address_fndecl;
40
41 /* A couple of backend routines from m88k.c */
42
43 /* Used to cache a call to __builtin_return_address.  */
44 static tree BuiltinReturnAddress;
45      
46
47 #include <stdio.h>
48
49 static void
50 easy_expand_asm (str)
51      char *str;
52 {
53   expand_asm (build_string (strlen (str)+1, str));
54 }
55
56
57 #if 0
58 /* This is the startup, and finish stuff per exception table.  */
59
60 /* XXX - Tad: exception handling section */
61 #ifndef EXCEPT_SECTION_ASM_OP
62 #define EXCEPT_SECTION_ASM_OP   "section\t.gcc_except_table,\"a\",@progbits"
63 #endif
64
65 #ifdef EXCEPT_SECTION_ASM_OP
66 typedef struct {
67     void *start_region;
68     void *end_region;
69     void *exception_handler;
70  } exception_table;
71 #endif /* EXCEPT_SECTION_ASM_OP */
72
73 #ifdef EXCEPT_SECTION_ASM_OP
74
75  /* on machines which support it, the exception table lives in another section,
76         but it needs a label so we can reference it...  This sets up that
77     label! */
78 asm (EXCEPT_SECTION_ASM_OP);
79 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
80 asm (TEXT_SECTION_ASM_OP);
81
82 #endif /* EXCEPT_SECTION_ASM_OP */
83
84 #ifdef EXCEPT_SECTION_ASM_OP
85
86  /* we need to know where the end of the exception table is... so this
87     is how we do it! */
88
89 asm (EXCEPT_SECTION_ASM_OP);
90 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
91 asm (TEXT_SECTION_ASM_OP);
92
93 #endif /* EXCEPT_SECTION_ASM_OP */
94
95 #endif
96
97 #include "decl.h"
98 #include "insn-flags.h"
99 #include "obstack.h"
100
101 /* ======================================================================
102    Briefly the algorithm works like this:
103
104      When a constructor or start of a try block is encountered,
105      push_eh_entry (&eh_stack) is called.  Push_eh_entry () creates a
106      new entry in the unwind protection stack and returns a label to
107      output to start the protection for that block.
108
109      When a destructor or end try block is encountered, pop_eh_entry
110      (&eh_stack) is called.  Pop_eh_entry () returns the eh_entry it
111      created when push_eh_entry () was called.  The eh_entry structure
112      contains three things at this point.  The start protect label,
113      the end protect label, and the exception handler label.  The end
114      protect label should be output before the call to the destructor
115      (if any). If it was a destructor, then its parse tree is stored
116      in the finalization variable in the eh_entry structure.  Otherwise
117      the finalization variable is set to NULL to reflect the fact that
118      is the the end of a try block.  Next, this modified eh_entry node
119      is enqueued in the finalizations queue by calling
120      enqueue_eh_entry (&queue,entry).
121
122         +---------------------------------------------------------------+
123         |XXX: Will need modification to deal with partially             |
124         |                       constructed arrays of objects           |
125         |                                                               |
126         |       Basically, this consists of keeping track of how many   |
127         |       of the objects have been constructed already (this      |
128         |       should be in a register though, so that shouldn't be a  |
129         |       problem.                                                |
130         +---------------------------------------------------------------+
131
132      When a catch block is encountered, there is a lot of work to be
133      done.
134
135      Since we don't want to generate the catch block inline with the
136      regular flow of the function, we need to have some way of doing
137      so.  Luckily, we can use sequences to defer the catch sections.
138      When the start of a catch block is encountered, we start the
139      sequence.  After the catch block is generated, we end the
140      sequence.
141
142      Next we must insure that when the catch block is executed, all
143      finalizations for the matching try block have been completed.  If
144      any of those finalizations throw an exception, we must call
145      terminate according to the ARM (section r.15.6.1).  What this
146      means is that we need to dequeue and emit finalizations for each
147      entry in the eh_queue until we get to an entry with a NULL
148      finalization field.  For any of the finalization entries, if it
149      is not a call to terminate (), we must protect it by giving it
150      another start label, end label, and exception handler label,
151      setting its finalization tree to be a call to terminate (), and
152      enqueue'ing this new eh_entry to be output at an outer level.
153      Finally, after all that is done, we can get around to outputting
154      the catch block which basically wraps all the "catch (...) {...}"
155      statements in a big if/then/else construct that matches the
156      correct block to call.
157      
158      ===================================================================== */
159
160 extern rtx emit_insn            PROTO((rtx));
161 extern rtx gen_nop              PROTO(());
162
163 /* local globals for function calls
164    ====================================================================== */
165
166 /* Used to cache "terminate", "unexpected", "set_terminate", and
167    "set_unexpected" after default_conversion. (lib-except.c)  */
168 static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
169
170 /* Used to cache __find_first_exception_table_match for throw.  */
171 static tree FirstExceptionMatch;
172
173 /* Used to cache a call to __unwind_function.  */
174 static tree Unwind;
175
176 /* Holds a ready to emit call to "terminate".  */
177 static tree TerminateFunctionCall;
178
179 static tree empty_fndecl;
180
181 /* ====================================================================== */
182
183
184 /* ========================================================================= */
185
186
187
188 /* local globals - these local globals are for storing data necessary for
189    generating the exception table and code in the correct order.
190
191    ========================================================================= */
192
193 /* Holds the pc for doing "throw" */
194 static tree saved_pc;
195 /* Holds the type of the thing being thrown.  */
196 static tree saved_throw_type;
197 /* Holds the value being thrown.  */
198 static tree saved_throw_value;
199 /* Holds the cleanup for the value being thrown.  */
200 static tree saved_cleanup;
201 /* Indicates if we are in a catch clause.  */
202 static tree saved_in_catch;
203
204 extern int throw_used;
205 extern rtx catch_clauses;
206
207 /* ========================================================================= */
208
209 /* Cheesyness to save some typing.  Returns the return value rtx.  */
210
211 static rtx
212 do_function_call (func, params, return_type)
213      tree func, params, return_type;
214 {
215   tree func_call;
216   func_call = build_function_call (func, params);
217   expand_call (func_call, NULL_RTX, 0);
218   if (return_type != NULL_TREE)
219     return hard_function_value (return_type, func_call);
220   return NULL_RTX;
221 }
222
223 /* ========================================================================= */
224
225 /* sets up all the global eh stuff that needs to be initialized at the
226    start of compilation.
227
228    This includes:
229                 - Setting up all the function call trees.  */
230
231 void
232 init_exception_processing ()
233 {
234   extern tree define_function ();
235   tree unexpected_fndecl, terminate_fndecl;
236   tree set_unexpected_fndecl, set_terminate_fndecl;
237   tree catch_match_fndecl;
238   tree find_first_exception_match_fndecl;
239   tree unwind_fndecl;
240   tree declspecs;
241   tree d;
242
243   /* void vtype () */
244   tree vtype = build_function_type (void_type_node, void_list_node);
245   
246   /* void (*)() */
247   tree PFV = build_pointer_type (vtype);
248
249   /* Arg list for the build_function_type call for set_terminate and
250      set_unexpected.  */
251   tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
252
253   /* void (*pfvtype (void (*) ()))() */
254   tree pfvtype = build_function_type (PFV, pfvlist);
255
256   set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
257                                         pfvtype, NOT_BUILT_IN);
258   set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
259                                          pfvtype, NOT_BUILT_IN);
260   unexpected_fndecl = auto_function (get_identifier ("unexpected"),
261                                      vtype, NOT_BUILT_IN);
262   terminate_fndecl = auto_function (get_identifier ("terminate"),
263                                     vtype, NOT_BUILT_IN);
264   TREE_THIS_VOLATILE (terminate_fndecl) = 1;
265
266   push_lang_context (lang_name_c);
267
268   catch_match_fndecl
269     = builtin_function (flag_rtti
270                         ? "__throw_type_match_rtti"
271                         : "__throw_type_match",
272                         build_function_type (ptr_type_node,
273                                              tree_cons (NULL_TREE, ptr_type_node,
274                                                         tree_cons (NULL_TREE, ptr_type_node,
275                                                                    tree_cons (NULL_TREE, ptr_type_node,
276                                                                               void_list_node)))),
277                         NOT_BUILT_IN, NULL_PTR);
278   find_first_exception_match_fndecl
279     = builtin_function ("__find_first_exception_table_match",
280                         build_function_type (ptr_type_node,
281                                              tree_cons (NULL_TREE, ptr_type_node,
282                                                         void_list_node)),
283                         NOT_BUILT_IN, NULL_PTR);
284   unwind_fndecl
285     = builtin_function ("__unwind_function",
286                         build_function_type (void_type_node,
287                                              tree_cons (NULL_TREE, ptr_type_node,
288                                                         void_list_node)),
289                         NOT_BUILT_IN, NULL_PTR);
290   empty_fndecl
291     = builtin_function ("__empty",
292                         vtype,
293                         NOT_BUILT_IN, NULL_PTR);
294   DECL_EXTERNAL (empty_fndecl) = 1;
295   TREE_PUBLIC (empty_fndecl) = 1;
296
297   Unexpected = default_conversion (unexpected_fndecl);
298   Terminate = default_conversion (terminate_fndecl);
299   SetTerminate = default_conversion (set_terminate_fndecl);
300   SetUnexpected = default_conversion (set_unexpected_fndecl);
301   CatchMatch = default_conversion (catch_match_fndecl);
302   FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
303   Unwind = default_conversion (unwind_fndecl);
304   BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
305
306   TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
307
308   pop_lang_context ();
309
310   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
311   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
312   d = start_decl (d, declspecs, 0);
313   DECL_COMMON (d) = 1;
314   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
315   saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
316
317   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
318   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
319   d = start_decl (d, declspecs, 0);
320   DECL_COMMON (d) = 1;
321   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
322   saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
323
324   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
325   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
326   d = start_decl (d, declspecs, 0);
327   DECL_COMMON (d) = 1;
328   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
329   saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
330
331   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
332   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
333   d = make_call_declarator (d, void_list_node, NULL_TREE, NULL_TREE);
334   d = start_decl (d, declspecs, 0);
335   DECL_COMMON (d) = 1;
336   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
337   saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
338
339   declspecs = tree_cons (NULL_TREE, get_identifier ("bool"), NULL_TREE);
340   d = get_identifier ("__eh_in_catch");
341   d = start_decl (d, declspecs, 0);
342   DECL_COMMON (d) = 1;
343   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
344   saved_in_catch = lookup_name (get_identifier ("__eh_in_catch"), 0);
345
346   /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
347      be protected with __terminate.  */
348   protect_cleanup_actions_with_terminate = 1;
349 }
350
351 /* Build a type value for use at runtime for a type that is matched
352    against by the exception handling system.  */
353
354 static tree
355 build_eh_type_type (type)
356      tree type;
357 {
358   char *typestring;
359   tree exp;
360
361   if (type == error_mark_node)
362     return error_mark_node;
363
364   /* peel back references, so they match.  */
365   if (TREE_CODE (type) == REFERENCE_TYPE)
366     type = TREE_TYPE (type);
367
368   /* Peel off cv qualifiers.  */
369   type = TYPE_MAIN_VARIANT (type);
370
371   if (flag_rtti)
372     {
373       return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
374     }
375
376   typestring = build_overload_name (type, 1, 1);
377   exp = combine_strings (build_string (strlen (typestring)+1, typestring));
378   return build1 (ADDR_EXPR, ptr_type_node, exp);
379 }
380
381 /* Build a type value for use at runtime for a exp that is thrown or
382    matched against by the exception handling system.  */
383
384 static tree
385 build_eh_type (exp)
386      tree exp;
387 {
388   if (flag_rtti)
389     {
390       exp = build_typeid (exp);
391       return build1 (ADDR_EXPR, ptr_type_node, exp);
392     }
393   return build_eh_type_type (TREE_TYPE (exp));
394 }
395
396 /* This routine creates the cleanup for the exception handling object.  */
397
398 static void
399 push_eh_cleanup ()
400 {
401   /* All cleanups must last longer than normal.  */
402   int yes = suspend_momentary ();
403
404   /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
405   tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
406   cleanup = build (COMPOUND_EXPR, void_type_node, cleanup,
407                    build_modify_expr (saved_in_catch, NOP_EXPR,
408                                       build_modify_expr (saved_throw_type, NOP_EXPR, integer_zero_node)));
409   expand_decl_cleanup (NULL_TREE, cleanup);
410
411   resume_momentary (yes);
412 }
413
414
415 /* call this to start a catch block. Typename is the typename, and identifier
416    is the variable to place the object in or NULL if the variable doesn't
417    matter.  If typename is NULL, that means its a "catch (...)" or catch
418    everything.  In that case we don't need to do any type checking.
419    (ie: it ends up as the "else" clause rather than an "else if" clause) */
420
421 void
422 expand_start_catch_block (declspecs, declarator)
423      tree declspecs, declarator;
424 {
425   rtx false_label_rtx;
426   tree decl = NULL_TREE;
427   tree init;
428
429   if (processing_template_decl)
430     {
431       if (declspecs)
432         {
433           decl = grokdeclarator (declarator, declspecs, CATCHPARM,
434                                  1, NULL_TREE);
435           pushdecl (decl);
436           decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
437                                copy_to_permanent (declspecs),
438                                NULL_TREE);
439           add_tree (decl);
440         }
441       return;
442     }
443
444   if (! doing_eh (1))
445     return;
446
447   /* Create a binding level for the parm.  */
448   pushlevel (0);
449   expand_start_bindings (0);
450
451   false_label_rtx = gen_label_rtx ();
452   push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
453
454   emit_line_note (input_filename, lineno);
455
456   if (declspecs)
457     {
458       tree exp;
459       rtx call_rtx, return_value_rtx;
460       tree init_type;
461
462       decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
463
464       if (decl == NULL_TREE)
465         {
466           error ("invalid catch parameter");
467
468           /* This is cheap, but we want to maintain the data
469              structures.  */
470
471           expand_eh_region_start ();
472
473           return;
474         }
475
476       /* Make sure we mark the catch param as used, otherwise we'll get
477          a warning about an unused ((anonymous)).  */
478       TREE_USED (decl) = 1;
479
480       /* Figure out the type that the initializer is.  */
481       init_type = TREE_TYPE (decl);
482       if (TREE_CODE (init_type) != REFERENCE_TYPE
483           && TREE_CODE (init_type) != POINTER_TYPE)
484         init_type = build_reference_type (init_type);
485
486       exp = saved_throw_value;
487       exp = tree_cons (NULL_TREE,
488                        build_eh_type_type (TREE_TYPE (decl)),
489                        tree_cons (NULL_TREE,
490                                   saved_throw_type,
491                                   tree_cons (NULL_TREE, exp, NULL_TREE)));
492       exp = build_function_call (CatchMatch, exp);
493       call_rtx = expand_call (exp, NULL_RTX, 0);
494       assemble_external (TREE_OPERAND (CatchMatch, 0));
495
496       return_value_rtx = hard_function_value (ptr_type_node, exp);
497
498       /* did the throw type match function return TRUE? */
499       emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
500                     GET_MODE (return_value_rtx), 0, 0);
501
502       /* if it returned FALSE, jump over the catch block, else fall into it */
503       emit_jump_insn (gen_beq (false_label_rtx));
504
505       push_eh_cleanup ();
506
507       init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
508
509       /* Do we need the below two lines? */
510       /* Let `cp_finish_decl' know that this initializer is ok.  */
511       DECL_INITIAL (decl) = init;
512       decl = pushdecl (decl);
513       cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
514     }
515   else
516     {
517       push_eh_cleanup ();
518
519       /* Fall into the catch all section.  */
520     }
521
522   emit_move_insn (DECL_RTL (saved_in_catch), const1_rtx);
523
524   /* If we are not doing setjmp/longjmp EH, because we are reordered
525      out of line, we arrange to rethrow in the outer context so as to
526      skip through the terminate region we are nested in, should we
527      encounter an exception in the catch handler.
528
529      If we are doing setjmp/longjmp EH, we need to skip through the EH
530      object cleanup region.  This isn't quite right, as we really need
531      to clean the object up, but we cannot do that until we track
532      multiple EH objects.
533
534      Matches the end in expand_end_catch_block.  */
535   expand_eh_region_start ();
536
537   emit_line_note (input_filename, lineno);
538 }
539
540
541
542 /* Call this to end a catch block.  Its responsible for emitting the
543    code to handle jumping back to the correct place, and for emitting
544    the label to jump to if this catch block didn't match.  */
545
546 void
547 expand_end_catch_block ()
548 {
549   rtx start_region_label_rtx;
550   rtx end_region_label_rtx;
551   tree decls, t;
552
553   if (! doing_eh (1))
554     return;
555
556   t = make_node (RTL_EXPR);
557   TREE_TYPE (t) = void_type_node;
558   RTL_EXPR_RTL (t) = const0_rtx;
559   TREE_SIDE_EFFECTS (t) = 1;
560   start_sequence_for_rtl_expr (t);
561
562   if (exceptions_via_longjmp)
563     {
564       /* If we are doing setjmp/longjmp EH, we need to skip through
565          the EH object cleanup region.  This isn't quite right, as we
566          really need to clean the object up, but we cannot do that
567          until we track multiple EH objects.  */
568
569       emit_library_call (sjpopnthrow_libfunc, 0, VOIDmode, 0);
570       emit_barrier ();
571     }
572   else
573     {
574       /* If we are not doing setjmp/longjmp EH, we need an extra
575          region around the whole catch block to skip through the
576          terminate region we are nested in.  */
577
578       expand_internal_throw (DECL_RTL (top_label_entry (&caught_return_label_stack)));
579     }
580
581   RTL_EXPR_SEQUENCE (t) = get_insns ();
582   end_sequence ();
583
584   /* Matches the start in expand_start_catch_block.  */
585   expand_eh_region_end (t);
586
587   /* Fall to outside the try statement when done executing handler and
588      we fall off end of handler.  This is jump Lresume in the
589      documentation.  */
590   expand_goto (top_label_entry (&caught_return_label_stack));
591
592   expand_leftover_cleanups ();
593
594   /* Cleanup the EH parameter.  */
595   expand_end_bindings (getdecls (), kept_level_p (), 0);
596   poplevel (kept_level_p (), 1, 0);
597       
598   /* label we emit to jump to if this catch block didn't match.  */
599   /* This the closing } in the `if (eq) {' of the documentation.  */
600   emit_label (pop_label_entry (&false_label_stack));
601 }
602
603 /* unwind the stack.  */
604
605 static void
606 do_unwind (inner_throw_label)
607      rtx inner_throw_label;
608 {
609 #if defined (SPARC_STACK_ALIGN) /* was sparc */
610   /* This doesn't work for the flat model sparc, I bet.  */
611   tree fcall;
612   tree params;
613   rtx next_pc;
614   rtx temp;
615
616   /* Call to  __builtin_return_address. */
617   params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
618   fcall = build_function_call (BuiltinReturnAddress, params);
619   next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
620   /* In the return, the new pc is pc+8, as the value coming in is
621      really the address of the call insn, not the next insn.  */
622   temp = gen_reg_rtx (Pmode);
623   emit_move_insn (temp, inner_throw_label);
624   emit_move_insn (next_pc, plus_constant (temp, -8));
625   emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31)));
626   easy_expand_asm ("ret");
627   easy_expand_asm ("restore");
628   emit_barrier ();
629 #endif
630 #if defined (ARM_FRAME_RTX)  /* was __arm */
631   if (flag_omit_frame_pointer)
632     sorry ("this implementation of exception handling requires a frame pointer");
633
634   emit_move_insn (stack_pointer_rtx,
635                   gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
636   emit_move_insn (hard_frame_pointer_rtx,
637                   gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
638 #endif
639 #if defined (TARGET_88000) /* was m88k */
640   rtx temp_frame = frame_pointer_rtx;
641
642   temp_frame = memory_address (Pmode, temp_frame);
643   temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
644
645   /* hopefully this will successfully pop the frame! */
646   emit_move_insn (frame_pointer_rtx, temp_frame);
647   emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
648   emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
649   emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
650                                                      (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
651
652 #if 0
653   emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
654                                                    -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
655
656   emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
657
658   emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
659                                                      (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
660 #endif
661 #endif
662 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
663   tree fcall;
664   tree params;
665   rtx next_pc;
666
667 #if 0
668   /* I would like to do this here, but the move below doesn't seem to work.  */
669   /* Call to  __builtin_return_address.  */
670   params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
671   fcall = build_function_call (BuiltinReturnAddress, params);
672   next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
673
674   emit_move_insn (next_pc, inner_throw_label);
675   /* So, for now, just pass throw label to stack unwinder.  */
676 #endif
677   params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
678                                             inner_throw_label), NULL_TREE);
679   
680   do_function_call (Unwind, params, NULL_TREE);
681   assemble_external (TREE_OPERAND (Unwind, 0));
682   emit_barrier ();
683 #endif
684 }
685
686
687 /* Is called from expand_exception_blocks to generate the code in a function
688    to "throw" if anything in the function needs to perform a throw.
689
690    expands "throw" as the following pseudo code:
691
692         throw:
693                 eh = find_first_exception_match (saved_pc);
694             if (!eh) goto gotta_rethrow_it;
695                 goto eh;
696
697         gotta_rethrow_it:
698                 saved_pc = __builtin_return_address (0);
699                 pop_to_previous_level ();
700                 goto throw;  */
701
702 void
703 expand_builtin_throw ()
704 {
705   tree fcall;
706   tree params;
707   rtx handler;
708   rtx saved_pcnthrow;
709   rtx next_pc;
710   rtx gotta_rethrow_it;
711   rtx gotta_call_terminate;
712   rtx after_unwind;
713   rtx top_of_loop;
714   tree t;
715   rtx x;
716
717   if (! doing_eh (0))
718     return;
719
720   if (! throw_used)
721     return;
722
723   params = void_list_node;
724   t = make_call_declarator (get_identifier ("__throw"), params, NULL_TREE,
725                             NULL_TREE);
726   start_function (decl_tree_cons (NULL_TREE,
727                                   get_identifier ("void"),
728                                   decl_tree_cons (NULL_TREE,
729                                                   get_identifier ("static"),
730                                                   NULL_TREE)),
731                   t, NULL_TREE, 0);
732   store_parm_decls ();
733   pushlevel (0);
734   clear_last_expr ();
735   push_momentary ();
736   expand_start_bindings (0);
737
738   gotta_rethrow_it = gen_label_rtx ();
739   gotta_call_terminate = gen_label_rtx ();
740
741   /* These two can be frontend specific.  If wanted, they can go in
742      expand_throw.  */
743   /* Do we have a valid object we are throwing? */
744   emit_cmp_insn (DECL_RTL (saved_throw_type), const0_rtx, EQ, NULL_RTX,
745                  GET_MODE (DECL_RTL (saved_throw_type)), 0, 0);
746   emit_jump_insn (gen_beq (gotta_call_terminate));
747
748   /* search for an exception handler for the saved_pc */
749   handler = do_function_call (FirstExceptionMatch,
750                               tree_cons (NULL_TREE, saved_pc,
751                                          NULL_TREE),
752                               ptr_type_node);
753   assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
754
755   /* did we find one? */
756   emit_cmp_insn (handler, const0_rtx, EQ, NULL_RTX,
757                  GET_MODE (handler), 0, 0);
758
759   /* if not, jump to gotta_rethrow_it */
760   emit_jump_insn (gen_beq (gotta_rethrow_it));
761
762   {
763     rtx ret_val, x;
764     ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
765                                           0, hard_frame_pointer_rtx);
766
767     /* Set it up so that we continue at the handler.  */
768     emit_move_insn (ret_val, handler);
769 #ifdef RETURN_ADDR_OFFSET
770     x = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
771     if (x != ret_val)
772       emit_move_insn (ret_val, x);
773 #endif
774
775     expand_null_return ();
776   }
777
778   top_of_loop = gen_label_rtx ();
779   emit_label (top_of_loop);
780   
781 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
782   if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
783     {
784       saved_pcnthrow = gen_reg_rtx (Pmode);
785       emit_move_insn (saved_pcnthrow, hard_function_value (ptr_type_node,
786                                                            NULL_TREE));
787     }
788 #endif
789       
790   /* Call to  __builtin_return_address.  */
791 #if defined (ARM_FRAME_RTX)  /* was __arm */
792   /* This should be moved into arm.h:RETURN_ADDR_RTX */
793   /* This replaces a 'call' to __builtin_return_address */
794   next_pc = gen_reg_rtx (Pmode);
795   emit_move_insn (next_pc,
796                   gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
797 #else
798   params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
799   fcall = build_function_call (BuiltinReturnAddress, params);
800   next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
801 #endif
802
803   /* Did __builtin_return_address return a valid address?  */
804   emit_cmp_insn (next_pc, const0_rtx, EQ, NULL_RTX,
805                  GET_MODE (next_pc), 0, 0);
806
807   emit_jump_insn (gen_beq (gotta_call_terminate));
808
809   next_pc = eh_outer_context (next_pc);
810
811   /* Yes it did.  */
812 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
813   if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
814     {
815       rtx x;
816
817       x = validize_mem (gen_rtx (MEM, Pmode, saved_pcnthrow));
818       emit_move_insn (validize_mem (gen_rtx (MEM, Pmode, x)),
819                       next_pc);
820 #ifdef FUNCTION_OUTGOING_VALUE  
821       emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
822                       validize_mem (gen_rtx (MEM, Pmode,
823                                              plus_constant (saved_pcnthrow,
824                                                             GET_MODE_SIZE (Pmode)))));
825       emit_insn (gen_rtx (USE, VOIDmode,
826                           FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
827 #endif
828     }
829   else
830 #endif
831     emit_move_insn (eh_saved_pc_rtx, next_pc);
832
833   after_unwind = gen_label_rtx ();
834   do_unwind (gen_rtx (LABEL_REF, Pmode, after_unwind));
835
836   emit_label (after_unwind);
837
838 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
839   if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
840     {
841       t = make_tree (build_pointer_type (TREE_TYPE (empty_fndecl)),
842                      hard_function_value (ptr_type_node,
843                                           NULL_TREE));
844       t = build_function_call (t, NULL_TREE);
845       expand_expr (t, const0_rtx, VOIDmode, 0);
846     }
847   else
848 #endif
849     emit_throw ();
850
851   /* no it didn't --> therefore we need to call terminate */
852   emit_label (gotta_call_terminate);
853   do_function_call (Terminate, NULL_TREE, NULL_TREE);
854   assemble_external (TREE_OPERAND (Terminate, 0));
855
856   {
857     rtx ret_val, x;
858     /* code to deal with unwinding and looking for it again */
859     emit_label (gotta_rethrow_it);
860     ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
861                                           0, hard_frame_pointer_rtx);
862
863     /* Set it up so that we continue inside, at the top of the loop.  */
864     emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
865 #ifdef RETURN_ADDR_OFFSET
866     x = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
867     if (x != ret_val)
868       emit_move_insn (ret_val, x);
869 #endif
870
871 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
872     if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
873       {
874         rtx x = emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode,
875                                                   "__eh_pcnthrow"),
876                                          NULL_RTX, 1,
877                                          Pmode, 0);
878         /* This is to get a version of throw that will throw properly.  */
879         emit_move_insn (validize_mem (gen_rtx (MEM, Pmode,
880                                                plus_constant (x, GET_MODE_SIZE (Pmode)))),
881                         throw_libfunc);
882 #ifdef FUNCTION_OUTGOING_VALUE  
883         emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
884                         x);
885         emit_insn (gen_rtx (USE, VOIDmode, FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
886 #endif
887       }
888 #endif
889
890     /* Fall into epilogue to unwind prologue.  */
891   }
892
893   expand_end_bindings (getdecls (), 1, 0);
894   poplevel (1, 0, 0);
895   pop_momentary ();
896
897   finish_function (lineno, 0, 0);
898 }
899
900
901 void
902 expand_start_eh_spec ()
903 {
904   expand_eh_region_start ();
905 }
906
907 static void
908 expand_end_eh_spec (raises)
909      tree raises;
910 {
911   tree expr, second_try;
912   rtx check = gen_label_rtx ();
913   rtx cont;
914   rtx ret = gen_reg_rtx (Pmode);
915   rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
916   rtx end = gen_label_rtx ();
917
918   expr = make_node (RTL_EXPR);
919   TREE_TYPE (expr) = void_type_node;
920   RTL_EXPR_RTL (expr) = const0_rtx;
921   TREE_SIDE_EFFECTS (expr) = 1;
922   start_sequence_for_rtl_expr (expr);
923   cont = gen_label_rtx ();
924   emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
925   emit_jump (check);
926   emit_label (cont);
927   jumpif (make_tree (integer_type_node, flag), end);
928   do_function_call (Terminate, NULL_TREE, NULL_TREE);
929   assemble_external (TREE_OPERAND (Terminate, 0));
930   emit_barrier ();
931   RTL_EXPR_SEQUENCE (expr) = get_insns ();
932   end_sequence ();
933   
934   second_try = expr;
935
936   expr = make_node (RTL_EXPR);
937   TREE_TYPE (expr) = void_type_node;
938   RTL_EXPR_RTL (expr) = const0_rtx;
939   TREE_SIDE_EFFECTS (expr) = 1;
940   start_sequence_for_rtl_expr (expr);
941
942   cont = gen_label_rtx ();
943   emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
944   emit_jump (check);
945   emit_label (cont);
946   jumpif (make_tree (integer_type_node, flag), end);
947   expand_eh_region_start ();
948   do_function_call (Unexpected, NULL_TREE, NULL_TREE);
949   assemble_external (TREE_OPERAND (Unexpected, 0));
950   emit_barrier ();
951
952   expand_eh_region_end (second_try);
953   
954   emit_label (check);
955   emit_move_insn (flag, const1_rtx);
956   cont = gen_label_rtx ();
957   while (raises)
958     {
959       tree exp;
960       tree match_type = TREE_VALUE (raises);
961       
962       if (match_type)
963         {
964           /* check TREE_VALUE (raises) here */
965           exp = saved_throw_value;
966           exp = tree_cons (NULL_TREE,
967                            build_eh_type_type (match_type),
968                            tree_cons (NULL_TREE,
969                                       saved_throw_type,
970                                       tree_cons (NULL_TREE, exp, NULL_TREE)));
971           exp = build_function_call (CatchMatch, exp);
972           assemble_external (TREE_OPERAND (CatchMatch, 0));
973
974           jumpif (exp, cont);
975         }
976
977       raises = TREE_CHAIN (raises);
978     }
979   emit_move_insn (flag, const0_rtx);
980   emit_label (cont);
981   emit_indirect_jump (ret);
982   emit_label (end);
983   
984   RTL_EXPR_SEQUENCE (expr) = get_insns ();
985   end_sequence ();
986   
987   expand_eh_region_end (expr);
988 }
989
990 /* This is called to expand all the toplevel exception handling
991    finalization for a function.  It should only be called once per
992    function.  */
993
994 void
995 expand_exception_blocks ()
996 {
997   push_to_sequence (catch_clauses);
998   expand_leftover_cleanups ();
999   catch_clauses = get_insns ();
1000   end_sequence ();
1001
1002   /* Do this after we expand leftover cleanups, so that the
1003      expand_eh_region_end that expand_end_eh_spec does will match the
1004      right expand_eh_region_start, and make sure it comes out before
1005      the terminate protected region.  */
1006   if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
1007     {
1008      expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
1009      push_to_sequence (catch_clauses);
1010      expand_leftover_cleanups ();
1011      catch_clauses = get_insns ();
1012      end_sequence ();
1013     }
1014
1015   if (catch_clauses)
1016     {
1017       rtx funcend = gen_label_rtx ();
1018       emit_jump (funcend);
1019
1020       /* We cannot protect n regions this way if we must flow into the
1021          EH region through the top of the region, as we have to with
1022          the setjmp/longjmp approach.  */
1023       if (exceptions_via_longjmp == 0)
1024         {
1025           /* Is this necessary?  */
1026           assemble_external (TREE_OPERAND (Terminate, 0));
1027
1028           expand_eh_region_start ();
1029         }
1030
1031       emit_insns (catch_clauses);
1032       catch_clauses = NULL_RTX;
1033
1034       if (exceptions_via_longjmp == 0)
1035         expand_eh_region_end (TerminateFunctionCall);
1036
1037       expand_leftover_cleanups ();
1038
1039       emit_label (funcend);
1040     }
1041 }
1042
1043 tree
1044 start_anon_func ()
1045 {
1046   static int counter = 0;
1047   int old_interface_unknown = interface_unknown;
1048   char name[32];
1049   tree params;
1050   tree t;
1051
1052   push_cp_function_context (NULL_TREE);
1053   push_to_top_level ();
1054
1055   /* No need to mangle this.  */
1056   push_lang_context (lang_name_c);
1057
1058   interface_unknown = 1;
1059
1060   params = void_list_node;
1061   /* tcf stands for throw clean funciton.  */
1062   sprintf (name, "__tcf_%d", counter++);
1063   t = make_call_declarator (get_identifier (name), params, NULL_TREE,
1064                             NULL_TREE);
1065   start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1066                                   void_list_node),
1067                   t, NULL_TREE, 0);
1068   store_parm_decls ();
1069   pushlevel (0);
1070   clear_last_expr ();
1071   push_momentary ();
1072   expand_start_bindings (0);
1073   emit_line_note (input_filename, lineno);
1074
1075   interface_unknown = old_interface_unknown;
1076
1077   pop_lang_context ();
1078
1079   return current_function_decl;
1080 }
1081
1082 void
1083 end_anon_func ()
1084 {
1085   expand_end_bindings (getdecls (), 1, 0);
1086   poplevel (1, 0, 0);
1087   pop_momentary ();
1088
1089   finish_function (lineno, 0, 0);
1090
1091   pop_from_top_level ();
1092   pop_cp_function_context (NULL_TREE);
1093 }
1094
1095 /* Expand a throw statement.  This follows the following
1096    algorithm:
1097
1098         1. Allocate space to save the current PC onto the stack.
1099         2. Generate and emit a label and save its address into the
1100                 newly allocated stack space since we can't save the pc directly.
1101         3. If this is the first call to throw in this function:
1102                 generate a label for the throw block
1103         4. jump to the throw block label.  */
1104
1105 void
1106 expand_throw (exp)
1107      tree exp;
1108 {
1109   rtx label;
1110
1111   if (! doing_eh (1))
1112     return;
1113
1114   if (exp)
1115     {
1116       tree throw_type;
1117       tree cleanup = empty_fndecl, e;
1118
1119       /* throw expression */
1120       /* First, decay it.  */
1121       exp = decay_conversion (exp);
1122
1123       if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1124         {
1125           throw_type = build_eh_type (exp);
1126           exp = build_reinterpret_cast (ptr_type_node, exp);
1127         }
1128       else
1129         {
1130           tree object;
1131
1132           /* Make a copy of the thrown object.  WP 15.1.5  */
1133           exp = build_new (NULL_TREE, TREE_TYPE (exp),
1134                            build_tree_list (NULL_TREE, exp),
1135                            0);
1136
1137           if (exp == error_mark_node)
1138             error ("  in thrown expression");
1139
1140           object = build_indirect_ref (exp, NULL_PTR);
1141           throw_type = build_eh_type (object);
1142
1143           start_sequence ();
1144           object = build_reinterpret_cast (TREE_TYPE (exp), saved_throw_value);
1145           object = build_indirect_ref (object, NULL_PTR);
1146           cleanup = maybe_build_cleanup_and_delete (object);
1147           end_sequence ();
1148
1149           if (cleanup)
1150             {
1151               cleanup = start_anon_func ();
1152
1153               expand_expr (maybe_build_cleanup_and_delete (object),
1154                            const0_rtx, VOIDmode, 0);
1155
1156               end_anon_func ();
1157
1158               mark_addressable (cleanup);
1159             }
1160           else
1161             {
1162               cleanup = empty_fndecl;
1163             }
1164         }
1165
1166       if (cleanup == empty_fndecl)
1167         assemble_external (empty_fndecl);
1168         
1169       e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
1170       expand_expr (e, const0_rtx, VOIDmode, 0);
1171
1172       e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
1173       e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
1174       expand_expr (e, const0_rtx, VOIDmode, 0);
1175
1176       cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
1177       cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
1178       expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1179     }
1180   else
1181     {
1182       /* rethrow current exception */
1183       /* This part is easy, as we don't have to do anything else.  */
1184     }
1185
1186   if (exceptions_via_longjmp)
1187     emit_throw ();
1188   else
1189     {
1190       /* This is the label that represents where in the code we were, when
1191          we got an exception.  This needs to be updated when we rethrow an
1192          exception, so that the matching routine knows to search out.  */
1193       label = gen_label_rtx ();
1194       emit_label (label);
1195
1196       expand_internal_throw (label);
1197     }
1198 }
1199
1200 /* Build a throw expression.  */
1201
1202 tree
1203 build_throw (e)
1204      tree e;
1205 {
1206   if (e != error_mark_node)
1207     {
1208       if (processing_template_decl)
1209         return build_min (THROW_EXPR, void_type_node, e);
1210       e = build1 (THROW_EXPR, void_type_node, e);
1211       TREE_SIDE_EFFECTS (e) = 1;
1212       TREE_USED (e) = 1;
1213     }
1214   return e;
1215 }