OSDN Git Service

83rd Cygnus<->FSF merge
[pf3gnuchains/gcc-fork.git] / gcc / cp / except.c
1 /* Handle exceptional things in C++.
2    Copyright (C) 1989, 1992, 1993, 1994, 1995 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 /* High-level class interface. */
26
27 #include "config.h"
28 #include "tree.h"
29 #include "rtl.h"
30 #include "cp-tree.h"
31 #include "flags.h"
32 #include "obstack.h"
33 #include "expr.h"
34 #include "output.h"
35
36 tree protect_list;
37
38 extern void (*interim_eh_hook)  PROTO((tree));
39 rtx expand_builtin_return_addr  PROTO((enum built_in_function, int, rtx));
40 static void end_eh_unwinder PROTO((rtx));
41
42 /* holds the fndecl for __builtin_return_address () */
43 tree builtin_return_address_fndecl;
44 tree throw_fndecl;
45
46 static int
47 doing_eh (do_warn)
48      int do_warn;
49 {
50   if (! flag_handle_exceptions)
51     {
52       static int warned = 0;
53       if (! warned && do_warn)
54         {
55           error ("exception handling disabled, use -fhandle-exceptions to enable.");
56           warned = 1;
57         }
58       return 0;
59     }
60   return 1;
61 }
62
63
64 /*
65 NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
66 to supporting exception handling as per ANSI C++ working draft.
67 It is a complete rewrite of all the EH stuff that was here before
68         Shortcomings:
69                 1. Throw specifications of functions still don't work.
70         Cool Things:
71                 1. Destructors are called properly :-)
72                 2. No overhead for the non-exception thrown case.
73                 3. Fixing shortcoming 1 is simple.
74                         -Tad Hunt       (tad@mail.csh.rit.edu)
75
76 */
77
78 /* A couple of backend routines from m88k.c */
79
80 /* used to cache a call to __builtin_return_address () */
81 static tree BuiltinReturnAddress;
82      
83
84 #include <stdio.h>
85
86 /* XXX - Tad: for EH */
87 /* output an exception table entry */
88
89 static void
90 output_exception_table_entry (file, start_label, end_label, eh_label)
91      FILE *file;
92      rtx start_label, end_label, eh_label;
93 {
94   assemble_integer (start_label, GET_MODE_SIZE (Pmode), 1);
95   assemble_integer (end_label, GET_MODE_SIZE (Pmode), 1);
96   assemble_integer (eh_label, GET_MODE_SIZE (Pmode), 1);
97   putc ('\n', file);            /* blank line */
98 }
99    
100 static void
101 easy_expand_asm (str)
102      char *str;
103 {
104   expand_asm (build_string (strlen (str)+1, str));
105 }
106
107
108 #if 0
109 /* This is the startup, and finish stuff per exception table. */
110
111 /* XXX - Tad: exception handling section */
112 #ifndef EXCEPT_SECTION_ASM_OP
113 #define EXCEPT_SECTION_ASM_OP   "section\t.gcc_except_table,\"a\",@progbits"
114 #endif
115
116 #ifdef EXCEPT_SECTION_ASM_OP
117 typedef struct {
118     void *start_protect;
119     void *end_protect;
120     void *exception_handler;
121  } exception_table;
122 #endif /* EXCEPT_SECTION_ASM_OP */
123
124 #ifdef EXCEPT_SECTION_ASM_OP
125
126  /* on machines which support it, the exception table lives in another section,
127         but it needs a label so we can reference it...  This sets up that
128     label! */
129 asm (EXCEPT_SECTION_ASM_OP);
130 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
131 asm (TEXT_SECTION_ASM_OP);
132
133 #endif /* EXCEPT_SECTION_ASM_OP */
134
135 #ifdef EXCEPT_SECTION_ASM_OP
136
137  /* we need to know where the end of the exception table is... so this
138     is how we do it! */
139
140 asm (EXCEPT_SECTION_ASM_OP);
141 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
142 asm (TEXT_SECTION_ASM_OP);
143
144 #endif /* EXCEPT_SECTION_ASM_OP */
145
146 #endif
147
148 static void
149 exception_section ()
150 {
151 #ifdef ASM_OUTPUT_SECTION_NAME
152   named_section (NULL_TREE, ".gcc_except_table");
153 #else
154   if (flag_pic)
155     data_section ();
156   else
157 #if defined (TARGET_POWERPC) /* are we on a __rs6000? */
158     data_section ();
159 #else
160     readonly_data_section ();
161 #endif
162 #endif
163 }
164
165
166
167
168 /* from: my-cp-except.c */
169
170 /* VI: ":set ts=4" */
171 #if 0
172 #include <stdio.h> */
173 #include "config.h"
174 #include "tree.h"
175 #include "rtl.h"
176 #include "cp-tree.h"
177 #endif
178 #include "decl.h"
179 #if 0
180 #include "flags.h"
181 #endif
182 #include "insn-flags.h"
183 #include "obstack.h"
184 #if 0
185 #include "expr.h"
186 #endif
187
188 /* ======================================================================
189    Briefly the algorithm works like this:
190
191      When a constructor or start of a try block is encountered,
192      push_eh_entry (&eh_stack) is called.  Push_eh_entry () creates a
193      new entry in the unwind protection stack and returns a label to
194      output to start the protection for that block.
195
196      When a destructor or end try block is encountered, pop_eh_entry
197      (&eh_stack) is called.  Pop_eh_entry () returns the ehEntry it
198      created when push_eh_entry () was called.  The ehEntry structure
199      contains three things at this point.  The start protect label,
200      the end protect label, and the exception handler label.  The end
201      protect label should be output before the call to the destructor
202      (if any). If it was a destructor, then its parse tree is stored
203      in the finalization variable in the ehEntry structure.  Otherwise
204      the finalization variable is set to NULL to reflect the fact that
205      is the the end of a try block.  Next, this modified ehEntry node
206      is enqueued in the finalizations queue by calling
207      enqueue_eh_entry (&queue,entry).
208
209         +---------------------------------------------------------------+
210         |XXX: Will need modification to deal with partially             |
211         |                       constructed arrays of objects           |
212         |                                                               |
213         |       Basically, this consists of keeping track of how many   |
214         |       of the objects have been constructed already (this      |
215         |       should be in a register though, so that shouldn't be a  |
216         |       problem.                                                |
217         +---------------------------------------------------------------+
218
219      When a catch block is encountered, there is a lot of work to be
220      done.
221
222      Since we don't want to generate the catch block inline with the
223      regular flow of the function, we need to have some way of doing
224      so.  Luckily, we can use sequences to defer the catch sections.
225      When the start of a catch block is encountered, we start the
226      sequence.  After the catch block is generated, we end the
227      sequence.
228
229      Next we must insure that when the catch block is executed, all
230      finalizations for the matching try block have been completed.  If
231      any of those finalizations throw an exception, we must call
232      terminate according to the ARM (section r.15.6.1).  What this
233      means is that we need to dequeue and emit finalizations for each
234      entry in the ehQueue until we get to an entry with a NULL
235      finalization field.  For any of the finalization entries, if it
236      is not a call to terminate (), we must protect it by giving it
237      another start label, end label, and exception handler label,
238      setting its finalization tree to be a call to terminate (), and
239      enqueue'ing this new ehEntry to be output at an outer level.
240      Finally, after all that is done, we can get around to outputting
241      the catch block which basically wraps all the "catch (...) {...}"
242      statements in a big if/then/else construct that matches the
243      correct block to call.
244      
245      ===================================================================== */
246
247 extern rtx emit_insn            PROTO((rtx));
248 extern rtx gen_nop              PROTO(());
249
250 /* local globals for function calls
251    ====================================================================== */
252
253 /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
254    "set_unexpected ()" after default_conversion. (lib-except.c)  */
255 static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch, Throw;
256
257 /* used to cache __find_first_exception_table_match ()
258    for throw (lib-except.c)  */
259 static tree FirstExceptionMatch;
260
261 /* used to cache a call to __unwind_function () (lib-except.c)  */
262 static tree Unwind;
263
264 /* holds a ready to emit call to "terminate ()".  */
265 static tree TerminateFunctionCall;
266
267 static tree empty_fndecl;
268
269 /* ====================================================================== */
270
271
272
273 /* data structures for my various quick and dirty stacks and queues
274    Eventually, most of this should go away, because I think it can be
275    integrated with stuff already built into the compiler.  */
276
277 /* =================================================================== */
278
279 struct labelNode {
280   union {
281     rtx rlabel;
282     tree tlabel;
283   } u;
284   struct labelNode *chain;
285 };
286
287
288 /* this is the most important structure here.  Basically this is how I store
289    an exception table entry internally. */
290 struct ehEntry {
291   rtx start_label;
292   rtx end_label;
293   rtx exception_handler_label;
294
295   tree finalization;
296   tree context;
297 };
298
299 struct ehNode {
300   struct ehEntry *entry;
301   struct ehNode *chain;
302 };
303
304 struct ehStack {
305   struct ehNode *top;
306 };
307
308 struct ehQueue {
309   struct ehNode *head;
310   struct ehNode *tail;
311 };
312 /* ========================================================================= */
313
314
315
316 /* local globals - these local globals are for storing data necessary for
317    generating the exception table and code in the correct order.
318
319    ========================================================================= */
320
321 /* Holds the pc for doing "throw" */
322 static tree saved_pc;
323 /* Holds the type of the thing being thrown. */
324 static tree saved_throw_type;
325 /* Holds the value being thrown.  */
326 static tree saved_throw_value;
327 /* Holds the cleanup for the value being thrown.  */
328 static tree saved_cleanup;
329
330 static int throw_used;
331
332 static rtx catch_clauses;
333
334 static struct ehStack ehstack;
335 static struct ehQueue ehqueue;
336 static struct ehQueue eh_table_output_queue;
337 static struct labelNode *false_label_stack = NULL;
338 static struct labelNode *caught_return_label_stack = NULL;
339 /* ========================================================================= */
340
341 /* function prototypes */
342 static struct ehEntry *pop_eh_entry     PROTO((struct ehStack *stack));
343 static void enqueue_eh_entry            PROTO((struct ehQueue *queue, struct ehEntry *entry));
344 static rtx push_eh_entry                PROTO((struct ehStack *stack));
345 static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
346 static void new_eh_queue                PROTO((struct ehQueue *queue));
347 static void new_eh_stack                PROTO((struct ehStack *stack));
348 static void push_label_entry            PROTO((struct labelNode **labelstack, rtx rlabel, tree tlabel));
349 static rtx pop_label_entry              PROTO((struct labelNode **labelstack));
350 static tree top_label_entry             PROTO((struct labelNode **labelstack));
351 static struct ehEntry *copy_eh_entry    PROTO((struct ehEntry *entry));
352
353
354 /* Routines to save and restore eh context information.  */
355 struct eh_context {
356   struct ehStack ehstack;
357   struct ehQueue ehqueue;
358   rtx catch_clauses;
359   struct labelNode *false_label_stack;
360   struct labelNode *caught_return_label_stack;
361   tree protect_list;
362 };
363
364 /* Save the context and push into a new one.  */
365 void*
366 push_eh_context ()
367 {
368   struct eh_context *p
369     = (struct eh_context*)xmalloc (sizeof (struct eh_context));
370
371   p->ehstack = ehstack;
372   p->ehqueue = ehqueue;
373   p->catch_clauses = catch_clauses;
374   p->false_label_stack = false_label_stack;
375   p->caught_return_label_stack = caught_return_label_stack;
376   p->protect_list = protect_list;
377
378   new_eh_stack (&ehstack);
379   new_eh_queue (&ehqueue);
380   catch_clauses = NULL_RTX;
381   false_label_stack = NULL;
382   caught_return_label_stack = NULL;
383   protect_list = NULL_TREE;
384   
385   return p;
386 }
387
388 /* Pop and restore the context.  */
389 void
390 pop_eh_context (vp)
391      void *vp;
392 {
393   struct eh_context *p = (struct eh_context *)vp;
394
395   protect_list = p->protect_list;
396   caught_return_label_stack = p->caught_return_label_stack;
397   false_label_stack = p->false_label_stack;
398   catch_clauses = p->catch_clauses;
399   ehqueue = p->ehqueue;
400   ehstack = p->ehstack;
401
402   free (p);
403 }
404
405
406
407 /* All my cheesy stack/queue/misc data structure handling routines
408
409    ========================================================================= */
410
411 static void
412 push_label_entry (labelstack, rlabel, tlabel)
413      struct labelNode **labelstack;
414      rtx rlabel;
415      tree tlabel;
416 {
417   struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
418
419   if (rlabel)
420     newnode->u.rlabel = rlabel;
421   else
422     newnode->u.tlabel = tlabel;
423   newnode->chain = *labelstack;
424   *labelstack = newnode;
425 }
426
427 static rtx
428 pop_label_entry (labelstack)
429      struct labelNode **labelstack;
430 {
431   rtx label;
432   struct labelNode *tempnode;
433
434   if (! *labelstack) return NULL_RTX;
435
436   tempnode = *labelstack;
437   label = tempnode->u.rlabel;
438   *labelstack = (*labelstack)->chain;
439   free (tempnode);
440
441   return label;
442 }
443
444 static tree
445 top_label_entry (labelstack)
446      struct labelNode **labelstack;
447 {
448   if (! *labelstack) return NULL_TREE;
449
450   return (*labelstack)->u.tlabel;
451 }
452
453 /* Push to permanent obstack for rtl generation.
454    One level only!  */
455 static struct obstack *saved_rtl_obstack;
456
457 static void
458 push_rtl_perm ()
459 {
460   extern struct obstack permanent_obstack;
461   extern struct obstack *rtl_obstack;
462   
463   saved_rtl_obstack = rtl_obstack;
464   rtl_obstack = &permanent_obstack;
465 }
466
467 /* Pop back to normal rtl handling.  */
468 static void
469 pop_rtl_from_perm ()
470 {
471   extern struct obstack *rtl_obstack;
472   rtl_obstack = saved_rtl_obstack;
473 }
474
475 static rtx
476 push_eh_entry (stack)
477      struct ehStack *stack;
478 {
479   struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
480   struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
481
482   /* These are saved for the exception table.  */
483   push_rtl_perm ();
484   entry->start_label = gen_label_rtx ();
485   entry->end_label = gen_label_rtx ();
486   entry->exception_handler_label = gen_label_rtx ();
487   pop_rtl_from_perm ();
488
489   LABEL_PRESERVE_P (entry->start_label) = 1;
490   LABEL_PRESERVE_P (entry->end_label) = 1;
491   LABEL_PRESERVE_P (entry->exception_handler_label) = 1;
492
493   entry->finalization = NULL_TREE;
494   entry->context = current_function_decl;
495
496   node->entry = entry;
497   node->chain = stack->top;
498   stack->top = node;
499
500   enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
501
502   return entry->start_label;
503 }
504
505 /* Pop an entry from the given STACK.  */
506 static struct ehEntry *
507 pop_eh_entry (stack)
508      struct ehStack *stack;
509 {
510   struct ehNode *tempnode;
511   struct ehEntry *tempentry;
512   
513   tempnode = stack->top;
514   tempentry = tempnode->entry;
515   stack->top = stack->top->chain;
516   free (tempnode);
517
518   return tempentry;
519 }
520
521 static struct ehEntry *
522 copy_eh_entry (entry)
523      struct ehEntry *entry;
524 {
525   struct ehEntry *newentry;
526
527   newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
528   memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
529
530   return newentry;
531 }
532
533 static void
534 enqueue_eh_entry (queue, entry)
535      struct ehQueue *queue;
536      struct ehEntry *entry;
537 {
538   struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
539
540   node->entry = entry;
541   node->chain = NULL;
542
543   if (queue->head == NULL)
544     {
545       queue->head = node;
546     }
547   else
548     {
549       queue->tail->chain = node;
550     }
551   queue->tail = node;
552 }
553
554 static struct ehEntry *
555 dequeue_eh_entry (queue)
556      struct ehQueue *queue;
557 {
558   struct ehNode *tempnode;
559   struct ehEntry *tempentry;
560
561   if (queue->head == NULL)
562     return NULL;
563
564   tempnode = queue->head;
565   queue->head = queue->head->chain;
566
567   tempentry = tempnode->entry;
568   free (tempnode);
569
570   return tempentry;
571 }
572
573 static void
574 new_eh_queue (queue)
575      struct ehQueue *queue;
576 {
577   queue->head = queue->tail = NULL;
578 }
579
580 static void
581 new_eh_stack (stack)
582      struct ehStack *stack;
583 {
584   stack->top = NULL;
585 }
586
587 /* cheesyness to save some typing. returns the return value rtx */
588 static rtx
589 do_function_call (func, params, return_type)
590      tree func, params, return_type;
591 {
592   tree func_call;
593   func_call = build_function_call (func, params);
594   expand_call (func_call, NULL_RTX, 0);
595   if (return_type != NULL_TREE)
596     return hard_function_value (return_type, func_call);
597   return NULL_RTX;
598 }
599
600 static void
601 expand_internal_throw (pc)
602      rtx pc;
603 {
604   emit_move_insn (DECL_RTL (saved_pc), pc);
605 #ifdef JUMP_TO_THROW
606   emit_indirect_jump (gen_rtx (SYMBOL_REF, Pmode, "__throw"));
607 #else
608   do_function_call (Throw, NULL_TREE, NULL_TREE);
609 #endif
610   throw_used = 1;
611 }
612
613 /* ========================================================================= */
614
615 static void
616 lang_interim_eh (finalization)
617      tree finalization;
618 {
619   if (finalization)
620     end_protect (finalization);
621   else
622     start_protect ();
623 }
624
625 extern tree auto_function PROTO((tree, tree, enum built_in_function));
626
627 /* sets up all the global eh stuff that needs to be initialized at the
628    start of compilation.
629
630    This includes:
631                 - Setting up all the function call trees
632                 - Initializing the ehqueue
633                 - Initializing the eh_table_output_queue
634                 - Initializing the ehstack
635 */
636
637 void
638 init_exception_processing ()
639 {
640   extern tree define_function ();
641   tree unexpected_fndecl, terminate_fndecl;
642   tree set_unexpected_fndecl, set_terminate_fndecl;
643   tree catch_match_fndecl;
644   tree find_first_exception_match_fndecl;
645   tree unwind_fndecl;
646   tree declspecs;
647   tree d;
648
649   /* void (*)() */
650   tree PFV = build_pointer_type (build_function_type
651                                  (void_type_node, void_list_node));
652
653   /* arg list for the build_function_type call for set_terminate () and
654      set_unexpected () */
655   tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
656
657   /* void (*pfvtype (void (*) ()))() */
658   tree pfvtype = build_function_type (PFV, pfvlist);
659
660   /* void vtype () */
661   tree vtype = build_function_type (void_type_node, void_list_node);
662   
663   set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
664                                         pfvtype, NOT_BUILT_IN);
665   set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
666                                          pfvtype, NOT_BUILT_IN);
667   unexpected_fndecl = auto_function (get_identifier ("unexpected"),
668                                      vtype, NOT_BUILT_IN);
669   terminate_fndecl = auto_function (get_identifier ("terminate"),
670                                     vtype, NOT_BUILT_IN);
671
672   interim_eh_hook = lang_interim_eh;
673
674   push_lang_context (lang_name_c);
675
676   catch_match_fndecl =
677     builtin_function (flag_rtti
678                       ? "__throw_type_match_rtti"
679                       : "__throw_type_match",
680                       build_function_type (ptr_type_node,
681                                            tree_cons (NULL_TREE, ptr_type_node,
682                                                       tree_cons (NULL_TREE, ptr_type_node,
683                                                                  tree_cons (NULL_TREE, ptr_type_node,
684                                                                             void_list_node)))),
685                       NOT_BUILT_IN, NULL_PTR);
686   find_first_exception_match_fndecl =
687     builtin_function ("__find_first_exception_table_match",
688                       build_function_type (ptr_type_node,
689                                            tree_cons (NULL_TREE, ptr_type_node,
690                                                       void_list_node)),
691                       NOT_BUILT_IN, NULL_PTR);
692   unwind_fndecl =
693     builtin_function ("__unwind_function",
694                       build_function_type (void_type_node,
695                                            tree_cons (NULL_TREE, ptr_type_node,
696                                                       void_list_node)),
697                       NOT_BUILT_IN, NULL_PTR);
698   throw_fndecl =
699     builtin_function ("__throw",
700                       build_function_type (void_type_node, void_list_node),
701                       NOT_BUILT_IN, NULL_PTR);
702   DECL_EXTERNAL (throw_fndecl) = 0;
703   TREE_PUBLIC (throw_fndecl) = 0;
704   empty_fndecl =
705     builtin_function ("__empty",
706                       build_function_type (void_type_node, void_list_node),
707                       NOT_BUILT_IN, NULL_PTR);
708   DECL_EXTERNAL (empty_fndecl) = 1;
709   TREE_PUBLIC (empty_fndecl) = 1;
710
711   Unexpected = default_conversion (unexpected_fndecl);
712   Terminate = default_conversion (terminate_fndecl);
713   SetTerminate = default_conversion (set_terminate_fndecl);
714   SetUnexpected = default_conversion (set_unexpected_fndecl);
715   CatchMatch = default_conversion (catch_match_fndecl);
716   FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
717   Unwind = default_conversion (unwind_fndecl);
718   Throw = default_conversion (throw_fndecl);
719   BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
720
721   TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
722
723   pop_lang_context ();
724
725   new_eh_queue (&ehqueue);
726   new_eh_queue (&eh_table_output_queue);
727   new_eh_stack (&ehstack);
728
729   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
730   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
731   d = start_decl (d, declspecs, 0, NULL_TREE);
732   DECL_COMMON (d) = 1;
733   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
734   saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
735
736   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
737   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
738   d = start_decl (d, declspecs, 0, NULL_TREE);
739   DECL_COMMON (d) = 1;
740   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
741   saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
742
743   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
744   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
745   d = start_decl (d, declspecs, 0, NULL_TREE);
746   DECL_COMMON (d) = 1;
747   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
748   saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
749
750   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
751   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
752   d = build_parse_node (CALL_EXPR, d, void_list_node, NULL_TREE);
753   d = start_decl (d, declspecs, 0, NULL_TREE);
754   DECL_COMMON (d) = 1;
755   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
756   saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
757 }
758
759 /* call this to begin a block of unwind protection (ie: when an object is
760    constructed) */
761 void
762 start_protect ()
763 {
764   if (! doing_eh (0))
765     return;
766
767   emit_label (push_eh_entry (&ehstack));
768 }
769    
770 /* call this to end a block of unwind protection.  the finalization tree is
771    the finalization which needs to be run in order to cleanly unwind through
772    this level of protection. (ie: call this when a scope is exited)*/
773 void
774 end_protect (finalization)
775      tree finalization;
776 {
777   struct ehEntry *entry;
778
779   if (! doing_eh (0))
780     return;
781
782   entry = pop_eh_entry (&ehstack);
783
784   emit_label (entry->end_label);
785   /* Put in something that takes up space, as otherwise the end
786      address for the EH region could have the exact same address as
787      the outer region, causing us to miss the fact that resuming
788      exception handling with this PC value would be inside the outer
789      region.  */
790   emit_insn (gen_nop ());
791
792   entry->finalization = finalization;
793
794   enqueue_eh_entry (&ehqueue, entry);
795 }
796
797 /* call this on start of a try block. */
798 void
799 expand_start_try_stmts ()
800 {
801   if (! doing_eh (1))
802     return;
803
804   start_protect ();
805 }
806
807 void
808 expand_end_try_stmts ()
809 {
810   end_protect (integer_zero_node);
811 }
812
813
814 /* call this to start processing of all the catch blocks. */
815 void
816 expand_start_all_catch ()
817 {
818   struct ehEntry *entry;
819   tree label;
820
821   if (! doing_eh (1))
822     return;
823
824   emit_line_note (input_filename, lineno);
825   label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
826
827   /* The label for the exception handling block we will save.  This is
828      Lresume, in the documention.  */
829   expand_label (label);
830   
831   /* Put in something that takes up space, as otherwise the end
832      address for the EH region could have the exact same address as
833      the outer region, causing us to miss the fact that resuming
834      exception handling with this PC value would be inside the outer
835      region.  */
836   emit_insn (gen_nop ());
837
838   push_label_entry (&caught_return_label_stack, NULL_RTX, label);
839
840   /* Start a new sequence for all the catch blocks.  We will add this
841      to the gloabl sequence catch_clauses, when we have completed all
842      the handlers in this handler-seq.  */
843   start_sequence ();
844
845   while (1)
846     {
847       entry = dequeue_eh_entry (&ehqueue);
848       emit_label (entry->exception_handler_label);
849
850       expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
851
852       /* When we get down to the matching entry, stop.  */
853       if (entry->finalization == integer_zero_node)
854         break;
855
856       /* The below can be optimized away, and we could just fall into the
857          next EH handler, if we are certain they are nested.  */
858       /* Code to throw out to outer context, if we fall off end of the
859          handler.  */
860       expand_internal_throw (gen_rtx (LABEL_REF,
861                                       Pmode,
862                                       entry->end_label));
863       free (entry);
864     }
865 }
866
867 /* call this to end processing of all the catch blocks. */
868 void
869 expand_end_all_catch ()
870 {
871   rtx new_catch_clause;
872
873   if (! doing_eh (1))
874     return;
875
876   /* Code to throw out to outer context, if we fall off end of catch
877      handlers.  This is rethrow (Lresume, same id, same obj); in the
878      documentation.  */
879   expand_internal_throw (gen_rtx (LABEL_REF,
880                                   Pmode,
881                                   DECL_RTL (top_label_entry (&caught_return_label_stack))));
882
883   /* Now we have the complete catch sequence.  */
884   new_catch_clause = get_insns ();
885   end_sequence ();
886   
887   /* this level of catch blocks is done, so set up the successful catch jump
888      label for the next layer of catch blocks. */
889   pop_label_entry (&caught_return_label_stack);
890
891   /* Add the new sequence of catchs to the main one for this
892      function.  */
893   push_to_sequence (catch_clauses);
894   emit_insns (new_catch_clause);
895   catch_clauses = get_insns ();
896   end_sequence ();
897   
898   /* Here we fall through into the continuation code.  */
899 }
900
901 /* Build a type value for use at runtime for a type that is matched
902    against by the exception handling system.  */
903 static tree
904 build_eh_type_type (type)
905      tree type;
906 {
907   char *typestring;
908   tree exp;
909
910   if (type == error_mark_node)
911     return error_mark_node;
912
913   /* peel back references, so they match. */
914   if (TREE_CODE (type) == REFERENCE_TYPE)
915     type = TREE_TYPE (type);
916
917   /* Peel off cv qualifiers. */
918   type = TYPE_MAIN_VARIANT (type);
919
920   if (flag_rtti)
921     {
922       return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
923     }
924
925   typestring = build_overload_name (type, 1, 1);
926   exp = combine_strings (build_string (strlen (typestring)+1, typestring));
927   return build1 (ADDR_EXPR, ptr_type_node, exp);
928 }
929
930 /* Build a type value for use at runtime for a exp that is thrown or
931    matched against by the exception handling system.  */
932 static tree
933 build_eh_type (exp)
934      tree exp;
935 {
936   if (flag_rtti)
937     {
938       exp = build_typeid (exp);
939       return build1 (ADDR_EXPR, ptr_type_node, exp);
940     }
941   return build_eh_type_type (TREE_TYPE (exp));
942 }
943
944 /* This routine creates the cleanup for the exception handling object.  */
945 static void
946 push_eh_cleanup ()
947 {
948   /* All cleanups must last longer than normal.  */
949   int yes = suspend_momentary ();
950
951   /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
952   tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
953   cp_expand_decl_cleanup (NULL_TREE, cleanup);
954
955   resume_momentary (yes);
956 }
957
958
959 /* call this to start a catch block. Typename is the typename, and identifier
960    is the variable to place the object in or NULL if the variable doesn't
961    matter.  If typename is NULL, that means its a "catch (...)" or catch
962    everything.  In that case we don't need to do any type checking.
963    (ie: it ends up as the "else" clause rather than an "else if" clause) */
964 void
965 expand_start_catch_block (declspecs, declarator)
966      tree declspecs, declarator;
967 {
968   rtx false_label_rtx;
969   rtx protect_label_rtx;
970   tree decl = NULL_TREE;
971   tree init;
972
973   if (! doing_eh (1))
974     return;
975
976   /* Create a binding level for the parm.  */
977   expand_start_bindings (0);
978
979   false_label_rtx = gen_label_rtx ();
980   /* This is saved for the exception table.  */
981   push_rtl_perm ();
982   protect_label_rtx = gen_label_rtx ();
983   pop_rtl_from_perm ();
984   push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
985   push_label_entry (&false_label_stack, protect_label_rtx, NULL_TREE);
986
987   if (declspecs)
988     {
989       tree exp;
990       rtx call_rtx, return_value_rtx;
991       tree init_type;
992
993       decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1,
994                              NULL_TREE, NULL_TREE);
995
996       if (decl == NULL_TREE)
997         {
998           error ("invalid catch parameter");
999           return;
1000         }
1001
1002       /* Make sure we mark the catch param as used, otherwise we'll get
1003          a warning about an unused ((anonymous)).  */
1004       TREE_USED (decl) = 1;
1005
1006       /* Figure out the type that the initializer is. */
1007       init_type = TREE_TYPE (decl);
1008       if (TREE_CODE (init_type) != REFERENCE_TYPE
1009           && TREE_CODE (init_type) != POINTER_TYPE)
1010         init_type = build_reference_type (init_type);
1011
1012       exp = saved_throw_value;
1013       exp = tree_cons (NULL_TREE,
1014                        build_eh_type_type (TREE_TYPE (decl)),
1015                        tree_cons (NULL_TREE,
1016                                   saved_throw_type,
1017                                   tree_cons (NULL_TREE, exp, NULL_TREE)));
1018       exp = build_function_call (CatchMatch, exp);
1019       call_rtx = expand_call (exp, NULL_RTX, 0);
1020       assemble_external (TREE_OPERAND (CatchMatch, 0));
1021
1022       return_value_rtx = hard_function_value (ptr_type_node, exp);
1023
1024       /* did the throw type match function return TRUE? */
1025       emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
1026                     GET_MODE (return_value_rtx), 0, 0);
1027
1028       /* if it returned FALSE, jump over the catch block, else fall into it */
1029       emit_jump_insn (gen_beq (false_label_rtx));
1030
1031       push_eh_cleanup ();
1032
1033       init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
1034
1035       /* Do we need the below two lines? */
1036       /* Let `cp_finish_decl' know that this initializer is ok.  */
1037       DECL_INITIAL (decl) = init;
1038       decl = pushdecl (decl);
1039       cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
1040     }
1041   else
1042     {
1043       push_eh_cleanup ();
1044
1045       /* Fall into the catch all section. */
1046     }
1047
1048   /* This is the starting of something to protect.  */
1049   emit_label (protect_label_rtx);
1050
1051   emit_line_note (input_filename, lineno);
1052 }
1053
1054
1055 /* this is called from expand_exception_blocks and
1056    expand_end_catch_block to expand the toplevel finalizations for a
1057    function.  We return the first label emitted, if any, otherwise
1058    return NULL_RTX.  */
1059 static rtx
1060 expand_leftover_cleanups ()
1061 {
1062   struct ehEntry *entry;
1063   rtx first_label = NULL_RTX;
1064
1065   while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
1066     {
1067       if (! first_label)
1068         first_label = entry->exception_handler_label;
1069       emit_label (entry->exception_handler_label);
1070
1071       expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1072
1073       /* The below can be optimized away, and we could just fall into the
1074          next EH handler, if we are certain they are nested.  */
1075       /* Code to throw out to outer context, if we fall off end of the
1076          handler.  */
1077       expand_internal_throw (gen_rtx (LABEL_REF,
1078                                       Pmode,
1079                                       entry->end_label));
1080
1081       /* leftover try block, opps.  */
1082       if (entry->finalization == integer_zero_node)
1083         abort ();
1084
1085       free (entry);
1086     }
1087
1088   return first_label;
1089 }
1090
1091 /* Call this to end a catch block.  Its responsible for emitting the
1092    code to handle jumping back to the correct place, and for emitting
1093    the label to jump to if this catch block didn't match.  */
1094 void expand_end_catch_block ()
1095 {
1096   rtx start_protect_label_rtx;
1097   rtx end_protect_label_rtx;
1098   tree decls;
1099   struct ehEntry entry;
1100
1101   if (! doing_eh (1))
1102     return;
1103
1104   /* fall to outside the try statement when done executing handler and
1105      we fall off end of handler.  This is jump Lresume in the
1106      documentation.  */
1107   expand_goto (top_label_entry (&caught_return_label_stack));
1108
1109   /* We end the rethrow protection region as soon as we hit a label. */
1110   end_protect_label_rtx = expand_leftover_cleanups ();
1111
1112   /* Code to throw out to outer context, if we get a throw from within
1113      our catch handler. */
1114   /* These are saved for the exception table.  */
1115   push_rtl_perm ();
1116   entry.exception_handler_label = gen_label_rtx ();
1117   pop_rtl_from_perm ();
1118   /* This label is Lhandler in the documentation.  */
1119   emit_label (entry.exception_handler_label);
1120   expand_internal_throw (gen_rtx (LABEL_REF,
1121                                   Pmode,
1122                                   DECL_RTL (top_label_entry (&caught_return_label_stack))));
1123
1124   /* No associated finalization.  */
1125   entry.finalization = NULL_TREE;
1126   entry.context = current_function_decl;
1127
1128   if (end_protect_label_rtx == NULL_RTX)
1129     end_protect_label_rtx = entry.exception_handler_label;
1130
1131   /* Because we are emitted out of line, we have to protect this. */
1132   /* label for the start of the protection region.  */
1133   start_protect_label_rtx = pop_label_entry (&false_label_stack);
1134
1135   /* Cleanup the EH parameter.  */
1136   decls = getdecls ();
1137   expand_end_bindings (decls, decls != NULL_TREE, 0);
1138       
1139   /* label we emit to jump to if this catch block didn't match. */
1140   /* This the closing } in the `if (eq) {' of the documentation.  */
1141   emit_label (pop_label_entry (&false_label_stack));
1142
1143   /* Because we are reordered out of line, we have to protect this. */
1144   entry.start_label = start_protect_label_rtx;
1145   entry.end_label = end_protect_label_rtx;
1146
1147   LABEL_PRESERVE_P (entry.start_label) = 1;
1148   LABEL_PRESERVE_P (entry.end_label) = 1;
1149   LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
1150
1151   /* These set up a call to throw the caught exception into the outer
1152      context.  */
1153   enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1154 }
1155
1156 /* unwind the stack. */
1157 static void
1158 do_unwind (inner_throw_label)
1159      rtx inner_throw_label;
1160 {
1161 #if defined (SPARC_STACK_ALIGN) /* was sparc */
1162   /* This doesn't work for the flat model sparc, I bet.  */
1163   tree fcall;
1164   tree params;
1165   rtx return_val_rtx;
1166   rtx temp;
1167
1168   /* call to  __builtin_return_address () */
1169   params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1170   fcall = build_function_call (BuiltinReturnAddress, params);
1171   return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
1172   /* In the return, the new pc is pc+8, as the value coming in is
1173      really the address of the call insn, not the next insn.  */
1174   temp = gen_reg_rtx (Pmode);
1175   emit_move_insn (temp, inner_throw_label);
1176   emit_move_insn (return_val_rtx, plus_constant (temp, -8));
1177   easy_expand_asm ("ret");
1178   easy_expand_asm ("restore");
1179   emit_barrier ();
1180 #endif
1181 #if defined (ARM_FRAME_RTX)  /* was __arm */
1182   if (flag_omit_frame_pointer)
1183     sorry ("this implementation of exception handling requires a frame pointer");
1184
1185   emit_move_insn (stack_pointer_rtx,
1186                   gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
1187   emit_move_insn (hard_frame_pointer_rtx,
1188                   gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
1189 #endif
1190 #if defined (TARGET_88000) /* was m88k */
1191   rtx temp_frame = frame_pointer_rtx;
1192
1193   temp_frame = memory_address (Pmode, temp_frame);
1194   temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
1195
1196   /* hopefully this will successfully pop the frame! */
1197   emit_move_insn (frame_pointer_rtx, temp_frame);
1198   emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
1199   emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
1200   emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1201                                                      (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
1202
1203 #if 0
1204   emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1205                                                    -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
1206
1207   emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
1208
1209   emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1210                                                      (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
1211 #endif
1212 #endif
1213 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
1214   tree fcall;
1215   tree params;
1216   rtx return_val_rtx;
1217
1218 #if 0
1219   /* I would like to do this here, but the move below doesn't seem to work. */
1220   /* call to  __builtin_return_address () */
1221   params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1222   fcall = build_function_call (BuiltinReturnAddress, params);
1223   return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
1224
1225   emit_move_insn (return_val_rtx, inner_throw_label);
1226   /* So, for now, just pass throw label to stack unwinder. */
1227 #endif
1228   params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
1229                                             inner_throw_label), NULL_TREE);
1230   
1231   do_function_call (Unwind, params, NULL_TREE);
1232   assemble_external (TREE_OPERAND (Unwind, 0));
1233   emit_barrier ();
1234 #endif
1235 }
1236
1237
1238 /* Given the return address, compute the new pc to throw.  This has to
1239    work for the current frame of the current function, and the one
1240    above it in the case of throw.  */
1241 static rtx
1242 eh_outer_context (addr)
1243      rtx addr;
1244 {
1245 #if defined (ARM_FRAME_RTX)  /* was __arm */
1246   /* On the ARM, '__builtin_return_address',  must have 4
1247      subtracted from it. */
1248   emit_insn (gen_add2_insn (addr, GEN_INT (-4)));
1249
1250   /* If we are generating code for an ARM2/ARM3 machine or for an ARM6
1251      in 26 bit mode, the condition codes must be masked out of the
1252      return value, or else they will confuse BuiltinReturnAddress.
1253      This does not apply to ARM6 and later processors when running in
1254      32 bit mode. */
1255   if (!TARGET_6)
1256     emit_insn (gen_rtx (SET, Pmode,
1257                         addr,
1258                         gen_rtx (AND, Pmode,
1259                                  addr, GEN_INT (0x03fffffc))));
1260 #else
1261 #if ! defined (SPARC_STACK_ALIGN) /* was sparc */
1262 #if defined (TARGET_SNAKE)
1263   /* On HPPA, the low order two bits hold the priviledge level, so we
1264      must get rid of them.  */
1265   emit_insn (gen_rtx (SET, Pmode,
1266                       addr,
1267                       gen_rtx (AND, Pmode,
1268                                addr, GEN_INT (0xfffffffc))));
1269 #endif
1270
1271   /* On the SPARC, __builtin_return_address is already -8 or -12, no
1272      need to subtract any more from it. */
1273   addr = plus_constant (addr, -1);
1274 #endif
1275 #endif
1276
1277   return addr;
1278 }
1279
1280 /* is called from expand_exception_blocks () to generate the code in a function
1281    to "throw" if anything in the function needs to perform a throw.
1282
1283    expands "throw" as the following pseudo code:
1284
1285         throw:
1286                 eh = find_first_exception_match (saved_pc);
1287             if (!eh) goto gotta_rethrow_it;
1288                 goto eh;
1289
1290         gotta_rethrow_it:
1291                 saved_pc = __builtin_return_address (0);
1292                 pop_to_previous_level ();
1293                 goto throw;
1294
1295  */
1296 void
1297 expand_builtin_throw ()
1298 {
1299   tree fcall;
1300   tree params;
1301   rtx return_val_rtx;
1302   rtx gotta_rethrow_it;
1303   rtx gotta_call_terminate;
1304   rtx top_of_loop;
1305   rtx unwind_first;
1306   tree t;
1307
1308   if (! doing_eh (0))
1309     return;
1310
1311   if (! throw_used)
1312     return;
1313
1314   params = void_list_node;
1315   t = build_parse_node (CALL_EXPR, get_identifier ("__throw"), params, NULL_TREE);
1316   start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1317                                   void_list_node),
1318                   t, NULL_TREE, NULL_TREE, 0);
1319   store_parm_decls ();
1320   pushlevel (0);
1321   clear_last_expr ();
1322   push_momentary ();
1323   expand_start_bindings (0);
1324
1325   gotta_rethrow_it = gen_label_rtx ();
1326   gotta_call_terminate = gen_label_rtx ();
1327   top_of_loop = gen_label_rtx ();
1328   unwind_first = gen_label_rtx ();
1329
1330   emit_jump (unwind_first);
1331
1332   emit_label (top_of_loop);
1333
1334   /* search for an exception handler for the saved_pc */
1335   return_val_rtx = do_function_call (FirstExceptionMatch,
1336                                      tree_cons (NULL_TREE, saved_pc, NULL_TREE),
1337                                      ptr_type_node);
1338   assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
1339
1340   /* did we find one? */
1341   emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1342                  GET_MODE (return_val_rtx), 0, 0);
1343
1344   /* if not, jump to gotta_rethrow_it */
1345   emit_jump_insn (gen_beq (gotta_rethrow_it));
1346
1347   /* we found it, so jump to it */
1348   emit_indirect_jump (return_val_rtx);
1349
1350   /* code to deal with unwinding and looking for it again */
1351   emit_label (gotta_rethrow_it);
1352
1353   /* call to  __builtin_return_address () */
1354 #if defined (ARM_FRAME_RTX)  /* was __arm */
1355   /* This should be moved into arm.h:RETURN_ADDR_RTX */
1356   /* This replaces a 'call' to __builtin_return_address */
1357   return_val_rtx = gen_reg_rtx (Pmode);
1358   emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
1359 #else
1360   params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1361   fcall = build_function_call (BuiltinReturnAddress, params);
1362   return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
1363 #endif
1364
1365   /* did __builtin_return_address () return a valid address? */
1366   emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1367                  GET_MODE (return_val_rtx), 0, 0);
1368
1369   emit_jump_insn (gen_beq (gotta_call_terminate));
1370
1371   return_val_rtx = eh_outer_context (return_val_rtx);
1372
1373   /* Yes it did.  */
1374   emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
1375
1376   do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop));
1377   emit_jump (top_of_loop);
1378
1379   /* no it didn't --> therefore we need to call terminate */
1380   emit_label (gotta_call_terminate);
1381   do_function_call (Terminate, NULL_TREE, NULL_TREE);
1382   assemble_external (TREE_OPERAND (Terminate, 0));
1383
1384   {
1385     rtx ret_val, return_val_rtx;
1386     emit_label (unwind_first);
1387     ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
1388                                           0, hard_frame_pointer_rtx);
1389
1390     /* Set it up so that we continue inside, at the top of the loop.  */
1391     emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
1392 #ifdef RETURN_ADDR_OFFSET
1393   return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
1394     if (return_val_rtx != ret_val)
1395       emit_move_insn (ret_val, return_val_rtx);
1396 #endif
1397
1398     /* Fall into epilogue to unwind prologue. */
1399   }
1400
1401   expand_end_bindings (getdecls(), 1, 0);
1402   poplevel (1, 0, 0);
1403   pop_momentary ();
1404
1405   finish_function (lineno, 0, 0);
1406 }
1407
1408
1409 void
1410 expand_start_eh_spec ()
1411 {
1412   start_protect ();
1413 }
1414
1415 static void
1416 expand_end_eh_spec (raises)
1417      tree raises;
1418 {
1419   tree expr, second_try;
1420   rtx check = gen_label_rtx ();
1421   rtx cont;
1422   rtx ret = gen_reg_rtx (Pmode);
1423   rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
1424   rtx end = gen_label_rtx ();
1425
1426   expr = make_node (RTL_EXPR);
1427   TREE_TYPE (expr) = void_type_node;
1428   RTL_EXPR_RTL (expr) = const0_rtx;
1429   TREE_SIDE_EFFECTS (expr) = 1;
1430   start_sequence_for_rtl_expr (expr);
1431   cont = gen_label_rtx ();
1432   emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1433   emit_jump (check);
1434   emit_label (cont);
1435   jumpif (make_tree (integer_type_node, flag), end);
1436   do_function_call (Terminate, NULL_TREE, NULL_TREE);
1437   assemble_external (TREE_OPERAND (Terminate, 0));
1438   emit_barrier ();
1439   RTL_EXPR_SEQUENCE (expr) = get_insns ();
1440   end_sequence ();
1441   
1442   second_try = expr;
1443
1444   expr = make_node (RTL_EXPR);
1445   TREE_TYPE (expr) = void_type_node;
1446   RTL_EXPR_RTL (expr) = const0_rtx;
1447   TREE_SIDE_EFFECTS (expr) = 1;
1448   start_sequence_for_rtl_expr (expr);
1449
1450   cont = gen_label_rtx ();
1451   emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1452   emit_jump (check);
1453   emit_label (cont);
1454   jumpif (make_tree (integer_type_node, flag), end);
1455   start_protect ();
1456   do_function_call (Unexpected, NULL_TREE, NULL_TREE);
1457   assemble_external (TREE_OPERAND (Unexpected, 0));
1458   emit_barrier ();
1459   end_protect (second_try);
1460   
1461   emit_label (check);
1462   emit_move_insn (flag, const1_rtx);
1463   cont = gen_label_rtx ();
1464   while (raises)
1465     {
1466       tree exp;
1467       tree match_type = TREE_VALUE (raises);
1468       
1469       if (match_type)
1470         {
1471           /* check TREE_VALUE (raises) here */
1472           exp = saved_throw_value;
1473           exp = tree_cons (NULL_TREE,
1474                            build_eh_type_type (match_type),
1475                            tree_cons (NULL_TREE,
1476                                       saved_throw_type,
1477                                       tree_cons (NULL_TREE, exp, NULL_TREE)));
1478           exp = build_function_call (CatchMatch, exp);
1479           assemble_external (TREE_OPERAND (CatchMatch, 0));
1480
1481           jumpif (exp, cont);
1482         }
1483
1484       raises = TREE_CHAIN (raises);
1485     }
1486   emit_move_insn (flag, const0_rtx);
1487   emit_label (cont);
1488   emit_indirect_jump (ret);
1489   emit_label (end);
1490   
1491   RTL_EXPR_SEQUENCE (expr) = get_insns ();
1492   end_sequence ();
1493   
1494   end_protect (expr);
1495 }
1496
1497 /* This is called to expand all the toplevel exception handling
1498    finalization for a function.  It should only be called once per
1499    function.  */
1500 void
1501 expand_exception_blocks ()
1502 {
1503   rtx funcend;
1504   rtx insns;
1505
1506   start_sequence ();
1507
1508   funcend = gen_label_rtx ();
1509   emit_jump (funcend);
1510   /* expand_null_return (); */
1511
1512   start_sequence ();
1513
1514   /* Add all the catch clauses here.  */
1515   emit_insns (catch_clauses);
1516   catch_clauses = NULL_RTX;
1517
1518   expand_leftover_cleanups ();
1519
1520   insns = get_insns ();
1521   end_sequence ();
1522   
1523   /* Do this after we expand leftover cleanups, so that the end_protect
1524      that expand_end_eh_spec does will match the right start_protect,
1525      and make sure it comes out before the terminate protected region.  */
1526   if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
1527     {
1528       expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
1529       push_to_sequence (insns);
1530
1531       /* Now expand any new ones.  */
1532       expand_leftover_cleanups ();
1533
1534       insns = get_insns ();
1535       end_sequence ();
1536     }
1537
1538   if (insns)
1539     {
1540       struct ehEntry entry;
1541
1542       /* These are saved for the exception table.  */
1543       push_rtl_perm ();
1544       entry.start_label = gen_label_rtx ();
1545       entry.end_label = gen_label_rtx ();
1546       entry.exception_handler_label = gen_label_rtx ();
1547       entry.finalization = TerminateFunctionCall;
1548       entry.context = current_function_decl;
1549       assemble_external (TREE_OPERAND (Terminate, 0));
1550       pop_rtl_from_perm ();
1551
1552       LABEL_PRESERVE_P (entry.start_label) = 1;
1553       LABEL_PRESERVE_P (entry.end_label) = 1;
1554       LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
1555
1556       emit_label (entry.start_label);
1557       emit_insns (insns);
1558
1559       enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1560
1561       emit_label (entry.exception_handler_label);
1562       expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
1563       emit_label (entry.end_label);
1564       emit_barrier ();
1565     }
1566
1567   {
1568     /* Mark the end of the stack unwinder.  */
1569     rtx unwind_insns;
1570     start_sequence ();
1571     end_eh_unwinder (funcend);
1572     expand_leftover_cleanups ();
1573     unwind_insns = get_insns ();
1574     end_sequence ();
1575     if (unwind_insns)
1576       {
1577         insns = unwind_insns;
1578         emit_insns (insns);
1579       }
1580   }
1581
1582   emit_label (funcend);
1583
1584   /* Only if we had previous insns do we want to emit the jump around
1585      them.  If there weren't any, then insns will remain NULL_RTX.  */
1586   if (insns)
1587     insns = get_insns ();
1588   end_sequence ();
1589
1590   emit_insns (insns);
1591 }
1592
1593 tree
1594 start_anon_func ()
1595 {
1596   static int counter = 0;
1597   char name[32];
1598   tree params;
1599   tree t;
1600
1601   push_cp_function_context (NULL_TREE);
1602   push_to_top_level ();
1603
1604   /* No need to mangle this.  */
1605   push_lang_context (lang_name_c);
1606
1607   params = void_list_node;
1608   /* tcf stands for throw clean funciton.  */
1609   sprintf (name, "__tcf_%d", counter++);
1610   t = build_parse_node (CALL_EXPR, get_identifier (name), params, NULL_TREE);
1611   start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1612                                   void_list_node),
1613                   t, NULL_TREE, NULL_TREE, 0);
1614   store_parm_decls ();
1615   pushlevel (0);
1616   clear_last_expr ();
1617   push_momentary ();
1618   expand_start_bindings (0);
1619   emit_line_note (input_filename, lineno);
1620
1621   pop_lang_context ();
1622
1623   return current_function_decl;
1624 }
1625
1626 void
1627 end_anon_func ()
1628 {
1629   expand_end_bindings (getdecls(), 1, 0);
1630   poplevel (1, 0, 0);
1631   pop_momentary ();
1632
1633   finish_function (lineno, 0, 0);
1634
1635   pop_from_top_level ();
1636   pop_cp_function_context (NULL_TREE);
1637 }
1638
1639 /* call this to expand a throw statement.  This follows the following
1640    algorithm:
1641
1642         1. Allocate space to save the current PC onto the stack.
1643         2. Generate and emit a label and save its address into the
1644                 newly allocated stack space since we can't save the pc directly.
1645         3. If this is the first call to throw in this function:
1646                 generate a label for the throw block
1647         4. jump to the throw block label.  */
1648 void
1649 expand_throw (exp)
1650      tree exp;
1651 {
1652   rtx label;
1653
1654   if (! doing_eh (1))
1655     return;
1656
1657   /* This is the label that represents where in the code we were, when
1658      we got an exception.  This needs to be updated when we rethrow an
1659      exception, so that the matching routine knows to search out.  */
1660   label = gen_label_rtx ();
1661   emit_label (label);
1662
1663   if (exp)
1664     {
1665       tree throw_type;
1666       tree cleanup = empty_fndecl, e;
1667
1668       /* throw expression */
1669       /* First, decay it. */
1670       exp = decay_conversion (exp);
1671
1672       if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1673         {
1674           throw_type = build_eh_type (exp);
1675           exp = build_reinterpret_cast (ptr_type_node, exp);
1676         }
1677       else
1678         {
1679           rtx cleanup_insns;
1680           tree object;
1681           /* Make a copy of the thrown object.  WP 15.1.5  */
1682           exp = build_new (NULL_TREE, TREE_TYPE (exp),
1683                            build_tree_list (NULL_TREE, exp),
1684                            0);
1685
1686           if (exp == error_mark_node)
1687             error ("  in thrown expression");
1688
1689           object = build_indirect_ref (exp, NULL_PTR);
1690           throw_type = build_eh_type (object);
1691
1692           start_sequence ();
1693           object = build_reinterpret_cast (TREE_TYPE (exp), saved_throw_value);
1694           object = build_indirect_ref (object, NULL_PTR);
1695           cleanup = maybe_build_cleanup (object);
1696           if (cleanup)
1697             expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1698           cleanup_insns = get_insns ();
1699           end_sequence ();
1700
1701           if (cleanup && cleanup_insns)
1702             {
1703               cleanup = start_anon_func ();
1704
1705               expand_expr (maybe_build_cleanup (object), const0_rtx, VOIDmode, 0);
1706
1707               end_anon_func ();
1708
1709               mark_addressable (cleanup);
1710             }
1711           else
1712             {
1713               cleanup = empty_fndecl;
1714             }
1715         }
1716
1717       if (cleanup == empty_fndecl)
1718         assemble_external (empty_fndecl);
1719         
1720       e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
1721       expand_expr (e, const0_rtx, VOIDmode, 0);
1722
1723       e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
1724       e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
1725       expand_expr (e, const0_rtx, VOIDmode, 0);
1726
1727       cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
1728       cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
1729       expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1730     }
1731   else
1732     {
1733       /* rethrow current exception */
1734       /* This part is easy, as we don't have to do anything else.  */
1735     }
1736
1737   expand_internal_throw (gen_rtx (LABEL_REF, Pmode, label));
1738 }
1739
1740 void
1741 end_protect_partials () {
1742   while (protect_list)
1743     {
1744       end_protect (TREE_VALUE (protect_list));
1745       protect_list = TREE_CHAIN (protect_list);
1746     }
1747 }
1748
1749 int
1750 might_have_exceptions_p ()
1751 {
1752   if (eh_table_output_queue.head)
1753     return 1;
1754   return 0;
1755 }
1756
1757 /* Output the exception table.
1758  Return the number of handlers.  */
1759 void
1760 emit_exception_table ()
1761 {
1762   int count = 0;
1763   extern FILE *asm_out_file;
1764   struct ehEntry *entry;
1765
1766   if (! doing_eh (0))
1767     return;
1768
1769   exception_section ();
1770
1771   /* Beginning marker for table. */
1772   assemble_align (GET_MODE_ALIGNMENT (Pmode));
1773   assemble_label ("__EXCEPTION_TABLE__");
1774   output_exception_table_entry (asm_out_file,
1775                                 const0_rtx, const0_rtx, const0_rtx);
1776
1777  while (entry = dequeue_eh_entry (&eh_table_output_queue))
1778    {
1779      tree context = entry->context;
1780
1781      if (context && ! TREE_ASM_WRITTEN (context))
1782        continue;
1783
1784      count++;
1785      output_exception_table_entry (asm_out_file,
1786                                    entry->start_label, entry->end_label,
1787                                    entry->exception_handler_label);
1788   }
1789
1790   /* Ending marker for table. */
1791   assemble_label ("__EXCEPTION_END__");
1792   output_exception_table_entry (asm_out_file,
1793                                 constm1_rtx, constm1_rtx, constm1_rtx);
1794 }
1795
1796 void
1797 register_exception_table ()
1798 {
1799   emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
1800                      VOIDmode, 1,
1801                      gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
1802                      Pmode);
1803 }
1804
1805 /* Build a throw expression.  */
1806 tree
1807 build_throw (e)
1808      tree e;
1809 {
1810   if (e != error_mark_node)
1811     {
1812       e = build1 (THROW_EXPR, void_type_node, e);
1813       TREE_SIDE_EFFECTS (e) = 1;
1814       TREE_USED (e) = 1;
1815     }
1816   return e;
1817 }
1818
1819 void
1820 start_eh_unwinder ()
1821 {
1822   start_protect ();
1823 }
1824
1825 static void
1826 end_eh_unwinder (end)
1827      rtx end;
1828 {
1829   tree expr;
1830   rtx return_val_rtx, ret_val, label;
1831
1832   if (! doing_eh (0))
1833     return;
1834
1835   expr = make_node (RTL_EXPR);
1836   TREE_TYPE (expr) = void_type_node;
1837   RTL_EXPR_RTL (expr) = const0_rtx;
1838   TREE_SIDE_EFFECTS (expr) = 1;
1839   start_sequence_for_rtl_expr (expr);
1840
1841   ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
1842                                         0, hard_frame_pointer_rtx);
1843   return_val_rtx = copy_to_reg (ret_val);
1844
1845   return_val_rtx = eh_outer_context (return_val_rtx);
1846
1847   emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
1848   
1849 #ifdef JUMP_TO_THROW
1850   emit_move_insn (ret_val, gen_rtx (SYMBOL_REF, Pmode, "__throw"));
1851 #else
1852   label = gen_label_rtx ();
1853   emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label));
1854 #endif
1855
1856 #ifdef RETURN_ADDR_OFFSET
1857   return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
1858   if (return_val_rtx != ret_val)
1859     emit_move_insn (ret_val, return_val_rtx);
1860 #endif
1861   
1862   emit_jump (end);  
1863
1864 #ifndef JUMP_TO_THROW
1865   emit_label (label);
1866   do_function_call (Throw, NULL_TREE, NULL_TREE);
1867 #endif
1868   
1869   RTL_EXPR_SEQUENCE (expr) = get_insns ();
1870   end_sequence ();
1871   end_protect (expr);
1872 }