OSDN Git Service

(struct function): Make frame_offset be HOST_WIDE_INT.
[pf3gnuchains/gcc-fork.git] / gcc / cp / except.c
index 7d748e9..fefcd02 100644 (file)
@@ -1,5 +1,5 @@
 /* Handle exceptional things in C++.
-   Copyright (C) 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1989, 92-95, 1996 Free Software Foundation, Inc.
    Contributed by Michael Tiemann <tiemann@cygnus.com>
    Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
    initial re-implementation courtesy Tad Hunt.
@@ -18,11 +18,10 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
-/* High-level class interface. */
-
 #include "config.h"
 #include "tree.h"
 #include "rtl.h"
@@ -30,157 +29,23 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "flags.h"
 #include "obstack.h"
 #include "expr.h"
+#include "output.h"
+#include "except.h"
+#include "function.h"
 
-extern void (*interim_eh_hook) PROTO((tree));
+rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
 
 /* holds the fndecl for __builtin_return_address () */
 tree builtin_return_address_fndecl;
 
-/* Define at your own risk!  */
-#ifndef CROSS_COMPILE
-#ifdef sun
-#ifdef sparc
-#define TRY_NEW_EH
-#endif
-#endif
-#endif
-
-#ifndef TRY_NEW_EH
-
-static void
-sorry_no_eh ()
-{
-  static int warned = 0;
-  if (! warned)
-    {
-      sorry ("exception handling not supported");
-      warned = 1;
-    }
-}
-
-void
-expand_exception_blocks ()
-{
-}
-
-void
-start_protect ()
-{
-}
-
-void
-end_protect (finalization)
-     tree finalization;
-{
-}
-
-void
-expand_start_try_stmts ()
-{
-  sorry_no_eh ();
-}
-
-void
-expand_end_try_stmts ()
-{
-}
-
-void
-expand_start_all_catch ()
-{
-}
-
-void
-expand_end_all_catch ()
-{
-}
-
-void
-expand_start_catch_block (declspecs, declarator)
-     tree declspecs, declarator;
-{
-}
-
-void
-expand_end_catch_block ()
-{
-}
-
-void
-init_exception_processing ()
-{
-}
-
-void
-expand_throw (exp)
-     tree exp;
-{
-  sorry_no_eh ();
-}
-
-#else
-
-static int
-doing_eh (do_warn)
-     int do_warn;
-{
-  if (! flag_handle_exceptions)
-    {
-      static int warned = 0;
-      if (! warned && do_warn)
-       {
-         error ("exception handling disabled, use -fhandle-exceptions to enable.");
-         warned = 1;
-       }
-      return 0;
-    }
-  return 1;
-}
-
-
-/*
-NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
-to supporting exception handling as per Stroustrup's 2nd edition.
-It is a complete rewrite of all the EH stuff that was here before
-       Shortcomings:
-               1. The type of the throw and catch must still match
-                  exactly (no support yet for matching base classes)
-               2. Throw specifications of functions still doesnt't work.
-       Cool Things:
-               1. Destructors are called properly :-)
-               2. No overhead for the non-exception thrown case.
-               3. Fixing shortcomings 1 and 2 is simple.
-                       -Tad Hunt       (tad@mail.csh.rit.edu)
-
-*/
-
 /* A couple of backend routines from m88k.c */
 
 /* used to cache a call to __builtin_return_address () */
 static tree BuiltinReturnAddress;
-
-
-
-
+     
 
 #include <stdio.h>
 
