OSDN Git Service

Fri Oct 31 01:45:31 1997 Jason Merrill <jason@yorick.cygnus.com>
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 31 Oct 1997 09:52:55 +0000 (09:52 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 31 Oct 1997 09:52:55 +0000 (09:52 +0000)
* libgcc2.c (L_eh): Define __eh_pc.
Replace __eh_type with generic pointer __eh_info.

Fri Oct 31 01:47:57 1997  Jason Merrill  <jason@yorick.cygnus.com>

Support for nested exceptions.
* tinfo2.cc (__is_pointer): New fn.
* exception.cc (struct cp_eh_info): Define.
(__cp_exception_info, __uncatch_exception): New fns.
(__cp_push_exception, __cp_pop_exception): New fns.
* except.c: Lose saved_throw_{type,value,cleanup,in_catch}.
  Lose empty_fndecl.
(init_exception_processing): Likewise.  __eh_pc is now external.
(push_eh_info): New fn.
(get_eh_{info,value,type,caught}): New fns.
(push_eh_cleanup): Just call __cp_pop_exception.
(expand_start_catch_block): Use push_eh_info.  Start the eh region
sooner.
(expand_end_eh_spec): Use push_eh_info.
(expand_throw): Call __cp_push_exception to set up the exception info.
Just pass the destructor or 0 as the cleanup.  Call __uncatch_exception
when we rethrow.
(expand_builtin_throw): Don't refer to empty_fndecl.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@16248 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/except.c
gcc/cp/exception.cc
gcc/cp/tinfo2.cc
gcc/libgcc2.c

index a417d4d..540f17f 100644 (file)
@@ -1,3 +1,8 @@
+Fri Oct 31 01:45:31 1997  Jason Merrill  <jason@yorick.cygnus.com>
+
+       * libgcc2.c (L_eh): Define __eh_pc.
+       Replace __eh_type with generic pointer __eh_info.
+
 Fri Oct 31 00:34:55 1996  J"orn Rennecke <amylaar@cygnus.co.uk>
 
        * expr.c (expand_increment): When enqueing a postincrement for a MEM,
index a1bb470..5ff066a 100644 (file)
@@ -1,3 +1,24 @@
+Fri Oct 31 01:47:57 1997  Jason Merrill  <jason@yorick.cygnus.com>
+
+       Support for nested exceptions.
+       * tinfo2.cc (__is_pointer): New fn.
+       * exception.cc (struct cp_eh_info): Define.
+       (__cp_exception_info, __uncatch_exception): New fns.
+       (__cp_push_exception, __cp_pop_exception): New fns.
+       * except.c: Lose saved_throw_{type,value,cleanup,in_catch}.
+       Lose empty_fndecl.
+       (init_exception_processing): Likewise.  __eh_pc is now external.
+       (push_eh_info): New fn.
+       (get_eh_{info,value,type,caught}): New fns.
+       (push_eh_cleanup): Just call __cp_pop_exception.
+       (expand_start_catch_block): Use push_eh_info.  Start the eh region
+       sooner.
+       (expand_end_eh_spec): Use push_eh_info.
+       (expand_throw): Call __cp_push_exception to set up the exception info.
+       Just pass the destructor or 0 as the cleanup.  Call __uncatch_exception
+       when we rethrow.
+       (expand_builtin_throw): Don't refer to empty_fndecl.
+
 Thu Oct 23 02:01:30 1997  Jason Merrill  <jason@yorick.cygnus.com>
 
        * pt.c (instantiate_decl): SET_DECL_IMPLICIT_INSTANTIATION on new decl.
index fe0a1b5..4d3622b 100644 (file)
@@ -180,8 +180,6 @@ static tree Unwind;
 /* Holds a ready to emit call to "terminate".  */
 static tree TerminateFunctionCall;
 
-static tree empty_fndecl;
-
 /* ====================================================================== */
 
 
@@ -196,14 +194,6 @@ static tree empty_fndecl;
 
 /* 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;
@@ -290,12 +280,6 @@ init_exception_processing ()
                                             tree_cons (NULL_TREE, ptr_type_node,
                                                        void_list_node)),
                        NOT_BUILT_IN, NULL_PTR);
-  empty_fndecl
-    = builtin_function ("__empty",
-                       vtype,
-                       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);
@@ -310,47 +294,118 @@ init_exception_processing ()
 
   pop_lang_context ();
 
-  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);
+  d = build_decl (VAR_DECL, get_identifier ("__eh_pc"), ptr_type_node);
+  TREE_PUBLIC (d) = 1;
+  DECL_EXTERNAL (d) = 1;
+  DECL_ARTIFICIAL (d) = 1;
+  cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
+  saved_pc = d;
 
   /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
      be protected with __terminate.  */
   protect_cleanup_actions_with_terminate = 1;
 }
 
