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.

Reply via email to