OSDN Git Service

(struct function): Make frame_offset be HOST_WIDE_INT.
[pf3gnuchains/gcc-fork.git] / gcc / cp / except.c
index d0fe130..fefcd02 100644 (file)
@@ -1,6 +1,8 @@
 /* Handle exceptional things in C++.
-   Copyright (C) 1989, 1992, 1993 Free Software Foundation, Inc.
-   Contributed by Michael Tiemann (tiemann@cygnus.com)
+   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.
 
 This file is part of GNU CC.
 
@@ -16,1209 +18,1125 @@ 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"
 #include "cp-tree.h"
 #include "flags.h"
-/* On Suns this can get you to the right definition if you
-   set the right value for TARGET.  */
-#include <setjmp.h>
-#ifdef sequent
-/* Can you believe they forgot this?  */
-#define _JBLEN 11
-#endif
+#include "obstack.h"
+#include "expr.h"
+#include "output.h"
+#include "except.h"
+#include "function.h"
 
-#ifndef _JBLEN
-#define _JBLEN (sizeof(jmp_buf)/sizeof(int))
-#endif
+rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
 
-#undef NULL
-#define NULL (char *)0
+/* holds the fndecl for __builtin_return_address () */
+tree builtin_return_address_fndecl;
 
-/* This should be part of `ansi_opname', or at least be defined by the std.  */
-#define EXCEPTION_NAME_PREFIX "__ex"
-#define EXCEPTION_NAME_LENGTH 4
+/* A couple of backend routines from m88k.c */
 
-void init_exception_processing ();
-void init_exception_processing_1 ();
+/* used to cache a call to __builtin_return_address () */
+static tree BuiltinReturnAddress;
+     
 
-/* If non-zero, a VAR_DECL whose cleanup will cause a throw to the
-   next exception handler.  Its value says whether to throw or not.
-   In the case of functions which do not issue a RAISE, it should be
-   possible to optimize away this VAR_DECL (and overhead associated
-   with it).  */
-tree exception_throw_decl;
-/* Use this to know that we did not set `exception_throw_decl',
-   until GCC optimizer is smart enough to figure it out for itself.  */
-int sets_exception_throw_decl;
+#include <stdio.h>
 
-/* The exception `type' currently in scope, or NULL_TREE if none.  */
-tree current_exception_type;
+static void
+easy_expand_asm (str)
+     char *str;
+{
+  expand_asm (build_string (strlen (str)+1, str));
+}
 
-/* The exception handler object for the given scope.  */
-tree current_exception_decl;
-rtx current_exception_name_as_rtx;
-rtx current_exception_parms_as_rtx;
 
-/* The ``object'' view of the current exception parameters.
-   We cast up from the `parms' field to `current_exception_type'.  */
-tree current_exception_object;
+#if 0
+/* This is the startup, and finish stuff per exception table.  */
 
-/* Cache `setjmp', `longjmp', `raise_exception', and `unhandled_exception'
-   after default conversion.  Maybe later they will get built-in.  */
-static tree BISJ, BILJ, BIR, BIUE;
+/* XXX - Tad: exception handling section */
+#ifndef EXCEPT_SECTION_ASM_OP
+#define EXCEPT_SECTION_ASM_OP  "section\t.gcc_except_table,\"a\",@progbits"
+#endif
 
-/* Local variables which give the appearance that exception
-   handling is part of the language and the execution model.  */
+#ifdef EXCEPT_SECTION_ASM_OP
+typedef struct {
+    void *start_region;
+    void *end_region;
+    void *exception_handler;
+ } exception_table;
+#endif /* EXCEPT_SECTION_ASM_OP */
 
-/* The type of the exception handler stack.  */
-tree EHS_type;
+#ifdef EXCEPT_SECTION_ASM_OP
 
-/* The global handler stack.  */
-tree EHS_decl;
+ /* on machines which support it, the exception table lives in another section,
+       but it needs a label so we can reference it...  This sets up that
+    label! */
+asm (EXCEPT_SECTION_ASM_OP);
+exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
+asm (TEXT_SECTION_ASM_OP);
 
-/* Cached component refs to fields of `EHS_decl'.  */
-static tree EHS_prev, EHS_handler, EHS_parms, EHS_name;
-static rtx EHS_parms_as_rtx, EHS_name_as_rtx;
+#endif /* EXCEPT_SECTION_ASM_OP */
 
-/* The parameter names of this exception type.  */
+#ifdef EXCEPT_SECTION_ASM_OP
 
-static tree last_exception_fields;
-static tree last_exception_field_types;
+ /* we need to know where the end of the exception table is... so this
+    is how we do it! */
 
-/* When ID is VOID_TYPE_NODE, it means ``raise all''.
-   Cannot be inline, since it uses `alloca', and that
-   breaks code which pushes the result of this function
-   on the stack.  */
-static tree
-exception_object_name (prefix, id)
-     tree prefix;
-     tree id;
-{
-  /* First, cons up the `name' of this exception.  */
-  char *name;
-  int length = (id == void_type_node ? 3 : IDENTIFIER_LENGTH (id)) + EXCEPTION_NAME_LENGTH;
+asm (EXCEPT_SECTION_ASM_OP);
+exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
+asm (TEXT_SECTION_ASM_OP);
 
-  if (prefix)
-    length += IDENTIFIER_LENGTH (prefix) + 2;
+#endif /* EXCEPT_SECTION_ASM_OP */
 
-  name = (char *)alloca (length);
-  strcpy (name, EXCEPTION_NAME_PREFIX);
-  length = EXCEPTION_NAME_LENGTH;
-  if (prefix)
-    {
-      strcpy (name + length, IDENTIFIER_POINTER (prefix));
-#ifdef JOINER
-      name[length + IDENTIFIER_LENGTH (prefix)] = JOINER;
-#else
-      name[length + IDENTIFIER_LENGTH (prefix)] = '_';
 #endif
-      length += IDENTIFIER_LENGTH (prefix) + 1;
-    }
-  if (id == void_type_node)
-    strcpy (name + length, "all");
-  else
-    strcpy (name + length, IDENTIFIER_POINTER (id));
-  return get_identifier (name);
-}
 