-/* XXX - Tad: for EH */
-/* output an exception table entry */
-
-static void
-output_exception_table_entry (file, start_label, end_label, eh_label)
-     FILE *file;
-     rtx start_label, end_label, eh_label;
-{
-  char label[100];
-
-  assemble_integer (start_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
-  assemble_integer (end_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
-  assemble_integer (eh_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
-  putc ('\n', file);           /* blank line */
-}
-   
 static void
 easy_expand_asm (str)
      char *str;
@@ -188,63 +53,9 @@ easy_expand_asm (str)
   expand_asm (build_string (strlen (str)+1, str));
 }
 
-/* unwind the stack. */
-static void
-do_unwind (throw_label)
-     rtx throw_label;
-{
-#ifdef sparc
-  extern FILE *asm_out_file;
-  tree fcall;
-  tree params;
-  rtx return_val_rtx;
-
-  /* call to  __builtin_return_address () */
-  params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
-  fcall = build_function_call (BuiltinReturnAddress, params);
-  return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
-  /* In the return, the new pc is pc+8, as the value comming in is
-     really the address of the call insn, not the next insn.  */
-  emit_move_insn (return_val_rtx, plus_constant(gen_rtx (LABEL_REF,
-                                                        Pmode,
-                                                        throw_label), -8));
-  /* We use three values, PC, type, and value */
-  easy_expand_asm ("st %l0,[%fp]");
-  easy_expand_asm ("st %l1,[%fp+4]");
-  easy_expand_asm ("st %l2,[%fp+8]");
-  easy_expand_asm ("ret");
-  easy_expand_asm ("restore");
-  emit_barrier ();
-#endif
-#if m88k
-  rtx temp_frame = frame_pointer_rtx;
-
-  temp_frame = memory_address (Pmode, temp_frame);
-  temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
-
-  /* hopefully this will successfully pop the frame! */
-  emit_move_insn (frame_pointer_rtx, temp_frame);
-  emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
-  emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
-  emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
-                                                    (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
-
-#if 0
-  emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
-                                                  -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
-
-  emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
-
-  emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
-                                                    (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
-#endif
-#endif
-}
-
-
 
 #if 0
-/* This is the startup, and finish stuff per exception table. */
+/* This is the startup, and finish stuff per exception table.  */
 
 /* XXX - Tad: exception handling section */
 #ifndef EXCEPT_SECTION_ASM_OP
@@ -253,8 +64,8 @@ do_unwind (throw_label)
 
 #ifdef EXCEPT_SECTION_ASM_OP
 typedef struct {
-    void *start_protect;
-    void *end_protect;
+    void *start_region;
+    void *end_region;
     void *exception_handler;
  } exception_table;
 #endif /* EXCEPT_SECTION_ASM_OP */
@@ -283,38 +94,9 @@ asm (TEXT_SECTION_ASM_OP);
 
 #endif
 
-void
-exception_section ()
-{
-#ifdef ASM_OUTPUT_SECTION_NAME
-  named_section (".gcc_except_table");
-#else
-  text_section ();
-#endif
-}
-
-
-
-
-/* from: my-cp-except.c */
-
-/* VI: ":set ts=4" */
-#if 0
-#include <stdio.h> */
-#include "config.h"
-#include "tree.h"
-#include "rtl.h"
-#include "cp-tree.h"
-#endif
 #include "decl.h"
-#if 0
-#include "flags.h"
-#endif
 #include "insn-flags.h"
 #include "obstack.h"
-#if 0
-#include "expr.h"
-#endif
 
 /* ======================================================================
    Briefly the algorithm works like this:
@@ -325,15 +107,15 @@ exception_section ()
      output to start the protection for that block.
 
      When a destructor or end try block is encountered, pop_eh_entry
-     (&eh_stack) is called.  Pop_eh_entry () returns the ehEntry it
-     created when push_eh_entry () was called.  The ehEntry structure
+     (&eh_stack) is called.  Pop_eh_entry () returns the eh_entry it
+     created when push_eh_entry () was called.  The eh_entry structure
      contains three things at this point.  The start protect label,
      the end protect label, and the exception handler label.  The end
      protect label should be output before the call to the destructor
      (if any). If it was a destructor, then its parse tree is stored
-     in the finalization variable in the ehEntry structure.  Otherwise
+     in the finalization variable in the eh_entry structure.  Otherwise
      the finalization variable is set to NULL to reflect the fact that
-     is the the end of a try block.  Next, this modified ehEntry node
+     is the the end of a try block.  Next, this modified eh_entry node
      is enqueued in the finalizations queue by calling
      enqueue_eh_entry (&queue,entry).
 
@@ -352,35 +134,22 @@ exception_section ()
 
      Since we don't want to generate the catch block inline with the
      regular flow of the function, we need to have some way of doing
-     so.  Luckily, we have a couple of routines "get_last_insn ()" and
-     "set_last_insn ()" provided.  When the start of a catch block is
-     encountered, we save a pointer to the last insn generated.  After
-     the catch block is generated, we save a pointer to the first
-     catch block insn and the last catch block insn with the routines
-     "NEXT_INSN ()" and "get_last_insn ()".  We then set the last insn
-     to be the last insn generated before the catch block, and set the
-     NEXT_INSN (last_insn) to zero.
-
-     Since catch blocks might be nested inside other catch blocks, and
-     we munge the chain of generated insns after the catch block is
-     generated, we need to store the pointers to the last insn
-     generated in a stack, so that when the end of a catch block is
-     encountered, the last insn before the current catch block can be
-     popped and set to be the last insn, and the first and last insns
-     of the catch block just generated can be enqueue'd for output at
-     a later time.
-               
+     so.  Luckily, we can use sequences to defer the catch sections.
+     When the start of a catch block is encountered, we start the
+     sequence.  After the catch block is generated, we end the
+     sequence.
+
      Next we must insure that when the catch block is executed, all
      finalizations for the matching try block have been completed.  If
      any of those finalizations throw an exception, we must call
      terminate according to the ARM (section r.15.6.1).  What this
      means is that we need to dequeue and emit finalizations for each
-     entry in the ehQueue until we get to an entry with a NULL
+     entry in the eh_queue until we get to an entry with a NULL
      finalization field.  For any of the finalization entries, if it
      is not a call to terminate (), we must protect it by giving it
      another start label, end label, and exception handler label,
      setting its finalization tree to be a call to terminate (), and
-     enqueue'ing this new ehEntry to be output at an outer level.
+     enqueue'ing this new eh_entry to be output at an outer level.
      Finally, after all that is done, we can get around to outputting
      the catch block which basically wraps all the "catch (...) {...}"
      statements in a big if/then/else construct that matches the
@@ -395,69 +164,24 @@ extern rtx gen_nop                PROTO(());
    ====================================================================== */
 
 /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
-   "set_unexpected ()" after default_conversion. (lib-except.c) */
+   "set_unexpected ()" after default_conversion. (lib-except.c)  */
 static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
 
 /* used to cache __find_first_exception_table_match ()
    for throw (lib-except.c)  */
 static tree FirstExceptionMatch;
 
-/* used to cache a call to __unwind_function () (lib-except.c) */
+/* used to cache a call to __unwind_function () (lib-except.c)  */
 static tree Unwind;
 
-/* holds a ready to emit call to "terminate ()". */
+/* holds a ready to emit call to "terminate ()".  */
 static tree TerminateFunctionCall;
 
-/* ====================================================================== */
-
-
-
-/* data structures for my various quick and dirty stacks and queues
-   Eventually, most of this should go away, because I think it can be
-   integrated with stuff already built into the compiler. */
-
-/* =================================================================== */
-
-struct labelNode {
-    rtx label;
-       struct labelNode *chain;
- };
-
+static tree empty_fndecl;
 
-/* this is the most important structure here.  Basically this is how I store
-   an exception table entry internally. */
-struct ehEntry {
-    rtx start_label;
-       rtx end_label;
-       rtx exception_handler_label;
-
-       tree finalization;
- };
-
-struct ehNode {
-    struct ehEntry *entry;
-       struct ehNode *chain;
- };
-
-struct ehStack {
-    struct ehNode *top;
- };
-
-struct ehQueue {
-    struct ehNode *head;
-       struct ehNode *tail;
- };
-
-struct exceptNode {
-    rtx catchstart;
-       rtx catchend;
+/* ====================================================================== */
 
-       struct exceptNode *chain;
- };
 
-struct exceptStack {
-       struct exceptNode *top;
- };
 /* ========================================================================= */
 
 
@@ -468,791 +192,455 @@ struct exceptStack {
    ========================================================================= */
 
 /* Holds the pc for doing "throw" */
-rtx saved_pc;
-/* Holds the type of the thing being thrown. */
-rtx saved_throw_type;
+static tree saved_pc;
+/* Holds the type of the thing being thrown.  */
+static tree saved_throw_type;
 /* Holds the value being thrown.  */
-rtx saved_throw_value;
+static tree saved_throw_value;
+/* Holds the cleanup for the value being thrown.  */
+static tree saved_cleanup;
+/* Indicates if we are in a catch clause.  */
+static tree saved_in_catch;
 
-rtx throw_label;
+extern int throw_used;
+extern rtx catch_clauses;
 
-static struct ehStack ehstack;
-static struct ehQueue ehqueue;
-static struct ehQueue eh_table_output_queue;
-static struct exceptStack exceptstack;
-static struct labelNode *false_label_stack = NULL;
-static struct labelNode *caught_return_label_stack = NULL;
 /* ========================================================================= */
 
-/* function prototypes */
-static struct ehEntry *pop_eh_entry    PROTO((struct ehStack *stack));
-static void enqueue_eh_entry           PROTO((struct ehQueue *queue, struct ehEntry *entry));
-static void push_except_stmts          PROTO((struct exceptStack *exceptstack,
-                                        rtx catchstart, rtx catchend));
-static int pop_except_stmts            PROTO((struct exceptStack *exceptstack,
-                                        rtx *catchstart, rtx *catchend));
-static rtx push_eh_entry               PROTO((struct ehStack *stack));
-static struct ehEntry *dequeue_eh_entry        PROTO((struct ehQueue *queue));
-static void new_eh_queue               PROTO((struct ehQueue *queue));
-static void new_eh_stack               PROTO((struct ehStack *stack));
-static void new_except_stack           PROTO((struct exceptStack *queue));
-static void push_last_insn             PROTO(());
-static rtx pop_last_insn               PROTO(());
-static void push_label_entry           PROTO((struct labelNode **labelstack, rtx label));
-static rtx pop_label_entry             PROTO((struct labelNode **labelstack));
-static rtx top_label_entry             PROTO((struct labelNode **labelstack));
-static struct ehEntry *copy_eh_entry   PROTO((struct ehEntry *entry));
-
-
-
-/* All my cheesy stack/queue/misc data structure handling routines
-
-   ========================================================================= */
+/* Cheesyness to save some typing.  Returns the return value rtx.  */
 
-static void
-push_label_entry (labelstack, label)
-     struct labelNode **labelstack;
-     rtx label;
+static rtx
+do_function_call (func, params, return_type)
+     tree func, params, return_type;
 {
-  struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
-
-  newnode->label = label;
-  newnode->chain = *labelstack;
-  *labelstack = newnode;
+  tree func_call;
+  func_call = build_function_call (func, params);
+  expand_call (func_call, NULL_RTX, 0);
+  if (return_type != NULL_TREE)
+    return hard_function_value (return_type, func_call);
+  return NULL_RTX;
 }
 
-static rtx
-pop_label_entry (labelstack)
-     struct labelNode **labelstack;
-{
-  rtx label;
-  struct labelNode *tempnode;
+/* ========================================================================= */
 
-  if (! *labelstack) return NULL_RTX;
+extern tree auto_function PROTO((tree, tree, enum built_in_function));
 
-  tempnode = *labelstack;
-  label = tempnode->label;
-  *labelstack = (*labelstack)->chain;
-  free (tempnode);
+/* sets up all the global eh stuff that needs to be initialized at the
+   start of compilation.
 
-  return label;
-}
+   This includes:
+               - Setting up all the function call trees.  */
 
-static rtx
-top_label_entry (labelstack)
-     struct labelNode **labelstack;
+void
+init_exception_processing ()
 {
-  if (! *labelstack) return NULL_RTX;
+  extern tree define_function ();
+  tree unexpected_fndecl, terminate_fndecl;
+  tree set_unexpected_fndecl, set_terminate_fndecl;
+  tree catch_match_fndecl;
+  tree find_first_exception_match_fndecl;
+  tree unwind_fndecl;
+  tree declspecs;
+  tree d;
 
-  return (*labelstack)->label;
-}
+  /* void (*)() */
+  tree PFV = build_pointer_type (build_function_type
+                                (void_type_node, void_list_node));
 
-static void
-push_except_stmts (exceptstack, catchstart, catchend)
-     struct exceptStack *exceptstack;
-     rtx catchstart, catchend;
-{
-  struct exceptNode *newnode = (struct exceptNode*)
-    xmalloc (sizeof (struct exceptNode));
+  /* arg list for the build_function_type call for set_terminate () and
+     set_unexpected () */
+  tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
 
-  newnode->catchstart = catchstart;
-  newnode->catchend = catchend;
-  newnode->chain = exceptstack->top;
+  /* void (*pfvtype (void (*) ()))() */
+  tree pfvtype = build_function_type (PFV, pfvlist);
 
-  exceptstack->top = newnode;
-}
+  /* void vtype () */
+  tree vtype = build_function_type (void_type_node, void_list_node);
+  
+  set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
+                                       pfvtype, NOT_BUILT_IN);
+  set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
+                                        pfvtype, NOT_BUILT_IN);
+  unexpected_fndecl = auto_function (get_identifier ("unexpected"),
+                                    vtype, NOT_BUILT_IN);
+  terminate_fndecl = auto_function (get_identifier ("terminate"),
+                                   vtype, NOT_BUILT_IN);
 
-static int
-pop_except_stmts (exceptstack, catchstart, catchend)
-     struct exceptStack *exceptstack;
-     rtx *catchstart, *catchend;
-{
-  struct exceptNode *tempnode;
+  push_lang_context (lang_name_c);
 
-  if (!exceptstack->top) {
-    *catchstart = *catchend = NULL_RTX;
-    return 0;
-  }
+  catch_match_fndecl =
+    builtin_function (flag_rtti
+                     ? "__throw_type_match_rtti"
+                     : "__throw_type_match",
+                     build_function_type (ptr_type_node,
+                                          tree_cons (NULL_TREE, ptr_type_node,
+                                                     tree_cons (NULL_TREE, ptr_type_node,
+                                                                tree_cons (NULL_TREE, ptr_type_node,
+                                                                           void_list_node)))),
+                     NOT_BUILT_IN, NULL_PTR);
+  find_first_exception_match_fndecl =
+    builtin_function ("__find_first_exception_table_match",
+                     build_function_type (ptr_type_node,
+                                          tree_cons (NULL_TREE, ptr_type_node,
+                                                     void_list_node)),
+                     NOT_BUILT_IN, NULL_PTR);
+  unwind_fndecl =
+    builtin_function ("__unwind_function",
+                     build_function_type (void_type_node,
+                                          tree_cons (NULL_TREE, ptr_type_node,
+                                                     void_list_node)),
+                     NOT_BUILT_IN, NULL_PTR);
+  empty_fndecl =
+    builtin_function ("__empty",
+                     build_function_type (void_type_node, void_list_node),
+                     NOT_BUILT_IN, NULL_PTR);
+  DECL_EXTERNAL (empty_fndecl) = 1;
+  TREE_PUBLIC (empty_fndecl) = 1;
 
-  tempnode = exceptstack->top;
-  exceptstack->top = exceptstack->top->chain;
+  Unexpected = default_conversion (unexpected_fndecl);
+  Terminate = default_conversion (terminate_fndecl);
+  SetTerminate = default_conversion (set_terminate_fndecl);
+  SetUnexpected = default_conversion (set_unexpected_fndecl);
+  CatchMatch = default_conversion (catch_match_fndecl);
+  FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
+  Unwind = default_conversion (unwind_fndecl);
+  BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
 
-  *catchstart = tempnode->catchstart;
-  *catchend = tempnode->catchend;
-  free (tempnode);
+  TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
 
-  return 1;
-}
+  pop_lang_context ();
 
-/* Push to permanent obstack for rtl generation.
-   One level only!  */
-static struct obstack *saved_rtl_obstack;
-void
-push_rtl_perm ()
-{
-  extern struct obstack permanent_obstack;
-  extern struct obstack *rtl_obstack;
-  
-  saved_rtl_obstack = rtl_obstack;
-  rtl_obstack = &permanent_obstack;
+  declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
+  d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
+  d = start_decl (d, declspecs, 0);
+  DECL_COMMON (d) = 1;
+  cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
+  saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
+
+  declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
+  d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
+  d = start_decl (d, declspecs, 0);
+  DECL_COMMON (d) = 1;
+  cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
+  saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
+
+  declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
+  d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
+  d = start_decl (d, declspecs, 0);
+  DECL_COMMON (d) = 1;
+  cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
+  saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
+
+  declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
+  d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
+  d = make_call_declarator (d, void_list_node, NULL_TREE, NULL_TREE);
+  d = start_decl (d, declspecs, 0);
+  DECL_COMMON (d) = 1;
+  cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
+  saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
+
+  declspecs = tree_cons (NULL_TREE, get_identifier ("bool"), NULL_TREE);
+  d = get_identifier ("__eh_in_catch");
+  d = start_decl (d, declspecs, 0);
+  DECL_COMMON (d) = 1;
+  cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
+  saved_in_catch = lookup_name (get_identifier ("__eh_in_catch"), 0);
 }
 
-/* Pop back to normal rtl handling.  */
-static void
-pop_rtl_from_perm ()
-{
-  extern struct obstack permanent_obstack;
-  extern struct obstack *rtl_obstack;
-  
-  rtl_obstack = saved_rtl_obstack;
-}
+/* Build a type value for use at runtime for a type that is matched
+   against by the exception handling system.  */
 
-static rtx
-push_eh_entry (stack)
-     struct ehStack *stack;
+static tree
+build_eh_type_type (type)
+     tree type;
 {
-  struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
-  struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
-
-  if (stack == NULL) {
-    free (node);
-    free (entry);
-    return NULL_RTX;
-  }
+  char *typestring;
+  tree exp;
 
-  /* These are saved for the exception table.  */
-  push_rtl_perm ();
-  entry->start_label = gen_label_rtx ();
-  entry->end_label = gen_label_rtx ();
-  entry->exception_handler_label = gen_label_rtx ();
-  pop_rtl_from_perm ();
+  if (type == error_mark_node)
+    return error_mark_node;
 
-  entry->finalization = NULL_TREE;
+  /* peel back references, so they match.  */
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    type = TREE_TYPE (type);
 
-  node->entry = entry;
-  node->chain = stack->top;
-  stack->top = node;
+  /* Peel off cv qualifiers.  */
+  type = TYPE_MAIN_VARIANT (type);
 
-  enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
+  if (flag_rtti)
+    {
+      return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
+    }
 
-  return entry->start_label;
+  typestring = build_overload_name (type, 1, 1);
+  exp = combine_strings (build_string (strlen (typestring)+1, typestring));
+  return build1 (ADDR_EXPR, ptr_type_node, exp);
 }
 
-static struct ehEntry *
-pop_eh_entry (stack)
-     struct ehStack *stack;
-{
-  struct ehNode *tempnode;
-  struct ehEntry *tempentry;
-
-  if (stack && (tempnode = stack->top)) {
-    tempentry = tempnode->entry;
-    stack->top = stack->top->chain;
-    free (tempnode);
-
-    return tempentry;
-  }
-
-  return NULL;
-}
+/* Build a type value for use at runtime for a exp that is thrown or
+   matched against by the exception handling system.  */
 
-static struct ehEntry *
-copy_eh_entry (entry)
-     struct ehEntry *entry;
+static tree
+build_eh_type (exp)
+     tree exp;
 {
-  struct ehEntry *newentry;
-
-  newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
-  memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
-
-  return newentry;
+  if (flag_rtti)
+    {
+      exp = build_typeid (exp);
+      return build1 (ADDR_EXPR, ptr_type_node, exp);
+    }
+  return build_eh_type_type (TREE_TYPE (exp));
 }
 
+/* This routine creates the cleanup for the exception handling object.  */
+
 static void
-enqueue_eh_entry (queue, entry)
-     struct ehQueue *queue;
-     struct ehEntry *entry;
+push_eh_cleanup ()
 {
-  struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
+  /* All cleanups must last longer than normal.  */
+  int yes = suspend_momentary ();
 
-  node->entry = entry;
-  node->chain = NULL;
+  /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
+  tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
+  cleanup = build (COMPOUND_EXPR, void_type_node, cleanup,
+                  build_modify_expr (saved_in_catch, NOP_EXPR,
+                                     build_modify_expr (saved_throw_type, NOP_EXPR, integer_zero_node)));
+  expand_decl_cleanup (NULL_TREE, cleanup);
 
-  if (queue->head == NULL)
-    {
-      queue->head = node;
-    }
-  else
-    {
-      queue->tail->chain = node;
-    }
-  queue->tail = node;
+  resume_momentary (yes);
 }
 
-static struct ehEntry *
-dequeue_eh_entry (queue)
-     struct ehQueue *queue;
-{
-  struct ehNode *tempnode;
-  struct ehEntry *tempentry;
 
-  if (queue->head == NULL)
-    return NULL;
+/* call this to start a catch block. Typename is the typename, and identifier
+   is the variable to place the object in or NULL if the variable doesn't
+   matter.  If typename is NULL, that means its a "catch (...)" or catch
+   everything.  In that case we don't need to do any type checking.
+   (ie: it ends up as the "else" clause rather than an "else if" clause) */
 
-  tempnode = queue->head;
-  queue->head = queue->head->chain;
+void
+expand_start_catch_block (declspecs, declarator)
+     tree declspecs, declarator;
+{
+  rtx false_label_rtx;
+  tree decl = NULL_TREE;
+  tree init;
 
-  tempentry = tempnode->entry;
-  free (tempnode);
+  if (! doing_eh (1))
+    return;
 
-  return tempentry;
-}
-
-static void
-new_eh_queue (queue)
-     struct ehQueue *queue;
-{
-  queue->head = queue->tail = NULL;
-}
+  /* Create a binding level for the parm.  */
+  pushlevel (0);
+  expand_start_bindings (0);
 
-static void
-new_eh_stack (stack)
-     struct ehStack *stack;
-{
-  stack->top = NULL;
-}
+  false_label_rtx = gen_label_rtx ();
+  push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
 
-static void
-new_except_stack (stack)
-     struct exceptStack *stack;
-{
-  stack->top = NULL;
-}
-/* ========================================================================= */
+  if (declspecs)
+    {
+      tree exp;
+      rtx call_rtx, return_value_rtx;
+      tree init_type;
 
-void
-lang_interim_eh (finalization)
-     tree finalization;
-{
-  if (finalization)
-    end_protect (finalization);
-  else
-    start_protect ();
-}
+      decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
 
-/* sets up all the global eh stuff that needs to be initialized at the
-   start of compilation.
-
-   This includes:
-               - Setting up all the function call trees
-               - Initializing the ehqueue
-               - Initializing the eh_table_output_queue
-               - Initializing the ehstack
-               - Initializing the exceptstack
-*/
+      if (decl == NULL_TREE)
+       {
+         error ("invalid catch parameter");
 
-void
-init_exception_processing ()
-{
-  extern tree define_function ();
-  tree unexpected_fndecl, terminate_fndecl;
-  tree set_unexpected_fndecl, set_terminate_fndecl;
-  tree catch_match_fndecl;
-  tree find_first_exception_match_fndecl;
-  tree unwind_fndecl;
-  tree temp, PFV;
+         /* This is cheap, but we want to maintain the data structures.  */
+         expand_eh_region_start ();
+         return;
+       }
 
-  interim_eh_hook = lang_interim_eh;
+      /* Make sure we mark the catch param as used, otherwise we'll get
+        a warning about an unused ((anonymous)).  */
+      TREE_USED (decl) = 1;
 
-  /* void (*)() */
-  PFV = build_pointer_type (build_function_type (void_type_node, void_list_node));
+      /* Figure out the type that the initializer is.  */
+      init_type = TREE_TYPE (decl);
+      if (TREE_CODE (init_type) != REFERENCE_TYPE
+         && TREE_CODE (init_type) != POINTER_TYPE)
+       init_type = build_reference_type (init_type);
 
-  /* arg list for the build_function_type call for set_terminate () and
-     set_unexpected () */
-  temp = tree_cons (NULL_TREE, PFV, void_list_node);
+      exp = saved_throw_value;
+      exp = tree_cons (NULL_TREE,
+                      build_eh_type_type (TREE_TYPE (decl)),
+                      tree_cons (NULL_TREE,
+                                 saved_throw_type,
+                                 tree_cons (NULL_TREE, exp, NULL_TREE)));
+      exp = build_function_call (CatchMatch, exp);
+      call_rtx = expand_call (exp, NULL_RTX, 0);
+      assemble_external (TREE_OPERAND (CatchMatch, 0));
 
-  push_lang_context (lang_name_c);
+      return_value_rtx = hard_function_value (ptr_type_node, exp);
 
-  set_terminate_fndecl =
-    define_function ("set_terminate",
-                    build_function_type (PFV, temp),
-                    NOT_BUILT_IN,
-                    pushdecl,
-                    0);
-  set_unexpected_fndecl =
-    define_function ("set_unexpected",
-                    build_function_type (PFV, temp),
-                    NOT_BUILT_IN,
-                    pushdecl,
-                    0);
-
-  unexpected_fndecl =
-    define_function ("unexpected",
-                    build_function_type (void_type_node, void_list_node),
-                    NOT_BUILT_IN,
-                    pushdecl,
-                    0);
-  terminate_fndecl =
-    define_function ("terminate",
-                    build_function_type (void_type_node, void_list_node),
-                    NOT_BUILT_IN,
-                    pushdecl,
-                    0);
-  catch_match_fndecl =
-    define_function ("__throw_type_match",
-                    build_function_type (integer_type_node,
-                                         tree_cons (NULL_TREE, string_type_node, tree_cons (NULL_TREE, ptr_type_node, void_list_node))),
-                    NOT_BUILT_IN,
-                    pushdecl,
-                    0);
-  find_first_exception_match_fndecl =
-    define_function ("__find_first_exception_table_match",
-                    build_function_type (ptr_type_node,
-                                         tree_cons (NULL_TREE, ptr_type_node,
-                                                    void_list_node)),
-                    NOT_BUILT_IN,
-                    pushdecl,
-                    0);
-  unwind_fndecl =
-    define_function ("__unwind_function",
-                    build_function_type (void_type_node,
-                                         tree_cons (NULL_TREE, ptr_type_node, void_list_node)),
-                    NOT_BUILT_IN,
-                    pushdecl,
-                    0);
+      /* did the throw type match function return TRUE? */
+      emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
+                   GET_MODE (return_value_rtx), 0, 0);
 
-  Unexpected = default_conversion (unexpected_fndecl);
-  Terminate = default_conversion (terminate_fndecl);
-  SetTerminate = default_conversion (set_terminate_fndecl);
-  SetUnexpected = default_conversion (set_unexpected_fndecl);
-  CatchMatch = default_conversion (catch_match_fndecl);
-  FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
-  Unwind = default_conversion (unwind_fndecl);
-  BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
+      /* if it returned FALSE, jump over the catch block, else fall into it */
+      emit_jump_insn (gen_beq (false_label_rtx));
 
-  TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
+      push_eh_cleanup ();
 
-  pop_lang_context ();
-  throw_label = gen_label_rtx ();
-  saved_pc = gen_rtx (REG, Pmode, 16);
-  saved_throw_type = gen_rtx (REG, Pmode, 17);
-  saved_throw_value = gen_rtx (REG, Pmode, 18);
-
-  new_eh_queue (&ehqueue);
-  new_eh_queue (&eh_table_output_queue);
-  new_eh_stack (&ehstack);
-  new_except_stack (&exceptstack);
-}
+      init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
 
-/* call this to begin a block of unwind protection (ie: when an object is
-   constructed) */
-void
-start_protect ()
-{
-  if (doing_eh (0))
-    {
-      emit_label (push_eh_entry (&ehstack));
+      /* Do we need the below two lines? */
+      /* Let `cp_finish_decl' know that this initializer is ok.  */
+      DECL_INITIAL (decl) = init;
+      decl = pushdecl (decl);
+      cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
     }
-}
-   
-/* call this to end a block of unwind protection.  the finalization tree is
-   the finalization which needs to be run in order to cleanly unwind through
-   this level of protection. (ie: call this when a scope is exited)*/
-void
-end_protect (finalization)
-     tree finalization;
-{
-  struct ehEntry *entry = pop_eh_entry (&ehstack);
-
-  if (! doing_eh (0))
-    return;
-
-  emit_label (entry->end_label);
-
-  entry->finalization = finalization;
-
-  enqueue_eh_entry (&ehqueue, entry);
-}
-
-/* call this on start of a try block. */
-void
-expand_start_try_stmts ()
-{
-  if (doing_eh (1))
+  else
     {
-      start_protect ();
-    }
-}
-
-void
-expand_end_try_stmts ()
-{
-  end_protect (integer_zero_node);
-}
+      push_eh_cleanup ();
 
-struct insn_save_node {
-       rtx last;
-       struct insn_save_node *chain;
- };
+      /* Fall into the catch all section.  */
+    }
 
-static struct insn_save_node *InsnSave = NULL;
+  emit_move_insn (DECL_RTL (saved_in_catch), const1_rtx);
 
+  /* Because we are reordered out of line, we arrange
+     to rethrow in the outer context, should we encounter
+     an exception in the catch handler.
 
-/* Used to keep track of where the catch blocks start.  */
-static void
-push_last_insn ()
-{
-  struct insn_save_node *newnode = (struct insn_save_node*)
-    xmalloc (sizeof (struct insn_save_node));
+     Matches the end in expand_end_catch_block ().  */
+  expand_eh_region_start ();
 
-  newnode->last = get_last_insn ();
-  newnode->chain = InsnSave;
-  InsnSave = newnode;
+  emit_line_note (input_filename, lineno);
 }
 
-/* Use to keep track of where the catch blocks start.  */
-static rtx
-pop_last_insn ()
-{
-  struct insn_save_node *tempnode;
-  rtx temprtx;
-
-  if (!InsnSave) return NULL_RTX;
-
-  tempnode = InsnSave;
-  temprtx = tempnode->last;
-  InsnSave = InsnSave->chain;
 
-  free (tempnode);
 
-  return temprtx;
-}
+/* Call this to end a catch block.  Its responsible for emitting the
+   code to handle jumping back to the correct place, and for emitting
+   the label to jump to if this catch block didn't match.  */
 
-/* call this to start processing of all the catch blocks. */
-void
-expand_start_all_catch ()
+void expand_end_catch_block ()
 {
-  struct ehEntry *entry;
-  rtx label;
+  rtx start_region_label_rtx;
+  rtx end_region_label_rtx;
+  tree decls, t;
 
   if (! doing_eh (1))
     return;
 
-  emit_line_note (input_filename, lineno);
-  label = gen_label_rtx ();
-  /* The label for the exception handling block we will save.  */
-  emit_label (label);
-  
-  push_label_entry (&caught_return_label_stack, label);
+  /* Fall to outside the try statement when done executing handler and
+     we fall off end of handler.  This is jump Lresume in the
+     documentation.  */
+  expand_goto (top_label_entry (&caught_return_label_stack));
 
-  /* Remember where we started. */
-  push_last_insn ();
+  t = make_node (RTL_EXPR);
+  TREE_TYPE (t) = void_type_node;
+  RTL_EXPR_RTL (t) = const0_rtx;
+  TREE_SIDE_EFFECTS (t) = 1;
+  start_sequence_for_rtl_expr (t);
+  expand_internal_throw (DECL_RTL (top_label_entry (&caught_return_label_stack)));
+  RTL_EXPR_SEQUENCE (t) = get_insns ();
+  end_sequence ();
 
-  emit_insn (gen_nop ());
+  /* Matches the start in expand_start_catch_block ().  */
+  expand_eh_region_end (t);
 
-  /* Will this help us not stomp on it? */
-  emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
-  emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
-
-  while (1)
-    {
-      entry = dequeue_eh_entry (&ehqueue);
-      emit_label (entry->exception_handler_label);
-
-      expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
-
-      /* When we get down to the matching entry, stop.  */
-      if (entry->finalization == integer_zero_node)
-       break;
-
-      free (entry);
-    }
-
-  /* This goes when the below moves out of our way.  */
-#if 1
-  label = gen_label_rtx ();
-  emit_jump (label);
-#endif
-  
-  /* All this should be out of line, and saved back in the exception handler
-     block area.  */
-#if 1
-  entry->start_label = entry->exception_handler_label;
-  /* These are saved for the exception table.  */
-  push_rtl_perm ();
-  entry->end_label = gen_label_rtx ();
-  entry->exception_handler_label = gen_label_rtx ();
-  entry->finalization = TerminateFunctionCall;
-  pop_rtl_from_perm ();
-  emit_label (entry->end_label);
-
-  enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
-
-  /* After running the finalization, continue on out to the next
-     cleanup, if we have nothing better to do.  */
-  emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry->end_label));
-  /* Will this help us not stomp on it? */
-  emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
-  emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
-  emit_jump (throw_label);
-  emit_label (entry->exception_handler_label);
-  expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
-  emit_barrier ();
-#endif
-  emit_label (label);
-}
-
-/* call this to end processing of all the catch blocks. */
-void
-expand_end_all_catch ()
-{
-  rtx catchstart, catchend, last;
-  rtx label;
-
-  if (! doing_eh (1))
-    return;
-
-  /* Find the start of the catch block.  */
-  last = pop_last_insn ();
-  catchstart = NEXT_INSN (last);
-  catchend = get_last_insn ();
-
-  NEXT_INSN (last) = 0;
-  set_last_insn (last);
-
-  /* this level of catch blocks is done, so set up the successful catch jump
-     label for the next layer of catch blocks. */
-  pop_label_entry (&caught_return_label_stack);
+  expand_leftover_cleanups ();
 
-  push_except_stmts (&exceptstack, catchstart, catchend);
-  
-  /* Here we fall through into the continuation code.  */
+  /* Cleanup the EH parameter.  */
+  expand_end_bindings (getdecls (), kept_level_p (), 0);
+  poplevel (kept_level_p (), 1, 0);
+      
+  /* label we emit to jump to if this catch block didn't match.  */
+  /* This the closing } in the `if (eq) {' of the documentation.  */
+  emit_label (pop_label_entry (&false_label_stack));
 }
 
+/* unwind the stack.  */
 
-/* this is called from expand_exception_blocks () to expand the toplevel
-   finalizations for a function. */
-void
-expand_leftover_cleanups ()
-{
-  struct ehEntry *entry;
-  rtx first_label = NULL_RTX;
-
-  if (! doing_eh (0))
-    return;
-
-  /* Will this help us not stomp on it? */
-  emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
-  emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
-
-  while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
-    {
-      if (! first_label)
-       first_label = entry->exception_handler_label;
-      emit_label (entry->exception_handler_label);
-
-      expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
-
-      /* leftover try block, opps.  */
-      if (entry->finalization == integer_zero_node)
-       abort ();
-
-      free (entry);
-    }
-  if (first_label)
-    {
-      rtx label;
-      struct ehEntry entry;
-      /* These are saved for the exception table.  */
-      push_rtl_perm ();
-      label = gen_label_rtx ();
-      entry.start_label = first_label;
-      entry.end_label = label;
-      entry.exception_handler_label = gen_label_rtx ();
-      entry.finalization = TerminateFunctionCall;
-      pop_rtl_from_perm ();
-      emit_label (label);
-
-      enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
-
-      /* After running the finalization, continue on out to the next
-        cleanup, if we have nothing better to do.  */
-      emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry.end_label));
-      /* Will this help us not stomp on it? */
-      emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
-      emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
-      emit_jump (throw_label);
-      emit_label (entry.exception_handler_label);
-      expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
-      emit_barrier ();
-    }
-}
-
-/* call this to start a catch block. Typename is the typename, and identifier
-   is the variable to place the object in or NULL if the variable doesn't
-   matter.  If typename is NULL, that means its a "catch (...)" or catch
-   everything.  In that case we don't need to do any type checking.
-   (ie: it ends up as the "else" clause rather than an "else if" clause) */
-void
-expand_start_catch_block (declspecs, declarator)
-     tree declspecs, declarator;
+static void
+do_unwind (inner_throw_label)
+     rtx inner_throw_label;
 {
-  rtx false_label_rtx;
-  rtx protect_label_rtx;
-  tree type;
-  tree decl;
-  tree init;
-
-  if (! doing_eh (1))
-    return;
-
-  /* Create a binding level for the parm.  */
-  expand_start_bindings (0);
-
-  if (declspecs)
-    {
-      tree init_type;
-      decl = grokdeclarator (declarator, declspecs, NORMAL, 1, NULL_TREE);
-
-      /* Figure out the type that the initializer is. */
-      init_type = TREE_TYPE (decl);
-      if (TREE_CODE (init_type) != REFERENCE_TYPE)
-       init_type = build_reference_type (init_type);
-
-      init = convert_from_reference (save_expr (make_tree (init_type, saved_throw_value)));
-      
-      /* Do we need the below two lines? */
-      /* Let `finish_decl' know that this initializer is ok.  */
-      DECL_INITIAL (decl) = init;
-      /* This needs to be preallocated under the try block,
-        in a union of all catch variables. */
-      pushdecl (decl);
-      type = TREE_TYPE (decl);
-
-      /* peel back references, so they match. */
-      if (TREE_CODE (type) == REFERENCE_TYPE)
-       type = TREE_TYPE (type);
-    }
-  else
-    type = NULL_TREE;
-
-  false_label_rtx = gen_label_rtx ();
-  push_label_entry (&false_label_stack, false_label_rtx);
-
-  /* This is saved for the exception table.  */
-  push_rtl_perm ();
-  protect_label_rtx = gen_label_rtx ();
-  pop_rtl_from_perm ();
-  push_label_entry (&false_label_stack, protect_label_rtx);
-
-  if (type)
-    {
-      tree params;
-      char *typestring;
-      rtx call_rtx, return_value_rtx;
-      tree catch_match_fcall;
-      tree catchmatch_arg, argval;
-
-      typestring = build_overload_name (type, 1, 1);
-
-      params = tree_cons (NULL_TREE,
-                        combine_strings (build_string (strlen (typestring)+1, typestring)),
-                        tree_cons (NULL_TREE,
-                                   make_tree (ptr_type_node, saved_throw_type),
-                                   NULL_TREE));
-      catch_match_fcall = build_function_call (CatchMatch, params);
-      call_rtx = expand_call (catch_match_fcall, NULL_RTX, 0);
-
-      return_value_rtx =
-       hard_function_value (integer_type_node, catch_match_fcall);
-
-      /* did the throw type match function return TRUE? */
-      emit_cmp_insn (return_value_rtx, const0_rtx, NE, NULL_RTX,
-                   GET_MODE (return_value_rtx), 0, 0);
+#if defined (SPARC_STACK_ALIGN) /* was sparc */
+  /* This doesn't work for the flat model sparc, I bet.  */
+  tree fcall;
+  tree params;
+  rtx return_val_rtx;
+  rtx temp;
 
-      /* if it returned FALSE, jump over the catch block, else fall into it */
-      emit_jump_insn (gen_bne (false_label_rtx));
-      finish_decl (decl, init, NULL_TREE, 0);
-    }
-  else
-    {
-      /* Fall into the catch all section. */
-    }
+  /* call to  __builtin_return_address () */
+  params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
+  fcall = build_function_call (BuiltinReturnAddress, params);
+  return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
+  /* In the return, the new pc is pc+8, as the value coming in is
+     really the address of the call insn, not the next insn.  */
+  temp = gen_reg_rtx (Pmode);
+  emit_move_insn (temp, inner_throw_label);
+  emit_move_insn (return_val_rtx, plus_constant (temp, -8));
+  emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31)));
+  easy_expand_asm ("ret");
+  easy_expand_asm ("restore");
+  emit_barrier ();
+#endif
+#if defined (ARM_FRAME_RTX)  /* was __arm */
+  if (flag_omit_frame_pointer)
+    sorry ("this implementation of exception handling requires a frame pointer");
+
+  emit_move_insn (stack_pointer_rtx,
+                 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
+  emit_move_insn (hard_frame_pointer_rtx,
+                 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
+#endif
+#if defined (TARGET_88000) /* was m88k */
+  rtx temp_frame = frame_pointer_rtx;
 
-  /* This is the starting of something to protect.  */
-  emit_label (protect_label_rtx);
+  temp_frame = memory_address (Pmode, temp_frame);
+  temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
 
-  emit_line_note (input_filename, lineno);
-}
+  /* hopefully this will successfully pop the frame! */
+  emit_move_insn (frame_pointer_rtx, temp_frame);
+  emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+  emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
+  emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
+                                                    (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
 
+#if 0
+  emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
+                                                  -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
 
-/* Call this to end a catch block.  Its responsible for emitting the
-   code to handle jumping back to the correct place, and for emitting
-   the label to jump to if this catch block didn't match.  */
-void expand_end_catch_block ()
-{
-  if (doing_eh (1))
-    {
-      rtx start_protect_label_rtx;
-      rtx end_protect_label_rtx;
-      tree decls;
-      struct ehEntry entry;
-
-      /* label we jump to if we caught the exception */
-      emit_jump (top_label_entry (&caught_return_label_stack));
-
-      /* Code to throw out to outer context, if we get an throw from within
-        our catch handler. */
-      /* These are saved for the exception table.  */
-      push_rtl_perm ();
-      entry.exception_handler_label = gen_label_rtx ();
-      pop_rtl_from_perm ();
-      emit_label (entry.exception_handler_label);
-      emit_move_insn (saved_pc, gen_rtx (LABEL_REF,
-                                        Pmode,
-                                        top_label_entry (&caught_return_label_stack)));
-      emit_jump (throw_label);
-      /* No associated finalization.  */
-      entry.finalization = NULL_TREE;
-
-      /* Because we are reordered out of line, we have to protect this. */
-      /* label for the start of the protection region.  */
-      start_protect_label_rtx = pop_label_entry (&false_label_stack);
-
-      /* Cleanup the EH paramater.  */
-      expand_end_bindings (decls = getdecls (), decls != NULL_TREE, 0);
-      
-      /* label we emit to jump to if this catch block didn't match. */
-      emit_label (end_protect_label_rtx = pop_label_entry (&false_label_stack));
+  emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
 
-      /* Because we are reordered out of line, we have to protect this. */
-      entry.start_label = start_protect_label_rtx;
-      entry.end_label = end_protect_label_rtx;
+  emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
+                                                    (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
+#endif
+#endif
+#if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
+  tree fcall;
+  tree params;
+  rtx return_val_rtx;
 
-      /* These set up a call to throw the caught exception into the outer
-       context.  */
-      enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
-    }
-}
+#if 0
+  /* I would like to do this here, but the move below doesn't seem to work.  */
+  /* call to  __builtin_return_address () */
+  params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
+  fcall = build_function_call (BuiltinReturnAddress, params);
+  return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
 
-/* cheesyness to save some typing. returns the return value rtx */
-rtx
-do_function_call (func, params, return_type)
-     tree func, params, return_type;
-{
-  tree func_call;
-  func_call = build_function_call (func, params);
-  expand_call (func_call, NULL_RTX, 0);
-  if (return_type != NULL_TREE)
-    return hard_function_value (return_type, func_call);
-  return NULL_RTX;
+  emit_move_insn (return_val_rtx, inner_throw_label);
+  /* So, for now, just pass throw label to stack unwinder.  */
+#endif
+  params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
+                                           inner_throw_label), NULL_TREE);
+  
+  do_function_call (Unwind, params, NULL_TREE);
+  assemble_external (TREE_OPERAND (Unwind, 0));
+  emit_barrier ();
+#endif
 }
 
 
-/* is called from expand_excpetion_blocks () to generate the code in a function
-   to "throw" if anything in the function needs to preform a throw.
+/* is called from expand_exception_blocks () to generate the code in a function
+   to "throw" if anything in the function needs to perform a throw.
 
-   expands "throw" as the following psuedo code:
+   expands "throw" as the following pseudo code:
 
        throw:
                eh = find_first_exception_match (saved_pc);
@@ -1262,26 +650,59 @@ do_function_call (func, params, return_type)
        gotta_rethrow_it:
                saved_pc = __builtin_return_address (0);
                pop_to_previous_level ();
-               goto throw;
+               goto throw;  */
 
- */
-static void
+void
 expand_builtin_throw ()
 {
   tree fcall;
   tree params;
   rtx return_val_rtx;
-  rtx gotta_rethrow_it = gen_label_rtx ();
-  rtx gotta_call_terminate = gen_label_rtx ();
-  rtx unwind_and_throw = gen_label_rtx ();
-  rtx goto_unwind_and_throw = gen_label_rtx ();
+  rtx gotta_rethrow_it;
+  rtx gotta_call_terminate;
+  rtx top_of_loop;
+  rtx unwind_first;
+  tree t;
+
+  if (! doing_eh (0))
+    return;
+
+  if (! throw_used)
+    return;
+
+  params = void_list_node;
+  t = make_call_declarator (get_identifier ("__throw"), params, NULL_TREE,
+                           NULL_TREE);
+  start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
+                                 void_list_node),
+                 t, NULL_TREE, 0);
+  store_parm_decls ();
+  pushlevel (0);
+  clear_last_expr ();
+  push_momentary ();
+  expand_start_bindings (0);
+
+  gotta_rethrow_it = gen_label_rtx ();
+  gotta_call_terminate = gen_label_rtx ();
+  top_of_loop = gen_label_rtx ();
+  unwind_first = gen_label_rtx ();
+
+  /* These two can be frontend specific.  If wanted, they can go in
+     expand_throw.  */
+  /* Do we have a valid object we are throwing? */
+  emit_cmp_insn (DECL_RTL (saved_throw_type), const0_rtx, EQ, NULL_RTX,
+                GET_MODE (DECL_RTL (saved_throw_type)), 0, 0);
+  emit_jump_insn (gen_beq (gotta_call_terminate));
+
+  emit_jump (unwind_first);
 
