On Wed, 25 Jun 2025 at 19:56, Jakub Jelinek <ja...@redhat.com> wrote: > > Hi! > > The following patch attempts to implement the C++26 P2927R3 - Inspecting > exception_ptr > paper (but not including P3748R0, I plan to play with it incrementally and > it will really depend on the Constexpr exceptions patch). > > The function template is implemented using an out of line private method of > exception_ptr, so that P3748R0 then can use if consteval and provide a > constant evaluation variant of it. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2025-06-25 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. > * 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-25 15:07:26.308301756 > +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; > @@ -274,6 +288,16 @@ namespace std _GLIBCXX_VISIBILITY(defaul > } > #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 > + { > + const type_info &__id = typeid(const _Ex&);
This won't work for -fno-rtti Maybe we should just have one definition of exception_ptr_cast, outside this #if group, like so: #if __cpp_lib_exception_ptr_cast >= 202506L template<typename _Ex> [[__gnu__::__always_inline__]] const _Ex* exception_ptr_cast(const exception_ptr& __p) noexcept { #ifdef __cpp_rtti const type_info& __id = typeid(_Ex); return static_cast<const _Ex*>(__p._M_exception_ptr_cast(__id)); #else return nullptr; #endif } #endif > + return static_cast<const _Ex*>(__p._M_exception_ptr_cast(__id)); > + } > +#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. > @@ -282,6 +306,15 @@ namespace std _GLIBCXX_VISIBILITY(defaul > inline exception_ptr > make_exception_ptr(_Ex) _GLIBCXX_USE_NOEXCEPT > { return exception_ptr(); } > + > +#if __cpp_lib_exception_ptr_cast >= 202506L > + template<typename _Ex> > + [[__gnu__::__always_inline__]] > + const _Ex* exception_ptr_cast(const exception_ptr& __p) noexcept > + { > + return nullptr; > + } > +#endif > #endif > > #undef _GLIBCXX_EH_PTR_USED > --- 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/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 >