-tree
-lookup_exception_cname (ctype, cname, raise_id)
-     tree ctype, cname;
-     tree raise_id;
+#include "decl.h"
+#include "insn-flags.h"
+#include "obstack.h"
+
+/* ======================================================================
+   Briefly the algorithm works like this:
+
+     When a constructor or start of a try block is encountered,
+     push_eh_entry (&eh_stack) is called.  Push_eh_entry () creates a
+     new entry in the unwind protection stack and returns a label to
+     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 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 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 eh_entry node
+     is enqueued in the finalizations queue by calling
+     enqueue_eh_entry (&queue,entry).
+
+       +---------------------------------------------------------------+
+       |XXX: Will need modification to deal with partially             |
+       |                       constructed arrays of objects           |
+       |                                                               |
+       |       Basically, this consists of keeping track of how many   |
+       |       of the objects have been constructed already (this      |
+       |       should be in a register though, so that shouldn't be a  |
+       |       problem.                                                |
+       +---------------------------------------------------------------+
+
+     When a catch block is encountered, there is a lot of work to be
+     done.
+
+     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 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 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 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
+     correct block to call.
+     
+     ===================================================================== */
+
+extern rtx emit_insn           PROTO((rtx));
+extern rtx gen_nop             PROTO(());
+
+/* local globals for function calls
+   ====================================================================== */
+
+/* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
+   "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)  */
+static tree Unwind;
+
+/* holds a ready to emit call to "terminate ()".  */
+static tree TerminateFunctionCall;
+
+static tree empty_fndecl;
+
+/* ====================================================================== */
+
+
+/* ========================================================================= */
+
+
+
+/* local globals - these local globals are for storing data necessary for
+   generating the exception table and code in the correct order.
+
+   ========================================================================= */
+
+/* Holds the pc for doing "throw" */
+static tree saved_pc;
+/* Holds the type of the thing being thrown.  */
+static tree saved_throw_type;
+/* Holds the value being thrown.  */
+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;
+
+extern int throw_used;
+extern rtx catch_clauses;
+
+/* ========================================================================= */
+
+/* Cheesyness to save some typing.  Returns the return value rtx.  */
+
+static rtx
+do_function_call (func, params, return_type)
+     tree func, params, return_type;
 {
-  tree this_cname = TREE_PURPOSE (raise_id);
-  if (this_cname == NULL_TREE)
-    {
-      if (cname)
-       {
-         tree name = TREE_VALUE (raise_id);
-         if (purpose_member (name, CLASSTYPE_TAGS (ctype)))
-           this_cname = cname;
-       }
-    }
-  else if (this_cname == void_type_node)
-    this_cname = NULL_TREE;
-  else if (TREE_CODE (this_cname) != IDENTIFIER_NODE)
-    {
-      sorry ("multiple scope refs in `cplus_expand_raise_stmt'");
-      this_cname = error_mark_node;
-    }
-  return this_cname;
+  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;
 }
 
-tree
-lookup_exception_tname (oname)
-     tree oname;
-{
-  return get_identifier (IDENTIFIER_POINTER (oname) + EXCEPTION_NAME_LENGTH);
-}
+/* ========================================================================= */
 
-tree
-lookup_exception_object (cname, name, complain)
-     tree cname, name;
-     int complain;
-{
-  tree oname;
-  tree decl;
+extern tree auto_function PROTO((tree, tree, enum built_in_function));
 
-  if (cname == void_type_node)
-    cname = NULL_TREE;
-  else if (cname && TREE_CODE (cname) != IDENTIFIER_NODE)
-    {
-      sorry ("multiple scope refs in `lookup_exception_object'");
-      cname = NULL_TREE;
-    }
-  oname = exception_object_name (cname, name);
-  decl = IDENTIFIER_GLOBAL_VALUE (oname);
-  if (decl == NULL_TREE || TREE_CODE (decl) != VAR_DECL)
-    {
-      if (complain)
-       {
-         push_obstacks_nochange ();
+/* sets up all the global eh stuff that needs to be initialized at the
+   start of compilation.
 
-         if (cname)
-           error ("no exception name object for name `%s::%s'",
-                  IDENTIFIER_POINTER (cname),
-                  IDENTIFIER_POINTER (name));
-         else
-           error ("no exception name object for name `%s'",
-                  IDENTIFIER_POINTER (name));
-         end_temporary_allocation ();
-         /* Avoid further error messages.  */
-         pushdecl_top_level (build_lang_field_decl (VAR_DECL,
-                                                    exception_object_name (cname, name),
-                                                    error_mark_node));
-         pop_obstacks ();
-       }
-      return NULL_TREE;
-    }
-  return decl;
-}
+   This includes:
+               - Setting up all the function call trees.  */
 