-  emit_label (throw_label);
+  emit_label (top_of_loop);
 
   /* search for an exception handler for the saved_pc */
   return_val_rtx = do_function_call (FirstExceptionMatch,
-                                    tree_cons (NULL_TREE, make_tree (ptr_type_node, saved_pc), NULL_TREE),
+                                    tree_cons (NULL_TREE, saved_pc, NULL_TREE),
                                     ptr_type_node);
+  assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
 
   /* did we find one? */
   emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
@@ -1297,9 +718,16 @@ expand_builtin_throw ()
   emit_label (gotta_rethrow_it);
 
   /* call to  __builtin_return_address () */
-  params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
+#if defined (ARM_FRAME_RTX)  /* was __arm */
+  /* This should be moved into arm.h:RETURN_ADDR_RTX */
+  /* This replaces a 'call' to __builtin_return_address */
+  return_val_rtx = gen_reg_rtx (Pmode);
+  emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
+#else
+  params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
   fcall = build_function_call (BuiltinReturnAddress, params);
-  return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
+  return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
+#endif
 
   /* did __builtin_return_address () return a valid address? */
   emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
@@ -1307,173 +735,408 @@ expand_builtin_throw ()
 
   emit_jump_insn (gen_beq (gotta_call_terminate));
 
-  /* yes it did */
-  emit_move_insn (saved_pc, return_val_rtx);
-  do_unwind (throw_label);
-  emit_jump (throw_label);
+  return_val_rtx = eh_outer_context (return_val_rtx);
+
+  /* Yes it did.  */
+  emit_move_insn (eh_saved_pc_rtx, return_val_rtx);
+
+  do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop));
+  emit_jump (top_of_loop);
 
   /* no it didn't --> therefore we need to call terminate */
   emit_label (gotta_call_terminate);
   do_function_call (Terminate, NULL_TREE, NULL_TREE);
