On Fri, Jul 3, 2026 at 1:48 PM Jonathan Wakely <[email protected]> wrote:

> On Thu, 02 Jul 2026 at 14:22 +0200, Tomasz Kamiński wrote:
> >This implements the remaining part of P3981R2 Better return types
> >in std::inplace_vector and std::exception_ptr_cast.
> >
> >For the following functions that are defined out of line in
> ><optional> header, that header must be included before their
> >use:
> >* value - throw bad_optional_access, and would cause cyclic include
> >  of <exception>,
> >* transform, and_then - couldn't be used with function that
> >  returns value (wrapped) in optional, as they would instantiate
> >  primary specialization
> >* or_else - reintroduce dependency of bits/invoke.h
> >* begin/end - dependency or normal_iterator from bits/stl_iterator.h.
> >
> >The value_or was also defined out of line for consistency, I think
> >it would be confisuing if calling value/transform requires <optional>
> >include, but not value_or.
> >
> >This patch also introduce _S_from_ptr function to optional<T&>, that
> >allows it to be constructed from pointer, without need to check for
> >null. This function is public, as I believe it will be usefull in more
> >places.
> >
> >libstdc++-v3/ChangeLog:
> >
> >       * include/bits/optional_ref.h (optional<_Tp&>::_S_from_ptr):
> >       Define.
> >       * include/bits/version.def (exception_ptr_cast): Bump value
> >       to 202603.
> >       * include/bits/version.h: Regenerate.
> >       * libsupc++/exception_ptr.h (exception_ptr_cast)
> >       [__cpp_lib_exception_ptr_cast >= 202603L]: Change return
> >       type to optional<const _Ex&>.
> >       * testsuite/18_support/exception_ptr/exception_ptr_cast.cc:
> >       Modify to handle change in the return type, and add test
> >       for type convertible to optional to reference to that value.
> >---
> >Testing on x86_64-linux. All test passed locally.
> >OK for trunk when exteded suite happens?
> >
> > libstdc++-v3/include/bits/optional_ref.h      |  8 ++++
> > libstdc++-v3/include/bits/version.def         |  4 +-
> > libstdc++-v3/include/bits/version.h           |  4 +-
> > libstdc++-v3/libsupc++/exception_ptr.h        | 21 +++++----
> > .../exception_ptr/exception_ptr_cast.cc       | 47 ++++++++++++++-----
> > 5 files changed, 60 insertions(+), 24 deletions(-)
> >
> >diff --git a/libstdc++-v3/include/bits/optional_ref.h
> b/libstdc++-v3/include/bits/optional_ref.h
> >index e018a4199e9..bc01d271a9a 100644
> >--- a/libstdc++-v3/include/bits/optional_ref.h
> >+++ b/libstdc++-v3/include/bits/optional_ref.h
> >@@ -132,6 +132,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >     public:
> >       using value_type = _Tp;
> >
> >+      constexpr static optional
> >+      _S_from_ptr(_Tp* __ptr)
>
> I don't love this being a public member, but OK for trunk.
>
I was thinking about it, and I believe we may need that in many places,
so befriending them would not viable option. And I think this would be also
beneficial for users, if they do not care about portability. The reserved
The reserved name should be enough of signal that it is not meant to be
portable.