-tree
-lookup_exception_type (ctype, cname, raise_id)
-     tree ctype, cname;
-     tree raise_id;
+void
+init_exception_processing ()
 {
-  tree name = TREE_VALUE (raise_id);
-  tree purpose = TREE_PURPOSE (raise_id);
+  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;
+
+  /* void (*)() */
+  tree PFV = build_pointer_type (build_function_type
+                                (void_type_node, void_list_node));
+
+  /* arg list for the build_function_type call for set_terminate () and
+     set_unexpected () */
+  tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
+
+  /* void (*pfvtype (void (*) ()))() */
+  tree pfvtype = build_function_type (PFV, pfvlist);
+
+  /* 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);
 
-  if (cname && purpose == NULL_TREE)
-    purpose = cname;
+  push_lang_context (lang_name_c);
 
-  if (purpose && purpose != void_type_node)
-    {
-      tree link = NULL_TREE;
+  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;
+
+  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);
+
+  TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
 
-      if (TREE_CODE (purpose) != IDENTIFIER_NODE)
-       {
-         sorry ("multiple scope refs in `lookup_exception_type'");
-         TREE_PURPOSE (raise_id) = NULL_TREE;
-         return NULL_TREE;
-       }
-      if (! is_aggr_typedef (purpose, 1))
-       return NULL_TREE;
-      ctype = IDENTIFIER_TYPE_VALUE (purpose);
-      link = purpose_member (name, CLASSTYPE_TAGS (ctype));
-      if (link)
-       return TREE_VALUE (link);
-    }
+  pop_lang_context ();
 
-  ctype = lookup_name (name, 1);
-  if (ctype && TREE_CODE (ctype) == TYPE_DECL)
-    ctype = TREE_TYPE (ctype);
-  if (ctype && TREE_CODE (ctype) == RECORD_TYPE
-      && CLASSTYPE_DECLARED_EXCEPTION (ctype))
-    return ctype;
-  return NULL_TREE;
+  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);
 }
 
-tree
-finish_exception (e, list_of_fieldlists)
-     tree e;
-     tree list_of_fieldlists;
-{
-  tree parmtypes = NULL_TREE, name_field;
-  tree cname = TYPE_NAME (e);
-
-  if (TREE_CODE (cname) == TYPE_DECL)
-    cname = DECL_NAME (cname);
+/* Build a type value for use at runtime for a type that is matched
+   against by the exception handling system.  */
 
-  if (last_exception_fields)
-    error ("cannot declare exceptions within exceptions");
-  if (list_of_fieldlists && ! ANON_AGGRNAME_P (cname))
-    cp_error ("exception name `%T' must follow body declaration", e);
-  if (list_of_fieldlists)
-    {
-      tree prev, field;
-
-      /* Note: no public, private, or protected allowed.  */
-      if (TREE_CHAIN (list_of_fieldlists))
-       error ("access declarations invalid in exception declaration");
-      else if (TREE_PURPOSE (list_of_fieldlists) != (tree)access_default)
-       error ("access declarations invalid in exception declaration");
-      TREE_PURPOSE (list_of_fieldlists) = (tree)access_default;
-
-      /* Note also: no member function declarations allowed.  */
-      for (prev = 0, field = TREE_VALUE (list_of_fieldlists);
-          field; prev = field, field = TREE_CHAIN (field))
-       {
-         switch (TREE_CODE (field))
-           {
-           case FIELD_DECL:
-             /* ok.  */
-             parmtypes = tree_cons (NULL_TREE, TREE_TYPE (field), parmtypes);
-             continue;
-           case FUNCTION_DECL:
-             cp_error ("declaration of function `%D' in exception invalid",
-                         field);
-             break;
-           case VAR_DECL:
-             if (TREE_STATIC (field))
-               cp_error ("declaration of static variable `%D' in exception invalid", field);
-             else
-               cp_error ("declaration of constant field `%D' in exception invalid", field);
-             break;
-           case CONST_DECL:
-             cp_error ("declaration of enum value `%D' in exception invalid", field);
-             break;
-           case SCOPE_REF:
-             error ("use of `::' in exception context invalid");
-             break;
-           }
-         if (prev)
-           TREE_CHAIN (prev) = TREE_CHAIN (field);
-         else
-           TREE_VALUE (list_of_fieldlists) = TREE_CHAIN (field);
-       }
-    }
+static tree
+build_eh_type_type (type)
+     tree type;
+{
+  char *typestring;
+  tree exp;
 
-  /* Now that we've cleaned up the fields, add a name identifier at front.  */
-  name_field = build_lang_field_decl (FIELD_DECL, get_identifier ("__name"),
-                                     ptr_type_node);
-  if (list_of_fieldlists)
-    {
-      TREE_CHAIN (name_field) = TREE_VALUE (list_of_fieldlists);
-      TREE_VALUE (list_of_fieldlists) = name_field;
-    }
-  else
-    list_of_fieldlists = build_tree_list (NULL_TREE, name_field);
+  if (type == error_mark_node)
+    return error_mark_node;
 
-  last_exception_fields = TREE_VALUE (list_of_fieldlists);
-  if (parmtypes)
-    {
-      last_exception_field_types = nreverse (parmtypes);
-      /* Set the TREE_CHAIN of what is now at the end of the
-        list to `void_list_node'.  */
-      TREE_CHAIN (parmtypes) = void_list_node;
-    }
-  else
-    last_exception_field_types = void_list_node;
+  /* peel back references, so they match.  */
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    type = TREE_TYPE (type);
 
-  popclass (0);
+  /* Peel off cv qualifiers.  */
+  type = TYPE_MAIN_VARIANT (type);
 
-#if 0
-  /* Remove aggregate types from the list of tags,
-     since these appear at global scope.  */
-  while (x && IS_AGGR_TYPE (TREE_VALUE (x)))
-    x = TREE_CHAIN (x);
-  CLASSTYPE_TAGS (t) = x;
-  y = x;
-  while (x)
+  if (flag_rtti)
     {
-      if (IS_AGGR_TYPE (TREE_VALUE (x)))
-       TREE_CHAIN (y) = TREE_CHAIN (x);
-      x = TREE_CHAIN (x);
+      return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
     }
-#endif
-
-  if (flag_cadillac)
-    cadillac_finish_exception (e);
 
-  return e;
+  typestring = build_overload_name (type, 1, 1);
+  exp = combine_strings (build_string (strlen (typestring)+1, typestring));
+  return build1 (ADDR_EXPR, ptr_type_node, exp);
 }
 
-void
-finish_exception_decl (cname, decl)
-     tree cname, decl;
+/* Build a type value for use at runtime for a exp that is thrown or
+   matched against by the exception handling system.  */
+
+static tree
+build_eh_type (exp)
+     tree exp;
 {
-  /* In decl.h.  */
-  extern tree last_function_parms;
-
-  /* An exception declaration.  */
-  tree t, ctor;
-  tree parmdecls = NULL_TREE, fields;
-  tree list_of_fieldlists = temp_tree_cons (NULL_TREE,
-                                           copy_list (last_exception_fields),
-                                           NULL_TREE);
-  tree edecl = build_lang_field_decl (VAR_DECL,
-                                     exception_object_name (cname, DECL_NAME (decl)),
-                                     ptr_type_node);
-
-  DECL_LANGUAGE (edecl) = lang_c;
-  TREE_STATIC (edecl) = 1;
-  TREE_PUBLIC (edecl) = 1;
-  finish_decl (pushdecl (edecl), NULL_TREE, NULL_TREE, 0);
-
-  /* Now instantiate the exception decl.  */
-  t = xref_tag (exception_type_node, DECL_NAME (decl), NULL_TREE, 0);
-
-  /* finish_struct will pop this.  */
-  pushclass (t, 0);
-
-  /* Now add a constructor which takes as parameters all the types we
-     just defined.  */
-  ctor = build_lang_decl (FUNCTION_DECL, DECL_NAME (decl),
-                         build_cplus_method_type (t, TYPE_POINTER_TO (t),
-                                                  last_exception_field_types));
-  /* Don't take `name'.  The constructor handles that.  */
-  fields = TREE_CHAIN (TREE_VALUE (list_of_fieldlists));
-  while (fields)
+  if (flag_rtti)
     {
-      tree parm = build_decl (PARM_DECL, DECL_NAME (fields), TREE_TYPE (fields));
-      /* Since there is a prototype, args are passed in their own types.  */
-      DECL_ARG_TYPE (parm) = TREE_TYPE (parm);
-#ifdef PROMOTE_PROTOTYPES
-      if ((TREE_CODE (TREE_TYPE (fields)) == INTEGER_TYPE
-          || TREE_CODE (TREE_TYPE (fields)) == ENUMERAL_TYPE)
-         && TYPE_PRECISION (TREE_TYPE (fields)) < TYPE_PRECISION (integer_type_node))
-       DECL_ARG_TYPE (parm) = integer_type_node;
-#endif
-      TREE_CHAIN (parm) = parmdecls;
-      parmdecls = parm;
-      fields = TREE_CHAIN (fields);
-    }
-  fields = TREE_VALUE (list_of_fieldlists);
-  last_function_parms = nreverse (parmdecls);
-
-  DECL_CONSTRUCTOR_P (ctor) = 1;
-  TYPE_HAS_CONSTRUCTOR (t) = 1;
-  grokclassfn (t, DECL_NAME (decl), ctor, NO_SPECIAL, NULL_TREE);
-  DECL_EXTERNAL (ctor) = 1;
-  TREE_STATIC (ctor) = 1;
-  TREE_PUBLIC (ctor) = 0;
-  DECL_INLINE (ctor) = 1;
-  make_decl_rtl (ctor, NULL_PTR, 1);
-  finish_decl (ctor, NULL_TREE, NULL_TREE, 0);
-  TREE_CHAIN (ctor) = TREE_VALUE (list_of_fieldlists);
-  TREE_VALUE (list_of_fieldlists) = ctor;
-
-  finish_struct (t, list_of_fieldlists, 0);
-
-  if (current_function_decl)
-    error ("cannot define exception inside function scope");
-  else
-    {
-      enum debug_info_type old_write_symbols = write_symbols;
-      write_symbols = NO_DEBUG;
-
-      /* Now build the constructor for this exception.  */
-      parmdecls = DECL_ARGUMENTS (ctor);
-      start_function (NULL_TREE, ctor, 0, 1);
-      store_parm_decls ();
-      pushlevel (0);
-      clear_last_expr ();
-      push_momentary ();
-      expand_start_bindings (0);
-
-      /* Move all the parameters to the fields, skipping `this'.  */
-      parmdecls = TREE_CHAIN (parmdecls);
-      /* Install `name' of this exception handler.  */
-      DECL_INITIAL (fields) = build_unary_op (ADDR_EXPR, edecl, 0);
-      fields = TREE_CHAIN (fields);
-      /* Install all the values.  */
-      while (fields)
-       {
-         /* Set up the initialization for this field.  */
-         DECL_INITIAL (fields) = parmdecls;
-         fields = TREE_CHAIN (fields);
-         parmdecls = TREE_CHAIN (parmdecls);
-       }
-      emit_base_init (t, 0);
-
-      finish_function (DECL_SOURCE_LINE (ctor), 1);
-      write_symbols = old_write_symbols;
+      exp = build_typeid (exp);
+      return build1 (ADDR_EXPR, ptr_type_node, exp);
     }
+  return build_eh_type_type (TREE_TYPE (exp));
 }
 
-void
-end_exception_decls ()
+/* This routine creates the cleanup for the exception handling object.  */
+
+static void
+push_eh_cleanup ()
 {
-  last_exception_field_types = NULL_TREE;
-  last_exception_fields = NULL_TREE;
+  /* All cleanups must last longer than normal.  */
+  int yes = suspend_momentary ();
+
+  /* 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);
+
+  resume_momentary (yes);
 }
-\f
-/* Statement-level exception semantics.  */
+
+
+/* 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
-cplus_expand_start_try (implicit)
-     int implicit;
+expand_start_catch_block (declspecs, declarator)
+     tree declspecs, declarator;
 {
-  tree call_to_setjmp;
-  tree handler, ref;
-
-  /* Start a new block enclosing the whole handler.  */
-  if (implicit)
-    {
-      pushlevel_temporary (1);
-    }
-  else
-    {
-      pushlevel (0);
-      clear_last_expr ();
-      push_momentary ();
-
-      /* Encompass whole exception handler in one big binding contour.
-        If RAISE should throw out of the whole TRY/EXCEPT block, call
-        `expand_start_bindings' with argument of 1.  */
-      expand_start_bindings (0);
-    }
+  rtx false_label_rtx;
+  tree decl = NULL_TREE;
+  tree init;
 
-  /* Allocate handler in that block.  It's real name will come later.
-     Note that it will be the first name in this binding contour.  */
-  handler = get_temp_name (EHS_type, 0);
-  DECL_INITIAL (handler) = error_mark_node;
-  finish_decl (handler, NULL_TREE, NULL_TREE, 0);
+  if (! doing_eh (1))
+    return;
 
-  /* Must come after call to `finish_decl', else the cleanup for the temp
-     for the handler will cause the contour we just created to be popped.  */
-  if (implicit)
-    declare_implicit_exception ();
+  /* Create a binding level for the parm.  */
+  pushlevel (0);
+  expand_start_bindings (0);
 
-  /* Catch via `setjmp'.  */
-  ref = build_component_ref (handler, get_identifier ("handler"), NULL_TREE, 0);
-  call_to_setjmp = build_function_call (BISJ, build_tree_list (NULL_TREE, ref));
+  false_label_rtx = gen_label_rtx ();
+  push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
 
-  /* RAISE throws to EXCEPT part.  */
-  expand_start_try (build_binary_op (EQ_EXPR, call_to_setjmp, integer_zero_node, 1), 0, 1);
-}
+  if (declspecs)
+    {
+      tree exp;
+      rtx call_rtx, return_value_rtx;
+      tree init_type;
 
-/* If KEEP is 1, then declarations in the TRY statement are worth keeping.
-   If KEEP is 2, then the TRY statement was generated by the compiler.
-   If KEEP is 0, the declarations in the TRY statement contain errors.  */
+      decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
 
-tree
-cplus_expand_end_try (keep)
-     int keep;
-{
-  tree decls, decl, block;
+      if (decl == NULL_TREE)
+       {
+         error ("invalid catch parameter");
 
-  if (keep < 2)
-    pop_implicit_try_blocks (NULL_TREE);
+         /* This is cheap, but we want to maintain the data structures.  */
+         expand_eh_region_start ();
+         return;
+       }
 
-  decls = getdecls ();
+      /* Make sure we mark the catch param as used, otherwise we'll get
+        a warning about an unused ((anonymous)).  */
+      TREE_USED (decl) = 1;
 
-  /* Emit code to avoid falling through into a default
-     handler that might come later.  */
-  expand_end_try ();
+      /* 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);
 
-  /* Pops binding contour local to TRY, and get the exception handler
-     object built by `...start_try'.  */
-  switch (keep)
-    {
-    case 0:
-      expand_end_bindings (decls, 0, 1);
-      block = poplevel (0, 0, 0);
-      pop_momentary (); 
-      decl = getdecls ();
-      break;
-
-    case 1:
-      expand_end_bindings (decls, 1, 1);
-      block = poplevel (1, 1, 0);
-      pop_momentary ();
-      decl = getdecls ();
-      break;
-
-    default:
-      decl = tree_last (decls);
-      block = NULL_TREE;
-      break;
-    }
+      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));
 
-  my_friendly_assert (TREE_CODE (decl) == VAR_DECL
-                     && TREE_TYPE (decl) == EHS_type, 203);
-  if (block)
-    {
-      BLOCK_HANDLER_BLOCK (block) = 1;
-      TREE_USED (block) = 1;
-    }
+      return_value_rtx = hard_function_value (ptr_type_node, exp);
 
-  /* Pass it back so that its rtl can be bound to its name
-     (or vice versa).  */
-  return decl;
-}
+      /* 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);
 
-void
-cplus_expand_start_except (name, decl)
-     tree name, decl;
-{
-  int yes;
-  tree tmp, init;
+      /* if it returned FALSE, jump over the catch block, else fall into it */
+      emit_jump_insn (gen_beq (false_label_rtx));
 