+  assemble_external (TREE_OPERAND (Terminate, 0));
+
+  {
+    rtx ret_val, return_val_rtx;
+    emit_label (unwind_first);
+    ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
+                                         0, hard_frame_pointer_rtx);
+
+    /* Set it up so that we continue inside, at the top of the loop.  */
+    emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
+#ifdef RETURN_ADDR_OFFSET
+  return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
+    if (return_val_rtx != ret_val)
+      emit_move_insn (ret_val, return_val_rtx);
+#endif
+
+    /* Fall into epilogue to unwind prologue.  */
+  }
+
+  expand_end_bindings (getdecls (), 1, 0);
+  poplevel (1, 0, 0);
+  pop_momentary ();
+
+  finish_function (lineno, 0, 0);
+}
+
+
+void
+expand_start_eh_spec ()
+{
+  expand_eh_region_start ();
 }
 
+static void
+expand_end_eh_spec (raises)
+     tree raises;
+{
+  tree expr, second_try;
+  rtx check = gen_label_rtx ();
+  rtx cont;
+  rtx ret = gen_reg_rtx (Pmode);
+  rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
+  rtx end = gen_label_rtx ();
+
+  expr = make_node (RTL_EXPR);
+  TREE_TYPE (expr) = void_type_node;
+  RTL_EXPR_RTL (expr) = const0_rtx;
+  TREE_SIDE_EFFECTS (expr) = 1;
+  start_sequence_for_rtl_expr (expr);
+  cont = gen_label_rtx ();
+  emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
+  emit_jump (check);
+  emit_label (cont);
+  jumpif (make_tree (integer_type_node, flag), end);
+  do_function_call (Terminate, NULL_TREE, NULL_TREE);
+  assemble_external (TREE_OPERAND (Terminate, 0));
+  emit_barrier ();
+  RTL_EXPR_SEQUENCE (expr) = get_insns ();
+  end_sequence ();
+  
+  second_try = expr;
+
+  expr = make_node (RTL_EXPR);
+  TREE_TYPE (expr) = void_type_node;
+  RTL_EXPR_RTL (expr) = const0_rtx;
+  TREE_SIDE_EFFECTS (expr) = 1;
+  start_sequence_for_rtl_expr (expr);
+
+  cont = gen_label_rtx ();
+  emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
+  emit_jump (check);
+  emit_label (cont);
+  jumpif (make_tree (integer_type_node, flag), end);
+  expand_eh_region_start ();
+  do_function_call (Unexpected, NULL_TREE, NULL_TREE);
+  assemble_external (TREE_OPERAND (Unexpected, 0));
+  emit_barrier ();
+  expand_eh_region_end (second_try);
+  
+  emit_label (check);
+  emit_move_insn (flag, const1_rtx);
+  cont = gen_label_rtx ();
+  while (raises)
+    {
+      tree exp;
+      tree match_type = TREE_VALUE (raises);
+      
+      if (match_type)
+       {
+         /* check TREE_VALUE (raises) here */
+         exp = saved_throw_value;
+         exp = tree_cons (NULL_TREE,
+                          build_eh_type_type (match_type),
+                          tree_cons (NULL_TREE,
+                                     saved_throw_type,
+                                     tree_cons (NULL_TREE, exp, NULL_TREE)));
+         exp = build_function_call (CatchMatch, exp);
+         assemble_external (TREE_OPERAND (CatchMatch, 0));
+
+         jumpif (exp, cont);
+       }
+
+      raises = TREE_CHAIN (raises);
+    }
+  emit_move_insn (flag, const0_rtx);
+  emit_label (cont);
+  emit_indirect_jump (ret);
+  emit_label (end);
+  
+  RTL_EXPR_SEQUENCE (expr) = get_insns ();
+  end_sequence ();
+  
+  expand_eh_region_end (expr);
+}
 
 /* This is called to expand all the toplevel exception handling
    finalization for a function.  It should only be called once per
    function.  */
