OSDN Git Service

* except.c (expand_start_try_stmts): Move to except.c in the backend.
[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 ()
171    for throw (lib-except.c)  */
172 static tree FirstExceptionMatch;
173
174 /* used to cache a call to __unwind_function () (lib-except.c)  */
175 static tree Unwind;
176
177 /* holds a ready to emit call to "terminate ()".  */
178 static tree TerminateFunctionCall;
179
180 static tree empty_fndecl;
181
182 /* ====================================================================== */
183
184
185 /* ========================================================================= */
186
187
188
189 /* local globals - these local globals are for storing data necessary for
190    generating the exception table and code in the correct order.
191
192    ========================================================================= */
193
194 /* Holds the pc for doing "throw" */
195 static tree saved_pc;
196 /* Holds the type of the thing being thrown.  */
197 static tree saved_throw_type;
198 /* Holds the value being thrown.  */
199 static tree saved_throw_value;
200 /* Holds the cleanup for the value being thrown.  */
201 static tree saved_cleanup;
202 /* Indicates if we are in a catch clause.  */
203 static tree saved_in_catch;
204
205 extern int throw_used;
206 extern rtx catch_clauses;
207
208 /* ========================================================================= */
209
210 /* Cheesyness to save some typing.  Returns the return value rtx.  */
211
212 static rtx
213 do_function_call (func, params, return_type)
214      tree func, params, return_type;
215 {
216   tree func_call;
217   func_call = build_function_call (func, params);
218   expand_call (func_call, NULL_RTX, 0);
219   if (return_type != NULL_TREE)
220     return hard_function_value (return_type, func_call);
221   return NULL_RTX;
222 }
223
224 /* ========================================================================= */
225
226 extern tree auto_function PROTO((tree, tree, enum built_in_function));
227
228 /* sets up all the global eh stuff that needs to be initialized at the
229    start of compilation.
230
231    This includes:
232                 - Setting up all the function call trees.  */
233
234 void
235 init_exception_processing ()
236 {
237   extern tree define_function ();
238   tree unexpected_fndecl, terminate_fndecl;
239   tree set_unexpected_fndecl, set_terminate_fndecl;
240   tree catch_match_fndecl;
241   tree find_first_exception_match_fndecl;
242   tree unwind_fndecl;
243   tree declspecs;
244   tree d;
245
246   /* void (*)() */
247   tree PFV = build_pointer_type (build_function_type
248                                  (void_type_node, void_list_node));
249
250   /* arg list for the build_function_type call for set_terminate () and
251      set_unexpected () */
252   tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
253
254   /* void (*pfvtype (void (*) ()))() */
255   tree pfvtype = build_function_type (PFV, pfvlist);
256
257   /* void vtype () */
258   tree vtype = build_function_type (void_type_node, void_list_node);
259   
260   set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
261                                         pfvtype, NOT_BUILT_IN);
262   set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
263                                          pfvtype, NOT_BUILT_IN);
264   unexpected_fndecl = auto_function (get_identifier ("unexpected"),
265                                      vtype, NOT_BUILT_IN);
266   terminate_fndecl = auto_function (get_identifier ("terminate"),
267                                     vtype, NOT_BUILT_IN);
268
269   push_lang_context (lang_name_c);
270
271   catch_match_fndecl =
272     builtin_function (flag_rtti
273                       ? "__throw_type_match_rtti"
274                       : "__throw_type_match",
275                       build_function_type (ptr_type_node,
276                                            tree_cons (NULL_TREE, ptr_type_node,
277                                                       tree_cons (NULL_TREE, ptr_type_node,
278                                                                  tree_cons (NULL_TREE, ptr_type_node,
279                                                                             void_list_node)))),
280                       NOT_BUILT_IN, NULL_PTR);
281   find_first_exception_match_fndecl =
282     builtin_function ("__find_first_exception_table_match",
283                       build_function_type (ptr_type_node,
284                                            tree_cons (NULL_TREE, ptr_type_node,
285                                                       void_list_node)),
286                       NOT_BUILT_IN, NULL_PTR);
287   unwind_fndecl =
288     builtin_function ("__unwind_function",
289                       build_function_type (void_type_node,
290                                            tree_cons (NULL_TREE, ptr_type_node,
291                                                       void_list_node)),
292                       NOT_BUILT_IN, NULL_PTR);
293   empty_fndecl =
294     builtin_function ("__empty",
295                       build_function_type (void_type_node, void_list_node),
296                       NOT_BUILT_IN, NULL_PTR);
297   DECL_EXTERNAL (empty_fndecl) = 1;
298   TREE_PUBLIC (empty_fndecl) = 1;
299
300   Unexpected = default_conversion (unexpected_fndecl);
301   Terminate = default_conversion (terminate_fndecl);
302   SetTerminate = default_conversion (set_terminate_fndecl);
303   SetUnexpected = default_conversion (set_unexpected_fndecl);
304   CatchMatch = default_conversion (catch_match_fndecl);
305   FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
306   Unwind = default_conversion (unwind_fndecl);
307   BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
308
309   TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
310
311   pop_lang_context ();
312
313   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
314   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
315   d = start_decl (d, declspecs, 0, NULL_TREE);
316   DECL_COMMON (d) = 1;
317   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
318   saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
319
320   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
321   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
322   d = start_decl (d, declspecs, 0, NULL_TREE);
323   DECL_COMMON (d) = 1;
324   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
325   saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
326
327   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
328   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
329   d = start_decl (d, declspecs, 0, NULL_TREE);
330   DECL_COMMON (d) = 1;
331   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
332   saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
333
334   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
335   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
336   d = build_parse_node (CALL_EXPR, d, void_list_node, NULL_TREE);
337   d = start_decl (d, declspecs, 0, NULL_TREE);
338   DECL_COMMON (d) = 1;
339   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
340   saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
341
342   declspecs = tree_cons (NULL_TREE, get_identifier ("bool"), NULL_TREE);
343   d = get_identifier ("__eh_in_catch");
344   d = start_decl (d, declspecs, 0, NULL_TREE);
345   DECL_COMMON (d) = 1;
346   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
347   saved_in_catch = lookup_name (get_identifier ("__eh_in_catch"), 0);
348 }
349
350 /* Build a type value for use at runtime for a type that is matched
351    against by the exception handling system.  */
352
353 static tree
354 build_eh_type_type (type)
355      tree type;
356 {
357   char *typestring;
358   tree exp;
359
360   if (type == error_mark_node)
361     return error_mark_node;
362
363   /* peel back references, so they match.  */
364   if (TREE_CODE (type) == REFERENCE_TYPE)
365     type = TREE_TYPE (type);
366
367   /* Peel off cv qualifiers.  */
368   type = TYPE_MAIN_VARIANT (type);
369
370   if (flag_rtti)
371     {
372       return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
373     }
374
375   typestring = build_overload_name (type, 1, 1);
376   exp = combine_strings (build_string (strlen (typestring)+1, typestring));
377   return build1 (ADDR_EXPR, ptr_type_node, exp);
378 }
379
380 /* Build a type value for use at runtime for a exp that is thrown or
381    matched against by the exception handling system.  */
382
383 static tree
384 build_eh_type (exp)
385      tree exp;
386 {
387   if (flag_rtti)
388     {
389       exp = build_typeid (exp);
390       return build1 (ADDR_EXPR, ptr_type_node, exp);
391     }
392   return build_eh_type_type (TREE_TYPE (exp));
393 }
394
395 /* This routine creates the cleanup for the exception handling object.  */
396
397 static void
398 push_eh_cleanup ()
399 {
400   /* All cleanups must last longer than normal.  */
401   int yes = suspend_momentary ();
402
403   /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
404   tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
405   cleanup = build (COMPOUND_EXPR, void_type_node, cleanup,
406                    build_modify_expr (saved_in_catch, NOP_EXPR,
407                                       build_modify_expr (saved_throw_type, NOP_EXPR, integer_zero_node)));
408   expand_decl_cleanup (NULL_TREE, cleanup);
409
410   resume_momentary (yes);
411 }
412
413
414 /* call this to start a catch block. Typename is the typename, and identifier
415    is the variable to place the object in or NULL if the variable doesn't
416    matter.  If typename is NULL, that means its a "catch (...)" or catch
417    everything.  In that case we don't need to do any type checking.
418    (ie: it ends up as the "else" clause rather than an "else if" clause) */
419
420 void
421 expand_start_catch_block (declspecs, declarator)
422      tree declspecs, declarator;
423 {
424   rtx false_label_rtx;
425   tree decl = NULL_TREE;
426   tree init;
427
428   if (! doing_eh (1))
429     return;
430
431   /* Create a binding level for the parm.  */
432   expand_start_bindings (0);
433
434   false_label_rtx = gen_label_rtx ();
435   push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
436
437   if (declspecs)
438     {
439       tree exp;
440       rtx call_rtx, return_value_rtx;
441       tree init_type;
442
443       decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1,
444                              NULL_TREE, NULL_TREE);
445
446       if (decl == NULL_TREE)
447         {
448           error ("invalid catch parameter");
449
450           /* This is cheap, but we want to maintain the data structures.  */
451           expand_eh_region_start ();
452           return;
453         }
454
455       /* Make sure we mark the catch param as used, otherwise we'll get
456          a warning about an unused ((anonymous)).  */
457       TREE_USED (decl) = 1;
458
459       /* Figure out the type that the initializer is.  */
460       init_type = TREE_TYPE (decl);
461       if (TREE_CODE (init_type) != REFERENCE_TYPE
462           && TREE_CODE (init_type) != POINTER_TYPE)
463         init_type = build_reference_type (init_type);
464
465       exp = saved_throw_value;
466       exp = tree_cons (NULL_TREE,
467                        build_eh_type_type (TREE_TYPE (decl)),
468                        tree_cons (NULL_TREE,
469                                   saved_throw_type,
470                                   tree_cons (NULL_TREE, exp, NULL_TREE)));
471       exp = build_function_call (CatchMatch, exp);
472       call_rtx = expand_call (exp, NULL_RTX, 0);
473       assemble_external (TREE_OPERAND (CatchMatch, 0));
474
475       return_value_rtx = hard_function_value (ptr_type_node, exp);
476
477       /* did the throw type match function return TRUE? */
478       emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
479                     GET_MODE (return_value_rtx), 0, 0);
480
481       /* if it returned FALSE, jump over the catch block, else fall into it */
482       emit_jump_insn (gen_beq (false_label_rtx));
483
484       push_eh_cleanup ();
485
486       init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
487
488       /* Do we need the below two lines? */
489       /* Let `cp_finish_decl' know that this initializer is ok.  */
490       DECL_INITIAL (decl) = init;
491       decl = pushdecl (decl);
492       cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
493     }
494   else
495     {
496       push_eh_cleanup ();
497
498       /* Fall into the catch all section.  */
499     }
500
501   emit_move_insn (DECL_RTL (saved_in_catch), const1_rtx);
502
503   /* Because we are reordered out of line, we arrange
504      to rethrow in the outer context, should we encounter
505      an exception in the catch handler.
506
507      Matches the end in expand_end_catch_block ().  */
508   expand_eh_region_start ();
509
510   emit_line_note (input_filename, lineno);
511 }
512
513
514
515 /* Call this to end a catch block.  Its responsible for emitting the
516    code to handle jumping back to the correct place, and for emitting
517    the label to jump to if this catch block didn't match.  */
518
519 void expand_end_catch_block ()
520 {
521   rtx start_region_label_rtx;
522   rtx end_region_label_rtx;
523   tree decls, t;
524
525   if (! doing_eh (1))
526     return;
527
528   /* Fall to outside the try statement when done executing handler and
529      we fall off end of handler.  This is jump Lresume in the
530      documentation.  */
531   expand_goto (top_label_entry (&caught_return_label_stack));
532
533   t = make_node (RTL_EXPR);
534   TREE_TYPE (t) = void_type_node;
535   RTL_EXPR_RTL (t) = const0_rtx;
536   TREE_SIDE_EFFECTS (t) = 1;
537   start_sequence_for_rtl_expr (t);
538   expand_internal_throw (DECL_RTL (top_label_entry (&caught_return_label_stack)));
539   RTL_EXPR_SEQUENCE (t) = get_insns ();
540   end_sequence ();
541
542   /* Matches the start in expand_start_catch_block ().  */
543   expand_eh_region_end (t);
544
545   expand_leftover_cleanups ();
546
547   /* Cleanup the EH parameter.  */
548   decls = getdecls ();
549   expand_end_bindings (decls, decls != NULL_TREE, 0);
550       
551   /* label we emit to jump to if this catch block didn't match.  */
552   /* This the closing } in the `if (eq) {' of the documentation.  */
553   emit_label (pop_label_entry (&false_label_stack));
554 }
555
556 /* unwind the stack.  */
557
558 static void
559 do_unwind (inner_throw_label)
560      rtx inner_throw_label;
561 {
562 #if defined (SPARC_STACK_ALIGN) /* was sparc */
563   /* This doesn't work for the flat model sparc, I bet.  */
564   tree fcall;
565   tree params;
566   rtx return_val_rtx;
567   rtx temp;
568
569   /* call to  __builtin_return_address () */
570   params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
571   fcall = build_function_call (BuiltinReturnAddress, params);
572   return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
573   /* In the return, the new pc is pc+8, as the value coming in is
574      really the address of the call insn, not the next insn.  */
575   temp = gen_reg_rtx (Pmode);
576   emit_move_insn (temp, inner_throw_label);
577   emit_move_insn (return_val_rtx, plus_constant (temp, -8));
578   emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31)));
579   easy_expand_asm ("ret");
580   easy_expand_asm ("restore");
581   emit_barrier ();
582 #endif
583 #if defined (ARM_FRAME_RTX)  /* was __arm */
584   if (flag_omit_frame_pointer)
585     sorry ("this implementation of exception handling requires a frame pointer");
586
587   emit_move_insn (stack_pointer_rtx,
588                   gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
589   emit_move_insn (hard_frame_pointer_rtx,
590                   gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
591 #endif
592 #if defined (TARGET_88000) /* was m88k */
593   rtx temp_frame = frame_pointer_rtx;
594
595   temp_frame = memory_address (Pmode, temp_frame);
596   temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
597
598   /* hopefully this will successfully pop the frame! */
599   emit_move_insn (frame_pointer_rtx, temp_frame);
600   emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
601   emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
602   emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
603                                                      (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
604
605 #if 0
606   emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
607                                                    -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
608
609   emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
610
611   emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
612                                                      (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
613 #endif
614 #endif
615 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
616   tree fcall;
617   tree params;
618   rtx return_val_rtx;
619
620 #if 0
621   /* I would like to do this here, but the move below doesn't seem to work.  */
622   /* call to  __builtin_return_address () */
623   params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
624   fcall = build_function_call (BuiltinReturnAddress, params);
625   return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
626
627   emit_move_insn (return_val_rtx, inner_throw_label);
628   /* So, for now, just pass throw label to stack unwinder.  */
629 #endif
630   params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
631                                             inner_throw_label), NULL_TREE);
632   
633   do_function_call (Unwind, params, NULL_TREE);
634   assemble_external (TREE_OPERAND (Unwind, 0));
635   emit_barrier ();
636 #endif
637 }
638
639
640 /* is called from expand_exception_blocks () to generate the code in a function
641    to "throw" if anything in the function needs to perform a throw.
642
643    expands "throw" as the following pseudo code:
644
645         throw:
646                 eh = find_first_exception_match (saved_pc);
647             if (!eh) goto gotta_rethrow_it;
648                 goto eh;
649
650         gotta_rethrow_it:
651                 saved_pc = __builtin_return_address (0);
652                 pop_to_previous_level ();
653                 goto throw;  */
654
655 void
656 expand_builtin_throw ()
657 {
658   tree fcall;
659   tree params;
660   rtx return_val_rtx;
661   rtx gotta_rethrow_it;
662   rtx gotta_call_terminate;
663   rtx top_of_loop;
664   rtx unwind_first;
665   tree t;
666
667   if (! doing_eh (0))
668     return;
669
670   if (! throw_used)
671     return;
672
673   params = void_list_node;
674   t = build_parse_node (CALL_EXPR, get_identifier ("__throw"), params, NULL_TREE);
675   start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
676                                   void_list_node),
677                   t, NULL_TREE, NULL_TREE, 0);
678   store_parm_decls ();
679   pushlevel (0);
680   clear_last_expr ();
681   push_momentary ();
682   expand_start_bindings (0);
683
684   gotta_rethrow_it = gen_label_rtx ();
685   gotta_call_terminate = gen_label_rtx ();
686   top_of_loop = gen_label_rtx ();
687   unwind_first = gen_label_rtx ();
688
689   /* These two can be frontend specific.  If wanted, they can go in
690      expand_throw.  */
691   /* Do we have a valid object we are throwing? */
692   emit_cmp_insn (DECL_RTL (saved_throw_type), const0_rtx, EQ, NULL_RTX,
693                  GET_MODE (DECL_RTL (saved_throw_type)), 0, 0);
694   emit_jump_insn (gen_beq (gotta_call_terminate));
695
696   emit_jump (unwind_first);
697
698   emit_label (top_of_loop);
699
700   /* search for an exception handler for the saved_pc */
701   return_val_rtx = do_function_call (FirstExceptionMatch,
702                                      tree_cons (NULL_TREE, saved_pc, NULL_TREE),
703                                      ptr_type_node);
704   assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
705
706   /* did we find one? */
707   emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
708                  GET_MODE (return_val_rtx), 0, 0);
709
710   /* if not, jump to gotta_rethrow_it */
711   emit_jump_insn (gen_beq (gotta_rethrow_it));
712
713   /* we found it, so jump to it */
714   emit_indirect_jump (return_val_rtx);
715
716   /* code to deal with unwinding and looking for it again */
717   emit_label (gotta_rethrow_it);
718
719   /* call to  __builtin_return_address () */
720 #if defined (ARM_FRAME_RTX)  /* was __arm */
721   /* This should be moved into arm.h:RETURN_ADDR_RTX */
722   /* This replaces a 'call' to __builtin_return_address */
723   return_val_rtx = gen_reg_rtx (Pmode);
724   emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
725 #else
726   params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
727   fcall = build_function_call (BuiltinReturnAddress, params);
728   return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
729 #endif
730
731   /* did __builtin_return_address () return a valid address? */
732   emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
733                  GET_MODE (return_val_rtx), 0, 0);
734
735   emit_jump_insn (gen_beq (gotta_call_terminate));
736
737   return_val_rtx = eh_outer_context (return_val_rtx);
738
739   /* Yes it did.  */
740   emit_move_insn (eh_saved_pc_rtx, return_val_rtx);
741
742   do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop));
743   emit_jump (top_of_loop);
744
745   /* no it didn't --> therefore we need to call terminate */
746   emit_label (gotta_call_terminate);
747   do_function_call (Terminate, NULL_TREE, NULL_TREE);
748   assemble_external (TREE_OPERAND (Terminate, 0));
749
750   {
751     rtx ret_val, return_val_rtx;
752     emit_label (unwind_first);
753     ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
754                                           0, hard_frame_pointer_rtx);
755
756     /* Set it up so that we continue inside, at the top of the loop.  */
757     emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
758 #ifdef RETURN_ADDR_OFFSET
759   return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
760     if (return_val_rtx != ret_val)
761       emit_move_insn (ret_val, return_val_rtx);
762 #endif
763
764     /* Fall into epilogue to unwind prologue.  */
765   }
766
767   expand_end_bindings (getdecls (), 1, 0);
768   poplevel (1, 0, 0);
769   pop_momentary ();
770
771   finish_function (lineno, 0, 0);
772 }
773
774
775 void
776 expand_start_eh_spec ()
777 {
778   expand_eh_region_start ();
779 }
780
781 static void
782 expand_end_eh_spec (raises)
783      tree raises;
784 {
785   tree expr, second_try;
786   rtx check = gen_label_rtx ();
787   rtx cont;
788   rtx ret = gen_reg_rtx (Pmode);
789   rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
790   rtx end = gen_label_rtx ();
791
792   expr = make_node (RTL_EXPR);
793   TREE_TYPE (expr) = void_type_node;
794   RTL_EXPR_RTL (expr) = const0_rtx;
795   TREE_SIDE_EFFECTS (expr) = 1;
796   start_sequence_for_rtl_expr (expr);
797   cont = gen_label_rtx ();
798   emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
799   emit_jump (check);
800   emit_label (cont);
801   jumpif (make_tree (integer_type_node, flag), end);
802   do_function_call (Terminate, NULL_TREE, NULL_TREE);
803   assemble_external (TREE_OPERAND (Terminate, 0));
804   emit_barrier ();
805   RTL_EXPR_SEQUENCE (expr) = get_insns ();
806   end_sequence ();
807   
808   second_try = expr;
809
810   expr = make_node (RTL_EXPR);
811   TREE_TYPE (expr) = void_type_node;
812   RTL_EXPR_RTL (expr) = const0_rtx;
813   TREE_SIDE_EFFECTS (expr) = 1;
814   start_sequence_for_rtl_expr (expr);
815
816   cont = gen_label_rtx ();
817   emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
818   emit_jump (check);
819   emit_label (cont);
820   jumpif (make_tree (integer_type_node, flag), end);
821   expand_eh_region_start ();
822   do_function_call (Unexpected, NULL_TREE, NULL_TREE);
823   assemble_external (TREE_OPERAND (Unexpected, 0));
824   emit_barrier ();
825   expand_eh_region_end (second_try);
826   
827   emit_label (check);
828   emit_move_insn (flag, const1_rtx);
829   cont = gen_label_rtx ();
830   while (raises)
831     {
832       tree exp;
833       tree match_type = TREE_VALUE (raises);
834       
835       if (match_type)
836         {
837           /* check TREE_VALUE (raises) here */
838           exp = saved_throw_value;
839           exp = tree_cons (NULL_TREE,
840                            build_eh_type_type (match_type),
841                            tree_cons (NULL_TREE,
842                                       saved_throw_type,
843                                       tree_cons (NULL_TREE, exp, NULL_TREE)));
844           exp = build_function_call (CatchMatch, exp);
845           assemble_external (TREE_OPERAND (CatchMatch, 0));
846
847           jumpif (exp, cont);
848         }
849
850       raises = TREE_CHAIN (raises);
851     }
852   emit_move_insn (flag, const0_rtx);
853   emit_label (cont);
854   emit_indirect_jump (ret);
855   emit_label (end);
856   
857   RTL_EXPR_SEQUENCE (expr) = get_insns ();
858   end_sequence ();
859   
860   expand_eh_region_end (expr);
861 }
862
863 /* This is called to expand all the toplevel exception handling
864    finalization for a function.  It should only be called once per
865    function.  */
866
867 void
868 expand_exception_blocks ()
869 {
870   rtx funcend;
871   rtx insns;
872   rtx eh_spec_insns = NULL_RTX;
873
874   start_sequence ();
875
876   funcend = gen_label_rtx ();
877   emit_jump (funcend);
878   /* expand_null_return (); */
879
880   start_sequence ();
881
882   /* Add all the catch clauses here.  */
883   emit_insns (catch_clauses);
884   catch_clauses = NULL_RTX;
885
886   expand_leftover_cleanups ();
887
888   insns = get_insns ();
889   end_sequence ();
890   
891   /* Do this after we expand leftover cleanups, so that the expand_eh_region_end
892      that expand_end_eh_spec does will match the right expand_eh_region_start,
893      and make sure it comes out before the terminate protected region.  */
894   if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
895     {
896 #if 1
897       {
898         rtx insns;
899         /* New...  */
900         start_sequence ();
901         expand_start_eh_spec ();
902         eh_spec_insns = get_insns ();
903         end_sequence ();
904       }
905 #endif
906
907       expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
908       push_to_sequence (insns);
909
910       /* Now expand any new ones.  */
911       expand_leftover_cleanups ();
912
913       insns = get_insns ();
914       end_sequence ();
915     }
916
917   if (insns)
918     {
919       /* Is this necessary?  */
920       assemble_external (TREE_OPERAND (Terminate, 0));
921
922       expand_eh_region_start ();
923       emit_insns (insns);
924       expand_eh_region_end (TerminateFunctionCall);
925       expand_leftover_cleanups ();
926     }
927
928   {
929     /* Mark the end of the stack unwinder.  */
930     rtx unwind_insns;
931     start_sequence ();
932 #if 0
933     end_eh_unwinder ();
934 #endif
935     unwind_insns = get_insns ();
936     end_sequence ();
937     if (unwind_insns)
938       {
939         insns = unwind_insns;
940         emit_insns (insns);
941       }
942   }
943
944   emit_label (funcend);
945
946   /* Only if we had previous insns do we want to emit the jump around
947      them.  If there weren't any, then insns will remain NULL_RTX.  */
948   if (insns)
949     insns = get_insns ();
950   end_sequence ();
951
952 #if 1
953   if (eh_spec_insns)
954     emit_insns_after (eh_spec_insns, get_insns ());
955 #else
956   if (eh_spec_insns)
957     store_after_parms (eh_spec_insns);
958 #endif
959
960   emit_insns (insns);
961 }
962
963 tree
964 start_anon_func ()
965 {
966   static int counter = 0;
967   int old_interface_unknown = interface_unknown;
968   char name[32];
969   tree params;
970   tree t;
971
972   push_cp_function_context (NULL_TREE);
973   push_to_top_level ();
974
975   /* No need to mangle this.  */
976   push_lang_context (lang_name_c);
977
978   interface_unknown = 1;
979
980   params = void_list_node;
981   /* tcf stands for throw clean funciton.  */
982   sprintf (name, "__tcf_%d", counter++);
983   t = build_parse_node (CALL_EXPR, get_identifier (name), params, NULL_TREE);
984   start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
985                                   void_list_node),
986                   t, NULL_TREE, NULL_TREE, 0);
987   store_parm_decls ();
988   pushlevel (0);
989   clear_last_expr ();
990   push_momentary ();
991   expand_start_bindings (0);
992   emit_line_note (input_filename, lineno);
993
994   interface_unknown = old_interface_unknown;
995
996   pop_lang_context ();
997
998   return current_function_decl;
999 }
1000
1001 void
1002 end_anon_func ()
1003 {
1004   expand_end_bindings (getdecls (), 1, 0);
1005   poplevel (1, 0, 0);
1006   pop_momentary ();
1007
1008   finish_function (lineno, 0, 0);
1009
1010   pop_from_top_level ();
1011   pop_cp_function_context (NULL_TREE);
1012 }
1013
1014 /* Expand a throw statement.  This follows the following
1015    algorithm:
1016
1017         1. Allocate space to save the current PC onto the stack.
1018         2. Generate and emit a label and save its address into the
1019                 newly allocated stack space since we can't save the pc directly.
1020         3. If this is the first call to throw in this function:
1021                 generate a label for the throw block
1022         4. jump to the throw block label.  */
1023
1024 void
1025 expand_throw (exp)
1026      tree exp;
1027 {
1028   rtx label;
1029
1030   if (! doing_eh (1))
1031     return;
1032
1033   if (exp)
1034     {
1035       tree throw_type;
1036       tree cleanup = empty_fndecl, e;
1037
1038       /* throw expression */
1039       /* First, decay it.  */
1040       exp = decay_conversion (exp);
1041
1042       if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1043         {
1044           throw_type = build_eh_type (exp);
1045           exp = build_reinterpret_cast (ptr_type_node, exp);
1046         }
1047       else
1048         {
1049           rtx cleanup_insns;
1050           tree object;
1051
1052           /* Make a copy of the thrown object.  WP 15.1.5  */
1053           exp = build_new (NULL_TREE, TREE_TYPE (exp),
1054                            build_tree_list (NULL_TREE, exp),
1055                            0);
1056
1057           if (exp == error_mark_node)
1058             error ("  in thrown expression");
1059
1060           object = build_indirect_ref (exp, NULL_PTR);
1061           throw_type = build_eh_type (object);
1062
1063           start_sequence ();
1064           object = build_reinterpret_cast (TREE_TYPE (exp), saved_throw_value);
1065           object = build_indirect_ref (object, NULL_PTR);
1066           cleanup = maybe_build_cleanup_and_delete (object);
1067           if (cleanup)
1068             expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1069           cleanup_insns = get_insns ();
1070           end_sequence ();
1071
1072           if (cleanup && cleanup_insns)
1073             {
1074               cleanup = start_anon_func ();
1075
1076               expand_expr (maybe_build_cleanup_and_delete (object),
1077                            const0_rtx, VOIDmode, 0);
1078
1079               end_anon_func ();
1080
1081               mark_addressable (cleanup);
1082             }
1083           else
1084             {
1085               cleanup = empty_fndecl;
1086             }
1087         }
1088
1089       if (cleanup == empty_fndecl)
1090         assemble_external (empty_fndecl);
1091         
1092       e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
1093       expand_expr (e, const0_rtx, VOIDmode, 0);
1094
1095       e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
1096       e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
1097       expand_expr (e, const0_rtx, VOIDmode, 0);
1098
1099       cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
1100       cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
1101       expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1102     }
1103   else
1104     {
1105       /* rethrow current exception */
1106       /* This part is easy, as we don't have to do anything else.  */
1107     }
1108
1109   /* This is the label that represents where in the code we were, when
1110      we got an exception.  This needs to be updated when we rethrow an
1111      exception, so that the matching routine knows to search out.  */
1112   label = gen_label_rtx ();
1113   emit_label (label);
1114
1115   expand_internal_throw (label);
1116 }
1117
1118 /* Build a throw expression.  */
1119
1120 tree
1121 build_throw (e)
1122      tree e;
1123 {
1124   if (e != error_mark_node)
1125     {
1126       if (current_template_parms)
1127         return build_min (THROW_EXPR, void_type_node, e);
1128       e = build1 (THROW_EXPR, void_type_node, e);
1129       TREE_SIDE_EFFECTS (e) = 1;
1130       TREE_USED (e) = 1;
1131     }
1132   return e;
1133 }