-  expand_start_except (0, 1);
+      push_eh_cleanup ();
 
-  /* This is internal `eh'.  */
-  current_exception_decl = decl;
-  current_exception_name_as_rtx
-    = expand_expr (build (COMPONENT_REF, ptr_type_node,
-                         current_exception_decl, TREE_OPERAND (EHS_name, 1)),
-                  0, 0, 0);
-  init = build (COMPONENT_REF, ptr_type_node, decl, TREE_OPERAND (EHS_parms, 1));
-  current_exception_parms_as_rtx = expand_expr (init, 0, 0, 0);
+      init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
 
-  if (name)
-    {
-      /* Get the exception object into scope (user declared `ex').  */
-      tmp = pushdecl (build_decl (VAR_DECL, name, ptr_type_node));
-      DECL_INITIAL (tmp) = error_mark_node;
-      finish_decl (tmp, init, 0, 0);
+      /* 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);
     }
-  current_exception_type = NULL_TREE;
-  yes = suspend_momentary ();
-  if (name)
+  else
     {
-      /* From now on, send the user to our faked-up object.  */
-      current_exception_object = build1 (INDIRECT_REF, void_type_node, tmp);
-      IDENTIFIER_LOCAL_VALUE (name) = current_exception_object;
+      push_eh_cleanup ();
+
+      /* Fall into the catch all section.  */
     }
-  resume_momentary (yes);
 
-  /* Pop exception handler stack.  */
-  expand_assignment (EHS_decl, EHS_prev, 0, 0);
+  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.
+
+     Matches the end in expand_end_catch_block ().  */
+  expand_eh_region_start ();
+
+  emit_line_note (input_filename, lineno);
 }
 
