https://gcc.gnu.org/g:87cf7de666efe5b7da0b32cc796f7289caf8f96c

commit r17-2117-g87cf7de666efe5b7da0b32cc796f7289caf8f96c
Author: Tomasz Kamiński <[email protected]>
Date:   Thu Jul 2 12:20:45 2026 +0200

    libstdc++: Return optional<const _Ex&> from exception_ptr_cast.
    
    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 confusing 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 useful 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.
    
    Reviewed-by: Jonathan Wakely <[email protected]>
    Signed-off-by: Tomasz Kamiński <[email protected]>

Diff:
---
 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 ++++++----
 .../18_support/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 69a87410e9fd..8e33771a8f6a 100644
--- a/libstdc++-v3/include/bits/optional_ref.h
+++ b/libstdc++-v3/include/bits/optional_ref.h
@@ -128,6 +128,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     public:
       using value_type = _Tp;
 
+      constexpr static optional
+      _S_from_ptr(_Tp* __ptr)
+      {
+       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 873cebb904d6..81484ad2f75d 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 1dce26f9ed57..9a73f771e72e 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 61ab0203fa0d..81efe49be1fc 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 3c40bef36a4a..1b980a32362c 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;

Reply via email to