summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2025-11-19 19:04:05 +0000
committerJonathan Wakely <redi@gcc.gnu.org>2025-11-21 15:30:50 +0000
commit1725567dfce807e6395d726057ccc85b47a7f3c1 (patch)
tree774d04f717e09f1fb663f8cba949a0cf49fbc4ed
parent0d4ab66aaf1f2ade8b6deab07f37b3137f5f5763 (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>
-rw-r--r--libstdc++-v3/include/std/expected18
-rw-r--r--libstdc++-v3/include/std/optional28
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.