Re: [PATCH RFC] do not throw in std::make_exception_ptr
On Wed, Aug 3, 2016 at 8:36 AM, Jonathan Wakelywrote: > On 03/08/16 15:02 +0300, Gleb Natapov wrote: >> >> On Wed, Aug 03, 2016 at 12:47:30PM +0100, Jonathan Wakely wrote: >>> Huh. If I'm reading the ABI spec correctly, we should terminate if the >>> copy constructor throws. >>> >> I'll make it terminate like you've suggested then. > > Let's leave it as you had it originally. I'm not sure if my reading of > the ABI is correct, so let's keep the behaviour consistent for now. > > We can always revisit it later if we decide terminating is correct. Terminating is not correct, the ABI document is out of date: CWG 475 (wg21.link/cwg475) clarified that terminate is not called if the copy constructor throws while initializing the exception object. Jason
Re: [PATCH RFC] do not throw in std::make_exception_ptr
On 03/08/16 15:02 +0300, Gleb Natapov wrote: On Wed, Aug 03, 2016 at 12:47:30PM +0100, Jonathan Wakely wrote: Huh. If I'm reading the ABI spec correctly, we should terminate if the copy constructor throws. I'll make it terminate like you've suggested then. Let's leave it as you had it originally. I'm not sure if my reading of the ABI is correct, so let's keep the behaviour consistent for now. We can always revisit it later if we decide terminating is correct. We don't seem to do that even without exception_ptr involved: Yes, that's the reason current make_exception_ptr behaves as it does, but to fix your test case below the code that generates code for 'throw' will have to be fixed. Right, and we wont' be changing that as part of this patch, so let's stay consistent with that too. #include #include struct E { E() {} E(const E&) { throw 5; } }; int main() { static E e; try { throw e; } catch(E& ep) { std::cout << "E" << std::endl; } catch (int& i) { std::cout << "int" << std::endl; } } [skip] > > > - 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? I missed this comment. typeid() returns const std::type_info so I either need to add const here or cast the const away from typeid() return value. Please use const_cast. std::type_info doesn't have any non-cosnt member that would allow modifications through that pointer anyway. Thanks.
Re: [PATCH RFC] do not throw in std::make_exception_ptr
On Wed, Aug 03, 2016 at 12:47:30PM +0100, Jonathan Wakely wrote: > > > > > > > + } // namespace __exception_ptr > > > > > > > > /// Obtain an exception_ptr pointing to a copy of the supplied object. > > > > template > > > > @@ -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? > > Because otherwise this valid C++ program won't compile: > > #define e 2.71828 > #include > int main() { } > Ah, I missed that fact that the code is in user visible include. > > > > > > > > > > + (void)__cxxabiv1::__cxa_init_primary_exception(e, > > > > (__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 > > #include > > > > 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; > >} > > } > > Huh. If I'm reading the ABI spec correctly, we should terminate if the > copy constructor throws. > I'll make it terminate like you've suggested then. > We don't seem to do that even without exception_ptr involved: > Yes, that's the reason current make_exception_ptr behaves as it does, but to fix your test case below the code that generates code for 'throw' will have to be fixed. > #include > #include > > struct E { >E() {} >E(const E&) { throw 5; } > }; > > int main() { >static E e; >try { >throw e; >} catch(E& ep) { >std::cout << "E" << std::endl; >} catch (int& i) { >std::cout << "int" << std::endl; >} > } [skip] > > > > - 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? I missed this comment. typeid() returns const std::type_info so I either need to add const here or cast the const away from typeid() return value. -- Gleb.
Re: [PATCH RFC] do not throw in std::make_exception_ptr
On 03/08/16 14:26 +0300, Gleb Natapov wrote: On Wed, Aug 03, 2016 at 10:48:27AM +0100, Jonathan Wakely wrote: Does bad_exception need to move to ? I think only std::exception is really needed by . 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. Yes, that way and are as small as possible, and only declare what they need. Code that wants std::bad_exception or std::set_unexpected() should include , as before. > swap(exception_ptr& __lhs, exception_ptr& __rhs) > { __lhs.swap(__rhs); } > > - } // namespace __exception_ptr > +template > + 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? Well it certainly *can* be, declaring it inline doesn't mean you can't take its address. Currently it's 'static' which means every translation unit that calls make_exception_ptr will instantiate a different copy of the function template. That produces more object code than needed, so it should not be static. It's a tiny function defined in a header, so should be 'inline'. Practically speaking, making it 'inline' doesn't make much difference, because an instantiated function template will produce a weak symbol anyway, which as the same effect as declaring it inline. But there's no reason _not_ to declare it inline. > + } // namespace __exception_ptr > > /// Obtain an exception_ptr pointing to a copy of the supplied object. > template > @@ -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? Because otherwise this valid C++ program won't compile: #define e 2.71828 #include int main() { } > + (void)__cxxabiv1::__cxa_init_primary_exception(e, (__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 #include 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; } } Huh. If I'm reading the ABI spec correctly, we should terminate if the copy constructor throws. We don't seem to do that even without exception_ptr involved: #include #include struct E { E() {} E(const E&) { throw 5; } }; int main() { static E e; try { throw e; } 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 exception_ptrmake_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, (__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 > -#include > +#include > #include > #include "unwind.h" > #include > @@ -62,7 +62,7 @@ namespace __cxxabiv1 > struct __cxa_exception > { > // Manage the exception object itself. > -
Re: [PATCH RFC] do not throw in std::make_exception_ptr
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 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 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 (>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 > > -#include > > - > > -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: > > -//
Re: [PATCH RFC] do not throw in std::make_exception_ptr
On 03/08/16 10:48 +0100, Jonathan Wakely wrote: On 28/07/16 10:20 +0300, Gleb Natapov wrote: +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. Oops, I meant to delete that comment. Please ignore it! You're only suggesting a new function in the "GNU extensions" part of our header, and it's only needed in our make_exception_ptr function, not required by any of the actual runtime files in libsupc++. So there's no need for it to be common to other implementations of the ABI.
Re: [PATCH RFC] do not throw in std::make_exception_ptr
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 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). include files. The former had to be split due to circular dependency that formed after including 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 (>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 -#include - -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 ? - /// 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 because
Re: [PATCH RFC] do not throw in std::make_exception_ptr
On Sun, Jul 31, 2016 at 02:28:51PM +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 and cxxabi.h > > include files. The former had to be split due to circular dependency > > that formed after including 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. > > > > Comments are welcome. > > Thanks for the patch, it would be great to make this improvement. > > Before I review the actual changes, do you have a GCC copyright > assignment, and if not would you be willing and able to sign one? > My company, ScyllaDB, has signed the copyright assignment. > See https://gcc.gnu.org/contribute.html#legal for more details. > > -- Gleb.
Re: [PATCH RFC] do not throw in std::make_exception_ptr
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 and cxxabi.h include files. The former had to be split due to circular dependency that formed after including 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. Comments are welcome. Thanks for the patch, it would be great to make this improvement. Before I review the actual changes, do you have a GCC copyright assignment, and if not would you be willing and able to sign one? See https://gcc.gnu.org/contribute.html#legal for more details.