-/* Generate the call to `unhandled_exception' that is appropriate
-   for this particular unhandled exception.  */
-static tree
-call_to_unhandled_exception ()
+
+
+/* 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 ()
 {
-  extern int lineno;
-  extern tree combine_strings ();
-  tree parms = tree_cons (NULL_TREE,
-                         combine_strings (build_string (strlen (input_filename + 1), input_filename)),
-                         build_tree_list (NULL_TREE, build_int_2 (lineno, 0)));
-  return build_function_call (BIUE, parms);
+  rtx start_region_label_rtx;
+  rtx end_region_label_rtx;
+  tree decls, t;
+
+  if (! doing_eh (1))
+    return;
+
+  /* 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));
+
+  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 ();
+
+  /* Matches the start in expand_start_catch_block ().  */
+  expand_eh_region_end (t);
+
+  expand_leftover_cleanups ();
+
+  /* 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));
 }
 
-/* Note that this must be mirror image of `...start_try'.
-   DFAULT is the default clause, if there was one.
-   DFAULT is ERROR_MARK_NODE when this ends an implicit handler.  */
-void
-cplus_expand_end_except (dfault)
-     tree dfault;
+/* unwind the stack.  */
+
+static void
+do_unwind (inner_throw_label)
+     rtx inner_throw_label;
 {
-  extern tree expand_end_except (); /* stmt.c.  */
-  tree decls, raised;
+#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;
+
+  /* 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;
 
-  if (dfault == NULL_TREE)
-    {
-      /* Uncaught exception at outermost level.  If raised locally,
-        reraise the exception.  Otherwise, generate code to call `abort'.  */
-      if (in_try_block (1) == 0)
-       {
-         expand_start_cond (build (EQ_EXPR, integer_type_node,
-                                   exception_throw_decl, integer_zero_node), 0);
-         expand_expr (call_to_unhandled_exception (), 0, VOIDmode, 0);
-         expand_end_cond ();
-       }
-      /* Try the next handler.  */
-      if (! expand_escape_except ())
-       compiler_error ("except nesting botch");
-    }
+  temp_frame = memory_address (Pmode, temp_frame);
+  temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
 
-  raised = expand_end_except ();
+  /* 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))));
 
-  decls = getdecls ();
-  expand_end_bindings (decls, decls != 0, 1);
-  poplevel (decls != 0, 1, 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))));
 
-  /* Implicit handlers do not use the momentary obstack.  */
-  if (dfault != error_mark_node)
-    pop_momentary ();
+  emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
 
-  if (! in_try_block (1))
-    {
-      /* Check that this function is not raising exceptions
-        it is not supposed to.  */
-      while (raised)
-       {
-         cp_error ("exception `%D' raised but not declared raisable",
-                     TREE_VALUE (raised));
-         raised = TREE_CHAIN (raised);
-       }
-    }
-  else if (dfault == NULL_TREE || dfault == error_mark_node)
-    {
-      expand_start_cond (build (NE_EXPR, integer_type_node,
-                               exception_throw_decl,
-                               integer_zero_node), 0);
-      /* We fell off the end of this try block.  Try going to the next.
-        The escape_label will be the beginning of the next try block.  */
-      if (! expand_escape_except ())
-       compiler_error ("except nesting botch");
-      expand_end_cond ();
-    }
+  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;
+
+#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);
+
+  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
 }
 
-/* Generate code to raise exception RAISE_ID.
-   If EXP is NULL_TREE, then PARMS is the list of parameters to use
-   for constructing this exception.
-   If EXP is non-NULL, then it is an already constructed object
-   of the kind that we want.
 
-   FOR_RERAISE is non-zero if this raise is called by reraise.  In
-   this case we do not need to emit extra gotos to avoid warning messages;
-   the caller will do that once after all the exceptions it reraises
-   are handled and raised.  */
+/* 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 pseudo code:
+
+       throw:
+               eh = find_first_exception_match (saved_pc);
+           if (!eh) goto gotta_rethrow_it;
+               goto eh;
+
+       gotta_rethrow_it:
+               saved_pc = __builtin_return_address (0);
+               pop_to_previous_level ();
+               goto throw;  */
+
 void
-cplus_expand_raise (raise_id, parms, exp, for_reraise)
-     tree raise_id;
-     tree parms;
-     tree exp;
-     int for_reraise;
+expand_builtin_throw ()
 {
-  /* Allocate new exception of appropriate type, passing
-     PARMS to its constructor.  */
-  tree cname, name;
-  tree decl;
-  tree xexp = exp;
-
-  cname = lookup_exception_cname (current_class_type, current_class_name, raise_id);
-  if (cname == error_mark_node)
+  tree fcall;
+  tree params;
+  rtx return_val_rtx;
+  rtx gotta_rethrow_it;
+  rtx gotta_call_terminate;
+  rtx top_of_loop;
+  rtx unwind_first;
+  tree t;
+
+  if (! doing_eh (0))
     return;
-  name = TREE_VALUE (raise_id);
 
-  decl = lookup_exception_object (cname, name, 1);
-  if (decl == NULL_TREE)
+  if (! throw_used)
     return;
 
-  if (exp == NULL_TREE)
-    {
-      exp = build_method_call (NULL_TREE, name, parms, NULL_TREE, LOOKUP_COMPLAIN);
-      if (exp == error_mark_node)
-       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 (top_of_loop);
+
+  /* search for an exception handler for the saved_pc */
+  return_val_rtx = do_function_call (FirstExceptionMatch,
+                                    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,
+                GET_MODE (return_val_rtx), 0, 0);
+
+  /* if not, jump to gotta_rethrow_it */
+  emit_jump_insn (gen_beq (gotta_rethrow_it));
+
+  /* we found it, so jump to it */
+  emit_indirect_jump (return_val_rtx);
+
+  /* code to deal with unwinding and looking for it again */
+  emit_label (gotta_rethrow_it);
+
+  /* call to  __builtin_return_address () */
+#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, Pmode, 0);
+#endif
 
-  if (in_try_block (1))
-    {
-      expand_raise (decl);
-    }
-  else if (! current_function_decl)
-    {
-      if (xexp == NULL_TREE)
-       cp_error ("invalid raise of `%D' outside of functions", decl);
-      else
-       cp_error ("invalid reraise of `%D' outside of functions", decl);
-    }
-  else
-    {
-      /* Test this raise against what this function permits.  */
-      tree names = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl));
-      while (names)
-       {
-         if (decl == TREE_TYPE (names))
-           break;
-         names = TREE_CHAIN (names);
-       }
-      if (names == NULL_TREE)
-       {
-         error ("current function not declared to raise exception `%s'",
-                IDENTIFIER_POINTER (name));
-         return;
-       }
-    }
+  /* did __builtin_return_address () return a valid address? */
+  emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
+                GET_MODE (return_val_rtx), 0, 0);
 
-  store_expr (exp, EHS_parms_as_rtx, 0);
+  emit_jump_insn (gen_beq (gotta_call_terminate));
 
