diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index f54dda6cd237..8b9fa9244213 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -1855,8 +1855,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator==(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) -> __optional_eq_t<_Tp, _Up> { - return static_cast(__lhs) == static_cast(__rhs) - && (!__lhs || *__lhs == *__rhs); + if (__lhs.has_value() != __rhs.has_value()) + return false; + if (!__lhs.has_value()) + return true; + return *__lhs == *__rhs; } template @@ -1864,8 +1867,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator!=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) -> __optional_ne_t<_Tp, _Up> { - return static_cast(__lhs) != static_cast(__rhs) - || (static_cast(__lhs) && *__lhs != *__rhs); + if (__lhs.has_value() != __rhs.has_value()) + return true; + if (!__lhs.has_value()) + return false; + return *__lhs != *__rhs; } template @@ -1873,7 +1879,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator<(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) -> __optional_lt_t<_Tp, _Up> { - return static_cast(__rhs) && (!__lhs || *__lhs < *__rhs); + if (!__rhs.has_value()) + return false; + if (!__lhs.has_value()) + return true; + return *__lhs < *__rhs; } template @@ -1881,7 +1891,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator>(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) -> __optional_gt_t<_Tp, _Up> { - return static_cast(__lhs) && (!__rhs || *__lhs > *__rhs); + if (!__lhs.has_value()) + return false; + if (!__rhs.has_value()) + return true; + return *__lhs > *__rhs; } template @@ -1889,7 +1903,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator<=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) -> __optional_le_t<_Tp, _Up> { - return !__lhs || (static_cast(__rhs) && *__lhs <= *__rhs); + if (!__lhs.has_value()) + return true; + if (!__rhs.has_value()) + return false; + return *__lhs <= *__rhs; } template @@ -1897,7 +1915,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator>=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) -> __optional_ge_t<_Tp, _Up> { - return !__rhs || (static_cast(__lhs) && *__lhs >= *__rhs); + if (!__rhs.has_value()) + return true; + if (!__lhs.has_value()) + return false; + return *__lhs >= *__rhs; } #ifdef __cpp_lib_three_way_comparison @@ -1994,84 +2016,132 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr auto operator== [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_eq_t<_Tp, _Up> - { return __lhs && *__lhs == __rhs; } + { + if (__lhs.has_value()) + return *__lhs == __rhs; + return false; + } template _REQUIRES_NOT_OPTIONAL(_Tp) constexpr auto operator== [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs) -> __optional_eq_t<_Tp, _Up> - { return __rhs && __lhs == *__rhs; } + { + if (__rhs.has_value()) + return __lhs == *__rhs; + return false; + } template _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto operator!= [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_ne_t<_Tp, _Up> - { return !__lhs || *__lhs != __rhs; } + { + if (__lhs.has_value()) + return *__lhs != __rhs; + return true; + } template _REQUIRES_NOT_OPTIONAL(_Tp) constexpr auto operator!= [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs) -> __optional_ne_t<_Tp, _Up> - { return !__rhs || __lhs != *__rhs; } + { + if (__rhs.has_value()) + return __lhs != *__rhs; + return true; + } template _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto operator< [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_lt_t<_Tp, _Up> - { return !__lhs || *__lhs < __rhs; } + { + if (__lhs.has_value()) + return *__lhs < __rhs; + return true; + } template _REQUIRES_NOT_OPTIONAL(_Tp) constexpr auto operator< [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs) -> __optional_lt_t<_Tp, _Up> - { return __rhs && __lhs < *__rhs; } + { + if (__rhs.has_value()) + return __lhs < *__rhs; + return false; + } template _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto operator> [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_gt_t<_Tp, _Up> - { return __lhs && *__lhs > __rhs; } + { + if (__lhs.has_value()) + return *__lhs > __rhs; + return false; + } template _REQUIRES_NOT_OPTIONAL(_Tp) constexpr auto operator> [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs) -> __optional_gt_t<_Tp, _Up> - { return !__rhs || __lhs > *__rhs; } + { + if (__rhs.has_value()) + return __lhs > *__rhs; + return true; + } template _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto operator<= [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_le_t<_Tp, _Up> - { return !__lhs || *__lhs <= __rhs; } + { + if (__lhs.has_value()) + return *__lhs <= __rhs; + return true; + } template _REQUIRES_NOT_OPTIONAL(_Tp) constexpr auto operator<= [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs) -> __optional_le_t<_Tp, _Up> - { return __rhs && __lhs <= *__rhs; } + { + if (__rhs.has_value()) + return __lhs <= *__rhs; + return false; + } template _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto operator>= [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_ge_t<_Tp, _Up> - { return __lhs && *__lhs >= __rhs; } + { + if (__lhs.has_value()) + return *__lhs >= __rhs; + return false; + } template _REQUIRES_NOT_OPTIONAL(_Tp) constexpr auto operator>= [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs) -> __optional_ge_t<_Tp, _Up> - { return !__rhs || __lhs >= *__rhs; } + { + if (__rhs.has_value()) + return __lhs >= *__rhs; + return true; + } #ifdef __cpp_lib_three_way_comparison // _GLIBCXX_RESOLVE_LIB_DEFECTS diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/lwg4370.cc b/libstdc++-v3/testsuite/20_util/optional/relops/lwg4370.cc new file mode 100644 index 000000000000..a292cbe6b404 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/optional/relops/lwg4370.cc @@ -0,0 +1,55 @@ +// { dg-do compile { target c++17 } } + +// LWG 4370. Comparison of optional to T may be ill-formed + +#include +#include + +struct Bool +{ + Bool(bool); + operator bool() const; +}; + +template void operator&&(Bool, T) = delete; +template void operator&&(T, Bool) = delete; +template void operator||(Bool, T) = delete; +template void operator||(T, Bool) = delete; + +struct S +{ + Bool operator==(S) const; + Bool operator!=(S) const; + Bool operator<(S) const; + Bool operator>(S) const; + Bool operator<=(S) const; + Bool operator>=(S) const; +}; + +void +test_lwg4370() +{ + std::optional o; + (void)(o == o); + (void)(o != o); + (void)(o < o); + (void)(o > o); + (void)(o <= o); + (void)(o >= o); + + S s; + (void)(o == s); + (void)(s == o); + (void)(o != s); + (void)(s != o); + (void)(o < s); + (void)(s < o); + (void)(o > s); + (void)(s > o); + (void)(o <= s); + (void)(s <= o); + (void)(o >= s); + (void)(s >= o); +} + +