re PR libstdc++/10606 (uncaught_exception() returns false too early)
authorRichard Henderson <rth@redhat.com>
Sat, 19 Feb 2005 02:35:25 +0000 (18:35 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Sat, 19 Feb 2005 02:35:25 +0000 (18:35 -0800)
        PR libstdc++/10606
gcc/cp/
        * except.c (do_get_exception_ptr): New.
        (expand_start_catch_block): Use it.
libstdc++/
        * config/linker-map.gnu (CXXABI_1.3.1): Add __cxa_get_exception_ptr.
        * libsupc++/eh_alloc.cc (__cxa_allocate_exception): Increment
        uncaughtExceptions here instead of ...
        * libsupc++/eh_throw.cc (__cxa_throw) ... here.
        (__cxa_rethrow): Increment uncaughtExceptions here instead of ...
        * libsupc++/eh_catch.cc (__cxa_end_catch): ... here.
        (__cxa_get_exception_ptr): New.
        * libsupc++/unwind-cxx.h (__cxa_get_exception_ptr): Declare.

From-SVN: r95262

gcc/cp/ChangeLog
gcc/cp/except.c
gcc/testsuite/g++.dg/eh/uncaught1.C [new file with mode: 0644]
libstdc++-v3/ChangeLog
libstdc++-v3/config/linker-map.gnu
libstdc++-v3/libsupc++/eh_alloc.cc
libstdc++-v3/libsupc++/eh_catch.cc
libstdc++-v3/libsupc++/eh_throw.cc
libstdc++-v3/libsupc++/unwind-cxx.h

index 92db68ec2631fba4632791516e9bb35904ddcad2..62e7a43ee37a5e37e6c3ab777628c50e25a75548 100644 (file)
@@ -1,3 +1,9 @@
+2005-02-18  Richard Henderson  <rth@redhat.com>
+
+       PR libstdc++/10606
+       * except.c (do_get_exception_ptr): New.
+       (expand_start_catch_block): Use it.
+
 2005-02-19  Jakub Jelinek  <jakub@redhat.com>
 
        * decl.c (start_decl_1): Only check TYPE_NEEDS_CONSTRUCTING
index 4a0ccb913b9af400414c826f17b832b910a641a6..ef4fb2193b51d11650eb6bb7a678c7bf545c3588 100644 (file)
@@ -153,6 +153,26 @@ build_exc_ptr (void)
   return build0 (EXC_PTR_EXPR, ptr_type_node);
 }
 
+/* Build up a call to __cxa_get_exception_ptr so that we can build a
+   copy constructor for the thrown object.  */
+
+static tree
+do_get_exception_ptr (void)
+{
+  tree fn;
+
+  fn = get_identifier ("__cxa_get_exception_ptr");
+  if (!get_global_value_if_present (fn, &fn))
+    {
+      /* Declare void* __cxa_get_exception_ptr (void *).  */
+      tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+      fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
+    }
+
+  return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (),
+                                            NULL_TREE));
+}
+
 /* Build up a call to __cxa_begin_catch, to tell the runtime that the
    exception has been handled.  */
 