> >+      {
> >+      optional __res;
> >+      __res._M_val = __ptr;
> >+      return __res;
> >+      }
> >+
> >       // Constructors.
> >       constexpr optional() noexcept = default;
> >       constexpr optional(nullopt_t) noexcept : optional() {}
> >diff --git a/libstdc++-v3/include/bits/version.def
> b/libstdc++-v3/include/bits/version.def
> >index cb48380e2fa..f47df2a0fb8 100644
> >--- a/libstdc++-v3/include/bits/version.def
> >+++ b/libstdc++-v3/include/bits/version.def
> >@@ -2339,9 +2339,11 @@ ftms = {
> > };
> >
> > ftms = {
> >+  // 202506 P2927R3 Observing exceptions stored in exception_ptr
> >+  // 202603 P3981R2 Better return types in std::inplace_vector and
> std::exception_ptr_cast
> >   name = exception_ptr_cast;
> >   values = {
> >-    v = 202506;
> >+    v = 202603;
> >     cxxmin = 26;
> >   };
> > };
> >diff --git a/libstdc++-v3/include/bits/version.h
> b/libstdc++-v3/include/bits/version.h
> >index c20c3d18535..05ded7cd7bd 100644
> >--- a/libstdc++-v3/include/bits/version.h
> >+++ b/libstdc++-v3/include/bits/version.h
> >@@ -2588,9 +2588,9 @@
> >
> > #if !defined(__cpp_lib_exception_ptr_cast)
> > # if (__cplusplus >  202302L)
> >-#  define __glibcxx_exception_ptr_cast 202506L
> >+#  define __glibcxx_exception_ptr_cast 202603L
> > #  if defined(__glibcxx_want_all) ||
> defined(__glibcxx_want_exception_ptr_cast)
> >-#   define __cpp_lib_exception_ptr_cast 202506L
> >+#   define __cpp_lib_exception_ptr_cast 202603L
> > #  endif
> > # endif
> > #endif /* !defined(__cpp_lib_exception_ptr_cast) */
> >diff --git a/libstdc++-v3/libsupc++/exception_ptr.h
> b/libstdc++-v3/libsupc++/exception_ptr.h
> >index 61ab0203fa0..81efe49be1f 100644
> >--- a/libstdc++-v3/libsupc++/exception_ptr.h
> >+++ b/libstdc++-v3/libsupc++/exception_ptr.h
> >@@ -41,6 +41,10 @@
> > # include <bits/move.h>
> > #endif
> >
> >+#if __cpp_lib_exception_ptr_cast >= 202603L
> >+# include <bits/optional_ref.h>
> >+#endif
> >+
> > #ifdef _GLIBCXX_EH_PTR_RELOPS_COMPAT
> > # define _GLIBCXX_EH_PTR_USED __attribute__((__used__))
> > #else
> >@@ -81,9 +85,9 @@ 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
> >+#if __cpp_lib_exception_ptr_cast >= 202603L
> >   template<typename _Ex>
> >-    constexpr const _Ex* exception_ptr_cast(const exception_ptr&)
> noexcept;
> >+    constexpr optional<const _Ex&> exception_ptr_cast(const
> exception_ptr&) noexcept;
> >   template<typename _Ex>
> >     void exception_ptr_cast(const exception_ptr&&) = delete;
> > #endif
> >@@ -139,7 +143,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
> >       _GLIBCXX_USE_NOEXCEPT;
> > #if __cpp_lib_exception_ptr_cast >= 202506L
> >       template<typename _Ex>
> >-      friend constexpr const _Ex*
> >+      friend constexpr optional<const _Ex&>
> >       std::exception_ptr_cast(const exception_ptr&) noexcept;
> > #endif
> >
> >@@ -352,10 +356,10 @@ namespace std _GLIBCXX_VISIBILITY(default)
> >       return exception_ptr();
> >     }
> >
> >-#if __cpp_lib_exception_ptr_cast >= 202506L
> >+#if __cpp_lib_exception_ptr_cast >= 202603L
> >   template<typename _Ex>
> >     [[__gnu__::__always_inline__]]
> >-    constexpr const _Ex*
> >+    constexpr optional<const _Ex&>
> >     exception_ptr_cast(const exception_ptr& __p) noexcept
> >     {
> >       static_assert(!std::is_const_v<_Ex>);
> >@@ -369,7 +373,8 @@ namespace std _GLIBCXX_VISIBILITY(default)
> >       // For runtime calls with -frtti enabled we can avoid try-catch
> overhead.
> >       if ! consteval {
> >       const type_info &__id = typeid(const _Ex&);
> >-      return static_cast<const _Ex*>(__p._M_exception_ptr_cast(__id));
> >+      const _Ex* __exp = static_cast<const
> _Ex*>(__p._M_exception_ptr_cast(__id));
> >+      return optional<const _Ex&>::_S_from_ptr(__exp);
> >       }
> > #endif
> >
> >@@ -381,14 +386,14 @@ namespace std _GLIBCXX_VISIBILITY(default)
> >         }
> >       catch (const _Ex& __exc)
> >         {
> >-          return &__exc;
> >+          return optional<const _Ex&>(std::in_place, __exc);
> >         }
> >       catch (...)
> >         {
> >         }
> > #endif
> >
> >-      return nullptr;
> >+      return std::nullopt;
> >     }
> > #endif
> >
> >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
> >index 3c40bef36a4..1b980a32362 100644
> >---
> a/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc
> >+++
> b/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc
> >@@ -22,8 +22,8 @@
> > #include <exception>
> > #include <testsuite_hooks.h>
> >
> >-#if __cpp_lib_exception_ptr_cast != 202506L
> >-# error "__cpp_lib_exception_ptr_cast != 202506"
> >+#if __cpp_lib_exception_ptr_cast != 202603L
> >+# error "__cpp_lib_exception_ptr_cast != 202606"
> > #endif
> >
> > struct A { int a; };
> >@@ -36,22 +36,33 @@ struct G : virtual F, virtual C, virtual E {
> >   constexpr G () : g (4) { a = 1; e = 2; f = 3; } int g;
> > };
> >
> >+// Convertible to optional<const Y&>
> >+struct Y
> >+{
> >+  constexpr operator std::optional<const Y&>() const
> >+  { return std::nullopt; }
> >+};
> >+
> > constexpr bool test01(bool x)
> > {
> >   auto a = std::make_exception_ptr(C{ 42 });
> >   auto b = std::exception_ptr_cast<C>(a);
> >-  VERIFY( b != nullptr );
> >+  auto bp = &*b;
> >+  VERIFY( b );
> >   VERIFY( b->a == 42 );
> >   auto c = std::exception_ptr_cast<B>(a);
> >-  VERIFY( c == static_cast<const B*>(b) );
> >+  VERIFY( c );
> >+  VERIFY( &*c == static_cast<const B*>(bp) );
> >   auto d = std::exception_ptr_cast<A>(a);
> >-  VERIFY( d == static_cast<const A*>(b) );
> >+  VERIFY( d );
> >+  VERIFY( &*d == static_cast<const A*>(bp) );
> >   auto e = std::exception_ptr_cast<D>(a);
> >-  VERIFY( e == nullptr );
> >+  VERIFY( !e );
> >   auto f = std::make_exception_ptr(42L);
> >   auto g = std::exception_ptr_cast<long>(f);
> >-  VERIFY( g != nullptr );
> >+  VERIFY( g );
> >   VERIFY( *g == 42L );
> >+
> >   try
> >     {
> >       throw G ();
> >@@ -64,19 +75,29 @@ constexpr bool test01(bool x)
> >       auto h = std::current_exception();
> > #endif
> >       auto i = std::exception_ptr_cast<G>(h);
> >-      VERIFY( i != nullptr );
> >+      VERIFY( i );
> >       VERIFY( i->a == 1 && i->e == 2 && i->f == 3 && i->g == 4 );
> >+      auto ip = &*i;
> >       auto j = std::exception_ptr_cast<A>(h);
> >-      VERIFY( j == static_cast<const A*>(i) );
> >+      VERIFY( j );
> >+      VERIFY( &*j == static_cast<const A*>(ip) );
> >       auto k = std::exception_ptr_cast<C>(h);
> >-      VERIFY( k == static_cast<const C*>(i) );
> >+      VERIFY( k );
> >+      VERIFY( &*k == static_cast<const C*>(ip) );
> >       auto l = std::exception_ptr_cast<E>(h);
> >-      VERIFY( l == static_cast<const E*>(i) );
> >+      VERIFY( l );
> >+      VERIFY( &*l == static_cast<const E*>(ip) );
> >       auto m = std::exception_ptr_cast<F>(h);
> >-      VERIFY( m == static_cast<const F*>(i) );
> >+      VERIFY( m );
> >+      VERIFY( &*m == static_cast<const F*>(ip) );
> >       auto n = std::exception_ptr_cast<G>(a);
> >-      VERIFY( n == nullptr );
> >+      VERIFY( !n );
> >     }
> >+
> >+  auto o = std::make_exception_ptr(Y{});
> >+  auto p = std::exception_ptr_cast<Y>(o);
> >+  VERIFY( p );
> >+
> >   if (x)
> >     throw 1;
> >   return true;
> >--
> >2.54.0
> >
> >
>
>

Reply via email to