-  /* Set the global exception handler stack's NAME field
-     to the `name' of this exception.  The global exception
-     handler stack is the container for the exception object
-     we just built.
+  return_val_rtx = eh_outer_context (return_val_rtx);
 
-     We go through a function call to make life easier when debugging.  */
-#if 0
-  expand_assignment (EHS_name, build_unary_op (ADDR_EXPR, decl, 0), 0, 0);
-#else
-  parms = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, EHS_name, 0),
-                    build_tree_list (NULL_TREE,
-                                     build_unary_op (ADDR_EXPR, decl, 0)));
-  expand_expr (build_function_call (BIR, parms), 0, 0, 0);
+  /* 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
 
-  /* Activate thrower.  If we are inside a TRY statement,
-     we can cheat and not do this, saving a longjmp.  */
-  if (in_try_block (1) == 0)
-    {
-      sets_exception_throw_decl = 1;
-      emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx);
-    }
+    /* Fall into epilogue to unwind prologue.  */
+  }
 
-  if (xexp == NULL_TREE)
-    {    
-      /* Invoke destructors for current procedure or handler.  */
-      if (! expand_escape_except ())
-       compiler_error ("except nesting botch");
-      /* Throw via `longjmp'... Done as side-effect of goto.  */
-    }
-  /* To avoid spurious warning messages, we add a goto to the end
-     of the function.  This code is dead, and the compiler should
-     know how to delete it, but for now, we are stuck with it.  */
-  if (! for_reraise
-      && TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node)
-    expand_null_return ();
+  expand_end_bindings (getdecls (), 1, 0);
+  poplevel (1, 0, 0);
+  pop_momentary ();
+
+  finish_function (lineno, 0, 0);
 }
 
-extern tree cplus_exception_name ();
 
-tree
-ansi_exception_object_lookup (type)
-     tree type;
+void
+expand_start_eh_spec ()
 {
-  tree raise_id = cplus_exception_name (type);
-  tree decl;
+  expand_eh_region_start ();
+}
 
-  decl = IDENTIFIER_GLOBAL_VALUE (raise_id);
-  if (decl == NULL_TREE || TREE_CODE (decl) != VAR_DECL)
+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)
     {
-      push_obstacks_nochange ();
-      end_temporary_allocation ();
-      decl = build_decl (VAR_DECL, raise_id, ptr_type_node);
-      TREE_PUBLIC (decl) = 1;
-      TREE_STATIC (decl) = 1;
-      pushdecl_top_level (decl);
-      make_decl_rtl (decl, (char*)0, 1);
-      pop_obstacks ();
+      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);
     }
-  return decl;
+  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);
 }
 
-/* Generate code to throw an exception using EXP.
-   Usng ANSI syntax and semantics.
-   If EXP is NULL_TREE< re-raise instead. */
+/* This is called to expand all the toplevel exception handling
+   finalization for a function.  It should only be called once per
+   function.  */
 
 void
-cplus_expand_throw (exp)
-     tree exp;
+expand_exception_blocks ()
 {
-  tree parms;
-  int for_reraise;
-  /* Allocate new exception of appropriate type, passing
-     PARMS to its constructor.  */
-  tree decl = ansi_exception_object_lookup (TREE_TYPE (exp));
-  tree xexp = exp;
-
-  if (in_try_block (1))
+  rtx funcend;
+  rtx insn, insns;
+  rtx eh_spec_insns = NULL_RTX;
+
+  start_sequence ();
+
+  funcend = gen_label_rtx ();
+  emit_jump (funcend);
+  /* expand_null_return (); */
+
+  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
-      my_friendly_abort (35);
-#else
-      expand_raise (decl);
-#endif
-    }
-  else if (! current_function_decl)
-    error ("invalid throw outside of functions");
-  else
-    {
-#if 0
-      /* Test this raise against what this function permits.  */
-      tree names = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl));
-      while (names)
-       {
-         if (decl == TREE_TYPE (names))
-           break;
-         names = TREE_CHAIN (names);
-       }
-      if (names == NULL_TREE)
-       {
-         error ("current function not declared to raise exception `%s'",
-                IDENTIFIER_POINTER (name));
-         return;
-       }
+      {
+       rtx insns;
+       /* New...  */
+       start_sequence ();
+       expand_start_eh_spec ();
+       eh_spec_insns = get_insns ();
+       end_sequence ();
+      }
 #endif
-    }
 
-  store_expr (exp, EHS_parms_as_rtx, 0);
+      expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
+      push_to_sequence (insns);
 
-  /* Set the global exception handler stack's NAME field
-     to the `name' of this exception.  The global exception
-     handler stack is the container for the exception object
-     we just built.
+      /* Now expand any new ones.  */
+      expand_leftover_cleanups ();
 
-     We go through a function call to make life easier when debugging.  */
-#if 0
-  expand_assignment (EHS_name, build_unary_op (ADDR_EXPR, decl, 0), 0, 0);
-#else
-  parms = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, EHS_name, 0),
-                    build_tree_list (NULL_TREE,
-                                     build_unary_op (ADDR_EXPR, decl, 0)));
-  expand_expr (build_function_call (BIR, parms), 0, 0, 0);
-#endif
+      insns = get_insns ();
+      end_sequence ();
+    }
 
-  /* Activate thrower.  If we are inside a TRY statement,
-     we can cheat and not do this, saving a longjmp.  */
-  if (in_try_block (1) == 0)
+  if (insns)
     {
-      sets_exception_throw_decl = 1;
-      emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx);
-    }
+      /* Is this necessary?  */
+      assemble_external (TREE_OPERAND (Terminate, 0));
 
-  if (xexp == NULL_TREE)
-    {    
-      /* Invoke destructors for current procedure or handler.  */
-      if (! expand_escape_except ())
-       compiler_error ("except nesting botch");
-      /* Throw via `longjmp'... Done as side-effect of goto.  */
+      expand_eh_region_start ();
+      emit_insns (insns);
+      expand_eh_region_end (TerminateFunctionCall);
+      expand_leftover_cleanups ();
     }
 
-  /* XXX: for_reraise is never set above here.  */
-  /* To avoid spurious warning messages, we add a goto to the end
-     of the function.  This code is dead, and the compiler should
-     know how to delete it, but for now, we are stuck with it.  */
-  if (! for_reraise
-      && TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node)
-    expand_null_return ();
+  {
+    /* 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)
+      {
+       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
-cplus_expand_start_catch (raise_id)
-     tree raise_id;
+start_anon_func ()
 {
-  tree cname = lookup_exception_cname (current_class_type, current_class_name, raise_id);
-  tree decl;
-  tree cond;
+  static int counter = 0;
+  int old_interface_unknown = interface_unknown;
+  char name[32];
+  tree params;
+  tree t;
 
-  if (cname == error_mark_node)
-    {
-      decl = error_mark_node;
-      cond = error_mark_node;
-    }
-  else
-    {
-      decl = lookup_exception_object (cname, TREE_VALUE (raise_id), 1);
-      if (decl == NULL_TREE)
-       cond = error_mark_node;
-      else
-       cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0),
-                               build (COMPONENT_REF, ptr_type_node,
-                                      current_exception_decl,
-                                      TREE_OPERAND (EHS_name, 1)),
-                               1);
-    }
-  expand_start_cond (cond, 0);
+  push_cp_function_context (NULL_TREE);
+  push_to_top_level ();
 
-  /* Does nothing right now.  */
-  expand_catch (decl);
-  if (current_exception_type
-      && TYPE_NEEDS_DESTRUCTOR (current_exception_type))
-    {
-      /* Make a cleanup for the name-specific exception object now in scope.  */
-      tree cleanup = maybe_build_cleanup (current_exception_object);
-      expand_start_bindings (0);
-      expand_decl_cleanup (NULL_TREE, cleanup);
-    }
-  return decl;
-}
-tree
-ansi_expand_start_catch (raise_type)
-     tree raise_type;
-{
-  tree decl = ansi_exception_object_lookup (raise_type);
-  tree cond;
+  /* No need to mangle this.  */
+  push_lang_context (lang_name_c);
 
-  if (decl == NULL_TREE)
-      cond = error_mark_node;
-  else
-      cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0),
-                             build (COMPONENT_REF, ptr_type_node,
-                                    current_exception_decl,
-                                    TREE_OPERAND (EHS_name, 1)),
-                             1);
-  expand_start_cond (cond, 0);
-
-  /* Does nothing right now.  */
-  expand_catch (decl);
-  return decl;
+  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;
+
+  pop_lang_context ();
+
+  return current_function_decl;
 }
 
 void
