diff options
| author | Jonathan Wakely <jwakely@redhat.com> | 2025-11-19 19:04:05 +0000 |
|---|---|---|
| committer | Jonathan Wakely <redi@gcc.gnu.org> | 2025-11-21 15:30:50 +0000 |
| commit | 1725567dfce807e6395d726057ccc85b47a7f3c1 (patch) | |
| tree | 774d04f717e09f1fb663f8cba949a0cf49fbc4ed /libstdc++-v3 | |
| parent | 0d4ab66aaf1f2ade8b6deab07f37b3137f5f5763 (diff) | |
libstdc++: Implement LWG 4406 and LWG 3424 for std::optional and std::expected
This adjusts the return statements of optional::value_or and
expected::value_or to not perform explicit conversions, so that the
actual conversion performed matches the requirements expressed in the
Mandates: elements (LWG 4406).
Also adjust the return types to remove cv-qualifiers (LWG 3424).
libstdc++-v3/ChangeLog:
* include/std/expected (expected::value_or): Use remove_cv_t for
the return type. Do not use static_cast for return statement.
Adjust static_assert conditions to match return statements.
* include/std/optional (optional::value_or): Likewise.
(optional<T&>::value_or): Likewise.
Reviewed-by: Tomasz KamiĆski <tkaminsk@redhat.com>
Diffstat (limited to 'libstdc++-v3')
| -rw-r--r-- | libstdc++-v3/include/std/expected | 18 | ||||
| -rw-r--r-- | libstdc++-v3/include/std/optional | 28 |
2 files changed, 27 insertions, 19 deletions
diff --git a/libstdc++-v3/include/std/expected b/libstdc++-v3/include/std/expected index 4eaaab693e1..591fc72a438 100644 --- a/libstdc++-v3/include/std/expected +++ b/libstdc++-v3/include/std/expected @@ -822,32 +822,36 @@ namespace __expected return std::move(_M_unex); } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4406. value_or return statement is inconsistent with Mandates template<typename _Up = remove_cv_t<_Tp>> - constexpr _Tp + constexpr remove_cv_t<_Tp> value_or(_Up&& __v) const & noexcept(__and_v<is_nothrow_copy_constructible<_Tp>, is_nothrow_convertible<_Up, _Tp>>) { - static_assert( is_copy_constructible_v<_Tp> ); + using _Xp = remove_cv_t<_Tp>; + static_assert( is_convertible_v<const _Tp&, _Xp> ); static_assert( is_convertible_v<_Up, _Tp> ); if (_M_has_value) return _M_val; - return static_cast<_Tp>(std::forward<_Up>(__v)); + return std::forward<_Up>(__v); } template<typename _Up = remove_cv_t<_Tp>> - constexpr _Tp + constexpr remove_cv_t<_Tp> value_or(_Up&& __v) && noexcept(__and_v<is_nothrow_move_constructible<_Tp>, is_nothrow_convertible<_Up, _Tp>>) { - static_assert( is_move_constructible_v<_Tp> ); - static_assert( is_convertible_v<_Up, _Tp> ); + using _Xp = remove_cv_t<_Tp>; + static_assert( is_convertible_v<_Tp, _Xp> ); + static_assert( is_convertible_v<_Up, _Xp> ); if (_M_has_value) return std::move(_M_val); - return static_cast<_Tp>(std::forward<_Up>(__v)); + return std::forward<_Up>(__v); } template<typename _Gr = _Er> diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index 41c04b10720..f54dda6cd23 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -1285,30 +1285,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __throw_bad_optional_access(); } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4406. value_or return statement is inconsistent with Mandates template<typename _Up = remove_cv_t<_Tp>> - constexpr _Tp + constexpr remove_cv_t<_Tp> value_or(_Up&& __u) const& { - static_assert(is_copy_constructible_v<_Tp>); - static_assert(is_convertible_v<_Up&&, _Tp>); + using _Xp = remove_cv_t<_Tp>; + static_assert(is_convertible_v<const _Tp&, _Xp>); + static_assert(is_convertible_v<_Up, _Xp>); if (this->_M_is_engaged()) return this->_M_get(); - else - return static_cast<_Tp>(std::forward<_Up>(__u)); + return std::forward<_Up>(__u); } template<typename _Up = remove_cv_t<_Tp>> - constexpr _Tp + constexpr remove_cv_t<_Tp> value_or(_Up&& __u) && { - static_assert(is_move_constructible_v<_Tp>); - static_assert(is_convertible_v<_Up&&, _Tp>); + using _Xp = remove_cv_t<_Tp>; + static_assert(is_convertible_v<_Tp, _Xp>); + static_assert(is_convertible_v<_Up, _Xp>); if (this->_M_is_engaged()) return std::move(this->_M_get()); - else - return static_cast<_Tp>(std::forward<_Up>(__u)); + return std::forward<_Up>(__u); } #if __cpp_lib_optional >= 202110L // C++23 @@ -1726,9 +1728,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION value_or(_Up&& __u) const { using _Xp = remove_cv_t<_Tp>; - static_assert(is_constructible_v<_Xp, _Tp&>); + static_assert(is_convertible_v<_Tp&, _Xp>); static_assert(is_convertible_v<_Up, _Xp>); - return _M_val ? *_M_val : static_cast<_Xp>(std::forward<_Up>(__u)); + if (_M_val) + return *_M_val; + return std::forward<_Up>(__u); } // Monadic operations. |
