]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Implement C++26 P3748R0 - Inspecting exception_ptr should be constexpr
authorJakub Jelinek <jakub@redhat.com>
Fri, 11 Jul 2025 11:50:07 +0000 (13:50 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 11 Jul 2025 11:50:07 +0000 (13:50 +0200)
The following patch makes std::exception_ptr_cast constexpr.
The paper suggests using dynamic_cast, but that does only work for
polymorphic exceptions, doesn't work if they are scalar or non-polymorphic
classes.

Furthermore, the patch adds some static_asserts for
"Mandates: E is a cv-unqualified complete object type. E is not an array type.
E is not a pointer or pointer-to-member type."

2025-07-11  Jakub Jelinek  <jakub@redhat.com>

* libsupc++/exception_ptr.h: Implement C++26 P3748R0 - Inspecting
exception_ptr should be constexpr.
(std::exception_ptr_cast): Make constexpr, remove inline keyword.  Add
static_asserts for Mandates.  For if consteval use std::rethrow_exception,
catch it and return its address or nullptr.
* testsuite/18_support/exception_ptr/exception_ptr_cast.cc (E::~E): Add
constexpr.
(G::G): Likewise.
(test01): Likewise.  Return bool and take bool argument, throw if the
argument is true.  Add static_assert(test01(false)).
(main): Call test01(true) in try.

libstdc++-v3/libsupc++/exception_ptr.h
libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc

index be516d7aae177b0cf192f15a4b7ecd1be719e3ea..ee009155a39c27d6c4184f2b81d463cdc31b5d4f 100644 (file)
@@ -83,7 +83,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
 
 #if __cpp_lib_exception_ptr_cast >= 202506L
   template<typename _Ex>
-  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;
 #endif
@@ -138,7 +138,8 @@ namespace std _GLIBCXX_VISIBILITY(default)
        _GLIBCXX_USE_NOEXCEPT;
 #if __cpp_lib_exception_ptr_cast >= 202506L
       template<typename _Ex>
-      friend 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
@@ -352,11 +353,33 @@ namespace std _GLIBCXX_VISIBILITY(default)
 #if __cpp_lib_exception_ptr_cast >= 202506L
   template<typename _Ex>
     [[__gnu__::__always_inline__]]
-    inline 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>);
+      static_assert(std::is_object_v<_Ex>);
+      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
-      const type_info &__id = typeid(const _Ex&);
-      return static_cast<const _Ex*>(__p._M_exception_ptr_cast(__id));
+      if consteval {
+       if (__p._M_exception_object)
+         try
+           {
+             std::rethrow_exception(__p);
+           }
+         catch (const _Ex& __exc)
+           {
+             return &__exc;
+           }
+         catch (...)
+           {
+           }
+       return nullptr;
+      } else {
+       const type_info &__id = typeid(const _Ex&);
+       return static_cast<const _Ex*>(__p._M_exception_ptr_cast(__id));
+      }
 #else
       return nullptr;
 #endif
index 6a6fbfee67aa04be5ebb1c6132c7a004121e0154..de371d1b7b7ffe47abd36180addaa8dac17705f7 100644 (file)
@@ -30,13 +30,13 @@ struct A { int a; };
 struct B : A {};
 struct C : B {};
 struct D {};
-struct E : virtual C { int e; virtual ~E () {} };
+struct E : virtual C { int e; constexpr 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;
+  constexpr G () : g (4) { a = 1; e = 2; f = 3; } int g;
 };
 
-void test01()
+constexpr bool test01(bool x)
 {
   auto a = std::make_exception_ptr(C{ 42 });
   auto b = std::exception_ptr_cast<C>(a);
@@ -73,9 +73,20 @@ void test01()
       auto n = std::exception_ptr_cast<G>(a);
       VERIFY( n == nullptr );
     }
+  if (x)
+    throw 1;
+  return true;
 }
 
+static_assert(test01(false));
+
 int main()
 {
-  test01();
+  try
+    {
+      test01(true);
+    }
+  catch (...)
+    {
+    }
 }