OSDN Git Service

merging
[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);
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);
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);
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 = make_call_declarator (d, void_list_node, NULL_TREE, NULL_TREE);
337   d = start_decl (d, declspecs, 0);
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);
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   pushlevel (0);
433   expand_start_bindings (0);
434
435   false_label_rtx = gen_label_rtx ();
436   push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
437
438   if (declspecs)
439     {
440       tree exp;
441       rtx call_rtx, return_value_rtx;
442       tree init_type;
443
444       decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, 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   expand_end_bindings (getdecls (), kept_level_p (), 0);
549   poplevel (kept_level_p (), 1, 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 = make_call_declarator (get_identifier ("__throw"), params, NULL_TREE,
675                             NULL_TREE);
676   start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
677                                   void_list_node),
678                   t, NULL_TREE, 0);
679   store_parm_decls ();
680   pushlevel (0);
681   clear_last_expr ();
682   push_momentary ();
683   expand_start_bindings (0);
684
685   gotta_rethrow_it = gen_label_rtx ();
686   gotta_call_terminate = gen_label_rtx ();
687   top_of_loop = gen_label_rtx ();
688   unwind_first = gen_label_rtx ();
689
690   /* These two can be frontend specific.  If wanted, they can go in
691      expand_throw.  */
692   /* Do we have a valid object we are throwing? */
693   emit_cmp_insn (DECL_RTL (saved_throw_type), const0_rtx, EQ, NULL_RTX,
694                  GET_MODE (DECL_RTL (saved_throw_type)), 0, 0);
695   emit_jump_insn (gen_beq (gotta_call_terminate));
696
697   emit_jump (unwind_first);
698
699   emit_label (top_of_loop);
700
701   /* search for an exception handler for the saved_pc */
702   return_val_rtx = do_function_call (FirstExceptionMatch,
703                                      tree_cons (NULL_TREE, saved_pc, NULL_TREE),
704                                      ptr_type_node);
705   assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
706
707   /* did we find one? */
708   emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
709                  GET_MODE (return_val_rtx), 0, 0);
710
711   /* if not, jump to gotta_rethrow_it */
712   emit_jump_insn (gen_beq (gotta_rethrow_it));
713
714   /* we found it, so jump to it */
715   emit_indirect_jump (return_val_rtx);
716
717   /* code to deal with unwinding and looking for it again */
718   emit_label (gotta_rethrow_it);
719
720   /* call to  __builtin_return_address () */
721 #if defined (ARM_FRAME_RTX)  /* was __arm */
722   /* This should be moved into arm.h:RETURN_ADDR_RTX */
723   /* This replaces a 'call' to __builtin_return_address */
724   return_val_rtx = gen_reg_rtx (Pmode);
725   emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
726 #else
727   params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
728   fcall = build_function_call (BuiltinReturnAddress, params);
729   return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
730 #endif
731
732   /* did __builtin_return_address () return a valid address? */
733   emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
734                  GET_MODE (return_val_rtx), 0, 0);
735
736   emit_jump_insn (gen_beq (gotta_call_terminate));
737
738   return_val_rtx = eh_outer_context (return_val_rtx);
739
740   /* Yes it did.  */
741   emit_move_insn (eh_saved_pc_rtx, return_val_rtx);
742
743   do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop));
744   emit_jump (top_of_loop);
745
746   /* no it didn't --> therefore we need to call terminate */
747   emit_label (gotta_call_terminate);
748   do_function_call (Terminate, NULL_TREE, NULL_TREE);
749   assemble_external (TREE_OPERAND (Terminate, 0));
750
751   {
752     rtx ret_val, return_val_rtx;
753     emit_label (unwind_first);
754     ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
755                                           0, hard_frame_pointer_rtx);
756
757     /* Set it up so that we continue inside, at the top of the loop.  */
758     emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
759 #ifdef RETURN_ADDR_OFFSET
760   return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
761     if (return_val_rtx != ret_val)
762       emit_move_insn (ret_val, return_val_rtx);
763 #endif
764
765     /* Fall into epilogue to unwind prologue.  */
766   }
767
768   expand_end_bindings (getdecls (), 1, 0);
769   poplevel (1, 0, 0);
770   pop_momentary ();
771
772   finish_function (lineno, 0, 0);
773 }
774
775
776 void
777 expand_start_eh_spec ()
778 {
779   expand_eh_region_start ();
780 }
781
782 static void
783 expand_end_eh_spec (raises)
784      tree raises;
785 {
786   tree expr, second_try;
787   rtx check = gen_label_rtx ();
788   rtx cont;
789   rtx ret = gen_reg_rtx (Pmode);
790   rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
791   rtx end = gen_label_rtx ();
792
793   expr = make_node (RTL_EXPR);
794   TREE_TYPE (expr) = void_type_node;
795   RTL_EXPR_RTL (expr) = const0_rtx;
796   TREE_SIDE_EFFECTS (expr) = 1;
797   start_sequence_for_rtl_expr (expr);
798   cont = gen_label_rtx ();
799   emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
800   emit_jump (check);
801   emit_label (cont);
802   jumpif (make_tree (integer_type_node, flag), end);
803   do_function_call (Terminate, NULL_TREE, NULL_TREE);
804   assemble_external (TREE_OPERAND (Terminate, 0));
805   emit_barrier ();
806   RTL_EXPR_SEQUENCE (expr) = get_insns ();
807   end_sequence ();
808   
809   second_try = expr;
810
811   expr = make_node (RTL_EXPR);
812   TREE_TYPE (expr) = void_type_node;
813   RTL_EXPR_RTL (expr) = const0_rtx;
814   TREE_SIDE_EFFECTS (expr) = 1;
815   start_sequence_for_rtl_expr (expr);
816
817   cont = gen_label_rtx ();
818   emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
819   emit_jump (check);
820   emit_label (cont);
821   jumpif (make_tree (integer_type_node, flag), end);
822   expand_eh_region_start ();
823   do_function_call (Unexpected, NULL_TREE, NULL_TREE);
824   assemble_external (TREE_OPERAND (Unexpected, 0));
825   emit_barrier ();
826   expand_eh_region_end (second_try);
827   
828   emit_label (check);
829   emit_move_insn (flag, const1_rtx);
830   cont = gen_label_rtx ();
831   while (raises)
832     {
833       tree exp;
834       tree match_type = TREE_VALUE (raises);
835       
836       if (match_type)
837         {
838           /* check TREE_VALUE (raises) here */
839           exp = saved_throw_value;
840           exp = tree_cons (NULL_TREE,
841                            build_eh_type_type (match_type),
842                            tree_cons (NULL_TREE,
843                                       saved_throw_type,
844                                       tree_cons (NULL_TREE, exp, NULL_TREE)));
845           exp = build_function_call (CatchMatch, exp);
846           assemble_external (TREE_OPERAND (CatchMatch, 0));
847
848           jumpif (exp, cont);
849         }
850
851       raises = TREE_CHAIN (raises);
852     }
853   emit_move_insn (flag, const0_rtx);
854   emit_label (cont);
855   emit_indirect_jump (ret);
856   emit_label (end);
857   
858   RTL_EXPR_SEQUENCE (expr) = get_insns ();
859   end_sequence ();
860   
861   expand_eh_region_end (expr);
862 }
863
864 /* This is called to expand all the toplevel exception handling
865    finalization for a function.  It should only be called once per
866    function.  */
867
868 void
869 expand_exception_blocks ()
870 {
871   rtx funcend;
872   rtx insn, insns;
873   rtx eh_spec_insns = NULL_RTX;
874
875   start_sequence ();
876
877   funcend = gen_label_rtx ();
878   emit_jump (funcend);
879   /* expand_null_return (); */
880
881   start_sequence ();
882
883   /* Add all the catch clauses here.  */
884   emit_insns (catch_clauses);
885   catch_clauses = NULL_RTX;
886
887   expand_leftover_cleanups ();
888
889   insns = get_insns ();
890   end_sequence ();
891   
892   /* Do this after we expand leftover cleanups, so that the expand_eh_region_end
893      that expand_end_eh_spec does will match the right expand_eh_region_start,
894      and make sure it comes out before the terminate protected region.  */
895   if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
896     {
897 #if 1
898       {
899         rtx insns;
900         /* New...  */
901         start_sequence ();
902         expand_start_eh_spec ();
903         eh_spec_insns = get_insns ();
904         end_sequence ();
905       }
906 #endif
907
908       expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
909       push_to_sequence (insns);
910
911       /* Now expand any new ones.  */
912       expand_leftover_cleanups ();
913
914       insns = get_insns ();
915       end_sequence ();
916     }
917
918   if (insns)
919     {
920       /* Is this necessary?  */
921       assemble_external (TREE_OPERAND (Terminate, 0));
922
923       expand_eh_region_start ();
924       emit_insns (insns);
925       expand_eh_region_end (TerminateFunctionCall);
926       expand_leftover_cleanups ();
927     }
928
929   {
930     /* Mark the end of the stack unwinder.  */
931     rtx unwind_insns;
932     start_sequence ();
933 #if 0
934     end_eh_unwinder ();
935 #endif
936     unwind_insns = get_insns ();
937     end_sequence ();
938     if (unwind_insns)
939       {
940         insns = unwind_insns;
941         emit_insns (insns);
942       }
943   }
944
945   emit_label (funcend);
946
947   /* Only if we had previous insns do we want to emit the jump around
948      them.  If there weren't any, then insns will remain NULL_RTX.  */
949   if (insns)
950     insns = get_insns ();
951   end_sequence ();
952
953 #if 1
954   if (eh_spec_insns)
955     emit_insns_after (eh_spec_insns, get_insns ());
956 #else
957   if (eh_spec_insns)
958     store_after_parms (eh_spec_insns);
959 #endif
960
961   insn = get_last_insn ();
962   while (GET_CODE (insn) == NOTE
963          || (GET_CODE (insn) == INSN
964              && (GET_CODE (PATTERN (insn)) == USE
965                  || GET_CODE (PATTERN (insn)) == CLOBBER)))
966     insn = PREV_INSN (insn);
967     
968   emit_insns_after (insns, insn);
969 }
970
971 tree
972 start_anon_func ()
973 {
974   static int counter = 0;
975   int old_interface_unknown = interface_unknown;
976   char name[32];
977   tree params;
978   tree t;
979
980   push_cp_function_context (NULL_TREE);
981   push_to_top_level ();
982
983   /* No need to mangle this.  */
984   push_lang_context (lang_name_c);
985
986   interface_unknown = 1;
987
988   params = void_list_node;
989   /* tcf stands for throw clean funciton.  */
990   sprintf (name, "__tcf_%d", counter++);
991   t = make_call_declarator (get_identifier (name), params, NULL_TREE,
992                             NULL_TREE);
993   start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
994                                   void_list_node),
995                   t, NULL_TREE, 0);
996   store_parm_decls ();
997   pushlevel (0);
998   clear_last_expr ();
999   push_momentary ();
1000   expand_start_bindings (0);
1001   emit_line_note (input_filename, lineno);
1002
1003   interface_unknown = old_interface_unknown;
1004
1005   pop_lang_context ();
1006
1007   return current_function_decl;
1008 }
1009
1010 void
1011 end_anon_func ()
1012 {
1013   expand_end_bindings (getdecls (), 1, 0);
1014   poplevel (1, 0, 0);
1015   pop_momentary ();
1016
1017   finish_function (lineno, 0, 0);
1018
1019   pop_from_top_level ();
1020   pop_cp_function_context (NULL_TREE);
1021 }
1022
1023 /* Expand a throw statement.  This follows the following
1024    algorithm:
1025
1026         1. Allocate space to save the current PC onto the stack.
1027         2. Generate and emit a label and save its address into the
1028                 newly allocated stack space since we can't save the pc directly.
1029         3. If this is the first call to throw in this function:
1030                 generate a label for the throw block
1031         4. jump to the throw block label.  */
1032
1033 void
1034 expand_throw (exp)
1035      tree exp;
1036 {
1037   rtx label;
1038
1039   if (! doing_eh (1))
1040     return;
1041
1042   if (exp)
1043     {
1044       tree throw_type;
1045       tree cleanup = empty_fndecl, e;
1046
1047       /* throw expression */
1048       /* First, decay it.  */
1049       exp = decay_conversion (exp);
1050
1051       if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1052         {
1053           throw_type = build_eh_type (exp);
1054           exp = build_reinterpret_cast (ptr_type_node, exp);
1055         }
1056       else
1057         {
1058           rtx cleanup_insns;
1059           tree object;
1060
1061           /* Make a copy of the thrown object.  WP 15.1.5  */
1062           exp = build_new (NULL_TREE, TREE_TYPE (exp),
1063                            build_tree_list (NULL_TREE, exp),
1064                            0);
1065
1066           if (exp == error_mark_node)
1067             error ("  in thrown expression");
1068
1069           object = build_indirect_ref (exp, NULL_PTR);
1070           throw_type = build_eh_type (object);
1071
1072           start_sequence ();
1073           object = build_reinterpret_cast (TREE_TYPE (exp), saved_throw_value);
1074           object = build_indirect_ref (object, NULL_PTR);
1075           cleanup = maybe_build_cleanup_and_delete (object);
1076           if (cleanup)
1077             expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1078           cleanup_insns = get_insns ();
1079           end_sequence ();
1080
1081           if (cleanup && cleanup_insns)
1082             {
1083               cleanup = start_anon_func ();
1084
1085               expand_expr (maybe_build_cleanup_and_delete (object),
1086                            const0_rtx, VOIDmode, 0);
1087
1088               end_anon_func ();
1089
1090               mark_addressable (cleanup);
1091             }
1092           else
1093             {
1094               cleanup = empty_fndecl;
1095             }
1096         }
1097
1098       if (cleanup == empty_fndecl)
1099         assemble_external (empty_fndecl);
1100         
1101       e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
1102       expand_expr (e, const0_rtx, VOIDmode, 0);
1103
1104       e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
1105       e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
1106       expand_expr (e, const0_rtx, VOIDmode, 0);
1107
1108       cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
1109       cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
1110       expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1111     }
1112   else
1113     {
1114       /* rethrow current exception */
1115       /* This part is easy, as we don't have to do anything else.  */
1116     }
1117
1118   /* This is the label that represents where in the code we were, when
1119      we got an exception.  This needs to be updated when we rethrow an
1120      exception, so that the matching routine knows to search out.  */
1121   label = gen_label_rtx ();
1122   emit_label (label);
1123
1124   expand_internal_throw (label);
1125 }
1126
1127 /* Build a throw expression.  */
1128
1129 tree
1130 build_throw (e)
1131      tree e;
1132 {
1133   if (e != error_mark_node)
1134     {
1135       if (current_template_parms)
1136         return build_min (THROW_EXPR, void_type_node, e);
1137       e = build1 (THROW_EXPR, void_type_node, e);
1138       TREE_SIDE_EFFECTS (e) = 1;
1139       TREE_USED (e) = 1;
1140     }
1141   return e;
1142 }