-cplus_expand_end_catch (for_reraise)
-     int for_reraise;
+end_anon_func ()
 {
-  if (current_exception_type
-      && TYPE_NEEDS_DESTRUCTOR (current_exception_type))
-    {
-      /* Destroy the specific exception object now in scope.  */
-      expand_end_bindings (getdecls (), 0, 1);
-    }
-  if (for_reraise)
-    {
-      if (! expand_escape_except ())
-       my_friendly_abort (36);
-    }
-  else
-    {
-      if (! expand_end_catch ())
-       my_friendly_abort (37);
-    }
-  expand_end_cond ();
+  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);
 }
 
-/* Reraise an exception.
-   If EXCEPTIONS is NULL_TREE, it means reraise whatever exception was caught.
-   If EXCEPTIONS is an IDENTIFIER_NODE, it means reraise the exception
-   object named by EXCEPTIONS.  This must be a variable declared in
-   an `except' clause.
-   If EXCEPTIONS is a TREE_LIST, it is the list of exceptions we are
-   willing to reraise.  */
+/* 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 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
-cplus_expand_reraise (exceptions)
-     tree exceptions;
+expand_throw (exp)
+     tree exp;
 {
-  tree ex_ptr;
-  tree ex_object = current_exception_object;
-  rtx ex_ptr_as_rtx;
+  rtx label;
 
-  if (exceptions && TREE_CODE (exceptions) == IDENTIFIER_NODE)
-    {
-      /* Don't get tripped up if its TREE_TYPE is `error_mark_node'.  */
-      ex_object = IDENTIFIER_LOCAL_VALUE (exceptions);
-      if (ex_object == NULL_TREE || TREE_CODE (ex_object) != INDIRECT_REF)
-       {
-         error ("`%s' is not an exception decl", IDENTIFIER_POINTER (exceptions));
-         return;
-       }
-      my_friendly_assert (TREE_CODE (TREE_OPERAND (ex_object, 0)) == VAR_DECL,
-                         204);
-      exceptions = NULL_TREE;
-    }
-
-  ex_ptr = build1 (NOP_EXPR, ptr_type_node, TREE_OPERAND (ex_object, 0));
-  ex_ptr_as_rtx = expand_expr (ex_ptr, 0, 0, 0);
+  if (! doing_eh (1))
+    return;
 
-  /* reraise ALL, used by compiler.  */
-  if (exceptions == NULL_TREE)
+  if (exp)
     {
-      /* Now treat reraise like catch/raise.  */
-      expand_catch (error_mark_node);
-      expand_raise (error_mark_node);
-      emit_move_insn (EHS_name_as_rtx, current_exception_name_as_rtx);
-      store_expr ((tree) EHS_parms_as_rtx, current_exception_parms_as_rtx, 0);
-      if (in_try_block (1) == 0)
-       {
-         sets_exception_throw_decl = 1;
-         emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx);
-       }
-      /* Set to zero so that destructor will not be called.  */
-      emit_move_insn (ex_ptr_as_rtx, const0_rtx);
-      if (! expand_escape_except ())
-       my_friendly_abort (38);
-
-      /* To avoid spurious warning messages, we add a goto to the end
-        of the function.  This code is dead, and the compiler should
-        know how to delete it, but for now, we are stuck with it.  */
-      if (TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node)
-       expand_null_return ();
-
-      return;
-    }
+      tree throw_type;
+      tree cleanup = empty_fndecl, e;
 
-  /* reraise from a list of exceptions.  */
-  while (exceptions)
-    {
-      tree type = lookup_exception_type (current_class_type, current_class_name,
-                                        exceptions);
-      if (type == NULL_TREE)
+      /* throw expression */
+      /* First, decay it.  */
+      exp = decay_conversion (exp);
+
+      if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
        {
-         error ("`%s' is not an exception type",
-                IDENTIFIER_POINTER (TREE_VALUE (exceptions)));
-         current_exception_type = NULL_TREE;
-         TREE_TYPE (ex_object) = error_mark_node;
-         TREE_TYPE (ex_ptr) = error_mark_node;
+         throw_type = build_eh_type (exp);
+         exp = build_reinterpret_cast (ptr_type_node, exp);
        }
       else
        {
-         current_exception_type = type;
-         /* In-place union.  */
-         TREE_TYPE (ex_object) = type;
-         TREE_TYPE (ex_ptr) = TYPE_POINTER_TO (type);
-       }
-
-      /* Now treat reraise like catch/raise.  */
-      cplus_expand_start_catch (exceptions);
-      cplus_expand_raise (exceptions, NULL_TREE, ex_ptr, 1);
-      /* Set to zero so that destructor will not be called.  */
-      if (TREE_TYPE (ex_ptr) != error_mark_node)
-       emit_move_insn (ex_ptr_as_rtx, const0_rtx);
-      cplus_expand_end_catch (1);
-      exceptions = TREE_CHAIN (exceptions);
-    }
-  /* Don't propagate any unhandled exceptions.  */
-  expand_expr (call_to_unhandled_exception (), 0, VOIDmode, 0);
-
-  /* To avoid spurious warning messages, we add a goto to the end
-     of the function.  This code is dead, and the compiler should
-     know how to delete it, but for now, we are stuck with it.  */
-  if (TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node)
-    expand_null_return ();
-}
-\f
-void
-setup_exception_throw_decl ()
-{
-  tree call_to_longjmp, parms;
-
-  int old = suspend_momentary ();
-
-  exception_throw_decl = build_decl (VAR_DECL, get_identifier (THROW_NAME), integer_type_node);
-  pushdecl (exception_throw_decl);
-  parms = tree_cons (NULL_TREE, EHS_handler,
-                    build_tree_list (0, integer_one_node));
-  call_to_longjmp = build_function_call (BILJ, parms);
-
-  expand_decl (exception_throw_decl);
-  expand_decl_cleanup (exception_throw_decl,
-                      build (COND_EXPR, void_type_node,
-                             exception_throw_decl,
-                             call_to_longjmp, integer_zero_node));
-  DECL_INITIAL (exception_throw_decl) = integer_zero_node;
-  sets_exception_throw_decl = 0;
-  resume_momentary (old);
-
-  /* Cache these, since they won't change throughout the function.  */
-  EHS_parms_as_rtx = expand_expr (EHS_parms, 0, 0, 0);
-  EHS_name_as_rtx = expand_expr (EHS_name, 0, 0, 0);
-}
+         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 ();
 
