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;