+/* Retrieve a pointer to the cp_eh_info node for the current exception
+   and save it in the current binding level.  */
+
+static void
+push_eh_info ()
+{
+  tree decl, fn;
+
+  fn = get_identifier ("__cp_exception_info");
+  if (IDENTIFIER_GLOBAL_VALUE (fn))
+    fn = IDENTIFIER_GLOBAL_VALUE (fn);
+  else
+    {
+      tree t, fields[5];
+
+      /* Declare cp_eh_info * __cp_exception_info (void),
+        as defined in exception.cc. */
+      push_obstacks_nochange ();
+      end_temporary_allocation ();
+
+      /* struct cp_eh_info.  This must match exception.cc.  Note that this
+        type is not pushed anywhere.  */
+      t = make_lang_type (RECORD_TYPE);
+      fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
+                                        ptr_type_node);
+      fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
+                                        ptr_type_node);
+      fields[2] = build_lang_field_decl
+       (FIELD_DECL, get_identifier ("cleanup"),
+        build_pointer_type (build_function_type
+                            (ptr_type_node, tree_cons
+                             (NULL_TREE, ptr_type_node, void_list_node))));
+      fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
+                                        boolean_type_node);
+      fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
+                                        build_pointer_type (t));
+      finish_builtin_type (t, "cp_eh_info", fields, 5, ptr_type_node);
+      t = build_pointer_type (t);
+
+      /* And now the function.  */
+      fn = build_lang_decl (FUNCTION_DECL, fn,
+                           build_function_type (t, void_list_node));
+      DECL_EXTERNAL (fn) = 1;
+      TREE_PUBLIC (fn) = 1;
+      DECL_ARTIFICIAL (fn) = 1;
+      pushdecl_top_level (fn);
+      make_function_rtl (fn);
+      assemble_external (fn);
+      pop_obstacks ();
+    }
+  fn = build_function_call (fn, NULL_TREE);
+
+  /* Remember the pointer to the current exception info; it won't change
+     during this catch block.  */
+  decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
+                    TREE_TYPE (fn));
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_INITIAL (decl) = fn;
+  decl = pushdecl (decl);
+  cp_finish_decl (decl, fn, NULL_TREE, 0, 0);
+}
+
+/* Returns a reference to the cp_eh_info node for the current exception.  */
+
+static tree
+get_eh_info ()
+{
+  /* Look for the pointer pushed in push_eh_info.  */
+  tree t = lookup_name (get_identifier ("__exception_info"), 0);
+  return build_indirect_ref (t, NULL_PTR);
+}
+
+/* Returns a reference to the current exception object.  */
+
+static tree
+get_eh_value ()
+{
+  return build_component_ref (get_eh_info (), get_identifier ("value"),
+                             NULL_TREE, 0);
+}
+
+/* Returns a reference to the current exception type.  */
+
+static tree
+get_eh_type ()
+{
+  return build_component_ref (get_eh_info (), get_identifier ("type"),
+                             NULL_TREE, 0);
+}
+
+/* Returns a reference to whether or not the current exception
+   has been caught.  */
+
+static tree
+get_eh_caught ()
+{
+  return build_component_ref (get_eh_info (), get_identifier ("caught"),
+                             NULL_TREE, 0);
+}
+
 /* Build a type value for use at runtime for a type that is matched
    against by the exception handling system.  */
 
