On Wed, Jun 25, 2025 at 08:20:55PM +0100, Jonathan Wakely wrote: > This won't work for -fno-rtti
I've missed the || __cpp_exceptions part in there, thought it is &&. Here is an updated patch which uses just one definition of std::exception_ptr_cast and additionally exports it from std.cc.in as well. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2025-06-26 Jakub Jelinek <ja...@redhat.com> * include/bits/version.def (exception_ptr_cast): Add. * include/bits/version.h: Regenerate. * libsupc++/exception: Define __glibcxx_want_exception_ptr_cast before including bits/version.h. * libsupc++/exception_ptr.h (std::exception_ptr_cast): Define. (std::__exception_ptr::exception_ptr::_M_exception_ptr_cast): Declare. * libsupc++/eh_ptr.cc (std::__exception_ptr::exception_ptr::_M_exception_ptr_cast): Define. * src/c++23/std.cc.in (std::exception_ptr_cast): Export. * config/abi/pre/gnu.ver: Export _ZNKSt15__exception_ptr13exception_ptr21_M_exception_ptr_castERKSt9type_info at CXXABI_1.3.17. * testsuite/util/testsuite_abi.cc (check_version): Allow CXXABI_1.3.17. * testsuite/18_support/exception_ptr/exception_ptr_cast.cc: New test. --- libstdc++-v3/include/bits/version.def.jj 2025-06-24 18:53:13.751807828 +0200 +++ libstdc++-v3/include/bits/version.def 2025-06-25 12:52:41.844921595 +0200 @@ -2012,6 +2012,14 @@ ftms = { }; }; +ftms = { + name = exception_ptr_cast; + values = { + v = 202506; + cxxmin = 26; + }; +}; + // Standard test specifications. stds[97] = ">= 199711L"; stds[03] = ">= 199711L"; --- libstdc++-v3/include/bits/version.h.jj 2025-06-24 18:53:13.751807828 +0200 +++ libstdc++-v3/include/bits/version.h 2025-06-25 12:52:47.754691329 +0200 @@ -2253,4 +2253,14 @@ #endif /* !defined(__cpp_lib_sstream_from_string_view) && defined(__glibcxx_want_sstream_from_string_view) */ #undef __glibcxx_want_sstream_from_string_view +#if !defined(__cpp_lib_exception_ptr_cast) +# if (__cplusplus > 202302L) +# define __glibcxx_exception_ptr_cast 202506L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_exception_ptr_cast) +# define __cpp_lib_exception_ptr_cast 202506L +# endif +# endif +#endif /* !defined(__cpp_lib_exception_ptr_cast) && defined(__glibcxx_want_exception_ptr_cast) */ +#undef __glibcxx_want_exception_ptr_cast + #undef __glibcxx_want_all --- libstdc++-v3/libsupc++/exception.jj 2025-06-12 09:49:19.924910752 +0200 +++ libstdc++-v3/libsupc++/exception 2025-06-25 12:53:09.924564775 +0200 @@ -38,6 +38,7 @@ #include <bits/exception.h> #define __glibcxx_want_uncaught_exceptions +#define __glibcxx_want_exception_ptr_cast #include <bits/version.h> extern "C++" { --- libstdc++-v3/libsupc++/exception_ptr.h.jj 2025-06-02 11:00:06.267523918 +0200 +++ libstdc++-v3/libsupc++/exception_ptr.h 2025-06-26 07:53:12.966100732 +0200 @@ -80,6 +80,13 @@ namespace std _GLIBCXX_VISIBILITY(defaul /// Throw the object pointed to by the exception_ptr. void rethrow_exception(exception_ptr) __attribute__ ((__noreturn__)); +#if __cpp_lib_exception_ptr_cast >= 202506L + template<typename _Ex> + const _Ex* exception_ptr_cast(const exception_ptr&) noexcept; + template<typename _Ex> + void exception_ptr_cast(const exception_ptr&&) = delete; +#endif + namespace __exception_ptr { using std::rethrow_exception; // So that ADL finds it. @@ -109,6 +116,13 @@ namespace std _GLIBCXX_VISIBILITY(defaul friend void std::rethrow_exception(exception_ptr); template<typename _Ex> friend exception_ptr std::make_exception_ptr(_Ex) _GLIBCXX_USE_NOEXCEPT; +#if __cpp_lib_exception_ptr_cast >= 202506L + template<typename _Ex> + friend const _Ex* std::exception_ptr_cast(const exception_ptr&) noexcept; +#endif + + const void* _M_exception_ptr_cast(const type_info&) const + _GLIBCXX_USE_NOEXCEPT; public: exception_ptr() _GLIBCXX_USE_NOEXCEPT; @@ -283,6 +299,20 @@ namespace std _GLIBCXX_VISIBILITY(defaul { return exception_ptr(); } #endif +#if __cpp_lib_exception_ptr_cast >= 202506L + template<typename _Ex> + [[__gnu__::__always_inline__]] + inline const _Ex* exception_ptr_cast(const exception_ptr& __p) noexcept + { +#ifdef __cpp_rtti + const type_info &__id = typeid(const _Ex&); + return static_cast<const _Ex*>(__p._M_exception_ptr_cast(__id)); +#else + return nullptr; +#endif + } +#endif + #undef _GLIBCXX_EH_PTR_USED /// @} group exceptions --- libstdc++-v3/libsupc++/eh_ptr.cc.jj 2025-04-08 14:10:30.518900025 +0200 +++ libstdc++-v3/libsupc++/eh_ptr.cc 2025-06-25 15:29:17.416393720 +0200 @@ -220,4 +220,20 @@ std::rethrow_exception(std::exception_pt std::terminate(); } +const void* +std::__exception_ptr::exception_ptr::_M_exception_ptr_cast(const type_info& t) + const noexcept +{ + void *ptr = _M_exception_object; + if (__builtin_expect(ptr == nullptr, false)) + return nullptr; + __cxa_refcounted_exception *eh + = __get_refcounted_exception_header_from_obj (_M_exception_object); + const type_info* __thr_type = eh->exc.exceptionType; + if (t.__do_catch(__thr_type, &ptr, 1)) + return ptr; + return nullptr; +} + + #undef _GLIBCXX_EH_PTR_COMPAT --- libstdc++-v3/src/c++23/std.cc.in.jj 2025-06-12 15:50:51.400821105 +0200 +++ libstdc++-v3/src/c++23/std.cc.in 2025-06-26 07:58:26.725045106 +0200 @@ -1050,6 +1050,9 @@ export namespace std using std::throw_with_nested; using std::uncaught_exception; using std::uncaught_exceptions; +#if __cpp_lib_exception_ptr_cast >= 202506L + using std::exception_ptr_cast; +#endif } // 34.4 <execution> --- libstdc++-v3/config/abi/pre/gnu.ver.jj 2025-06-02 11:00:17.686375875 +0200 +++ libstdc++-v3/config/abi/pre/gnu.ver 2025-06-25 15:32:59.627528296 +0200 @@ -2899,6 +2899,16 @@ CXXABI_1.3.16 { } CXXABI_1.3.15; #endif +CXXABI_1.3.17 { + # std::exception_ptr::_M_exception_ptr_cast + _ZNKSt15__exception_ptr13exception_ptr21_M_exception_ptr_castERKSt9type_info; +} +#ifdef __riscv +CXXABI_1.3.16; +#else +CXXABI_1.3.15; +#endif + # Symbols in the support library (libsupc++) supporting transactional memory. CXXABI_TM_1 { --- libstdc++-v3/testsuite/util/testsuite_abi.cc.jj 2025-06-02 11:00:18.007371713 +0200 +++ libstdc++-v3/testsuite/util/testsuite_abi.cc 2025-06-25 15:51:56.745085075 +0200 @@ -241,6 +241,7 @@ check_version(symbol& test, bool added) #ifdef __riscv known_versions.push_back("CXXABI_1.3.16"); #endif + known_versions.push_back("CXXABI_1.3.17"); known_versions.push_back("CXXABI_IEEE128_1.3.13"); known_versions.push_back("CXXABI_TM_1"); known_versions.push_back("CXXABI_FLOAT128"); --- libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc.jj 2025-06-25 15:45:25.864969085 +0200 +++ libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc 2025-06-25 15:47:11.156653475 +0200 @@ -0,0 +1,81 @@ +// { dg-do run { target c++26 } } + +// Copyright (C) 2025 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// exception_ptr_cast. + +#include <exception> +#include <testsuite_hooks.h> + +#if __cpp_lib_exception_ptr_cast != 202506L +# error "__cpp_lib_exception_ptr_cast != 202506" +#endif + +struct A { int a; }; +struct B : A {}; +struct C : B {}; +struct D {}; +struct E : virtual C { int e; virtual ~E () {} }; +struct F : virtual E, virtual C { int f; }; +struct G : virtual F, virtual C, virtual E { + G () : g (4) { a = 1; e = 2; f = 3; } int g; +}; + +void test01() +{ + auto a = std::make_exception_ptr(C{ 42 }); + auto b = std::exception_ptr_cast<C>(a); + VERIFY( b != nullptr ); + VERIFY( b->a == 42 ); + auto c = std::exception_ptr_cast<B>(a); + VERIFY( c == static_cast<const B*>(b) ); + auto d = std::exception_ptr_cast<A>(a); + VERIFY( d == static_cast<const A*>(b) ); + auto e = std::exception_ptr_cast<D>(a); + VERIFY( e == nullptr ); + auto f = std::make_exception_ptr(42L); + auto g = std::exception_ptr_cast<long>(f); + VERIFY( g != nullptr ); + VERIFY( *g == 42L ); + try + { + throw G (); + } + catch (...) + { + auto h = std::current_exception(); + auto i = std::exception_ptr_cast<G>(h); + VERIFY( i != nullptr ); + VERIFY( i->a == 1 && i->e == 2 && i->f == 3 && i->g == 4 ); + auto j = std::exception_ptr_cast<A>(h); + VERIFY( j == static_cast<const A*>(i) ); + auto k = std::exception_ptr_cast<C>(h); + VERIFY( k == static_cast<const C*>(i) ); + auto l = std::exception_ptr_cast<E>(h); + VERIFY( l == static_cast<const E*>(i) ); + auto m = std::exception_ptr_cast<F>(h); + VERIFY( m == static_cast<const F*>(i) ); + auto n = std::exception_ptr_cast<G>(a); + VERIFY( n == nullptr ); + } +} + +int main() +{ + test01(); +} Jakub