+
 void
 expand_exception_blocks ()
 {
-  rtx catchstart, catchend;
-  rtx last;
-  static rtx funcend;
+  rtx funcend;
+  rtx insn, insns;
+  rtx eh_spec_insns = NULL_RTX;
+
+  start_sequence ();
 
   funcend = gen_label_rtx ();
   emit_jump (funcend);
   /* expand_null_return (); */
 
-  while (pop_except_stmts (&exceptstack, &catchstart, &catchend)) {
-    last = get_last_insn ();
-    NEXT_INSN (last) = catchstart;
-    PREV_INSN (catchstart) = last;
-    NEXT_INSN (catchend) = 0;
-    set_last_insn (catchend);
-  }
+  start_sequence ();
+
+  /* Add all the catch clauses here.  */
+  emit_insns (catch_clauses);
+  catch_clauses = NULL_RTX;
 
   expand_leftover_cleanups ();
 
+  insns = get_insns ();
+  end_sequence ();
+  
+  /* Do this after we expand leftover cleanups, so that the expand_eh_region_end
+     that expand_end_eh_spec does will match the right expand_eh_region_start,
+     and make sure it comes out before the terminate protected region.  */
+  if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
+    {
+#if 1
+      {
+       rtx insns;
+       /* New...  */
+       start_sequence ();
+       expand_start_eh_spec ();
+       eh_spec_insns = get_insns ();
+       end_sequence ();
+      }
+#endif
+
+      expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
+      push_to_sequence (insns);
+
+      /* Now expand any new ones.  */
+      expand_leftover_cleanups ();
+
+      insns = get_insns ();
+      end_sequence ();
+    }
+
+  if (insns)
+    {
+      /* Is this necessary?  */
+      assemble_external (TREE_OPERAND (Terminate, 0));
+
+      expand_eh_region_start ();
+      emit_insns (insns);
+      expand_eh_region_end (TerminateFunctionCall);
+      expand_leftover_cleanups ();
+    }
+
   {
-    static int have_done = 0;
-    if (! have_done && TREE_PUBLIC (current_function_decl)
-       && ! DECL_INLINE (current_function_decl))
+    /* Mark the end of the stack unwinder.  */
+    rtx unwind_insns;
+    start_sequence ();
+#if 0
+    end_eh_unwinder ();
+#endif
+    unwind_insns = get_insns ();
+    end_sequence ();
+    if (unwind_insns)
       {
-       have_done = 1;
-       expand_builtin_throw ();
+       insns = unwind_insns;
+       emit_insns (insns);
       }
   }
+
   emit_label (funcend);
+
+  /* Only if we had previous insns do we want to emit the jump around
+     them.  If there weren't any, then insns will remain NULL_RTX.  */
+  if (insns)
+    insns = get_insns ();
+  end_sequence ();
+
+#if 1
+  if (eh_spec_insns)
+    emit_insns_after (eh_spec_insns, get_insns ());
+#else
+  if (eh_spec_insns)
+    store_after_parms (eh_spec_insns);
+#endif
+
+  insn = get_last_insn ();
+  while (GET_CODE (insn) == NOTE
+        || (GET_CODE (insn) == INSN
+            && (GET_CODE (PATTERN (insn)) == USE
+                || GET_CODE (PATTERN (insn)) == CLOBBER)))
+    insn = PREV_INSN (insn);
+    
+  emit_insns_after (insns, insn);
 }
 
