[PATCH] libstdc++: Implement C++26 P3748R0 - Inspecting exception_ptr should be constexpr

Jonathan Wakely jwakely@redhat.com
Fri Jul 11 11:16:17 GMT 2025


On Fri, 11 Jul 2025 at 12:14, Jonathan Wakely <jwakely@redhat.com> wrote:
>
> On Fri, 11 Jul 2025 at 12:05, Jakub Jelinek <jakub@redhat.com> wrote:
> >
> > Hi!
> >
> > 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."
> >
> > Tested on x86_64-linux, ok for trunk if it passes full bootstrap/regtest?
> >
> > 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.jj   2025-07-11 00:40:08.861188412 +0200
> > +++ libstdc++-v3/libsupc++/exception_ptr.h      2025-07-11 11:36:01.564267603 +0200
> > @@ -83,7 +83,7 @@ namespace std _GLIBCXX_VISIBILITY(defaul
> >
> >  #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(defaul
> >         _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(defaul
> >  #if __cpp_lib_exception_ptr_cast >= 202506L

This would need to be adjusted for my suggestions, of course.
Maybe to just #ifdef __glibcxx_exception_ptr_cast

> >    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
>
> This won't compile with -fno-exceptions, so maybe we only want it to
> be usable in constexpr when __cpp_exceptions is defined?
>
> And so maybe the feature test macro should be defined something like:
>
> ftms = {
>   name = exception_ptr_cast;
>   values = {
>     v = 202506;
>     cxxmin = 26;
>     extra_cond = "__cpp_exceptions";
>   };
>   values = {
>     v = 1;
>     cxxmin = 26;
>     no_stdname = yes;
>   };
> };
>
> This would give us __glibcxx_exception_ptr_cast for C++26 with or
> without exceptions, but would only define __cpp_lib_exception_ptr_cast
> when it's fully supported.
>
> Alternatively:
>
> ftms = {
>   name = exception_ptr_cast;
>   values = {
>     v = 202506;
>     cxxmin = 26;
>     extra_cond = "__cpp_exceptions";
>   };
>   values = {
>     v = 202500;
>     cxxmin = 26;
>   };
> };
>
> So we would still define __cpp_lib_exception_ptr_cast for
> -fno-exceptions, but with the value 202500 to indicate that it's not
> 100% conforming.
>
>
>
> > +           {
> > +             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
> > --- libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc.jj    2025-06-26 16:31:04.958266404 +0200
> > +++ libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc       2025-07-11 11:39:39.275381406 +0200
> > @@ -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 (...)
> > +    {
> > +    }
> >  }
> >
> >         Jakub
> >



More information about the Libstdc++ mailing list