This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: Implementing Exception Propagation (N2179)
Hi once more,
So I've implemented this as I said in my last mail: by splitting out the
actual exception object and adding reference counting to that. Attached
is a patch for this. It should be applied to the trunk. It's built
against a tree that's about a week old.
GCC passes the test suite with this patch, except for a few tests. I've
yet to run the test suite for the unmodified version to have a baseline
to compare to, but I think none of the failures - except obviously the
libstdc++ abi_check failure - have anything to do with my patch.
I've not written any tests yet, or even tried exception_ptr out. But
normal throwing works.
This makes the questions I can't answer myself all the more pressing:
1) I've broken the C++ Base ABI. I believe that this ABI is not capable
of supporting exception_ptr, and that breaking it is unavoidable.
However, it seems that I should propose my changes to the base ABI group
instead of just changing the GCC code. Who should I contact? Should I
just send a mail to the base ABI group?
2) What should I change the exception class to? I may get an answer to
this as a result of #1, but then, maybe not.
3) Should I change the G++ ABI namespace? It's currently __cxxabiv1.
Should I change it to __cxxabiv2? It seems appropriate. And it would
turn the crashes I saw when I accidentally linked against the old
libstdc++ into load time failures.
Anyway, have fun trying out the patch. It contains an implementation of
exception_ptr and nested_exception.
Sebastian
Index: gcc/cp/except.c
===================================================================
--- gcc/cp/except.c (revision 135411)
+++ gcc/cp/except.c (working copy)
@@ -1,6 +1,7 @@
/* Handle exceptional things in C++.
Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
+ 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.
@@ -707,14 +708,23 @@
expression first. Since there could be temps in the
expression, we need to handle that, too. We also expand
the call to __cxa_allocate_exception first (which doesn't
- matter, since it can't throw). */
+ matter, since it can't throw).
+ Also, note the __cxa_allocate_exception doesn't return a
+ pointer to the target object, but to the unwind wrapper.
+ Dereference once to get the target object. */
+
/* Allocate the space for the exception. */
allocate_expr = do_allocate_exception (temp_type);
allocate_expr = get_target_expr (allocate_expr);
ptr = TARGET_EXPR_SLOT (allocate_expr);
- object = build_nop (build_pointer_type (temp_type), ptr);
+ /* That's a double pointer. */
+ tmp = build_pointer_type (temp_type);
+ tmp = build_pointer_type (tmp);
+ object = build_nop (tmp, ptr);
+ /* Dereference it twice to get the object. */
object = cp_build_indirect_ref (object, NULL, tf_warning_or_error);
+ object = cp_build_indirect_ref (object, NULL, tf_warning_or_error);
elided = (TREE_CODE (exp) == TARGET_EXPR);
Index: libstdc++-v3/libsupc++/eh_type.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_type.cc (revision 135411)
+++ libstdc++-v3/libsupc++/eh_type.cc (working copy)
@@ -1,5 +1,5 @@
// -*- C++ -*- Exception handling routines for catching.
-// Copyright (C) 2001 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2008 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -43,7 +43,7 @@
__cxa_eh_globals *globals = __cxa_get_globals ();
__cxa_exception *header = globals->caughtExceptions;
if (header)
- return header->exceptionType;
+ return __get_exception_info_from_header(header)->exceptionType;
else
return 0;
}
Index: libstdc++-v3/libsupc++/Makefile.in
===================================================================
--- libstdc++-v3/libsupc++/Makefile.in (revision 135411)
+++ libstdc++-v3/libsupc++/Makefile.in (working copy)
@@ -79,7 +79,7 @@
bad_cast.cc bad_typeid.cc class_type_info.cc del_op.cc \
del_opnt.cc del_opv.cc del_opvnt.cc dyncast.cc eh_alloc.cc \
eh_arm.cc eh_aux_runtime.cc eh_call.cc eh_catch.cc \
- eh_exception.cc eh_globals.cc eh_personality.cc \
+ eh_exception.cc eh_globals.cc eh_personality.cc eh_ptr.cc \
eh_term_handler.cc eh_terminate.cc eh_throw.cc eh_type.cc \
eh_unex_handler.cc enum_type_info.cc function_type_info.cc \
fundamental_type_info.cc guard.cc new_handler.cc new_op.cc \
@@ -91,7 +91,7 @@
bad_typeid.lo class_type_info.lo del_op.lo del_opnt.lo \
del_opv.lo del_opvnt.lo dyncast.lo eh_alloc.lo eh_arm.lo \
eh_aux_runtime.lo eh_call.lo eh_catch.lo eh_exception.lo \
- eh_globals.lo eh_personality.lo eh_term_handler.lo \
+ eh_globals.lo eh_personality.lo eh_ptr.lo eh_term_handler.lo \
eh_terminate.lo eh_throw.lo eh_type.lo eh_unex_handler.lo \
enum_type_info.lo function_type_info.lo \
fundamental_type_info.lo guard.lo new_handler.lo new_op.lo \
@@ -107,7 +107,7 @@
atexit_arm.cc bad_cast.cc bad_typeid.cc class_type_info.cc \
del_op.cc del_opnt.cc del_opv.cc del_opvnt.cc dyncast.cc \
eh_alloc.cc eh_arm.cc eh_aux_runtime.cc eh_call.cc eh_catch.cc \
- eh_exception.cc eh_globals.cc eh_personality.cc \
+ eh_exception.cc eh_globals.cc eh_personality.cc eh_ptr.cc \
eh_term_handler.cc eh_terminate.cc eh_throw.cc eh_type.cc \
eh_unex_handler.cc enum_type_info.cc function_type_info.cc \
fundamental_type_info.cc guard.cc new_handler.cc new_op.cc \
@@ -263,13 +263,9 @@
VERSION = @VERSION@
WARN_FLAGS = @WARN_FLAGS@
WERROR = @WERROR@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_AS = @ac_ct_AS@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-ac_ct_RANLIB = @ac_ct_RANLIB@
-ac_ct_STRIP = @ac_ct_STRIP@
am__leading_dot = @am__leading_dot@
am__tar = @am__tar@
am__untar = @am__untar@
@@ -282,6 +278,9 @@
build_vendor = @build_vendor@
check_msgfmt = @check_msgfmt@
datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
enable_shared = @enable_shared@
enable_static = @enable_static@
exec_prefix = @exec_prefix@
@@ -301,21 +300,25 @@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
+htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
libtool_VERSION = @libtool_VERSION@
+localedir = @localedir@
localstatedir = @localstatedir@
lt_ECHO = @lt_ECHO@
mandir = @mandir@
mkdir_p = @mkdir_p@
multi_basedir = @multi_basedir@
oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
port_specific_symbol_files = @port_specific_symbol_files@
prefix = @prefix@
program_transform_name = @program_transform_name@
+psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
@@ -378,6 +381,7 @@
eh_exception.cc \
eh_globals.cc \
eh_personality.cc \
+ eh_ptr.cc \
eh_term_handler.cc \
eh_terminate.cc \
eh_throw.cc \
Index: libstdc++-v3/libsupc++/eh_alloc.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_alloc.cc (revision 135411)
+++ libstdc++-v3/libsupc++/eh_alloc.cc (working copy)
@@ -1,5 +1,5 @@
// -*- C++ -*- Allocate exception objects.
-// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
+// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008
// Free Software Foundation, Inc.
//
// This file is part of GCC.
@@ -39,7 +39,6 @@
#include <climits>
#include <exception>
#include "unwind-cxx.h"
-#include <ext/concurrence.h>
#if _GLIBCXX_HOSTED
using std::free;
@@ -58,6 +57,8 @@
// ??? How to control these parameters.
// Guess from the size of basic types how large a buffer is reasonable.
+// TODO: The comment below is out of date. Adjust it and maybe change the
+// emergency buffer sizes.
// Note that the basic c++ exception header has 13 pointers and 2 ints,
// so on a system with PSImode pointers we're talking about 56 bytes
// just for overhead.
@@ -95,13 +96,12 @@
__gnu_cxx::__mutex emergency_mutex;
}
-extern "C" void *
-__cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw()
+static void *
+__gxx_eh_allocate(std::size_t bytes) throw()
{
void *ret;
- thrown_size += sizeof (__cxa_exception);
- ret = malloc (thrown_size);
+ ret = malloc (bytes);
if (! ret)
{
@@ -110,7 +110,7 @@
bitmask_type used = emergency_used;
unsigned int which = 0;
- if (thrown_size > EMERGENCY_OBJ_SIZE)
+ if (bytes > EMERGENCY_OBJ_SIZE)
goto failed;
while (used & 1)
{
@@ -128,20 +128,11 @@
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));
+ return ret;
}
-
-extern "C" void
-__cxxabiv1::__cxa_free_exception(void *vptr) throw()
+static void
+__gxx_eh_free(void *vptr) throw()
{
char *base = (char *) emergency_buffer;
char *ptr = (char *) vptr;
@@ -155,5 +146,67 @@
emergency_used &= ~((bitmask_type)1 << which);
}
else
- free (ptr - sizeof (__cxa_exception));
+ free (ptr);
}
+
+extern "C" void *
+__cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw()
+{
+ __cxa_exception_info *info = __cxa_allocate_exception_object (thrown_size);
+ return __cxa_allocate_exception_wrapper (info);
+}
+
+extern "C" __cxa_exception_info *
+__cxxabiv1::__cxa_allocate_exception_object(std::size_t thrown_size) throw()
+{
+ void *obj = __gxx_eh_allocate (sizeof(__cxa_exception_info) + thrown_size);
+ memset (obj, 0, sizeof (__cxa_exception_info));
+ return static_cast<__cxa_exception_info *>(obj);
+}
+
+extern "C" __cxa_exception *
+__cxxabiv1::__cxa_allocate_exception_wrapper(__cxa_exception_info *obj) throw()
+{
+ void *mem = __gxx_eh_allocate (sizeof (__cxa_exception));
+ memset (mem, 0, sizeof (__cxa_exception));
+ __cxa_exception *header = static_cast<__cxa_exception*>(mem);
+ // exceptionObject points at the exception, not the info header
+ header->exceptionObject = obj + 1;
+
+ {
+ __gnu_cxx::__scoped_lock sentry(__cxa_eh_refcount_mutex);
+ ++obj->referenceCount;
+ }
+
+ // 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;
+
+ return header;
+}
+
+extern "C" void
+__cxxabiv1::__cxa_free_exception(void *vptr) throw()
+{
+ __cxa_exception *header = static_cast<__cxa_exception*>(vptr);
+ __cxa_exception_info *info = __get_exception_info_from_header (header);
+ bool destroy = false;
+ {
+ __gnu_cxx::__scoped_lock sentry(__cxa_eh_refcount_mutex);
+ if (--info->referenceCount == 0)
+ destroy = true;
+ }
+ if (destroy)
+ __cxa_free_exception_object (info);
+ __gxx_eh_free (vptr);
+}
+
+extern "C" void
+__cxxabiv1::__cxa_free_exception_object(__cxa_exception_info *obj) throw()
+{
+ if (obj->exceptionDestructor)
+ obj->exceptionDestructor (obj + 1);
+ __gxx_eh_free (obj);
+}
Index: libstdc++-v3/libsupc++/unwind-cxx.h
===================================================================
--- libstdc++-v3/libsupc++/unwind-cxx.h (revision 135411)
+++ libstdc++-v3/libsupc++/unwind-cxx.h (working copy)
@@ -1,5 +1,5 @@
// -*- C++ -*- Exception handling and frame unwind runtime interface routines.
-// Copyright (C) 2001 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2008 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -39,22 +39,36 @@
#include <exception>
#include <cstddef>
#include "unwind.h"
+#include <ext/concurrence.h>
#pragma GCC visibility push(default)
namespace __cxxabiv1
{
-// A C++ exception object consists of a header, which is a wrapper around
-// an unwind object header with additional C++ specific information,
-// followed by the exception object itself.
+// A C++ exception object consists of a C++-specific extension of an unwind
+// object header, which contains a pointer to the actual exception and some
+// additional information needed for bookkeeping.
-struct __cxa_exception
-{
+// This is the header for the actual object.
+struct __cxa_exception_info
+{
+ // How many exception_ptrs and __cxa_exceptions are referring to this
+ // exception.
+ int referenceCount;
+
// Manage the exception object itself.
std::type_info *exceptionType;
- void (*exceptionDestructor)(void *);
+ void (*exceptionDestructor)(void *);
+};
+// This is the extension of the unwind header.
+struct __cxa_exception
+{
+ // Pointer to the actual object. Also, before this address, the info header.
+ // Must be first!
+ void *exceptionObject;
+
// The C++ standard has entertaining rules wrt calling set_terminate
// and set_unexpected in the middle of the exception cleanup process.
std::unexpected_handler unexpectedHandler;
@@ -97,7 +111,12 @@
#endif
};
+// This mutex protects the reference counts of all exception objects.
+// Doing it per-object would be unreasonable overhead.
+// Atomics would be better, but I'm not sure about their availability.
+extern __gnu_cxx::__mutex __cxa_eh_refcount_mutex;
+
// The __cxa_eh_globals for the current thread can be obtained by using
// either of the following functions. The "fast" version assumes at least
// one prior call of __cxa_get_globals has been made from the current
@@ -105,14 +124,30 @@
extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
extern "C" __cxa_eh_globals *__cxa_get_globals_fast () throw();
-// Allocate memory for the exception plus the thown object.
+// Allocate memory for the wrapper plus the thrown object. Returns the
+// unwind header wrapper. (Return type is void* for simplicity in the tree
+// declaration.)
extern "C" void *__cxa_allocate_exception(std::size_t thrown_size) throw();
-// Free the space allocated for the exception.
-extern "C" void __cxa_free_exception(void *thrown_exception) throw();
+// Allocate memory for the thrown object and its info header. Returns a pointer
+// to the info header; the object is placed immediately afterwards.
+extern "C" __cxa_exception_info *
+__cxa_allocate_exception_object(std::size_t thrown_size) throw();
+// Allocate memory for the wrapper only, wrapping the given object. Returns
+// the unwind header wrapper.
+extern "C" __cxa_exception *
+__cxa_allocate_exception_wrapper(__cxa_exception_info *obj) throw();
+
+// Free the unwind wrapper, and the exception itself if it's no longer
+// referenced.
+extern "C" void __cxa_free_exception(void *unwind_wrapper) throw();
+
+// Free the exception object, unconditionally.
+extern "C" void __cxa_free_exception_object(__cxa_exception_info *obj) throw();
+
// Throw the exception.
-extern "C" void __cxa_throw (void *thrown_exception,
+extern "C" void __cxa_throw (void *unwind_wrapper,
std::type_info *tinfo,
void (*dest) (void *))
__attribute__((noreturn));
@@ -159,11 +194,10 @@
// These are explicitly GNU C++ specific.
-// Acquire the C++ exception header from the C++ object.
-static inline __cxa_exception *
-__get_exception_header_from_obj (void *ptr)
+static inline __cxa_exception_info *
+__get_exception_info_from_header (__cxa_exception *hdr)
{
- return reinterpret_cast<__cxa_exception *>(ptr) - 1;
+ return reinterpret_cast<__cxa_exception_info *>(hdr->exceptionObject) - 1;
}
// Acquire the C++ exception header from the generic exception header.
@@ -184,7 +218,7 @@
&& c[3] == 'C'
&& c[4] == 'C'
&& c[5] == '+'
- && c[6] == '+'
+ && c[6] == '1'
&& c[7] == '\0';
}
@@ -197,7 +231,7 @@
c[3] = 'C';
c[4] = 'C';
c[5] = '+';
- c[6] = '+';
+ c[6] = '1';
c[7] = '\0';
}
@@ -207,7 +241,7 @@
return (void*)eo->barrier_cache.bitpattern[0];
}
#else // !__ARM_EABI_UNWINDER__
-// This is the exception class we report -- "GNUCC++\0".
+// This is the exception class we report -- "GNUCC+1\0".
const _Unwind_Exception_Class __gxx_exception_class
= ((((((((_Unwind_Exception_Class) 'G'
<< 8 | (_Unwind_Exception_Class) 'N')
@@ -215,7 +249,7 @@
<< 8 | (_Unwind_Exception_Class) 'C')
<< 8 | (_Unwind_Exception_Class) 'C')
<< 8 | (_Unwind_Exception_Class) '+')
- << 8 | (_Unwind_Exception_Class) '+')
+ << 8 | (_Unwind_Exception_Class) '1')
<< 8 | (_Unwind_Exception_Class) '\0');
static inline bool
Index: libstdc++-v3/libsupc++/exception
===================================================================
--- libstdc++-v3/libsupc++/exception (revision 135411)
+++ libstdc++-v3/libsupc++/exception (working copy)
@@ -1,7 +1,7 @@
// Exception Handling support header for -*- C++ -*-
// Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-// 2004, 2005, 2006, 2007
+// 2004, 2005, 2006, 2007, 2008
// Free Software Foundation
//
// This file is part of GCC.
@@ -79,6 +79,88 @@
virtual const char* what() const throw();
};
+ /**
+ * @brief An opaque pointer to an arbitrary exception.
+ */
+ class exception_ptr
+ {
+ void* _M_exception_object;
+
+ explicit exception_ptr(void* e)
+ : _M_exception_object(e)
+ {
+ addref();
+ }
+
+ void addref() throw();
+ void release() throw();
+
+ void *get() const { return _M_exception_object; }
+
+ friend exception_ptr current_exception() throw();
+ friend void rethrow_exception(exception_ptr);
+
+ public:
+ exception_ptr()
+ : _M_exception_object(0)
+ {
+ }
+
+ exception_ptr(const exception_ptr& o)
+ : _M_exception_object(o._M_exception_object)
+ {
+ addref();
+ }
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+ exception_ptr(exception_ptr&& o)
+ : _M_exception_object(o._M_exception_object)
+ {
+ o._M_exception_object = 0;
+ }
+#endif
+
+ exception_ptr& operator=(const exception_ptr& o)
+ {
+ exception_ptr(o).swap(*this);
+ return *this;
+ }
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+ exception_ptr& operator=(exception_ptr&& o)
+ {
+ exception_ptr(o).swap(*this);
+ return *this;
+ }
+#endif
+
+ ~exception_ptr()
+ {
+ release();
+ }
+
+ void swap(exception_ptr &o)
+ {
+ void *tmp = _M_exception_object;
+ _M_exception_object = o._M_exception_object;
+ o._M_exception_object = tmp;
+ }
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+ void swap(exception_ptr &&o)
+ {
+ void *tmp = _M_exception_object;
+ _M_exception_object = o._M_exception_object;
+ o._M_exception_object = tmp;
+ }
+#endif
+
+ friend bool operator ==(const exception_ptr& lhs, const exception_ptr& rhs)
+ {
+ return lhs._M_exception_object == rhs._M_exception_object;
+ }
+ };
+
/// If you write a replacement %terminate handler, it must be of this type.
typedef void (*terminate_handler) ();
@@ -110,6 +192,50 @@
* result in a call of @c terminate() (15.5.1)."
*/
bool uncaught_exception() throw();
+
+ /** Obtain an %exception_ptr to the currently handled exception. If there
+ * is none, or the currently handled exception is foreign, return the null
+ * value.
+ */
+ exception_ptr current_exception() throw();
+
+ /// Throw the object pointed to by the %exception_ptr.
+ void rethrow_exception(exception_ptr) __attribute__ ((__noreturn__));
+
+ /// Obtain an %exception_ptr pointing to a copy of the supplied object.
+ template <class E>
+ exception_ptr copy_exception(E e) throw();
+
+ /**
+ * @brief A mixin class for holding a nested exception.
+ *
+ * This class allows wrapping arbitrary exceptions in other exceptions.
+ */
+ class nested_exception
+ {
+ exception_ptr _M_inner;
+
+ public:
+ nested_exception() throw();
+ // Lacking =default, don't write explicit copy functions yet.
+ virtual ~nested_exception() throw();
+
+ void rethrow_nested() const __attribute__ ((noreturn));
+ exception_ptr nested_ptr() const { return _M_inner; }
+ };
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+ template <class T>
+ void throw_with_nested(T&& t) __attribute__ ((noreturn));
+#else
+ // Fall back to a normal reference.
+ template <class T>
+ void throw_with_nested(const T &t) __attribute ((noreturn));
+#endif
+
+ template <class E>
+ void throw_if_nested(const E& e);
+
} // namespace std
_GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
@@ -130,6 +256,8 @@
} // extern "C++"
+#include <exception_inlines.h>
+
#pragma GCC visibility pop
#endif
Index: libstdc++-v3/libsupc++/eh_throw.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_throw.cc (revision 135411)
+++ libstdc++-v3/libsupc++/eh_throw.cc (working copy)
@@ -1,5 +1,5 @@
// -*- C++ -*- Exception handling routines for throwing.
-// Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2003, 2008 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -38,6 +38,10 @@
{
__cxa_exception *header = __get_exception_header_from_ue (exc);
+ // TODO: The below comment was never really correct. The native handler uses
+ // _Unwind_DeleteException too. Also, relying on header->terminateHandler
+ // being valid is risky if we've already established that there's a problem.
+
// If we haven't been caught by a foreign handler, then this is
// some sort of unwind error. In that case just die immediately.
// _Unwind_DeleteException in the HP-UX IA64 libunwind library
@@ -46,20 +50,18 @@
if (code != _URC_FOREIGN_EXCEPTION_CAUGHT && code != _URC_NO_REASON)
__terminate (header->terminateHandler);
- if (header->exceptionDestructor)
- header->exceptionDestructor (header + 1);
-
- __cxa_free_exception (header + 1);
+ __cxa_free_exception (header);
}
extern "C" void
-__cxxabiv1::__cxa_throw (void *obj, std::type_info *tinfo,
+__cxxabiv1::__cxa_throw (void *hdr, std::type_info *tinfo,
void (*dest) (void *))
{
- __cxa_exception *header = __get_exception_header_from_obj (obj);
- header->exceptionType = tinfo;
- header->exceptionDestructor = dest;
+ __cxa_exception *header = static_cast<__cxa_exception *>(hdr);
+ __cxa_exception_info *info = __get_exception_info_from_header (header);
+ info->exceptionType = tinfo;
+ info->exceptionDestructor = dest;
header->unexpectedHandler = __unexpected_handler;
header->terminateHandler = __terminate_handler;
__GXX_INIT_EXCEPTION_CLASS(header->unwindHeader.exception_class);
@@ -91,8 +93,15 @@
if (!__is_gxx_exception_class(header->unwindHeader.exception_class))
globals->caughtExceptions = 0;
else
- header->handlerCount = -header->handlerCount;
+ {
+ header->handlerCount = -header->handlerCount;
+ // throw; is a throw-expression too, so terminate and unexpected
+ // should have updated handlers. cf. [18.7.3.3]/2 and [18.7.2.4]/2
+ header->unexpectedHandler = __unexpected_handler;
+ header->terminateHandler = __terminate_handler;
+ }
+
#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
_Unwind_SjLj_Resume_or_Rethrow (&header->unwindHeader);
#else
@@ -108,3 +117,33 @@
}
std::terminate ();
}
+
+void
+std::rethrow_exception (exception_ptr p)
+{
+ if (!p.get())
+ std::terminate ();
+
+ __cxa_exception_info *info = static_cast<__cxa_exception_info *>(p.get()) - 1;
+
+ __cxa_exception *header = __cxa_allocate_exception_wrapper (info);
+
+ header->unexpectedHandler = __unexpected_handler;
+ header->terminateHandler = __terminate_handler;
+ __GXX_INIT_EXCEPTION_CLASS(header->unwindHeader.exception_class);
+ header->unwindHeader.exception_cleanup = __gxx_exception_cleanup;
+
+#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
+ _Unwind_SjLj_Resume_or_Rethrow (&header->unwindHeader);
+#else
+#if defined(_LIBUNWIND_STD_ABI)
+ _Unwind_RaiseException (&header->unwindHeader);
+#else
+ _Unwind_Resume_or_Rethrow (&header->unwindHeader);
+#endif
+#endif
+
+ // Some sort of unwinding error. Note that terminate is a handler.
+ __cxa_begin_catch (&header->unwindHeader);
+ std::terminate ();
+}
Index: libstdc++-v3/libsupc++/exception_inlines.h
===================================================================
--- libstdc++-v3/libsupc++/exception_inlines.h (revision 0)
+++ libstdc++-v3/libsupc++/exception_inlines.h (revision 0)
@@ -0,0 +1,91 @@
+// -*- C++ -*- Inline and template implementation file for <exception>.
+//
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+
+/** @file exception_inlines.h
+ * This is an internal header file, included by other library headers.
+ * You should not attempt to use it directly.
+ */
+
+#ifndef __EXCEPTION_INLINES_H__
+#define __EXCEPTION_INLINES_H__
+
+// ??? The semantics of this in the face of rvalue and lvalue references aren't
+// quite right.
+
+namespace std
+{
+ template <class T>
+ class __with_nested_exception : public T, public nested_exception
+ {
+ public:
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+ __with_nested_exception(T&& t) : T(t) { }
+#else
+ __with_nested_exception(const T& t) : T(t) { }
+#endif
+ };
+}
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+template <class T>
+void
+std::throw_with_nested(T&& t)
+{
+ if(dynamic_cast<nested_exception&&>(t))
+ throw t;
+ else
+ throw __with_nested_exception<T>(t);
+}
+#else
+template <class T>
+void
+std::throw_with_nested(const T& t)
+{
+ if(dynamic_cast<const nested_exception&>(t))
+ throw t;
+ else
+ throw __with_nested_exception<T>(t);
+}
+#endif
+
+template <class E>
+std::exception_ptr std::copy_exception(E e) throw()
+{
+ try
+ {
+ throw e;
+ }
+ catch(...)
+ {
+ return current_exception ();
+ }
+}
+
+#endif
Index: libstdc++-v3/libsupc++/eh_ptr.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_ptr.cc (revision 0)
+++ libstdc++-v3/libsupc++/eh_ptr.cc (revision 0)
@@ -0,0 +1,87 @@
+// -*- C++ -*- Implement the members of exception_ptr.
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+
+#include <bits/c++config.h>
+#include <exception>
+#include "unwind-cxx.h"
+
+using namespace __cxxabiv1;
+
+static inline __cxa_exception_info *
+__exception_info(void *obj)
+{
+ return static_cast<__cxa_exception_info *>(obj) - 1;
+}
+
+
+void
+std::exception_ptr::addref() throw()
+{
+ if (_M_exception_object)
+ {
+ __cxa_exception_info *info = __exception_info (_M_exception_object);
+ __gnu_cxx::__scoped_lock sentry(__cxa_eh_refcount_mutex);
+ ++info->referenceCount;
+ }
+}
+
+
+void
+std::exception_ptr::release() throw()
+{
+ if (_M_exception_object)
+ {
+ __cxa_exception_info *info = __exception_info (_M_exception_object);
+
+ __cxa_eh_refcount_mutex.lock ();
+ --info->referenceCount;
+ bool destroy = info->referenceCount == 0;
+ __cxa_eh_refcount_mutex.unlock ();
+
+ if (destroy)
+ __cxa_free_exception_object (info);
+ }
+}
+
+
+std::exception_ptr
+std::current_exception() throw()
+{
+ __cxa_eh_globals *globals = __cxa_get_globals ();
+ __cxa_exception *header = globals->caughtExceptions;
+
+ if (!header)
+ return std::exception_ptr();
+
+ // Since foreign exceptions can't be counted, we can't return them.
+ if (!__is_gxx_exception_class (header->unwindHeader.exception_class))
+ return std::exception_ptr();
+
+ return std::exception_ptr(header->exceptionObject);
+}
Index: libstdc++-v3/libsupc++/eh_catch.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_catch.cc (revision 135411)
+++ libstdc++-v3/libsupc++/eh_catch.cc (working copy)
@@ -1,5 +1,5 @@
// -*- C++ -*- Exception handling routines for catching.
-// Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2003, 2004, 2008 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -53,9 +53,7 @@
// Foreign exceptions can't be stacked here. If the exception stack is
// empty, then fine. Otherwise we really have no choice but to terminate.
- // Note that this use of "header" is a lie. It's fine so long as we only
- // examine header->unwindHeader though.
- if (!__is_gxx_exception_class(header->unwindHeader.exception_class))
+ if (!__is_gxx_exception_class(exceptionObject->exception_class))
{
if (prev != 0)
std::terminate ();
@@ -103,8 +101,8 @@
if (!header)
return;
- // A foreign exception couldn't have been stacked (see above),
- // so by definition processing must be complete.
+ // A foreign exception couldn't have been stacked (see above) or been
+ // assigned to an exception_ptr, so by definition processing must be complete.
if (!__is_gxx_exception_class(header->unwindHeader.exception_class))
{
globals->caughtExceptions = 0;
@@ -134,7 +132,6 @@
header->handlerCount = count;
}
-
bool
std::uncaught_exception() throw()
{
Index: libstdc++-v3/libsupc++/eh_globals.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_globals.cc (revision 135411)
+++ libstdc++-v3/libsupc++/eh_globals.cc (working copy)
@@ -1,5 +1,5 @@
// -*- C++ -*- Manage the thread-local exception globals.
-// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
+// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008
// Free Software Foundation, Inc.
//
// This file is part of GCC.
@@ -47,6 +47,8 @@
using namespace __cxxabiv1;
+__gnu_cxx::__mutex __cxxabiv1::__cxa_eh_refcount_mutex;
+
#if _GLIBCXX_HAVE_TLS
namespace
Index: libstdc++-v3/libsupc++/eh_exception.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_exception.cc (revision 135411)
+++ libstdc++-v3/libsupc++/eh_exception.cc (working copy)
@@ -1,6 +1,6 @@
// -*- C++ -*- std::exception implementation.
// Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-// 2003, 2004, 2005, 2006, 2007
+// 2003, 2004, 2005, 2006, 2007, 2008
// Free Software Foundation
//
// This file is part of GCC.
@@ -55,3 +55,16 @@
{
return "std::bad_exception";
}
+
+std::nested_exception::nested_exception() throw()
+ : _M_inner(current_exception())
+{
+}
+
+std::nested_exception::~nested_exception() throw() { }
+
+void
+std::nested_exception::rethrow_nested() const
+{
+ rethrow_exception(_M_inner);
+}
Index: libstdc++-v3/libsupc++/eh_personality.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_personality.cc (revision 135411)
+++ libstdc++-v3/libsupc++/eh_personality.cc (working copy)
@@ -377,7 +377,7 @@
const unsigned char *p;
_Unwind_Ptr landing_pad, ip;
int handler_switch_value;
- void* thrown_ptr = ue_header + 1;
+ void* thrown_ptr;
bool foreign_exception;
int ip_before_insn = 0;
@@ -547,6 +547,12 @@
if ((actions & _UA_FORCE_UNWIND)
|| foreign_exception)
thrown_ptr = 0;
+ else
+ {
+ // This is finally safe to do here.
+ __cxa_exception* xh = __get_exception_header_from_ue(ue_header);
+ thrown_ptr = __get_exception_info_from_header(xh) + 1;
+ }
#else
// During forced unwinding, match a magic exception type.
if (actions & _UA_FORCE_UNWIND)
@@ -562,7 +568,10 @@
thrown_ptr = 0;
}
else
- throw_type = xh->exceptionType;
+ {
+ throw_type = __get_exception_info_from_header(xh)->exceptionType;
+ thrown_ptr = xh->exceptionObject;
+ }
#endif
while (1)
@@ -754,13 +763,15 @@
__cxa_eh_globals *globals = __cxa_get_globals_fast ();
__cxa_exception *new_xh = globals->caughtExceptions;
- void *new_ptr = new_xh + 1;
+ void *new_ptr = new_xh->exceptionObject;
// We don't quite have enough stuff cached; re-parse the LSDA.
parse_lsda_header (0, xh_lsda, &info);
// If this new exception meets the exception spec, allow it.
- if (check_exception_spec (&info, new_xh->exceptionType,
+ if (check_exception_spec (&info,
+ __get_exception_info_from_header
+ (new_xh)->exceptionType,
new_ptr, xh_switch_value))
__throw_exception_again;
Index: libstdc++-v3/libsupc++/Makefile.am
===================================================================
--- libstdc++-v3/libsupc++/Makefile.am (revision 135411)
+++ libstdc++-v3/libsupc++/Makefile.am (working copy)
@@ -1,6 +1,6 @@
## Makefile for the GNU C++ Support library.
##
-## Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
+## Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
## Free Software Foundation, Inc.
##
## Process this file with automake to produce Makefile.in.
@@ -59,6 +59,7 @@
eh_exception.cc \
eh_globals.cc \
eh_personality.cc \
+ eh_ptr.cc \
eh_term_handler.cc \
eh_terminate.cc \
eh_throw.cc \
Index: libstdc++-v3/libsupc++/eh_call.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_call.cc (revision 135411)
+++ libstdc++-v3/libsupc++/eh_call.cc (working copy)
@@ -1,5 +1,5 @@
// -*- C++ -*- Helpers for calling unextected and terminate
-// Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2002, 2003, 2008 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -125,7 +125,7 @@
__cxa_eh_globals* globals = __cxa_get_globals_fast();
__cxa_exception* new_xh = globals->caughtExceptions;
- void* new_ptr = new_xh + 1;
+ void* new_ptr = new_xh->exceptionObject;
const std::type_info* catch_type;
int n;
bool bad_exception_allowed = false;