+tree
+start_anon_func ()
+{
+  static int counter = 0;
+  int old_interface_unknown = interface_unknown;
+  char name[32];
+  tree params;
+  tree t;
+
+  push_cp_function_context (NULL_TREE);
+  push_to_top_level ();
+
+  /* No need to mangle this.  */
+  push_lang_context (lang_name_c);
+
+  interface_unknown = 1;
+
+  params = void_list_node;
+  /* tcf stands for throw clean funciton.  */
+  sprintf (name, "__tcf_%d", counter++);
+  t = make_call_declarator (get_identifier (name), params, NULL_TREE,
+                           NULL_TREE);
+  start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
+                                 void_list_node),
+                 t, NULL_TREE, 0);
+  store_parm_decls ();
+  pushlevel (0);
+  clear_last_expr ();
+  push_momentary ();
+  expand_start_bindings (0);
+  emit_line_note (input_filename, lineno);
+
+  interface_unknown = old_interface_unknown;
 
-/* call this to expand a throw statement.  This follows the following
+  pop_lang_context ();
+
+  return current_function_decl;
+}
+
+void
+end_anon_func ()
+{
+  expand_end_bindings (getdecls (), 1, 0);
+  poplevel (1, 0, 0);
+  pop_momentary ();
+
+  finish_function (lineno, 0, 0);
+
+  pop_from_top_level ();
+  pop_cp_function_context (NULL_TREE);
+}
+
+/* Expand a throw statement.  This follows the following
    algorithm:
 
        1. Allocate space to save the current PC onto the stack.
        2. Generate and emit a label and save its address into the
-               newly allocate stack space since we can't save the pc directly.
+               newly allocated stack space since we can't save the pc directly.
        3. If this is the first call to throw in this function:
                generate a label for the throw block
        4. jump to the throw block label.  */