-void
-init_exception_processing ()
-{
-  extern tree build_function_type (), define_function ();
-  extern tree unhandled_exception_fndecl;
-  tree cname = get_identifier ("ExceptionHandler");
-  tree field, chain;
-  tree ctor, dtor;
-  tree jmp_buf_type = build_array_type (integer_type_node,
-                                       build_index_type (build_int_2 (_JBLEN-1, 0)));
-  tree jmp_buf_arg_type = build_pointer_type (integer_type_node);
-
-  tree parmtypes = hash_tree_chain (jmp_buf_arg_type, void_list_node);
-  tree setjmp_fndecl, longjmp_fndecl, raise_fndecl;
-
-  int old_interface_only = interface_only;
-  int old_interface_unknown = interface_unknown;
-  interface_only = 1;
-  interface_unknown = 0;
-  EHS_type = xref_tag (record_type_node, cname, NULL_TREE, 0);
-  push_lang_context (lang_name_c);
-  setjmp_fndecl = define_function ("setjmp",
-                                  build_function_type (integer_type_node,
-                                                       parmtypes),
-                                  NOT_BUILT_IN, pushdecl, 0);
-  BISJ = default_conversion (setjmp_fndecl);
-  parmtypes = hash_tree_chain (jmp_buf_arg_type,
-                              hash_tree_chain (integer_type_node, void_list_node));
-  longjmp_fndecl = define_function ("longjmp",
-                                   build_function_type (void_type_node, parmtypes),
-                                   NOT_BUILT_IN, pushdecl, 0);
-  raise_fndecl = define_function ("__raise_exception",
-                                 build_function_type (void_type_node,
-                                                      hash_tree_chain (ptr_type_node,
-                                                                       hash_tree_chain (build_pointer_type (ptr_type_node), void_list_node))),
-                                 NOT_BUILT_IN, pushdecl, 0);
-  BILJ = default_conversion (longjmp_fndecl);
-  BIR = default_conversion (raise_fndecl);
-  BIUE = default_conversion (unhandled_exception_fndecl);
+             expand_expr (maybe_build_cleanup_and_delete (object),
+                          const0_rtx, VOIDmode, 0);
 
-  pop_lang_context ();
+             end_anon_func ();
 
-  /* finish_struct will pop this.  */
-  pushclass (EHS_type, 0);
-  field = build_lang_field_decl (FIELD_DECL, get_identifier ("parms"), ptr_type_node);
-  chain = field;
-  field = build_lang_field_decl (FIELD_DECL, get_identifier ("name"),
-                                build_pointer_type (default_function_type));
-  TREE_CHAIN (field) = chain;
-  chain = field;
-  field = build_lang_field_decl (FIELD_DECL, get_identifier ("handler"), jmp_buf_type);
-  TREE_CHAIN (field) = chain;
-  chain = field;
-  field = build_lang_field_decl (FIELD_DECL, get_identifier ("prev"),
-                                TYPE_POINTER_TO (EHS_type));
-  TREE_CHAIN (field) = chain;
-  chain = field;
-
-  ctor = build_lang_decl (FUNCTION_DECL, cname,
-                         build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node));
-  DECL_CONSTRUCTOR_P (ctor) = 1;
-  TREE_STATIC (ctor) = 1;
-  TREE_PUBLIC (ctor) = 1;
-  DECL_EXTERNAL (ctor) = 1;
-  grokclassfn (EHS_type, cname, ctor, NO_SPECIAL, 0);
-  grok_ctor_properties (EHS_type, ctor);
-  finish_decl (pushdecl (ctor), NULL_TREE, NULL_TREE, 0);
-  /* Must copy the node here because the FUNCTION_DECL
-     used inside the struct ain't the same as the
-     FUNCTION_DECL we stick into the global binding
-     contour.  */
-  ctor = copy_node (ctor);
-  TREE_CHAIN (ctor) = chain;
-  chain = ctor;
-  dtor = build_lang_decl (FUNCTION_DECL, cname,
-                         build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node));
-  TREE_STATIC (dtor) = 1;
-  TREE_PUBLIC (dtor) = 1;
-  DECL_EXTERNAL (dtor) = 1;
-  grokclassfn (EHS_type, cname, dtor, DTOR_FLAG, 0);
-  finish_decl (pushdecl (dtor), NULL_TREE, NULL_TREE, 0);
-  /* Copy for the same reason as copying ctor.  */
-  dtor = copy_node (dtor);
-  TREE_CHAIN (dtor) = chain;
-  chain = dtor;
-  TYPE_HAS_CONSTRUCTOR (EHS_type) = 1;
-  TYPE_HAS_DESTRUCTOR (EHS_type) = 1;
-  finish_struct (EHS_type, temp_tree_cons (NULL_TREE, chain, NULL_TREE), 0);
-  interface_only = old_interface_only;
-  interface_unknown = old_interface_unknown;
-}
+             mark_addressable (cleanup);
+           }
+         else
+           {
+             cleanup = empty_fndecl;
+           }
+       }
 
-void
-init_exception_processing_1 ()
-{
-  register tree EHS_id = get_identifier ("exceptionHandlerStack");
+      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);
 
-  EHS_decl = IDENTIFIER_GLOBAL_VALUE (EHS_id);
+      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 we have no other definition, default to library implementation.  */
-  if (EHS_decl == NULL_TREE)
+      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
     {
-      EHS_decl = build_decl (VAR_DECL, EHS_id, TYPE_POINTER_TO (EHS_type));
-      /* If we don't push this, its definition, should it be encountered,
-        will not be seen.  */
-      EHS_decl = pushdecl (EHS_decl);
-      DECL_EXTERNAL (EHS_decl) = 1;
-      TREE_STATIC (EHS_decl) = 1;
-      TREE_PUBLIC (EHS_decl) = 1;
-      finish_decl (EHS_decl, NULL_TREE, NULL_TREE, 0);
+      /* rethrow current exception */
+      /* This part is easy, as we don't have to do anything else.  */
     }
-  else if (TREE_CODE (EHS_decl) != VAR_DECL
-          || TREE_TYPE (EHS_decl) != TYPE_POINTER_TO (EHS_type))
-    fatal ("exception handling declarations conflict with compiler's internal model");
 
-  if (EHS_prev == NULL_TREE)
+  /* 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);
+
+  expand_internal_throw (label);
+}
+
+/* Build a throw expression.  */
+
+tree
+build_throw (e)
+     tree e;
+{
+  if (e != error_mark_node)
     {
-      register tree EHS_DECL = build1 (INDIRECT_REF, EHS_type, EHS_decl);
-      EHS_prev = build_component_ref (EHS_DECL, get_identifier ("prev"), 0, 0);
-      EHS_handler = build_component_ref (EHS_DECL, get_identifier ("handler"), 0, 0);
-      EHS_parms = build_component_ref (EHS_DECL, get_identifier ("parms"), 0, 0);
-      EHS_name = build_component_ref (EHS_DECL, get_identifier ("name"), 0, 0);
+      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;
 }