@@ -396,19 +451,37 @@ build_eh_type (exp)
   return build_eh_type_type (TREE_TYPE (exp));
 }
 
-/* This routine creates the cleanup for the exception handling object.  */
+/* This routine creates the cleanup for the current exception.  */
 
 static void
 push_eh_cleanup ()
 {
   /* All cleanups must last longer than normal.  */
   int yes = suspend_momentary ();
+  tree fn, cleanup;
+
+  fn = get_identifier ("__cp_pop_exception");
+  if (IDENTIFIER_GLOBAL_VALUE (fn))
+    fn = IDENTIFIER_GLOBAL_VALUE (fn);
+  else
+    {
+      /* Declare void __cp_pop_exception (void), as defined in exception.cc. */
+      push_obstacks_nochange ();
+      end_temporary_allocation ();
+      fn = build_lang_decl (FUNCTION_DECL, fn,
+                           build_function_type (void_type_node,
+                                                void_list_node));
+      DECL_EXTERNAL (fn) = 1;
+      TREE_PUBLIC (fn) = 1;
+      DECL_ARTIFICIAL (fn) = 1;
+      pushdecl_top_level (fn);
+      make_function_rtl (fn);
+      assemble_external (fn);
+      pop_obstacks ();
+    }
 
   /* 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)));
+  cleanup = build_function_call (fn, NULL_TREE);
   expand_decl_cleanup (NULL_TREE, cleanup);
 
   resume_momentary (yes);
@@ -456,6 +529,23 @@ expand_start_catch_block (declspecs, declarator)
 
   emit_line_note (input_filename, lineno);
 
+  push_eh_info ();
+
+  /* If we are not doing setjmp/longjmp EH, because we are reordered
+     out of line, we arrange to rethrow in the outer context so as to
+     skip through the terminate region we are nested in, should we
+     encounter an exception in the catch handler.
+
+     If we are doing setjmp/longjmp EH, we need to skip through the EH
+     object cleanup region.  This isn't quite right, as we really need
+     to clean the object up, but we cannot do that until we track
+     multiple EH objects.
+
+     Matches the end in expand_end_catch_block.  */
+  expand_eh_region_start ();
+
+  push_eh_cleanup ();
+
   if (declspecs)
     {
       tree exp;
@@ -467,12 +557,6 @@ expand_start_catch_block (declspecs, declarator)
       if (decl == NULL_TREE)
        {
          error ("invalid catch parameter");
-
-         /* This is cheap, but we want to maintain the data
-             structures.  */
-
-         expand_eh_region_start ();
-
          return;
        }
 
@@ -486,11 +570,11 @@ expand_start_catch_block (declspecs, declarator)
          && TREE_CODE (init_type) != POINTER_TYPE)
        init_type = build_reference_type (init_type);
 
-      exp = saved_throw_value;
+      exp = get_eh_value ();
       exp = expr_tree_cons (NULL_TREE,
                       build_eh_type_type (TREE_TYPE (decl)),
                       expr_tree_cons (NULL_TREE,
-                                 saved_throw_type,
+                                 get_eh_type (),
                                  expr_tree_cons (NULL_TREE, exp, NULL_TREE)));
       exp = build_function_call (CatchMatch, exp);
       call_rtx = expand_call (exp, NULL_RTX, 0);
@@ -505,8 +589,6 @@ expand_start_catch_block (declspecs, declarator)
       /* if it returned FALSE, jump over the catch block, else fall into it */
       emit_jump_insn (gen_beq (false_label_rtx));
 
-      push_eh_cleanup ();
-
       init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
 
       /* Do we need the below two lines? */
@@ -515,27 +597,9 @@ expand_start_catch_block (declspecs, declarator)
       decl = pushdecl (decl);
       cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
     }