@@ -381,9 +401,8 @@ initialize_handler_parm (tree decl, tree exp)
 tree
 expand_start_catch_block (tree decl)
 {
-  tree exp = NULL_TREE;
+  tree exp;
   tree type;
-  bool is_java;
 
   if (! doing_eh (1))
     return NULL_TREE;
@@ -397,45 +416,50 @@ expand_start_catch_block (tree decl)
   else
     type = NULL_TREE;
 
-  is_java = false;
-  if (decl)
+  if (decl && decl_is_java_type (type, 1))
+    {
+      /* Java only passes object via pointer and doesn't require
+        adjusting.  The java object is immediately before the
+        generic exception header.  */
+      exp = build_exc_ptr ();
+      exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
+      exp = build2 (MINUS_EXPR, TREE_TYPE (exp), exp,
+                   TYPE_SIZE_UNIT (TREE_TYPE (exp)));
+      exp = build_indirect_ref (exp, NULL);
+      initialize_handler_parm (decl, exp);
+      return type;
+    }
+
+  /* Call __cxa_end_catch at the end of processing the exception.  */
+  push_eh_cleanup (type);
+
+  /* If there's no decl at all, then all we need to do is make sure
+     to tell the runtime that we've begun handling the exception.  */
+  if (decl == NULL)
+    finish_expr_stmt (do_begin_catch ());
+
+  /* If the C++ object needs constructing, we need to do that before
+     calling __cxa_begin_catch, so that std::uncaught_exception gets
+     the right value during the copy constructor.  */
+  else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
     {
-      tree init;
+      exp = do_get_exception_ptr ();
+      initialize_handler_parm (decl, exp);
+      finish_expr_stmt (do_begin_catch ());
+    }
 
-      if (decl_is_java_type (type, 1))
-       {
-         /* Java only passes object via pointer and doesn't require
-            adjusting.  The java object is immediately before the
-            generic exception header.  */
-         init = build_exc_ptr ();
-         init = build1 (NOP_EXPR, build_pointer_type (type), init);
-         init = build2 (MINUS_EXPR, TREE_TYPE (init), init,
-                        TYPE_SIZE_UNIT (TREE_TYPE (init)));
-         init = build_indirect_ref (init, NULL);
-         is_java = true;
-       }
-      else
-       {
-         /* C++ requires that we call __cxa_begin_catch to get the
-            pointer to the actual object.  */
-         init = do_begin_catch ();
-       }
-         
+  /* Otherwise the type uses a bitwise copy, and we don't have to worry
+     about the value of std::uncaught_exception and therefore can do the
+     copy with the return value of __cxa_end_catch instead.  */
+  else
+    {
+      tree init = do_begin_catch ();
       exp = create_temporary_var (ptr_type_node);
       DECL_REGISTER (exp) = 1;
       cp_finish_decl (exp, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
       finish_expr_stmt (build_modify_expr (exp, INIT_EXPR, init));
+      initialize_handler_parm (decl, exp);
     }
-  else
-    finish_expr_stmt (do_begin_catch ());
-
-  /* C++ requires that we call __cxa_end_catch at the end of
-     processing the exception.  */
-  if (! is_java)
-    push_eh_cleanup (type);
-
-  if (decl)
-    initialize_handler_parm (decl, exp);
 
   return type;
 }
diff --git a/gcc/testsuite/g++.dg/eh/uncaught1.C b/gcc/testsuite/g++.dg/eh/uncaught1.C
new file mode 100644 (file)
index 0000000..2aa1068
--- /dev/null
@@ -0,0 +1,83 @@
+// PR libstdc++/10606
+// { dg-do run }
+
+#include <exception>
+#include <cstdlib>
+
+
+struct Check {
+  int obj1, obj2;
+  bool state;
+};
+
+static Check const data[] = {
+  { 0, 0, false },     // construct [0]
+  { 1, 0, true  },     // [1] = [0]
+  { 0, 0, true  },     // destruct [0]
+  { 2, 1, true  },     // [2] = [1]
+  { 2, 2, true  },      // destruct [2]
+  { 3, 1, true  },     // [3] = [1]
+  { 3, 3, false },     // destruct [3]
+  { 1, 1, false },     // destruct [1]
+  { 9, 9, false }      // end-of-data
+};
+
+static int pos = 0;
+
+static void test(int obj1, int obj2, bool state)
+{
+  if (obj1 != data[pos].obj1) abort ();
+  if (obj2 != data[pos].obj2) abort ();
+  if (state != data[pos].state) abort ();
+  pos++;
+}
+
+
+struct S {
+  int id;
+  S ();
+  S (const S &);
+  ~S ();
+};
+
+static int next_id = 0;
+
+S::S()
+  : id (next_id++)
+{
+  test (id, id, std::uncaught_exception ());
+}
+
+S::S(const S &x)
+  : id (next_id++)
+{
+  test (id, x.id, std::uncaught_exception ());
+}
+
+S::~S()
+{
+  test (id, id, std::uncaught_exception ());
+}
+
+extern void foo (S *);
+
+int main()
+{
+  try
+    {
+      try
+       {
+         S s0;
+         throw s0;     // s1 is the exception object
+       }
+      catch (S s2)
+       {
+         throw;
+       }
+    }
+  catch (S s3)
+    {
+    }
+  return 0;
+}
index e54c43b3930454a57fbb17e50c254d1d8ef51571..9b27b0b65e93a2d8efe46c620055adfda92b889c 100644 (file)
@@ -1,4 +1,17 @@
+2005-02-18  Richard Henderson  <rth@redhat.com>
+
+       PR libstdc++/10606
+       * config/linker-map.gnu (CXXABI_1.3.1): Add __cxa_get_exception_ptr.
+       * libsupc++/eh_alloc.cc (__cxa_allocate_exception): Increment
+       uncaughtExceptions here instead of ...
+       * libsupc++/eh_throw.cc (__cxa_throw) ... here.
+       (__cxa_rethrow): Increment uncaughtExceptions here instead of ...
+       * libsupc++/eh_catch.cc (__cxa_end_catch): ... here.
+       (__cxa_get_exception_ptr): New.
+       * libsupc++/unwind-cxx.h (__cxa_get_exception_ptr): Declare.
+
 2005-02-18  Matt Austern  <austern@apple.com>
+
        * testsuite/tr1/6_containers/unordered/insert/array_syntax.cc: Fix
        test case to use assignment instead of ==
        * testsuite/tr1/6_containers/unordered/insert/map_range.cc: New test.
index df3c674f96f150d31ee06601050a84de48bbdb8d..d7d291485b682a81b733495c96c4cf5c4deba145 100644 (file)
@@ -410,3 +410,9 @@ CXXABI_1.3 {
   local:
     *;
 };
+
+CXXABI_1.3.1 {
+
+    __cxa_get_exception_ptr;
+
+} CXXABI_1.3;
index 4728bcbf380ff31063f2f830a432a1e0cae76158..3b7319ea235cc23954fb1e6d5e022acef8d4156b 100644 (file)
@@ -147,6 +147,12 @@ __cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw()
        std::terminate ();
     }
 
