OSDN Git Service

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