From: Tomasz Kamiński Date: Thu, 2 Jul 2026 10:20:45 +0000 (+0200) Subject: libstdc++: Return optional from exception_ptr_cast. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=87cf7de666efe5b7da0b32cc796f7289caf8f96c;p=thirdparty%2Fgcc.git libstdc++: Return optional 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 header, that header must be included before their use: * value - throw bad_optional_access, and would cause cyclic include of , * 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 include, but not value_or. This patch also introduce _S_from_ptr function to optional, 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. * 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 Signed-off-by: Tomasz Kamiński --- diff --git a/libstdc++-v3/include/bits/optional_ref.h b/libstdc++-v3/include/bits/optional_ref.h index 69a87410e9f..8e33771a8f6 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 873cebb904d..81484ad2f75 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 1dce26f9ed5..9a73f771e72 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 #endif +#if __cpp_lib_exception_ptr_cast >= 202603L +# include +#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 - constexpr const _Ex* exception_ptr_cast(const exception_ptr&) noexcept; + constexpr optional exception_ptr_cast(const exception_ptr&) noexcept; template 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 - friend constexpr const _Ex* + friend constexpr optional 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 [[__gnu__::__always_inline__]] - constexpr const _Ex* + constexpr optional 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(__p._M_exception_ptr_cast(__id)); + const _Ex* __exp = static_cast(__p._M_exception_ptr_cast(__id)); + return optional::_S_from_ptr(__exp); } #endif @@ -381,14 +386,14 @@ namespace std _GLIBCXX_VISIBILITY(default) } catch (const _Ex& __exc) { - return &__exc; + return optional(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 #include -#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 +struct Y +{ + constexpr operator std::optional() const + { return std::nullopt; } +}; + constexpr bool test01(bool x) { auto a = std::make_exception_ptr(C{ 42 }); auto b = std::exception_ptr_cast(a); - VERIFY( b != nullptr ); + auto bp = &*b; + VERIFY( b ); VERIFY( b->a == 42 ); auto c = std::exception_ptr_cast(a); - VERIFY( c == static_cast(b) ); + VERIFY( c ); + VERIFY( &*c == static_cast(bp) ); auto d = std::exception_ptr_cast(a); - VERIFY( d == static_cast(b) ); + VERIFY( d ); + VERIFY( &*d == static_cast(bp) ); auto e = std::exception_ptr_cast(a); - VERIFY( e == nullptr ); + VERIFY( !e ); auto f = std::make_exception_ptr(42L); auto g = std::exception_ptr_cast(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(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(h); - VERIFY( j == static_cast(i) ); + VERIFY( j ); + VERIFY( &*j == static_cast(ip) ); auto k = std::exception_ptr_cast(h); - VERIFY( k == static_cast(i) ); + VERIFY( k ); + VERIFY( &*k == static_cast(ip) ); auto l = std::exception_ptr_cast(h); - VERIFY( l == static_cast(i) ); + VERIFY( l ); + VERIFY( &*l == static_cast(ip) ); auto m = std::exception_ptr_cast(h); - VERIFY( m == static_cast(i) ); + VERIFY( m ); + VERIFY( &*m == static_cast(ip) ); auto n = std::exception_ptr_cast(a); - VERIFY( n == nullptr ); + VERIFY( !n ); } + + auto o = std::make_exception_ptr(Y{}); + auto p = std::exception_ptr_cast(o); + VERIFY( p ); + if (x) throw 1; return true;