On Wed, Aug 03, 2016 at 10:48:27AM +0100, Jonathan Wakely wrote:
> On 28/07/16 10:20 +0300, Gleb Natapov wrote:
> > [resent with hopefully correct libstdc++ mailing list address this time]
> >
> > Here is my attempt to fix
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68297. The resulting patch
> > is a little bit long because I had to split <exception> and cxxabi.h
>
> "A little bit", yes ;-)
>
> A changelog would help review it, because it's not clear what has
> moved to where. You've split files, but not said what parts end up
> where (which obviously can be seen by the patch, but it would be
> easier with a summary in ChangeLog form).
>
Will do for next submission.
> > include files. The former had to be split due to circular dependency
> > that formed after including <typeinfo> in exception_ptr.h and the later
> > is because of inability to include cxxabi.h in exception_ptr.h because
> > it makes libstdc++/30586 to reappear again.
>
>
> > diff --git a/libstdc++-v3/libsupc++/eh_throw.cc
> > b/libstdc++-v3/libsupc++/eh_throw.cc
> > index 9aac218..b368f8a 100644
> > --- a/libstdc++-v3/libsupc++/eh_throw.cc
> > +++ b/libstdc++-v3/libsupc++/eh_throw.cc
> > @@ -55,6 +55,22 @@ __gxx_exception_cleanup (_Unwind_Reason_Code code,
> > _Unwind_Exception *exc)
> > #endif
> > }
> >
> > +extern "C" __cxa_refcounted_exception*
> > +__cxxabiv1::__cxa_init_primary_exception(void *obj, const std::type_info
> > *tinfo,
> > + void (_GLIBCXX_CDTOR_CALLABI
> > *dest) (void *))
> > +{
> > + __cxa_refcounted_exception *header
> > + = __get_refcounted_exception_header_from_obj (obj);
> > + header->referenceCount = 0;
> > + header->exc.exceptionType = tinfo;
> > + header->exc.exceptionDestructor = dest;
> > + header->exc.unexpectedHandler = std::get_unexpected ();
> > + header->exc.terminateHandler = std::get_terminate ();
> > +
> > __GXX_INIT_PRIMARY_EXCEPTION_CLASS(header->exc.unwindHeader.exception_class);
> > + header->exc.unwindHeader.exception_cleanup = __gxx_exception_cleanup;
> > +
> > + return header;
> > +}
>
> I'd like to see any additions like this function discussed on the C++
> ABI list, so we at least have an idea whether other vendors would
> consider implementing it too.
>
>
>
> >
> > extern "C" void
> > __cxxabiv1::__cxa_throw (void *obj, std::type_info *tinfo,
> > @@ -64,17 +80,10 @@ __cxxabiv1::__cxa_throw (void *obj, std::type_info
> > *tinfo,
> >
> > __cxa_eh_globals *globals = __cxa_get_globals ();
> > globals->uncaughtExceptions += 1;
> > -
> > // Definitely a primary.
> > - __cxa_refcounted_exception *header
> > - = __get_refcounted_exception_header_from_obj (obj);
> > + __cxa_refcounted_exception *header =
> > + __cxa_init_primary_exception(obj, tinfo, dest);
> > header->referenceCount = 1;
> > - header->exc.exceptionType = tinfo;
> > - header->exc.exceptionDestructor = dest;
> > - header->exc.unexpectedHandler = std::get_unexpected ();
> > - header->exc.terminateHandler = std::get_terminate ();
> > -
> > __GXX_INIT_PRIMARY_EXCEPTION_CLASS(header->exc.unwindHeader.exception_class);
> > - header->exc.unwindHeader.exception_cleanup = __gxx_exception_cleanup;
> >
> > #ifdef __USING_SJLJ_EXCEPTIONS__
> > _Unwind_SjLj_RaiseException (&header->exc.unwindHeader);
> > diff --git a/libstdc++-v3/libsupc++/exception
> > b/libstdc++-v3/libsupc++/exception
> > index 63631f6..6f8b596 100644
> > --- a/libstdc++-v3/libsupc++/exception
> > +++ b/libstdc++-v3/libsupc++/exception
> > @@ -34,135 +34,7 @@
> >
> > #pragma GCC visibility push(default)
> >
> > -#include <bits/c++config.h>
> > -#include <bits/atomic_lockfree_defines.h>
> > -
> > -extern "C++" {
> > -
> > -namespace std
> > -{
> > - /**
> > - * @defgroup exceptions Exceptions
> > - * @ingroup diagnostics
> > - *
> > - * Classes and functions for reporting errors via exception classes.
> > - * @{
> > - */
> > -
> > - /**
> > - * @brief Base class for all library exceptions.
> > - *
> > - * This is the base class for all exceptions thrown by the standard
> > - * library, and by certain language expressions. You are free to derive
> > - * your own %exception classes, or use a different hierarchy, or to
> > - * throw non-class data (e.g., fundamental types).
> > - */
> > - class exception
> > - {
> > - public:
> > - exception() _GLIBCXX_USE_NOEXCEPT { }
> > - virtual ~exception() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT;
> > -
> > - /** Returns a C-style character string describing the general cause
> > - * of the current error. */
> > - virtual const char*
> > - what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT;
> > - };
> > -
> > - /** If an %exception is thrown which is not listed in a function's
> > - * %exception specification, one of these may be thrown. */
> > - class bad_exception : public exception
> > - {
> > - public:
> > - bad_exception() _GLIBCXX_USE_NOEXCEPT { }
> > -
> > - // This declaration is not useless:
> > - // http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118
> > - virtual ~bad_exception() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT;
> > -
> > - // See comment in eh_exception.cc.
> > - virtual const char*
> > - what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT;
> > - };
>
>
> Does bad_exception need to move to <bits/exception.h> ?
>
>
I think only std::exception is really needed by <typeinfo>. When I
did header split I when with "move as much as possible" approach, not
the other way around. You seems to suggest the opposite approach. I'll
try it.
> > - /// If you write a replacement %terminate handler, it must be of this
> > type.
> > - typedef void (*terminate_handler) ();
> > -
> > - /// If you write a replacement %unexpected handler, it must be of this
> > type.
> > - typedef void (*unexpected_handler) ();
>
> These typedefs are certainly needed in <bits/exception.h> because
> unwind-cxx.h uses them, but ...
>
>
> > -
> > - /// Takes a new handler function as an argument, returns the old
> > function.
> > - terminate_handler set_terminate(terminate_handler) _GLIBCXX_USE_NOEXCEPT;
> > -
> > -#if __cplusplus >= 201103L
> > - /// Return the current terminate handler.
> > - terminate_handler get_terminate() noexcept;
> > -#endif
> > -
> > - /** The runtime will call this function if %exception handling must be
> > - * abandoned for any reason. It can also be called by the user. */
> > - void terminate() _GLIBCXX_USE_NOEXCEPT __attribute__ ((__noreturn__));
> > -
> > - /// Takes a new handler function as an argument, returns the old
> > function.
> > - unexpected_handler set_unexpected(unexpected_handler)
> > _GLIBCXX_USE_NOEXCEPT;
> > -
> > -#if __cplusplus >= 201103L
> > - /// Return the current unexpected handler.
> > - unexpected_handler get_unexpected() noexcept;
> > -#endif
> > -
> > - /** The runtime will call this function if an %exception is thrown which
> > - * violates the function's %exception specification. */
> > - void unexpected() __attribute__ ((__noreturn__));
> > -
> > - /** [18.6.4]/1: 'Returns true after completing evaluation of a
> > - * throw-expression until either completing initialization of the
> > - * exception-declaration in the matching handler or entering @c
> > unexpected()
> > - * due to the throw; or after entering @c terminate() for any reason
> > - * other than an explicit call to @c terminate(). [Note: This includes
> > - * stack unwinding [15.2]. end note]'
> > - *
> > - * 2: 'When @c uncaught_exception() is true, throwing an
> > - * %exception can result in a call of @c terminate()
> > - * (15.5.1).'
> > - */
> > - bool uncaught_exception() _GLIBCXX_USE_NOEXCEPT __attribute__
> > ((__pure__));
> > -
> > -#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++98
> > -#define __cpp_lib_uncaught_exceptions 201411
> > - /// The number of uncaught exceptions.
> > - int uncaught_exceptions() _GLIBCXX_USE_NOEXCEPT __attribute__
> > ((__pure__));
> > -#endif
>
> None of these seem to be needed in <bits/exception.h>, is that right?
>
> If we're splitting <exception> so that a smaller piece of it can be
> used elsewhere without the entire file, then lets make that smaller
> piece *only* contain what's needed elsewhere.
>
> There's no need to move things out of <exception> if they aren't
> needed by the files you are changing to include <bits/exception.h>.
>
OK. I'll try to do that.
> > -
> > - // @} group exceptions
> > -} // namespace std
> > -
> > -namespace __gnu_cxx
> > -{
> > -_GLIBCXX_BEGIN_NAMESPACE_VERSION
> > -
> > - /**
> > - * @brief A replacement for the standard terminate_handler which
> > - * prints more information about the terminating exception (if any)
> > - * on stderr.
> > - *
> > - * @ingroup exceptions
> > - *
> > - * Call
> > - * @code
> > - * std::set_terminate(__gnu_cxx::__verbose_terminate_handler)
> > - * @endcode
> > - * to use. For more info, see
> > - * http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt02ch06s02.html
> > - *
> > - * In 3.4 and later, this is on by default.
> > - */
> > - void __verbose_terminate_handler();
>
> Likewise, does this need to move to <bits/exception.h> ?
>
> It's not needed by the ABI headers, only by <bits/basic_ios.h> and the
> .cc files in libsupc++.
>
> > diff --git a/libstdc++-v3/libsupc++/exception_ptr.h
> > b/libstdc++-v3/libsupc++/exception_ptr.h
> > index 783e539..6127b00 100644
> > --- a/libstdc++-v3/libsupc++/exception_ptr.h
> > +++ b/libstdc++-v3/libsupc++/exception_ptr.h
> > @@ -35,6 +35,9 @@
> >
> > #include <bits/c++config.h>
> > #include <bits/exception_defines.h>
> > +#include <typeinfo>
> > +#include <new>
> > +#include <bits/cxxabiv1.h>
> >
> > #if ATOMIC_INT_LOCK_FREE < 2
> > # error This platform does not support exception propagation.
> > @@ -62,6 +65,8 @@ namespace std
> > * value.
> > */
> > exception_ptr current_exception() _GLIBCXX_USE_NOEXCEPT;
> > + template<typename _Ex>
> > + exception_ptr make_exception_ptr(_Ex) _GLIBCXX_USE_NOEXCEPT;
> >
> > /// Throw the object pointed to by the exception_ptr.
> > void rethrow_exception(exception_ptr) __attribute__ ((__noreturn__));
> > @@ -87,6 +92,8 @@ namespace std
> >
> > friend exception_ptr std::current_exception() _GLIBCXX_USE_NOEXCEPT;
> > friend void std::rethrow_exception(exception_ptr);
> > + template<typename _Ex>
> > + friend exception_ptr std::make_exception_ptr(_Ex)
> > _GLIBCXX_USE_NOEXCEPT;
> >
> > public:
> > exception_ptr() _GLIBCXX_USE_NOEXCEPT;
> > @@ -162,8 +169,12 @@ namespace std
> > swap(exception_ptr& __lhs, exception_ptr& __rhs)
> > { __lhs.swap(__rhs); }
> >
> > - } // namespace __exception_ptr
> > + template<typename _Ex>
> > + static void dest_thunk(void* x) {
> > + reinterpret_cast<_Ex*>(x)->_Ex::~_Ex();
> > + }
>
> This isn't a name reserved for implementors, it needs to be uglified,
> e.g. __dest_thunk.
>
OK.
> This function should be declared 'inline' too.
>
We take a pointer to it. How can it be inline?
>
> > + } // namespace __exception_ptr
> >
> > /// Obtain an exception_ptr pointing to a copy of the supplied object.
> > template<typename _Ex>
> > @@ -173,7 +184,15 @@ namespace std
> > #if __cpp_exceptions
> > try
> > {
> > - throw __ex;
> > +#if __cpp_rtti && !_GLIBCXX_HAVE_CDTOR_CALLABI
> > + void *e = __cxxabiv1::__cxa_allocate_exception(sizeof(_Ex));
>
> Again, 'e' isn't a reserved name.
It is local variable, why should it be reserved?
>
> > + (void)__cxxabiv1::__cxa_init_primary_exception(e, &typeid(__ex),
> > +
> > __exception_ptr::dest_thunk<_Ex>);
> > + new (e) _Ex(__ex);
>
> If the copy constructor of _Ex throws an exception should we call
> std::terminate here?
>
> That's what would have happened previously, I believe.
>
I do not think so. throw compiles to something like:
__cxa_allocate_exception
call move_or_copy_constructor
__cxa_throw
If move_or_copy_constructor throws the code does not terminate, but
catch() gets different exception instead.
> I don't think we want to catch that exception and store it
> in the exception_ptr in place of the __ex object we were asked to
> store.
>
I wrote a test program below to check current behaviour and this is what code
does now.
#include <iostream>
#include <exception>
struct E {
E() {}
E(const E&) { throw 5; }
};
int main() {
auto x = std::make_exception_ptr(E());
try {
std::rethrow_exception(x);
} catch(E& ep) {
std::cout << "E" << std::endl;
} catch (int& i) {
std::cout << "int" << std::endl;
}
}
> So on that basis, do we need the try/catch around your new code?
>
> Can we just do:
>
> template<typename _Ex>
> exception_ptr make_exception_ptr(_Ex __ex) _GLIBCXX_USE_NOEXCEPT
> {
> #if __cpp_exceptions
> # if __cpp_rtti && !_GLIBCXX_HAVE_CDTOR_CALLABI
> void *__ptr = __cxxabiv1::__cxa_allocate_exception(sizeof(_Ex));
> (void)__cxxabiv1::__cxa_init_primary_exception(__ptr, &typeid(__ex),
> __exception_ptr::__dest_thunk<_Ex>);
> new (__ptr) _Ex(__ex);
> # else
> try
> {
> throw __ex;
> }
> catch(...)
> {
> return current_exception();
> }
> # endif
> #else
> return exception_ptr();
> #endif
> }
>
> The noexcept spec will cause it to terminate if the copy constructor
> of _Ex throws.
>
>
> > + return exception_ptr(e);
> > +#else
> > + throw __ex;
> > +#endif
> > }
> > catch(...)
> > {
>
>
> > diff --git a/libstdc++-v3/libsupc++/unwind-cxx.h
> > b/libstdc++-v3/libsupc++/unwind-cxx.h
> > index 9121934..11da4a7 100644
> > --- a/libstdc++-v3/libsupc++/unwind-cxx.h
> > +++ b/libstdc++-v3/libsupc++/unwind-cxx.h
> > @@ -31,7 +31,7 @@
> > // Level 2: C++ ABI
> >
> > #include <typeinfo>
> > -#include <exception>
> > +#include <bits/exception.h>
> > #include <cstddef>
> > #include "unwind.h"
> > #include <bits/atomic_word.h>
> > @@ -62,7 +62,7 @@ namespace __cxxabiv1
> > struct __cxa_exception
> > {
> > // Manage the exception object itself.
> > - std::type_info *exceptionType;
> > + const std::type_info *exceptionType;
> > void (_GLIBCXX_CDTOR_CALLABI *exceptionDestructor)(void *);
>
> The __cxa_exception type is defined by
> https://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-data and this
> doesn't conform to that spec. Is this change necessary?
>
--
Gleb.