+
 void
 expand_throw (exp)
      tree exp;
 {
   rtx label;
-  tree type;
 
   if (! doing_eh (1))
     return;
 
-  /* This is the label that represents where in the code we were, when
-     we got an exception.  This needs to be updated when we rethrow an
-     exception, so that the matching routine knows to search out.  */
-  label = gen_label_rtx ();
-  emit_label (label);
-  emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, label));
-
   if (exp)
     {
-      /* throw expression */
-      /* First, decay it. */
-      exp = default_conversion (exp);
-      type = TREE_TYPE (exp);
-
-      {
-       char *typestring = build_overload_name (type, 1, 1);
-       tree throw_type = build1 (ADDR_EXPR, ptr_type_node, combine_strings (build_string (strlen (typestring)+1, typestring)));
-       rtx throw_type_rtx = expand_expr (throw_type, NULL_RTX, VOIDmode, 0);
-       rtx throw_value_rtx;
-
-       emit_move_insn (saved_throw_type, throw_type_rtx);
-       exp = convert_to_reference (build_reference_type (build_type_variant (TREE_TYPE (exp), 1, 0)), exp, CONV_STATIC, LOOKUP_COMPLAIN, NULL_TREE);
-       if (exp == error_mark_node)
-         error ("  in thrown expression");
-       throw_value_rtx = expand_expr (build_unary_op (ADDR_EXPR, exp, 0), NULL_RTX, VOIDmode, 0);
-       emit_move_insn (saved_throw_value, throw_value_rtx);
-      }
-    }
-  else
-    {
-      /* rethrow current exception */
-      /* This part is easy, as we dont' have to do anything else.  */
-    }
-
-  emit_jump (throw_label);
-}
+      tree throw_type;
+      tree cleanup = empty_fndecl, e;
 
