[Bug libstdc++/85813] make_exception_ptr should support __cxa_init_primary_exception path even with -fno-exceptions
redi at gcc dot gnu.org
gcc-bugzilla@gcc.gnu.org
Thu Dec 9 18:36:05 GMT 2021
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85813
--- Comment #9 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Mathias Stearn from comment #3)
> My assumption was that if E(...) throws and it can't be caught, it should be
> treated as any other case when an -fno-exceptions TU calls a throwing
> function. In this case that would mean calling terminate() due to the
> noexcept, which seems better than returning a null exception_ptr.
Unfortunately, if E(...) throws and std::make_exception_ptr<E> was compiled
with -fno-exceptions, the noexcept on that function is ignored and the
exception propagates to the caller of std::make_exception_ptr. So exceptions
can propagate out of a noexcept function compiled with -fno-exceptions, which
is pretty counterintuitive because that's the last kind of function you'd
expect to throw when you call it! But that's not unique to
std::make_exception_ptr, it's true for any noexcept function compiled with
-fno-exceptions that calls that could throw.
(In reply to Mathias Stearn from comment #7)
> Silently dropping errors always skeeves me out. I'm not sure if anyone is
> well served by the current behavior. If it were up to me (and I know it
> isn't) I'd make that case call std::terminate() or similar rather than
> returning the "no error" value. That seems consistent with the behavior of
> the __throw* functions, but it is a breaking change. Or even better, since
> gcc seems fine throwing through functions marked noexcept in -fno-exceptions
> TUs, maybe in the (very rare) case where copying/moving an exception throws
> inside an -fno-exceptions TU, just let it bubble out.
I'm persuaded that if constructing the E throws, we should just let it bubble
out. We can't really do anything else.
But we still have the case of -fno-rtti -fno-exceptions case where we can't use
the newer non-throwing implementation of make_exception_ptr (because it uses
typeid) and we can't use the original throwing one (because it uses throw). So
that either has to terminate or return an empty exception_ptr, and either case
is a problem if you mix'n'match, so ...
> Do you think this case warrants a [[gnu::always_inline]]?
I now think the -fno-rtti -fno-exceptions case should be always_inline.
Here's what I'm considering ...
/// Obtain an exception_ptr pointing to a copy of the supplied object.
#if (__cplusplus >= 201103L && __cpp_rtti) || __cpp_exceptions
template<typename _Ex>
exception_ptr
make_exception_ptr(_Ex __ex) _GLIBCXX_USE_NOEXCEPT
{
#if __cplusplus >= 201103L && __cpp_rtti
using _Ex2 = typename decay<_Ex>::type;
void* __e = __cxxabiv1::__cxa_allocate_exception(sizeof(_Ex));
(void) __cxxabiv1::__cxa_init_primary_exception(
__e, const_cast<std::type_info*>(&typeid(_Ex)),
__exception_ptr::__dest_thunk<_Ex2>);
__try
{
::new (__e) _Ex2(__ex);
return exception_ptr(__e);
}
__catch(...)
{
__cxxabiv1::__cxa_free_exception(__e);
return current_exception();
}
#else
try
{
throw __ex;
}
catch(...)
{
return current_exception();
}
#endif
}
#else // no RTTI and no exceptions
// This is always_inline so the linker will never use this useless definition
// instead of a working one compiled with RTTI and/or exceptions enabled.
template<typename _Ex>
__attribute__ ((__always_inline))
exception_ptr
make_exception_ptr(_Ex) _GLIBCXX_USE_NOEXCEPT
{ return exception_ptr(); }
#endif
Because only the no-op implementation is always_inline, there won't be any
bloat caused by inlining the working implementation into a hot path.
More information about the Gcc-bugs
mailing list