]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Implement C++26 P2927R3 - Inspecting exception_ptr
authorJakub Jelinek <jakub@redhat.com>
Thu, 26 Jun 2025 14:18:38 +0000 (16:18 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 26 Jun 2025 14:18:38 +0000 (16:18 +0200)
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.

2025-06-26  Jakub Jelinek  <jakub@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/config/abi/pre/gnu.ver
libstdc++-v3/include/bits/version.def
libstdc++-v3/include/bits/version.h
libstdc++-v3/libsupc++/eh_ptr.cc
libstdc++-v3/libsupc++/exception
libstdc++-v3/libsupc++/exception_ptr.h
libstdc++-v3/src/c++23/std.cc.in
libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc [new file with mode: 0644]
libstdc++-v3/testsuite/util/testsuite_abi.cc

index c36f1c347675428a382167272af2aae6962f94e9..bba5705509c6e1b03117fb39ccfef813cbcaa6e6 100644 (file)
@@ -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 {
 
index caec5d1144794fc8cdaad645b204ef3d34e24614..f4ba501c403ff80cdd55d087a4c2dabbdb9ee09e 100644 (file)
@@ -2022,6 +2022,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = exception_ptr_cast;
+  values = {
+    v = 202506;
+    cxxmin = 26;
+  };
+};
+
 // Standard test specifications.
 stds[97] = ">= 199711L";
 stds[03] = ">= 199711L";
index 2dc21b693656612b93885168956131aff5fa35b9..dc8ac07be166a5ebe35d088b03f3c2a3e6fb287f 100644 (file)
 #endif /* !defined(__cpp_lib_type_order) && defined(__glibcxx_want_type_order) */
 #undef __glibcxx_want_type_order
 
+#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
index 6512449a32ccd900373599b70452d60e5aa031e8..1fb35d82f53934ff1113b284606e2527817ecd9d 100644 (file)
@@ -220,4 +220,20 @@ std::rethrow_exception(std::exception_ptr ep)
   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
index 8c3bb33c831b4573762f6501e9ab3dfd261f4f8f..61d41315f9f1f987c73b43937b940c5e716669f4 100644 (file)
@@ -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++" {
index a7e5e527d212f6b81d0a6c1dfb9b2a9e3be35f21..a6ff8c0d6982a96047d3aa167c1208897b7e06ca 100644 (file)
@@ -80,6 +80,13 @@ namespace std _GLIBCXX_VISIBILITY(default)
   /// 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(default)
       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;
@@ -284,6 +298,20 @@ namespace std _GLIBCXX_VISIBILITY(default)
     { 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
index 36b19aec5ff3dc8129fe647e35d87bfe791e10d9..9336118f5d9458e0ed111c00443d9cdf6fbc2657 100644 (file)
@@ -1054,6 +1054,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>
diff --git a/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc b/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc
new file mode 100644 (file)
index 0000000..6a6fbfe
--- /dev/null
@@ -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();
+}
index 7bffc6b74f751265255959e4134a63eb6c792a06..4b01023fbaef089b01ae1e93bc59830bf7249f9e 100644 (file)
@@ -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");