The if-consteval branches in std::make_exception_ptr and std::exception_ptr_cast use a try-catch block, which gives an error for -fno-exceptions. Just make them return a null pointer at compile-time when -fno-exceptions is used, because there's no way to get an active exception with -fno-exceptions.
For both functions we have a runtime-only branch that depends on RTTI, and a fallback using try-catch which works for runtime and consteval. Rearrange both functions to express this logic more clearly. Also adjust some formatting and whitespace elsewhere in the file. libstdc++-v3/ChangeLog: * libsupc++/exception_ptr.h (make_exception_ptr): Return null for consteval when -fno-exceptions is used. (exception_ptr_cast): Likewise. Allow consteval path to work with -fno-rtti. --- Testing x86_64-linux. libstdc++-v3/libsupc++/exception_ptr.h | 113 ++++++++++++------------- 1 file changed, 55 insertions(+), 58 deletions(-) diff --git a/libstdc++-v3/libsupc++/exception_ptr.h b/libstdc++-v3/libsupc++/exception_ptr.h index ee009155a39c..f673a3343338 100644 --- a/libstdc++-v3/libsupc++/exception_ptr.h +++ b/libstdc++-v3/libsupc++/exception_ptr.h @@ -83,9 +83,9 @@ namespace std _GLIBCXX_VISIBILITY(default) #if __cpp_lib_exception_ptr_cast >= 202506L template<typename _Ex> - constexpr const _Ex* exception_ptr_cast(const exception_ptr&) noexcept; + constexpr const _Ex* exception_ptr_cast(const exception_ptr&) noexcept; template<typename _Ex> - void exception_ptr_cast(const exception_ptr&&) = delete; + void exception_ptr_cast(const exception_ptr&&) = delete; #endif namespace __exception_ptr @@ -138,8 +138,8 @@ namespace std _GLIBCXX_VISIBILITY(default) _GLIBCXX_USE_NOEXCEPT; #if __cpp_lib_exception_ptr_cast >= 202506L template<typename _Ex> - friend constexpr const _Ex* std::exception_ptr_cast(const exception_ptr&) - noexcept; + friend constexpr const _Ex* + std::exception_ptr_cast(const exception_ptr&) noexcept; #endif const void* _M_exception_ptr_cast(const type_info&) const @@ -296,40 +296,41 @@ namespace std _GLIBCXX_VISIBILITY(default) using __exception_ptr::swap; // So that std::swap(exp1, exp2) finds it. /// Obtain an exception_ptr pointing to a copy of the supplied object. -#if (__cplusplus >= 201103L && __cpp_rtti) || __cpp_exceptions template<typename _Ex> +#if !(__cplusplus >= 201103L && __cpp_rtti) && !__cpp_exceptions + // This is always_inline so the linker will never use a useless definition + // instead of a working one compiled with RTTI and/or exceptions enabled. + __attribute__ ((__always_inline__)) inline +#endif _GLIBCXX26_CONSTEXPR exception_ptr make_exception_ptr(_Ex __ex) _GLIBCXX_USE_NOEXCEPT { -#if __cplusplus >= 202400L - if consteval { - try - { - throw __ex; - } - catch(...) - { - return current_exception(); - } - } -#endif #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 + // For runtime calls with -frtti enabled we can avoid try-catch overhead. + // We can't use this for C++98 because it relies on std::decay. +#ifdef __glibcxx_constexpr_exceptions + if ! consteval +#endif { - ::new (__e) _Ex2(__ex); - return exception_ptr(__e); + 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(); + } } - __catch(...) - { - __cxxabiv1::__cxa_free_exception(__e); - return current_exception(); - } -#else +#endif + +#ifdef __cpp_exceptions try { throw __ex; @@ -339,21 +340,14 @@ namespace std _GLIBCXX_VISIBILITY(default) return current_exception(); } #endif + return exception_ptr(); } -#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__)) - _GLIBCXX26_CONSTEXPR inline exception_ptr - make_exception_ptr(_Ex) _GLIBCXX_USE_NOEXCEPT - { return exception_ptr(); } -#endif #if __cpp_lib_exception_ptr_cast >= 202506L template<typename _Ex> [[__gnu__::__always_inline__]] - constexpr const _Ex* exception_ptr_cast(const exception_ptr& __p) noexcept + constexpr const _Ex* + exception_ptr_cast(const exception_ptr& __p) noexcept { static_assert(!std::is_const_v<_Ex>); static_assert(!std::is_reference_v<_Ex>); @@ -361,28 +355,31 @@ namespace std _GLIBCXX_VISIBILITY(default) static_assert(!std::is_array_v<_Ex>); static_assert(!std::is_pointer_v<_Ex>); static_assert(!std::is_member_pointer_v<_Ex>); + #ifdef __cpp_rtti - if consteval { - if (__p._M_exception_object) - try - { - std::rethrow_exception(__p); - } - catch (const _Ex& __exc) - { - return &__exc; - } - catch (...) - { - } - return nullptr; - } else { + // For runtime calls with -frtti enabled we can avoid try-catch overhead. + if ! consteval { const type_info &__id = typeid(const _Ex&); return static_cast<const _Ex*>(__p._M_exception_ptr_cast(__id)); } -#else - return nullptr; #endif + +#ifdef __cpp_exceptions + if (__p._M_exception_object) + try + { + std::rethrow_exception(__p); + } + catch (const _Ex& __exc) + { + return &__exc; + } + catch (...) + { + } +#endif + + return nullptr; } #endif -- 2.50.0