[PATCH RFC] do not throw in std::make_exception_ptr
Jonathan Wakely
jwakely@redhat.com
Wed Aug 3 11:47:00 GMT 2016
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 <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.
Yes, that way <typeinfo> and <cxxabi.h> are as small as possible, and
only declare what they need.
Code that wants std::bad_exception or std::set_unexpected() should
include <exception>, as before.
>> > 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?
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<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?
Because otherwise this valid C++ program won't compile:
#define e 2.71828
#include <exception>
int main() { }
>
>>
>> > + (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;
> }
>}
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 <iostream>
#include <exception>
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<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.
More information about the Gcc-patches
mailing list