+  // We have an uncaught exception as soon as we allocate memory.  This
+  // yields uncaught_exception() true during the copy-constructor that
+  // initializes the exception object.  See Issue 475.
+  __cxa_eh_globals *globals = __cxa_get_globals ();
+  globals->uncaughtExceptions += 1;
+
   memset (ret, 0, sizeof (__cxa_exception));
 
   return (void *)((char *)ret + sizeof (__cxa_exception));
index bdcbd7e085cbdad7cc869023aedf4284acc95292..88060d9f9cda0cd22e8b4a062352f4a581276bea 100644 (file)
 
 using namespace __cxxabiv1;
 
+extern "C" void *
+__cxxabiv1::__cxa_get_exception_ptr(void *exc_obj_in) throw()
+{
+  _Unwind_Exception *exceptionObject
+    = reinterpret_cast <_Unwind_Exception *>(exc_obj_in);
+  __cxa_exception *header = __get_exception_header_from_ue (exceptionObject);
+
+  return header->adjustedPtr;
+}
 
 extern "C" void *
 __cxxabiv1::__cxa_begin_catch (void *exc_obj_in) throw()
@@ -107,10 +116,7 @@ __cxxabiv1::__cxa_end_catch ()
       // This exception was rethrown.  Decrement the (inverted) catch
       // count and remove it from the chain when it reaches zero.
       if (++count == 0)
-       {
-         globals->uncaughtExceptions += 1;
-         globals->caughtExceptions = header->nextException;
-       }
+       globals->caughtExceptions = header->nextException;
     }
   else if (--count == 0)
     {
index b02efdad6dcc52bd08c7a9ebb35080d2fd1974b0..0807c5e1df77a3cd1b8032e4af1096d00e09e2ec 100644 (file)
@@ -66,9 +66,6 @@ __cxxabiv1::__cxa_throw (void *obj, std::type_info *tinfo,
   header->unwindHeader.exception_class = __gxx_exception_class;
   header->unwindHeader.exception_cleanup = __gxx_exception_cleanup;
 
-  __cxa_eh_globals *globals = __cxa_get_globals ();
-  globals->uncaughtExceptions += 1;
-
 #ifdef _GLIBCXX_SJLJ_EXCEPTIONS
   _Unwind_SjLj_RaiseException (&header->unwindHeader);
 #else
@@ -86,6 +83,8 @@ __cxxabiv1::__cxa_rethrow ()
   __cxa_eh_globals *globals = __cxa_get_globals ();
   __cxa_exception *header = globals->caughtExceptions;
 
+  globals->uncaughtExceptions += 1;
+
   // Watch for luser rethrowing with no active exception.
   if (header)
     {
index 67ea5cc21100714e3423ce528bb6dcdab9729f77..e79dd83628eda375a1e50ce2bb1bd22ffbd5202d 100644 (file)
@@ -107,6 +107,7 @@ extern "C" void __cxa_throw (void *thrown_exception,
      __attribute__((noreturn));
 
 // Used to implement exception handlers.
+extern "C" void *__cxa_get_exception_ptr (void *) throw();
 extern "C" void *__cxa_begin_catch (void *) throw();
 extern "C" void __cxa_end_catch ();
 extern "C" void __cxa_rethrow () __attribute__((noreturn));