-/* end of: my-cp-except.c */
-#endif
+      /* throw expression */
+      /* First, decay it.  */
+      exp = decay_conversion (exp);
 
+      if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
+       {
+         throw_type = build_eh_type (exp);
+         exp = build_reinterpret_cast (ptr_type_node, exp);
+       }
+      else
+       {
+         rtx cleanup_insns;
+         tree object;
+
+         /* Make a copy of the thrown object.  WP 15.1.5  */
+         exp = build_new (NULL_TREE, TREE_TYPE (exp),
+                          build_tree_list (NULL_TREE, exp),
+                          0);
+
+         if (exp == error_mark_node)
+           error ("  in thrown expression");
+
+         object = build_indirect_ref (exp, NULL_PTR);
+         throw_type = build_eh_type (object);
+
+         start_sequence ();
+         object = build_reinterpret_cast (TREE_TYPE (exp), saved_throw_value);
+         object = build_indirect_ref (object, NULL_PTR);
+         cleanup = maybe_build_cleanup_and_delete (object);
+         if (cleanup)
+           expand_expr (cleanup, const0_rtx, VOIDmode, 0);
+         cleanup_insns = get_insns ();
+         end_sequence ();
+
+         if (cleanup && cleanup_insns)
+           {
+             cleanup = start_anon_func ();
+
+             expand_expr (maybe_build_cleanup_and_delete (object),
+                          const0_rtx, VOIDmode, 0);
+
+             end_anon_func ();
+
+             mark_addressable (cleanup);
+           }
+         else
+           {
+             cleanup = empty_fndecl;
+           }
+       }
 
-/* Output the exception table.
- Return the number of handlers.  */
-int
-build_exception_table ()
-{
-  int count = 0;
-#ifdef TRY_NEW_EH
-  extern FILE *asm_out_file;
-  struct ehEntry *entry;
-  tree eh_node_decl;
+      if (cleanup == empty_fndecl)
+       assemble_external (empty_fndecl);
+       
+      e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
+      expand_expr (e, const0_rtx, VOIDmode, 0);
 
-  if (! doing_eh (0))
-    return 0;
-
- while (entry = dequeue_eh_entry (&eh_table_output_queue))
-   {
-     if (count == 0)
-       {
-        exception_section ();
-
-        /* Beginning marker for table. */
-        ASM_OUTPUT_ALIGN (asm_out_file, 2);
-        ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_TABLE__");
-        fprintf (asm_out_file, "        .word   0, 0, 0\n");
-       }
-     count++;
-     output_exception_table_entry (asm_out_file,
-                                  entry->start_label, entry->end_label,
-                                  entry->exception_handler_label);
-  }
+      e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
+      e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
+      expand_expr (e, const0_rtx, VOIDmode, 0);
 
-  if (count)
+      cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
+      cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
+      expand_expr (cleanup, const0_rtx, VOIDmode, 0);
+    }
+  else
     {
-      /* Ending marker for table. */
-      ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_END__");
-      fprintf (asm_out_file, "        .word   -1, -1, -1\n");
+      /* rethrow current exception */
+      /* This part is easy, as we don't have to do anything else.  */
     }
 
-#endif /* TRY_NEW_EH */
-  return count;
-}
+  /* This is the label that represents where in the code we were, when
+     we got an exception.  This needs to be updated when we rethrow an
+     exception, so that the matching routine knows to search out.  */
+  label = gen_label_rtx ();
+  emit_label (label);
 
-void
-register_exception_table ()
-{
-#ifdef TRY_NEW_EH
-  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
-                    VOIDmode, 1,
-                    gen_rtx (SYMBOL_REF, PTRmode, "__EXCEPTION_TABLE__"),
-                    Pmode);
-#endif /* TRY_NEW_EH */
+  expand_internal_throw (label);
 }
 
 /* Build a throw expression.  */
+
 tree
 build_throw (e)
      tree e;
 {
-  e = build1 (THROW_EXPR, void_type_node, e);
-  TREE_SIDE_EFFECTS (e) = 1;
+  if (e != error_mark_node)
+    {
+      if (processing_template_decl)
+       return build_min (THROW_EXPR, void_type_node, e);
+      e = build1 (THROW_EXPR, void_type_node, e);
+      TREE_SIDE_EFFECTS (e) = 1;
+      TREE_USED (e) = 1;
+    }
   return e;
 }