-  else
-    {
-      push_eh_cleanup ();
 
-      /* Fall into the catch all section.  */
-    }
-
-  emit_move_insn (DECL_RTL (saved_in_catch), const1_rtx);
-
-  /* If we are not doing setjmp/longjmp EH, because we are reordered
-     out of line, we arrange to rethrow in the outer context so as to
-     skip through the terminate region we are nested in, should we
-     encounter an exception in the catch handler.
-
-     If we are doing setjmp/longjmp EH, we need to skip through the EH
-     object cleanup region.  This isn't quite right, as we really need
-     to clean the object up, but we cannot do that until we track
-     multiple EH objects.
-
-     Matches the end in expand_end_catch_block.  */
-  expand_eh_region_start ();
+  init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node);
+  expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
   emit_line_note (input_filename, lineno);
 }
@@ -845,7 +909,8 @@ expand_builtin_throw ()
 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
   if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
     {
-      t = make_tree (build_pointer_type (TREE_TYPE (empty_fndecl)),
+      t = build_function_type (void_type_node, void_list_node);
+      t = make_tree (build_pointer_type (t),
                     hard_function_value (ptr_type_node,
                                          NULL_TREE));
       t = build_function_call (t, NULL_TREE);
@@ -965,6 +1030,9 @@ expand_end_eh_spec (raises)
   emit_label (check);
   emit_move_insn (flag, const1_rtx);
   cont = gen_label_rtx ();
+
+  push_eh_info ();
+
   while (raises)
     {
       tree exp;
@@ -973,11 +1041,11 @@ expand_end_eh_spec (raises)
       if (match_type)
        {
          /* check TREE_VALUE (raises) here */
-         exp = saved_throw_value;
+         exp = get_eh_value ();
          exp = expr_tree_cons (NULL_TREE,
                           build_eh_type_type (match_type),
                           expr_tree_cons (NULL_TREE,
-                                     saved_throw_type,
+                                     get_eh_type (),
                                      expr_tree_cons (NULL_TREE, exp, NULL_TREE)));
          exp = build_function_call (CatchMatch, exp);
          assemble_external (TREE_OPERAND (CatchMatch, 0));
@@ -1123,6 +1191,8 @@ expand_throw (exp)
      tree exp;
 {
   rtx label;
+  tree fn;
+  static tree cleanup_type;
 
   if (! doing_eh (1))
     return;
@@ -1130,12 +1200,26 @@ expand_throw (exp)
   if (exp)
     {
       tree throw_type;
-      tree cleanup = empty_fndecl, e;
+      tree cleanup = NULL_TREE, e;
 
       /* throw expression */
       /* First, decay it.  */
       exp = decay_conversion (exp);
 
+      /* cleanup_type is void (*)(void *, int),
+        the internal type of a destructor. */
+      if (cleanup_type == NULL_TREE)
+       {
+         push_obstacks_nochange ();
+         end_temporary_allocation ();
+         cleanup_type = build_pointer_type
+           (build_function_type
+            (void_type_node, tree_cons
+             (NULL_TREE, ptr_type_node, tree_cons
+              (NULL_TREE, integer_type_node, void_list_node))));
+         pop_obstacks ();
+       }
+
       if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
        {
          throw_type = build_eh_type (exp);
@@ -1156,33 +1240,83 @@ expand_throw (exp)
          object = build_indirect_ref (exp, NULL_PTR);
          throw_type = build_eh_type (object);
 
-                 /* Build __tcf_ function. */
-         cleanup = start_anon_func ();
-         object = build_delete (TREE_TYPE (exp), saved_throw_value, 
-                                integer_three_node, LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
-         expand_expr (object, const0_rtx, VOIDmode, 0);
-         end_anon_func ();
-         mark_addressable (cleanup);
+         if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
+           {
+             cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
+                                        dtor_identifier, 0);
+             cleanup = TREE_VALUE (cleanup);
+             mark_addressable (cleanup);
+             /* Pretend it's a normal function.  */
+             cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
+           }
        }
 
-      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 (cleanup == NULL_TREE)
+       {
+         cleanup = build_int_2 (0, 0);
+         TREE_TYPE (cleanup) = cleanup_type;
+       }
 
-      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);
+      fn = get_identifier ("__cp_push_exception");
+      if (IDENTIFIER_GLOBAL_VALUE (fn))
+       fn = IDENTIFIER_GLOBAL_VALUE (fn);
+      else
+       {
+         /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
+            as defined in exception.cc.  */
+         tree tmp;
+         push_obstacks_nochange ();
+         end_temporary_allocation ();
+         tmp = tree_cons
+           (NULL_TREE, ptr_type_node, tree_cons
+            (NULL_TREE, ptr_type_node, tree_cons
+             (NULL_TREE, cleanup_type, void_list_node)));
+         fn = build_lang_decl (FUNCTION_DECL, fn,
+                               build_function_type (void_type_node, tmp));
+         DECL_EXTERNAL (fn) = 1;
+         TREE_PUBLIC (fn) = 1;
+         DECL_ARTIFICIAL (fn) = 1;
+         pushdecl_top_level (fn);
+         make_function_rtl (fn);
+         assemble_external (fn);
+         pop_obstacks ();
+       }
 
-      cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
-      cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
-      expand_expr (cleanup, const0_rtx, VOIDmode, 0);
+      /* The throw expression is a full-expression.  */
+      exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
+      e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons
+                         (NULL_TREE, throw_type, expr_tree_cons
+                          (NULL_TREE, cleanup, NULL_TREE)));
+      e = build_function_call (fn, e);
+      expand_expr (e, const0_rtx, VOIDmode, 0);
     }
   else
     {
-      /* rethrow current exception */
-      /* This part is easy, as we don't have to do anything else.  */
+      /* rethrow current exception; note that it's no longer caught.  */
+
+      tree fn = get_identifier ("__uncatch_exception");
+      if (IDENTIFIER_GLOBAL_VALUE (fn))
+       fn = IDENTIFIER_GLOBAL_VALUE (fn);
+      else
+       {
+         /* Declare void __uncatch_exception (void)
+            as defined in exception.cc. */
+         push_obstacks_nochange ();
+         end_temporary_allocation ();
+         fn = build_lang_decl (FUNCTION_DECL, fn,
+                               build_function_type (void_type_node,
+                                                    void_list_node));
+         DECL_EXTERNAL (fn) = 1;
+         TREE_PUBLIC (fn) = 1;
+         DECL_ARTIFICIAL (fn) = 1;
+         pushdecl_top_level (fn);
+         make_function_rtl (fn);
+         assemble_external (fn);
+         pop_obstacks ();
+       }
+
+      exp = build_function_call (fn, NULL_TREE);
+      expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
     }
 
   if (exceptions_via_longjmp)
index 839525f..4099d47 100644 (file)
@@ -73,6 +73,79 @@ unexpected ()
   __unexpected_func ();
 }
 
+/* C++-specific state about the current exception.
+   This must match init_exception_processing().  */
+
+struct cp_eh_info
+{
+  void *value;
+  void *type;
+  void (*cleanup)(void *, int);
+  bool caught;
+  cp_eh_info *next;
+};
+
+/* Language-specific EH info pointer, defined in libgcc2.  */
+
+extern cp_eh_info *__eh_info;  // actually void*
+
+/* Is P the type_info node for a pointer of some kind?  */
+
+extern bool __is_pointer (void *);
+
+/* Compiler hook to return a pointer to the info for the current exception.
+   Used by get_eh_info ().  */
+
+extern "C" cp_eh_info *
+__cp_exception_info (void)
+{
+  return __eh_info;
+}
+
+/* Compiler hook to push a new exception onto the stack.
+   Used by expand_throw().  */
+
+extern "C" void
+__cp_push_exception (void *value, void *type, void (*cleanup)(void *, int))
+{
+  cp_eh_info *p = new cp_eh_info;
+  p->value = value;
+  p->type = type;
+  p->cleanup = cleanup;
+  p->caught = false;
+  p->next = __eh_info;
+  __eh_info = p;
+}
+
+/* Compiler hook to pop an exception that has been finalized.  Used by
+   push_eh_cleanup().  */
+
+extern "C" void
+__cp_pop_exception (void)
+{
+  cp_eh_info *p = __eh_info;
+
+  if (p->cleanup)
+    /* 3 is a magic value for destructors; see build_delete().  */
+    p->cleanup (p->value, 3);
+  else if (__is_pointer (p->type))
+    /* do nothing; pointers are passed directly in p->value.  */;
+  else
+    delete p->value;
+
+  __eh_info = p->next;
+  delete p;
+}
+
+extern "C" void
+__uncatch_exception (void)
+{
+  cp_eh_info *p = __cp_exception_info ();
+  if (p)
+    p->caught = false;
+  /* otherwise __throw will call terminate(); don't crash here.  */
+}
+
 extern "C" void
 __throw_bad_cast (void)
 {
@@ -91,12 +164,13 @@ __throw_bad_exception (void)
   throw bad_exception ();
 }
 
+/* Has the current exception been caught?  */
+
 bool
 uncaught_exception ()
 {
-  extern void *__eh_type;
-  extern bool __eh_in_catch;
-  return __eh_type && ! __eh_in_catch;
+  cp_eh_info *p = __cp_exception_info ();
+  return p && ! p->caught;
 }
 
 const char * exception::
index 72870df..128661c 100644 (file)
@@ -258,6 +258,18 @@ __throw_type_match_rtti (void *catch_type_r, void *throw_type_r, void *objptr)
   return new_objptr;
 }
 
+/* Called from __cp_pop_exception.  Is P the type_info node for a pointer
+   of some kind?  */
+
+bool
+__is_pointer (void *p)
+{
+  const type_info *t = reinterpret_cast <const type_info *>(p);
+  const __pointer_type_info *pt =
+    dynamic_cast <const __pointer_type_info *> (t);
+  return pt != 0;
+}
+
 extern "C" void
 __rtti_ptr (void *addr, const char *n, const type_info *ti)
 { new (addr) __pointer_type_info (n, *ti); }
index ae97c53..6c34da7 100644 (file)
@@ -3109,7 +3109,9 @@ int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
 
 /* Shared exception handling support routines.  */
 
-extern void *__eh_type;
+/* Language-specific information about the active exception(s).  If there
+   are no active exceptions, it is set to 0.  */
+void *__eh_info;
 
 void
 __default_terminate ()
@@ -3224,7 +3226,7 @@ __sjthrow ()
   /* We must call terminate if we try and rethrow an exception, when
      there is no exception currently active and when there are no
      handlers left.  */
-  if (! __eh_type || (*dhc) == top_elt)
+  if (! __eh_info || (*dhc) == top_elt)
     __terminate ();
     
   /* Find the jmpbuf associated with the top element of the dynamic
@@ -3307,7 +3309,7 @@ __sjpopnthrow ()
 /* This value identifies the place from which an exception is being
    thrown.  */
 
-extern void *__eh_pc;
+void *__eh_pc;
 
 #ifdef EH_TABLE_LOOKUP
 
@@ -3652,7 +3654,7 @@ __throw ()
   /* This is required for C++ semantics.  We must call terminate if we
      try and rethrow an exception, when there is no exception currently
      active.  */
-  if (! __eh_type)
+  if (! __eh_info)
     __terminate ();
     
   /* Start at our stack frame.  */