OSDN Git Service

87 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 /* Indicates if we are in a catch clause.  */
330 static tree saved_in_catch;
331
332 static int throw_used;
333
334 static rtx catch_clauses;
335
336 static struct ehStack ehstack;
337 static struct ehQueue ehqueue;
338 static struct ehQueue eh_table_output_queue;
339 static struct labelNode *false_label_stack = NULL;
340 static struct labelNode *caught_return_label_stack = NULL;
341 /* ========================================================================= */
342
343 /* function prototypes */
344 static struct ehEntry *pop_eh_entry     PROTO((struct ehStack *stack));
345 static void enqueue_eh_entry            PROTO((struct ehQueue *queue, struct ehEntry *entry));
346 static rtx push_eh_entry                PROTO((struct ehStack *stack));
347 static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
348 static void new_eh_queue                PROTO((struct ehQueue *queue));
349 static void new_eh_stack                PROTO((struct ehStack *stack));
350 static void push_label_entry            PROTO((struct labelNode **labelstack, rtx rlabel, tree tlabel));
351 static rtx pop_label_entry              PROTO((struct labelNode **labelstack));
352 static tree top_label_entry             PROTO((struct labelNode **labelstack));
353 static struct ehEntry *copy_eh_entry    PROTO((struct ehEntry *entry));
354
355
356 /* Routines to save and restore eh context information.  */
357 struct eh_context {
358   struct ehStack ehstack;
359   struct ehQueue ehqueue;
360   rtx catch_clauses;
361   struct labelNode *false_label_stack;
362   struct labelNode *caught_return_label_stack;
363   tree protect_list;
364 };
365
366 /* Save the context and push into a new one.  */
367 void*
368 push_eh_context ()
369 {
370   struct eh_context *p
371     = (struct eh_context*)xmalloc (sizeof (struct eh_context));
372
373   p->ehstack = ehstack;
374   p->ehqueue = ehqueue;
375   p->catch_clauses = catch_clauses;
376   p->false_label_stack = false_label_stack;
377   p->caught_return_label_stack = caught_return_label_stack;
378   p->protect_list = protect_list;
379
380   new_eh_stack (&ehstack);
381   new_eh_queue (&ehqueue);
382   catch_clauses = NULL_RTX;
383   false_label_stack = NULL;
384   caught_return_label_stack = NULL;
385   protect_list = NULL_TREE;
386   
387   return p;
388 }
389
390 /* Pop and restore the context.  */
391 void
392 pop_eh_context (vp)
393      void *vp;
394 {
395   struct eh_context *p = (struct eh_context *)vp;
396
397   protect_list = p->protect_list;
398   caught_return_label_stack = p->caught_return_label_stack;
399   false_label_stack = p->false_label_stack;
400   catch_clauses = p->catch_clauses;
401   ehqueue = p->ehqueue;
402   ehstack = p->ehstack;
403
404   free (p);
405 }
406
407
408
409 /* All my cheesy stack/queue/misc data structure handling routines
410
411    ========================================================================= */
412
413 static void
414 push_label_entry (labelstack, rlabel, tlabel)
415      struct labelNode **labelstack;
416      rtx rlabel;
417      tree tlabel;
418 {
419   struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
420
421   if (rlabel)
422     newnode->u.rlabel = rlabel;
423   else
424     newnode->u.tlabel = tlabel;
425   newnode->chain = *labelstack;
426   *labelstack = newnode;
427 }
428
429 static rtx
430 pop_label_entry (labelstack)
431      struct labelNode **labelstack;
432 {
433   rtx label;
434   struct labelNode *tempnode;
435
436   if (! *labelstack) return NULL_RTX;
437
438   tempnode = *labelstack;
439   label = tempnode->u.rlabel;
440   *labelstack = (*labelstack)->chain;
441   free (tempnode);
442
443   return label;
444 }
445
446 static tree
447 top_label_entry (labelstack)
448      struct labelNode **labelstack;
449 {
450   if (! *labelstack) return NULL_TREE;
451
452   return (*labelstack)->u.tlabel;
453 }
454
455 /* Push to permanent obstack for rtl generation.
456    One level only!  */
457 static struct obstack *saved_rtl_obstack;
458
459 static void
460 push_rtl_perm ()
461 {
462   extern struct obstack permanent_obstack;
463   extern struct obstack *rtl_obstack;
464   
465   saved_rtl_obstack = rtl_obstack;
466   rtl_obstack = &permanent_obstack;
467 }
468
469 /* Pop back to normal rtl handling.  */
470 static void
471 pop_rtl_from_perm ()
472 {
473   extern struct obstack *rtl_obstack;
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   /* These are saved for the exception table.  */
485   push_rtl_perm ();
486   entry->start_label = gen_label_rtx ();
487   entry->end_label = gen_label_rtx ();
488   entry->exception_handler_label = gen_label_rtx ();
489   pop_rtl_from_perm ();
490
491   LABEL_PRESERVE_P (entry->start_label) = 1;
492   LABEL_PRESERVE_P (entry->end_label) = 1;
493   LABEL_PRESERVE_P (entry->exception_handler_label) = 1;
494
495   entry->finalization = NULL_TREE;
496   entry->context = current_function_decl;
497
498   node->entry = entry;
499   node->chain = stack->top;
500   stack->top = node;
501
502   enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
503
504   return entry->start_label;
505 }
506
507 /* Pop an entry from the given STACK.  */
508 static struct ehEntry *
509 pop_eh_entry (stack)
510      struct ehStack *stack;
511 {
512   struct ehNode *tempnode;
513   struct ehEntry *tempentry;
514   
515   tempnode = stack->top;
516   tempentry = tempnode->entry;
517   stack->top = stack->top->chain;
518   free (tempnode);
519
520   return tempentry;
521 }
522
523 static struct ehEntry *
524 copy_eh_entry (entry)
525      struct ehEntry *entry;
526 {
527   struct ehEntry *newentry;
528
529   newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
530   memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
531
532   return newentry;
533 }
534
535 static void
536 enqueue_eh_entry (queue, entry)
537      struct ehQueue *queue;
538      struct ehEntry *entry;
539 {
540   struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
541
542   node->entry = entry;
543   node->chain = NULL;
544
545   if (queue->head == NULL)
546     {
547       queue->head = node;
548     }
549   else
550     {
551       queue->tail->chain = node;
552     }
553   queue->tail = node;
554 }
555
556 static struct ehEntry *
557 dequeue_eh_entry (queue)
558      struct ehQueue *queue;
559 {
560   struct ehNode *tempnode;
561   struct ehEntry *tempentry;
562
563   if (queue->head == NULL)
564     return NULL;
565
566   tempnode = queue->head;
567   queue->head = queue->head->chain;
568
569   tempentry = tempnode->entry;
570   free (tempnode);
571
572   return tempentry;
573 }
574
575 static void
576 new_eh_queue (queue)
577      struct ehQueue *queue;
578 {
579   queue->head = queue->tail = NULL;
580 }
581
582 static void
583 new_eh_stack (stack)
584      struct ehStack *stack;
585 {
586   stack->top = NULL;
587 }
588
589 /* cheesyness to save some typing. returns the return value rtx */
590 static rtx
591 do_function_call (func, params, return_type)
592      tree func, params, return_type;
593 {
594   tree func_call;
595   func_call = build_function_call (func, params);
596   expand_call (func_call, NULL_RTX, 0);
597   if (return_type != NULL_TREE)
598     return hard_function_value (return_type, func_call);
599   return NULL_RTX;
600 }
601
602 static void
603 expand_internal_throw (pc)
604      rtx pc;
605 {
606   emit_move_insn (DECL_RTL (saved_pc), pc);
607 #ifdef JUMP_TO_THROW
608   emit_indirect_jump (gen_rtx (SYMBOL_REF, Pmode, "__throw"));
609 #else
610   do_function_call (Throw, NULL_TREE, NULL_TREE);
611 #endif
612   throw_used = 1;
613 }
614
615 /* ========================================================================= */
616
617 static void
618 lang_interim_eh (finalization)
619      tree finalization;
620 {
621   if (finalization)
622     end_protect (finalization);
623   else
624     start_protect ();
625 }
626
627 extern tree auto_function PROTO((tree, tree, enum built_in_function));
628
629 /* sets up all the global eh stuff that needs to be initialized at the
630    start of compilation.
631
632    This includes:
633                 - Setting up all the function call trees
634                 - Initializing the ehqueue
635                 - Initializing the eh_table_output_queue
636                 - Initializing the ehstack
637 */
638
639 void
640 init_exception_processing ()
641 {
642   extern tree define_function ();
643   tree unexpected_fndecl, terminate_fndecl;
644   tree set_unexpected_fndecl, set_terminate_fndecl;
645   tree catch_match_fndecl;
646   tree find_first_exception_match_fndecl;
647   tree unwind_fndecl;
648   tree declspecs;
649   tree d;
650
651   /* void (*)() */
652   tree PFV = build_pointer_type (build_function_type
653                                  (void_type_node, void_list_node));
654
655   /* arg list for the build_function_type call for set_terminate () and
656      set_unexpected () */
657   tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
658
659   /* void (*pfvtype (void (*) ()))() */
660   tree pfvtype = build_function_type (PFV, pfvlist);
661
662   /* void vtype () */
663   tree vtype = build_function_type (void_type_node, void_list_node);
664   
665   set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
666                                         pfvtype, NOT_BUILT_IN);
667   set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
668                                          pfvtype, NOT_BUILT_IN);
669   unexpected_fndecl = auto_function (get_identifier ("unexpected"),
670                                      vtype, NOT_BUILT_IN);
671   terminate_fndecl = auto_function (get_identifier ("terminate"),
672                                     vtype, NOT_BUILT_IN);
673
674   interim_eh_hook = lang_interim_eh;
675
676   push_lang_context (lang_name_c);
677
678   catch_match_fndecl =
679     builtin_function (flag_rtti
680                       ? "__throw_type_match_rtti"
681                       : "__throw_type_match",
682                       build_function_type (ptr_type_node,
683                                            tree_cons (NULL_TREE, ptr_type_node,
684                                                       tree_cons (NULL_TREE, ptr_type_node,
685                                                                  tree_cons (NULL_TREE, ptr_type_node,
686                                                                             void_list_node)))),
687                       NOT_BUILT_IN, NULL_PTR);
688   find_first_exception_match_fndecl =
689     builtin_function ("__find_first_exception_table_match",
690                       build_function_type (ptr_type_node,
691                                            tree_cons (NULL_TREE, ptr_type_node,
692                                                       void_list_node)),
693                       NOT_BUILT_IN, NULL_PTR);
694   unwind_fndecl =
695     builtin_function ("__unwind_function",
696                       build_function_type (void_type_node,
697                                            tree_cons (NULL_TREE, ptr_type_node,
698                                                       void_list_node)),
699                       NOT_BUILT_IN, NULL_PTR);
700   throw_fndecl =
701     builtin_function ("__throw",
702                       build_function_type (void_type_node, void_list_node),
703                       NOT_BUILT_IN, NULL_PTR);
704   DECL_EXTERNAL (throw_fndecl) = 0;
705   TREE_PUBLIC (throw_fndecl) = 0;
706   empty_fndecl =
707     builtin_function ("__empty",
708                       build_function_type (void_type_node, void_list_node),
709                       NOT_BUILT_IN, NULL_PTR);
710   DECL_EXTERNAL (empty_fndecl) = 1;
711   TREE_PUBLIC (empty_fndecl) = 1;
712
713   Unexpected = default_conversion (unexpected_fndecl);
714   Terminate = default_conversion (terminate_fndecl);
715   SetTerminate = default_conversion (set_terminate_fndecl);
716   SetUnexpected = default_conversion (set_unexpected_fndecl);
717   CatchMatch = default_conversion (catch_match_fndecl);
718   FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
719   Unwind = default_conversion (unwind_fndecl);
720   Throw = default_conversion (throw_fndecl);
721   BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
722
723   TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
724
725   pop_lang_context ();
726
727   new_eh_queue (&ehqueue);
728   new_eh_queue (&eh_table_output_queue);
729   new_eh_stack (&ehstack);
730
731   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
732   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
733   d = start_decl (d, declspecs, 0, NULL_TREE);
734   DECL_COMMON (d) = 1;
735   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
736   saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
737
738   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
739   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
740   d = start_decl (d, declspecs, 0, NULL_TREE);
741   DECL_COMMON (d) = 1;
742   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
743   saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
744
745   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
746   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
747   d = start_decl (d, declspecs, 0, NULL_TREE);
748   DECL_COMMON (d) = 1;
749   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
750   saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
751
752   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
753   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
754   d = build_parse_node (CALL_EXPR, d, void_list_node, NULL_TREE);
755   d = start_decl (d, declspecs, 0, NULL_TREE);
756   DECL_COMMON (d) = 1;
757   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
758   saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
759
760   declspecs = tree_cons (NULL_TREE, get_identifier ("bool"), NULL_TREE);
761   d = get_identifier ("__eh_in_catch");
762   d = start_decl (d, declspecs, 0, NULL_TREE);
763   DECL_COMMON (d) = 1;
764   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
765   saved_in_catch = lookup_name (get_identifier ("__eh_in_catch"), 0);
766 }
767
768 /* call this to begin a block of unwind protection (ie: when an object is
769    constructed) */
770 void
771 start_protect ()
772 {
773   if (! doing_eh (0))
774     return;
775
776   emit_label (push_eh_entry (&ehstack));
777 }
778    
779 /* call this to end a block of unwind protection.  the finalization tree is
780    the finalization which needs to be run in order to cleanly unwind through
781    this level of protection. (ie: call this when a scope is exited)*/
782 void
783 end_protect (finalization)
784      tree finalization;
785 {
786   struct ehEntry *entry;
787
788   if (! doing_eh (0))
789     return;
790
791   entry = pop_eh_entry (&ehstack);
792
793   emit_label (entry->end_label);
794   /* Put in something that takes up space, as otherwise the end
795      address for the EH region could have the exact same address as
796      the outer region, causing us to miss the fact that resuming
797      exception handling with this PC value would be inside the outer
798      region.  */
799   emit_insn (gen_nop ());
800
801   entry->finalization = finalization;
802
803   enqueue_eh_entry (&ehqueue, entry);
804 }
805
806 /* call this on start of a try block. */
807 void
808 expand_start_try_stmts ()
809 {
810   if (! doing_eh (1))
811     return;
812
813   start_protect ();
814 }
815
816 void
817 expand_end_try_stmts ()
818 {
819   end_protect (integer_zero_node);
820 }
821
822
823 /* call this to start processing of all the catch blocks. */
824 void
825 expand_start_all_catch ()
826 {
827   struct ehEntry *entry;
828   tree label;
829
830   if (! doing_eh (1))
831     return;
832
833   emit_line_note (input_filename, lineno);
834   label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
835
836   /* The label for the exception handling block we will save.  This is
837      Lresume, in the documention.  */
838   expand_label (label);
839   
840   /* Put in something that takes up space, as otherwise the end
841      address for the EH region could have the exact same address as
842      the outer region, causing us to miss the fact that resuming
843      exception handling with this PC value would be inside the outer
844      region.  */
845   emit_insn (gen_nop ());
846
847   push_label_entry (&caught_return_label_stack, NULL_RTX, label);
848
849   /* Start a new sequence for all the catch blocks.  We will add this
850      to the gloabl sequence catch_clauses, when we have completed all
851      the handlers in this handler-seq.  */
852   start_sequence ();
853
854   while (1)
855     {
856       entry = dequeue_eh_entry (&ehqueue);
857       emit_label (entry->exception_handler_label);
858
859       expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
860
861       /* When we get down to the matching entry, stop.  */
862       if (entry->finalization == integer_zero_node)
863         break;
864
865       /* The below can be optimized away, and we could just fall into the
866          next EH handler, if we are certain they are nested.  */
867       /* Code to throw out to outer context, if we fall off end of the
868          handler.  */
869       expand_internal_throw (gen_rtx (LABEL_REF,
870                                       Pmode,
871                                       entry->end_label));
872       free (entry);
873     }
874 }
875
876 /* call this to end processing of all the catch blocks. */
877 void
878 expand_end_all_catch ()
879 {
880   rtx new_catch_clause;
881
882   if (! doing_eh (1))
883     return;
884
885   /* Code to throw out to outer context, if we fall off end of catch
886      handlers.  This is rethrow (Lresume, same id, same obj); in the
887      documentation.  */
888   expand_internal_throw (gen_rtx (LABEL_REF,
889                                   Pmode,
890                                   DECL_RTL (top_label_entry (&caught_return_label_stack))));
891
892   /* Now we have the complete catch sequence.  */
893   new_catch_clause = get_insns ();
894   end_sequence ();
895   
896   /* this level of catch blocks is done, so set up the successful catch jump
897      label for the next layer of catch blocks. */
898   pop_label_entry (&caught_return_label_stack);
899
900   /* Add the new sequence of catchs to the main one for this
901      function.  */
902   push_to_sequence (catch_clauses);
903   emit_insns (new_catch_clause);
904   catch_clauses = get_insns ();
905   end_sequence ();
906   
907   /* Here we fall through into the continuation code.  */
908 }
909
910 /* Build a type value for use at runtime for a type that is matched
911    against by the exception handling system.  */
912 static tree
913 build_eh_type_type (type)
914      tree type;
915 {
916   char *typestring;
917   tree exp;
918
919   if (type == error_mark_node)
920     return error_mark_node;
921
922   /* peel back references, so they match.  */
923   if (TREE_CODE (type) == REFERENCE_TYPE)
924     type = TREE_TYPE (type);
925
926   /* Peel off cv qualifiers.  */
927   type = TYPE_MAIN_VARIANT (type);
928
929   if (flag_rtti)
930     {
931       return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
932     }
933
934   typestring = build_overload_name (type, 1, 1);
935   exp = combine_strings (build_string (strlen (typestring)+1, typestring));
936   return build1 (ADDR_EXPR, ptr_type_node, exp);
937 }
938
939 /* Build a type value for use at runtime for a exp that is thrown or
940    matched against by the exception handling system.  */
941 static tree
942 build_eh_type (exp)
943      tree exp;
944 {
945   if (flag_rtti)
946     {
947       exp = build_typeid (exp);
948       return build1 (ADDR_EXPR, ptr_type_node, exp);
949     }
950   return build_eh_type_type (TREE_TYPE (exp));
951 }
952
953 /* This routine creates the cleanup for the exception handling object.  */
954 static void
955 push_eh_cleanup ()
956 {
957   /* All cleanups must last longer than normal.  */
958   int yes = suspend_momentary ();
959
960   /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
961   tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
962   cleanup = build (COMPOUND_EXPR, void_type_node, cleanup,
963                    build_modify_expr (saved_in_catch, NOP_EXPR,
964                                       build_modify_expr (saved_throw_type, NOP_EXPR, integer_zero_node)));
965   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
985   if (! doing_eh (1))
986     return;
987
988   /* Create a binding level for the parm.  */
989   expand_start_bindings (0);
990
991   false_label_rtx = gen_label_rtx ();
992   /* This is saved for the exception table.  */
993   push_rtl_perm ();
994   protect_label_rtx = gen_label_rtx ();
995   pop_rtl_from_perm ();
996   push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
997   push_label_entry (&false_label_stack, protect_label_rtx, NULL_TREE);
998
999   if (declspecs)
1000     {
1001       tree exp;
1002       rtx call_rtx, return_value_rtx;
1003       tree init_type;
1004
1005       decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1,
1006                              NULL_TREE, NULL_TREE);
1007
1008       if (decl == NULL_TREE)
1009         {
1010           error ("invalid catch parameter");
1011           return;
1012         }
1013
1014       /* Make sure we mark the catch param as used, otherwise we'll get
1015          a warning about an unused ((anonymous)).  */
1016       TREE_USED (decl) = 1;
1017
1018       /* Figure out the type that the initializer is.  */
1019       init_type = TREE_TYPE (decl);
1020       if (TREE_CODE (init_type) != REFERENCE_TYPE
1021           && TREE_CODE (init_type) != POINTER_TYPE)
1022         init_type = build_reference_type (init_type);
1023
1024       exp = saved_throw_value;
1025       exp = tree_cons (NULL_TREE,
1026                        build_eh_type_type (TREE_TYPE (decl)),
1027                        tree_cons (NULL_TREE,
1028                                   saved_throw_type,
1029                                   tree_cons (NULL_TREE, exp, NULL_TREE)));
1030       exp = build_function_call (CatchMatch, exp);
1031       call_rtx = expand_call (exp, NULL_RTX, 0);
1032       assemble_external (TREE_OPERAND (CatchMatch, 0));
1033
1034       return_value_rtx = hard_function_value (ptr_type_node, exp);
1035
1036       /* did the throw type match function return TRUE? */
1037       emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
1038                     GET_MODE (return_value_rtx), 0, 0);
1039
1040       /* if it returned FALSE, jump over the catch block, else fall into it */
1041       emit_jump_insn (gen_beq (false_label_rtx));
1042
1043       push_eh_cleanup ();
1044
1045       init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
1046
1047       /* Do we need the below two lines? */
1048       /* Let `cp_finish_decl' know that this initializer is ok.  */
1049       DECL_INITIAL (decl) = init;
1050       decl = pushdecl (decl);
1051       cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
1052     }
1053   else
1054     {
1055       push_eh_cleanup ();
1056
1057       /* Fall into the catch all section.  */
1058     }
1059
1060   emit_move_insn (DECL_RTL (saved_in_catch), const1_rtx);
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 static 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 top_of_loop;
1318   rtx unwind_first;
1319   tree t;
1320
1321   if (! doing_eh (0))
1322     return;
1323
1324   if (! throw_used)
1325     return;
1326
1327   params = void_list_node;
1328   t = build_parse_node (CALL_EXPR, get_identifier ("__throw"), params, NULL_TREE);
1329   start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1330                                   void_list_node),
1331                   t, NULL_TREE, NULL_TREE, 0);
1332   store_parm_decls ();
1333   pushlevel (0);
1334   clear_last_expr ();
1335   push_momentary ();
1336   expand_start_bindings (0);
1337
1338   gotta_rethrow_it = gen_label_rtx ();
1339   gotta_call_terminate = gen_label_rtx ();
1340   top_of_loop = gen_label_rtx ();
1341   unwind_first = gen_label_rtx ();
1342
1343   /* These two can be frontend specific.  If wanted, they can go in
1344      expand_throw.  */
1345   /* Do we have a valid object we are throwing? */
1346   emit_cmp_insn (DECL_RTL (saved_throw_type), const0_rtx, EQ, NULL_RTX,
1347                  GET_MODE (DECL_RTL (saved_throw_type)), 0, 0);
1348   emit_jump_insn (gen_beq (gotta_call_terminate));
1349
1350   emit_jump (unwind_first);
1351
1352   emit_label (top_of_loop);
1353
1354   /* search for an exception handler for the saved_pc */
1355   return_val_rtx = do_function_call (FirstExceptionMatch,
1356                                      tree_cons (NULL_TREE, saved_pc, NULL_TREE),
1357                                      ptr_type_node);
1358   assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
1359
1360   /* did we find one? */
1361   emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1362                  GET_MODE (return_val_rtx), 0, 0);
1363
1364   /* if not, jump to gotta_rethrow_it */
1365   emit_jump_insn (gen_beq (gotta_rethrow_it));
1366
1367   /* we found it, so jump to it */
1368   emit_indirect_jump (return_val_rtx);
1369
1370   /* code to deal with unwinding and looking for it again */
1371   emit_label (gotta_rethrow_it);
1372
1373   /* call to  __builtin_return_address () */
1374 #if defined (ARM_FRAME_RTX)  /* was __arm */
1375   /* This should be moved into arm.h:RETURN_ADDR_RTX */
1376   /* This replaces a 'call' to __builtin_return_address */
1377   return_val_rtx = gen_reg_rtx (Pmode);
1378   emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
1379 #else
1380   params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1381   fcall = build_function_call (BuiltinReturnAddress, params);
1382   return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
1383 #endif
1384
1385   /* did __builtin_return_address () return a valid address? */
1386   emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1387                  GET_MODE (return_val_rtx), 0, 0);
1388
1389   emit_jump_insn (gen_beq (gotta_call_terminate));
1390
1391   return_val_rtx = eh_outer_context (return_val_rtx);
1392
1393   /* Yes it did.  */
1394   emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
1395
1396   do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop));
1397   emit_jump (top_of_loop);
1398
1399   /* no it didn't --> therefore we need to call terminate */
1400   emit_label (gotta_call_terminate);
1401   do_function_call (Terminate, NULL_TREE, NULL_TREE);
1402   assemble_external (TREE_OPERAND (Terminate, 0));
1403
1404   {
1405     rtx ret_val, return_val_rtx;
1406     emit_label (unwind_first);
1407     ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
1408                                           0, hard_frame_pointer_rtx);
1409
1410     /* Set it up so that we continue inside, at the top of the loop.  */
1411     emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
1412 #ifdef RETURN_ADDR_OFFSET
1413   return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
1414     if (return_val_rtx != ret_val)
1415       emit_move_insn (ret_val, return_val_rtx);
1416 #endif
1417
1418     /* Fall into epilogue to unwind prologue.  */
1419   }
1420
1421   expand_end_bindings (getdecls (), 1, 0);
1422   poplevel (1, 0, 0);
1423   pop_momentary ();
1424
1425   finish_function (lineno, 0, 0);
1426 }
1427
1428
1429 void
1430 expand_start_eh_spec ()
1431 {
1432   start_protect ();
1433 }
1434
1435 static void
1436 expand_end_eh_spec (raises)
1437      tree raises;
1438 {
1439   tree expr, second_try;
1440   rtx check = gen_label_rtx ();
1441   rtx cont;
1442   rtx ret = gen_reg_rtx (Pmode);
1443   rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
1444   rtx end = gen_label_rtx ();
1445
1446   expr = make_node (RTL_EXPR);
1447   TREE_TYPE (expr) = void_type_node;
1448   RTL_EXPR_RTL (expr) = const0_rtx;
1449   TREE_SIDE_EFFECTS (expr) = 1;
1450   start_sequence_for_rtl_expr (expr);
1451   cont = gen_label_rtx ();
1452   emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1453   emit_jump (check);
1454   emit_label (cont);
1455   jumpif (make_tree (integer_type_node, flag), end);
1456   do_function_call (Terminate, NULL_TREE, NULL_TREE);
1457   assemble_external (TREE_OPERAND (Terminate, 0));
1458   emit_barrier ();
1459   RTL_EXPR_SEQUENCE (expr) = get_insns ();
1460   end_sequence ();
1461   
1462   second_try = expr;
1463
1464   expr = make_node (RTL_EXPR);
1465   TREE_TYPE (expr) = void_type_node;
1466   RTL_EXPR_RTL (expr) = const0_rtx;
1467   TREE_SIDE_EFFECTS (expr) = 1;
1468   start_sequence_for_rtl_expr (expr);
1469
1470   cont = gen_label_rtx ();
1471   emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1472   emit_jump (check);
1473   emit_label (cont);
1474   jumpif (make_tree (integer_type_node, flag), end);
1475   start_protect ();
1476   do_function_call (Unexpected, NULL_TREE, NULL_TREE);
1477   assemble_external (TREE_OPERAND (Unexpected, 0));
1478   emit_barrier ();
1479   end_protect (second_try);
1480   
1481   emit_label (check);
1482   emit_move_insn (flag, const1_rtx);
1483   cont = gen_label_rtx ();
1484   while (raises)
1485     {
1486       tree exp;
1487       tree match_type = TREE_VALUE (raises);
1488       
1489       if (match_type)
1490         {
1491           /* check TREE_VALUE (raises) here */
1492           exp = saved_throw_value;
1493           exp = tree_cons (NULL_TREE,
1494                            build_eh_type_type (match_type),
1495                            tree_cons (NULL_TREE,
1496                                       saved_throw_type,
1497                                       tree_cons (NULL_TREE, exp, NULL_TREE)));
1498           exp = build_function_call (CatchMatch, exp);
1499           assemble_external (TREE_OPERAND (CatchMatch, 0));
1500
1501           jumpif (exp, cont);
1502         }
1503
1504       raises = TREE_CHAIN (raises);
1505     }
1506   emit_move_insn (flag, const0_rtx);
1507   emit_label (cont);
1508   emit_indirect_jump (ret);
1509   emit_label (end);
1510   
1511   RTL_EXPR_SEQUENCE (expr) = get_insns ();
1512   end_sequence ();
1513   
1514   end_protect (expr);
1515 }
1516
1517 /* This is called to expand all the toplevel exception handling
1518    finalization for a function.  It should only be called once per
1519    function.  */
1520 void
1521 expand_exception_blocks ()
1522 {
1523   rtx funcend;
1524   rtx insns;
1525
1526   start_sequence ();
1527
1528   funcend = gen_label_rtx ();
1529   emit_jump (funcend);
1530   /* expand_null_return (); */
1531
1532   start_sequence ();
1533
1534   /* Add all the catch clauses here.  */
1535   emit_insns (catch_clauses);
1536   catch_clauses = NULL_RTX;
1537
1538   expand_leftover_cleanups ();
1539
1540   insns = get_insns ();
1541   end_sequence ();
1542   
1543   /* Do this after we expand leftover cleanups, so that the end_protect
1544      that expand_end_eh_spec does will match the right start_protect,
1545      and make sure it comes out before the terminate protected region.  */
1546   if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
1547     {
1548       expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
1549       push_to_sequence (insns);
1550
1551       /* Now expand any new ones.  */
1552       expand_leftover_cleanups ();
1553
1554       insns = get_insns ();
1555       end_sequence ();
1556     }
1557
1558   if (insns)
1559     {
1560       struct ehEntry entry;
1561
1562       /* These are saved for the exception table.  */
1563       push_rtl_perm ();
1564       entry.start_label = gen_label_rtx ();
1565       entry.end_label = gen_label_rtx ();
1566       entry.exception_handler_label = gen_label_rtx ();
1567       entry.finalization = TerminateFunctionCall;
1568       entry.context = current_function_decl;
1569       assemble_external (TREE_OPERAND (Terminate, 0));
1570       pop_rtl_from_perm ();
1571
1572       LABEL_PRESERVE_P (entry.start_label) = 1;
1573       LABEL_PRESERVE_P (entry.end_label) = 1;
1574       LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
1575
1576       emit_label (entry.start_label);
1577       emit_insns (insns);
1578
1579       enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1580
1581       emit_label (entry.exception_handler_label);
1582       expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
1583       emit_label (entry.end_label);
1584       emit_barrier ();
1585     }
1586
1587   {
1588     /* Mark the end of the stack unwinder.  */
1589     rtx unwind_insns;
1590     start_sequence ();
1591     end_eh_unwinder (funcend);
1592     expand_leftover_cleanups ();
1593     unwind_insns = get_insns ();
1594     end_sequence ();
1595     if (unwind_insns)
1596       {
1597         insns = unwind_insns;
1598         emit_insns (insns);
1599       }
1600   }
1601
1602   emit_label (funcend);
1603
1604   /* Only if we had previous insns do we want to emit the jump around
1605      them.  If there weren't any, then insns will remain NULL_RTX.  */
1606   if (insns)
1607     insns = get_insns ();
1608   end_sequence ();
1609
1610   emit_insns (insns);
1611 }
1612
1613 tree
1614 start_anon_func ()
1615 {
1616   static int counter = 0;
1617   int old_interface_unknown = interface_unknown;
1618   char name[32];
1619   tree params;
1620   tree t;
1621
1622   push_cp_function_context (NULL_TREE);
1623   push_to_top_level ();
1624
1625   /* No need to mangle this.  */
1626   push_lang_context (lang_name_c);
1627
1628   interface_unknown = 1;
1629
1630   params = void_list_node;
1631   /* tcf stands for throw clean funciton.  */
1632   sprintf (name, "__tcf_%d", counter++);
1633   t = build_parse_node (CALL_EXPR, get_identifier (name), params, NULL_TREE);
1634   start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1635                                   void_list_node),
1636                   t, NULL_TREE, NULL_TREE, 0);
1637   store_parm_decls ();
1638   pushlevel (0);
1639   clear_last_expr ();
1640   push_momentary ();
1641   expand_start_bindings (0);
1642   emit_line_note (input_filename, lineno);
1643
1644   interface_unknown = old_interface_unknown;
1645
1646   pop_lang_context ();
1647
1648   return current_function_decl;
1649 }
1650
1651 void
1652 end_anon_func ()
1653 {
1654   expand_end_bindings (getdecls (), 1, 0);
1655   poplevel (1, 0, 0);
1656   pop_momentary ();
1657
1658   finish_function (lineno, 0, 0);
1659
1660   pop_from_top_level ();
1661   pop_cp_function_context (NULL_TREE);
1662 }
1663
1664 /* call this to expand a throw statement.  This follows the following
1665    algorithm:
1666
1667         1. Allocate space to save the current PC onto the stack.
1668         2. Generate and emit a label and save its address into the
1669                 newly allocated stack space since we can't save the pc directly.
1670         3. If this is the first call to throw in this function:
1671                 generate a label for the throw block
1672         4. jump to the throw block label.  */
1673 void
1674 expand_throw (exp)
1675      tree exp;
1676 {
1677   rtx label;
1678
1679   if (! doing_eh (1))
1680     return;
1681
1682   /* This is the label that represents where in the code we were, when
1683      we got an exception.  This needs to be updated when we rethrow an
1684      exception, so that the matching routine knows to search out.  */
1685   label = gen_label_rtx ();
1686   emit_label (label);
1687
1688   if (exp)
1689     {
1690       tree throw_type;
1691       tree cleanup = empty_fndecl, e;
1692
1693       /* throw expression */
1694       /* First, decay it.  */
1695       exp = decay_conversion (exp);
1696
1697       if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1698         {
1699           throw_type = build_eh_type (exp);
1700           exp = build_reinterpret_cast (ptr_type_node, exp);
1701         }
1702       else
1703         {
1704           rtx cleanup_insns;
1705           tree object;
1706
1707           /* Make a copy of the thrown object.  WP 15.1.5  */
1708           exp = build_new (NULL_TREE, TREE_TYPE (exp),
1709                            build_tree_list (NULL_TREE, exp),
1710                            0);
1711
1712           if (exp == error_mark_node)
1713             error ("  in thrown expression");
1714
1715           object = build_indirect_ref (exp, NULL_PTR);
1716           throw_type = build_eh_type (object);
1717
1718           start_sequence ();
1719           object = build_reinterpret_cast (TREE_TYPE (exp), saved_throw_value);
1720           object = build_indirect_ref (object, NULL_PTR);
1721           cleanup = maybe_build_cleanup (object);
1722           if (cleanup)
1723             expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1724           cleanup_insns = get_insns ();
1725           end_sequence ();
1726
1727           if (cleanup && cleanup_insns)
1728             {
1729               cleanup = start_anon_func ();
1730
1731               expand_expr (maybe_build_cleanup (object), const0_rtx, VOIDmode, 0);
1732
1733               end_anon_func ();
1734
1735               mark_addressable (cleanup);
1736             }
1737           else
1738             {
1739               cleanup = empty_fndecl;
1740             }
1741         }
1742
1743       if (cleanup == empty_fndecl)
1744         assemble_external (empty_fndecl);
1745         
1746       e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
1747       expand_expr (e, const0_rtx, VOIDmode, 0);
1748
1749       e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
1750       e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
1751       expand_expr (e, const0_rtx, VOIDmode, 0);
1752
1753       cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
1754       cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
1755       expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1756     }
1757   else
1758     {
1759       /* rethrow current exception */
1760       /* This part is easy, as we don't have to do anything else.  */
1761     }
1762
1763   expand_internal_throw (gen_rtx (LABEL_REF, Pmode, label));
1764 }
1765
1766 void
1767 end_protect_partials () {
1768   while (protect_list)
1769     {
1770       end_protect (TREE_VALUE (protect_list));
1771       protect_list = TREE_CHAIN (protect_list);
1772     }
1773 }
1774
1775 int
1776 might_have_exceptions_p ()
1777 {
1778   if (eh_table_output_queue.head)
1779     return 1;
1780   return 0;
1781 }
1782
1783 /* Output the exception table.
1784  Return the number of handlers.  */
1785 void
1786 emit_exception_table ()
1787 {
1788   int count = 0;
1789   extern FILE *asm_out_file;
1790   struct ehEntry *entry;
1791
1792   if (! doing_eh (0))
1793     return;
1794
1795   exception_section ();
1796
1797   /* Beginning marker for table. */
1798   assemble_align (GET_MODE_ALIGNMENT (Pmode));
1799   assemble_label ("__EXCEPTION_TABLE__");
1800   output_exception_table_entry (asm_out_file,
1801                                 const0_rtx, const0_rtx, const0_rtx);
1802
1803  while (entry = dequeue_eh_entry (&eh_table_output_queue))
1804    {
1805      tree context = entry->context;
1806
1807      if (context && ! TREE_ASM_WRITTEN (context))
1808        continue;
1809
1810      count++;
1811      output_exception_table_entry (asm_out_file,
1812                                    entry->start_label, entry->end_label,
1813                                    entry->exception_handler_label);
1814   }
1815
1816   /* Ending marker for table. */
1817   assemble_label ("__EXCEPTION_END__");
1818   output_exception_table_entry (asm_out_file,
1819                                 constm1_rtx, constm1_rtx, constm1_rtx);
1820 }
1821
1822 void
1823 register_exception_table ()
1824 {
1825   emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
1826                      VOIDmode, 1,
1827                      gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
1828                      Pmode);
1829 }
1830
1831 /* Build a throw expression.  */
1832 tree
1833 build_throw (e)
1834      tree e;
1835 {
1836   if (e != error_mark_node)
1837     {
1838       if (current_template_parms)
1839         return build_min (THROW_EXPR, void_type_node, e);
1840       e = build1 (THROW_EXPR, void_type_node, e);
1841       TREE_SIDE_EFFECTS (e) = 1;
1842       TREE_USED (e) = 1;
1843     }
1844   return e;
1845 }
1846
1847 void
1848 start_eh_unwinder ()
1849 {
1850   start_protect ();
1851 }
1852
1853 static void
1854 end_eh_unwinder (end)
1855      rtx end;
1856 {
1857   tree expr;
1858   rtx return_val_rtx, ret_val, label;
1859
1860   if (! doing_eh (0))
1861     return;
1862
1863   expr = make_node (RTL_EXPR);
1864   TREE_TYPE (expr) = void_type_node;
1865   RTL_EXPR_RTL (expr) = const0_rtx;
1866   TREE_SIDE_EFFECTS (expr) = 1;
1867   start_sequence_for_rtl_expr (expr);
1868
1869   ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
1870                                         0, hard_frame_pointer_rtx);
1871   return_val_rtx = copy_to_reg (ret_val);
1872
1873   return_val_rtx = eh_outer_context (return_val_rtx);
1874
1875   emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
1876   
1877 #ifdef JUMP_TO_THROW
1878   emit_move_insn (ret_val, gen_rtx (SYMBOL_REF, Pmode, "__throw"));
1879 #else
1880   label = gen_label_rtx ();
1881   emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label));
1882 #endif
1883
1884 #ifdef RETURN_ADDR_OFFSET
1885   return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
1886   if (return_val_rtx != ret_val)
1887     emit_move_insn (ret_val, return_val_rtx);
1888 #endif
1889   
1890   emit_jump (end);  
1891
1892 #ifndef JUMP_TO_THROW
1893   emit_label (label);
1894   do_function_call (Throw, NULL_TREE, NULL_TREE);
1895 #endif
1896   
1897   RTL_EXPR_SEQUENCE (expr) = get_insns ();
1898   end_sequence ();
1899   end_protect (expr);
1900 }