diff options
-rw-r--r-- | libstdc++-v3/ChangeLog | 39 | ||||
-rw-r--r-- | libstdc++-v3/include/experimental/optional | 4 | ||||
-rw-r--r-- | libstdc++-v3/include/std/optional | 125 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/optional/constexpr/relops/2.cc | 12 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/optional/constexpr/relops/4.cc | 12 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/optional/relops/1.cc | 16 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/optional/relops/2.cc | 16 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/optional/relops/3.cc | 16 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/optional/relops/4.cc | 16 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/optional/requirements.cc | 79 |
10 files changed, 283 insertions, 52 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 17e612b..f4d0996 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,42 @@ + Implement P0307R2, Making Optional Greater Equal Again. + * include/experimental/optional (_Has_addressof): Fix the comment. + * include/std/optional (_Has_addressof): Likewise. + (operator=(_Up&&)): Constrain. + (operator=(const optional<_Up>&)): Likewise. + (operator=(optional<_Up>&&)): Likewise. + (__optional_relop_t): New. + (operator==(const optional<_Tp>&, const optional<_Tp>&)): Constrain. + (operator!=(const optional<_Tp>&, const optional<_Tp>&)): + Constrain and make transparent. + (operator<(const optional<_Tp>&, const optional<_Tp>&)): Constrain. + (operator>(const optional<_Tp>&, const optional<_Tp>&)): + Constrain and make transparent. + (operator<=(const optional<_Tp>&, const optional<_Tp>&)): Likewise. + (operator>=(const optional<_Tp>&, const optional<_Tp>&)): Likewise. + (operator==(const optional<_Tp>&, const _Tp&): Constrain. + (operator==(const _Tp&, const optional<_Tp>&)): Likewise. + (operator!=(const optional<_Tp>&, _Tp const&)): + Constrain and make transparent. + (operator!=(const _Tp&, const optional<_Tp>&)): Likewise. + (operator<(const optional<_Tp>&, const _Tp&)): Constrain. + (operator<(const _Tp&, const optional<_Tp>&)): Likewise. + (operator>(const optional<_Tp>&, const _Tp&)): + Constrain and make transparent. + (operator>(const _Tp&, const optional<_Tp>&)): Likewise. + (operator<=(const optional<_Tp>&, const _Tp&)): Likewise. + (operator<=(const _Tp&, const optional<_Tp>&)): Likewise. + (operator>=(const optional<_Tp>&, const _Tp&)): Likewise. + (operator>=(const _Tp&, const optional<_Tp>&)): Likewise. + * testsuite/20_util/optional/constexpr/relops/2.cc: Adjust. + * testsuite/20_util/optional/constexpr/relops/4.cc: Likewise. + * testsuite/20_util/optional/relops/1.cc: Likewise. + * testsuite/20_util/optional/relops/2.cc: Likewise. + * testsuite/20_util/optional/relops/3.cc: Likewise. + * testsuite/20_util/optional/relops/4.cc: Likewise. + * testsuite/20_util/optional/requirements.cc: Add tests to verify + that optional's relops are transparent and don't synthesize + operators. Also test that assignment sfinaes. + 2016-07-13 Jonathan Wakely <jwakely@redhat.com> * include/bits/basic_string.h [_GLIBCXX_USE_CXX11_ABI] (_M_c_str): diff --git a/libstdc++-v3/include/experimental/optional b/libstdc++-v3/include/experimental/optional index b6425b7..ea8f6fb 100644 --- a/libstdc++-v3/include/experimental/optional +++ b/libstdc++-v3/include/experimental/optional @@ -155,8 +155,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @brief Trait that detects the presence of an overloaded unary operator&. * * Practically speaking this detects the presence of such an operator when - * called on a const-qualified lvalue (i.e. - * declval<_Tp * const&>().operator&()). + * called on a const-qualified lvalue (e.g. + * declval<const _Tp&>().operator&()). */ template<typename _Tp> struct _Has_addressof diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index e9a86a4..f1bb17c 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -131,8 +131,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @brief Trait that detects the presence of an overloaded unary operator&. * * Practically speaking this detects the presence of such an operator when - * called on a const-qualified lvalue (i.e. - * declval<_Tp * const&>().operator&()). + * called on a const-qualified lvalue (e.g. + * declval<const _Tp&>().operator&()). */ template<typename _Tp> struct _Has_addressof @@ -577,16 +577,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Up, enable_if_t<__and_< + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>, __not_<is_same<_Up, nullopt_t>>, __not_<__is_optional<_Up>>>::value, bool> = true> optional& operator=(_Up&& __u) { - static_assert(__and_<is_constructible<_Tp, _Up>, - is_assignable<_Tp&, _Up>>(), - "Cannot assign to value type from argument"); - if (this->_M_is_engaged()) this->_M_get() = std::forward<_Up>(__u); else @@ -597,15 +595,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Up, enable_if_t<__and_< - __not_<is_same<_Tp, _Up>>>::value, - bool> = true> + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>, + __not_<is_same<_Tp, _Up>>>::value, + bool> = true> optional& operator=(const optional<_Up>& __u) { - static_assert(__and_<is_constructible<_Tp, _Up>, - is_assignable<_Tp&, _Up>>(), - "Cannot assign to value type from argument"); - if (__u) { if (this->_M_is_engaged()) @@ -621,16 +617,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Up, - enable_if_t<__and_< - __not_<is_same<_Tp, _Up>>>::value, - bool> = true> + enable_if_t<__and_< + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>, + __not_<is_same<_Tp, _Up>>>::value, + bool> = true> optional& operator=(optional<_Up>&& __u) { - static_assert(__and_<is_constructible<_Tp, _Up>, - is_assignable<_Tp&, _Up>>(), - "Cannot assign to value type from argument"); - if (__u) { if (this->_M_is_engaged()) @@ -785,41 +779,60 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; + template<typename _Tp> + using __optional_relop_t = + enable_if_t<is_convertible<_Tp, bool>::value, bool>; + // [X.Y.8] Comparisons between optional values. template<typename _Tp> - constexpr bool + constexpr auto operator==(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t<decltype(declval<_Tp>() == declval<_Tp>())> { return static_cast<bool>(__lhs) == static_cast<bool>(__rhs) && (!__lhs || *__lhs == *__rhs); } template<typename _Tp> - constexpr bool + constexpr auto operator!=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs) - { return !(__lhs == __rhs); } + -> __optional_relop_t<decltype(declval<_Tp>() != declval<_Tp>())> + { + return static_cast<bool>(__lhs) != static_cast<bool>(__rhs) + || (static_cast<bool>(__lhs) && *__lhs != *__rhs); + } template<typename _Tp> - constexpr bool + constexpr auto operator<(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t<decltype(declval<_Tp>() < declval<_Tp>())> { return static_cast<bool>(__rhs) && (!__lhs || *__lhs < *__rhs); } template<typename _Tp> - constexpr bool + constexpr auto operator>(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs) - { return __rhs < __lhs; } + -> __optional_relop_t<decltype(declval<_Tp>() > declval<_Tp>())> + { + return static_cast<bool>(__lhs) && (!__rhs || *__lhs > *__rhs); + } template<typename _Tp> - constexpr bool + constexpr auto operator<=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs) - { return !(__rhs < __lhs); } + -> __optional_relop_t<decltype(declval<_Tp>() <= declval<_Tp>())> + { + return !__lhs || (static_cast<bool>(__rhs) && *__lhs <= *__rhs); + } template<typename _Tp> - constexpr bool + constexpr auto operator>=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs) - { return !(__lhs < __rhs); } + -> __optional_relop_t<decltype(declval<_Tp>() >= declval<_Tp>())> + { + return !__rhs || (static_cast<bool>(__lhs) && *__lhs >= *__rhs); + } // [X.Y.9] Comparisons with nullopt. template<typename _Tp> @@ -884,64 +897,76 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // [X.Y.10] Comparisons with value type. template<typename _Tp> - constexpr bool + constexpr auto operator==(const optional<_Tp>& __lhs, const _Tp& __rhs) + -> __optional_relop_t<decltype(declval<_Tp>() == declval<_Tp>())> { return __lhs && *__lhs == __rhs; } template<typename _Tp> - constexpr bool + constexpr auto operator==(const _Tp& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t<decltype(declval<_Tp>() == declval<_Tp>())> { return __rhs && __lhs == *__rhs; } template<typename _Tp> - constexpr bool - operator!=(const optional<_Tp>& __lhs, _Tp const& __rhs) - { return !__lhs || !(*__lhs == __rhs); } + constexpr auto + operator!=(const optional<_Tp>& __lhs, const _Tp& __rhs) + -> __optional_relop_t<decltype(declval<_Tp>() != declval<_Tp>())> + { return !__lhs || *__lhs != __rhs; } template<typename _Tp> - constexpr bool + constexpr auto operator!=(const _Tp& __lhs, const optional<_Tp>& __rhs) - { return !__rhs || !(__lhs == *__rhs); } + -> __optional_relop_t<decltype(declval<_Tp>() != declval<_Tp>())> + { return !__rhs || __lhs != *__rhs; } template<typename _Tp> - constexpr bool + constexpr auto operator<(const optional<_Tp>& __lhs, const _Tp& __rhs) + -> __optional_relop_t<decltype(declval<_Tp>() < declval<_Tp>())> { return !__lhs || *__lhs < __rhs; } template<typename _Tp> - constexpr bool + constexpr auto operator<(const _Tp& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t<decltype(declval<_Tp>() < declval<_Tp>())> { return __rhs && __lhs < *__rhs; } template<typename _Tp> - constexpr bool + constexpr auto operator>(const optional<_Tp>& __lhs, const _Tp& __rhs) - { return __lhs && __rhs < *__lhs; } + -> __optional_relop_t<decltype(declval<_Tp>() > declval<_Tp>())> + { return __lhs && *__lhs > __rhs; } template<typename _Tp> - constexpr bool + constexpr auto operator>(const _Tp& __lhs, const optional<_Tp>& __rhs) - { return !__rhs || *__rhs < __lhs; } + -> __optional_relop_t<decltype(declval<_Tp>() > declval<_Tp>())> + { return !__rhs || __lhs > *__rhs; } template<typename _Tp> - constexpr bool + constexpr auto operator<=(const optional<_Tp>& __lhs, const _Tp& __rhs) - { return !__lhs || !(__rhs < *__lhs); } + -> __optional_relop_t<decltype(declval<_Tp>() <= declval<_Tp>())> + { return !__lhs || *__lhs <= __rhs; } template<typename _Tp> - constexpr bool + constexpr auto operator<=(const _Tp& __lhs, const optional<_Tp>& __rhs) - { return __rhs && !(*__rhs < __lhs); } + -> __optional_relop_t<decltype(declval<_Tp>() <= declval<_Tp>())> + { return __rhs && __lhs <= *__rhs; } template<typename _Tp> - constexpr bool + constexpr auto operator>=(const optional<_Tp>& __lhs, const _Tp& __rhs) - { return __lhs && !(*__lhs < __rhs); } + -> __optional_relop_t<decltype(declval<_Tp>() >= declval<_Tp>())> + { return __lhs && *__lhs >= __rhs; } template<typename _Tp> - constexpr bool + constexpr auto operator>=(const _Tp& __lhs, const optional<_Tp>& __rhs) - { return !__rhs || !(__lhs < *__rhs); } + -> __optional_relop_t<decltype(declval<_Tp>() >= declval<_Tp>())> + { return !__rhs || __lhs >= *__rhs; } // [X.Y.11] template<typename _Tp> diff --git a/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/2.cc b/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/2.cc index 9aa9273..0ce00c1 100644 --- a/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/2.cc +++ b/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/2.cc @@ -54,6 +54,18 @@ namespace ns operator<(value_type const& lhs, value_type const& rhs) { return (lhs.i < rhs.i) || (!(rhs.i < lhs.i) && strrel(lhs.s, rhs.s)); } + constexpr bool + operator>(value_type const& lhs, value_type const& rhs) + { return rhs < lhs; } + + constexpr bool + operator<=(value_type const& lhs, value_type const& rhs) + { return lhs < rhs || lhs == rhs; } + + constexpr bool + operator>=(value_type const& lhs, value_type const& rhs) + { return lhs > rhs || lhs == rhs; } + } // namespace ns int main() diff --git a/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/4.cc b/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/4.cc index 15130d4..d6294ad 100644 --- a/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/4.cc +++ b/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/4.cc @@ -54,6 +54,18 @@ namespace ns operator<(value_type const& lhs, value_type const& rhs) { return (lhs.i < rhs.i) || (!(rhs.i < lhs.i) && strrel(lhs.s, rhs.s)); } + constexpr bool + operator>(value_type const& lhs, value_type const& rhs) + { return rhs < lhs; } + + constexpr bool + operator<=(value_type const& lhs, value_type const& rhs) + { return lhs < rhs || lhs == rhs; } + + constexpr bool + operator>=(value_type const& lhs, value_type const& rhs) + { return lhs > rhs || lhs == rhs; } + } // namespace ns int main() diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/1.cc b/libstdc++-v3/testsuite/20_util/optional/relops/1.cc index 6277032..1315902 100644 --- a/libstdc++-v3/testsuite/20_util/optional/relops/1.cc +++ b/libstdc++-v3/testsuite/20_util/optional/relops/1.cc @@ -37,9 +37,25 @@ namespace ns { return std::tie(lhs.i, lhs.s) == std::tie(rhs.i, rhs.s); } bool + operator!=(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) != std::tie(rhs.i, rhs.s); } + + bool operator<(value_type const& lhs, value_type const& rhs) { return std::tie(lhs.i, lhs.s) < std::tie(rhs.i, rhs.s); } + bool + operator>(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) > std::tie(rhs.i, rhs.s); } + + bool + operator<=(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) <= std::tie(rhs.i, rhs.s); } + + bool + operator>=(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) >= std::tie(rhs.i, rhs.s); } + } // namespace ns int main() diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/2.cc b/libstdc++-v3/testsuite/20_util/optional/relops/2.cc index 65071c0..1351265 100644 --- a/libstdc++-v3/testsuite/20_util/optional/relops/2.cc +++ b/libstdc++-v3/testsuite/20_util/optional/relops/2.cc @@ -37,9 +37,25 @@ namespace ns { return std::tie(lhs.i, lhs.s) == std::tie(rhs.i, rhs.s); } bool + operator!=(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) != std::tie(rhs.i, rhs.s); } + + bool operator<(value_type const& lhs, value_type const& rhs) { return std::tie(lhs.i, lhs.s) < std::tie(rhs.i, rhs.s); } + bool + operator>(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) > std::tie(rhs.i, rhs.s); } + + bool + operator<=(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) <= std::tie(rhs.i, rhs.s); } + + bool + operator>=(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) >= std::tie(rhs.i, rhs.s); } + } // namespace ns int main() diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/3.cc b/libstdc++-v3/testsuite/20_util/optional/relops/3.cc index 2fd9e8b..95fde3b 100644 --- a/libstdc++-v3/testsuite/20_util/optional/relops/3.cc +++ b/libstdc++-v3/testsuite/20_util/optional/relops/3.cc @@ -37,9 +37,25 @@ namespace ns { return std::tie(lhs.i, lhs.s) == std::tie(rhs.i, rhs.s); } bool + operator!=(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) != std::tie(rhs.i, rhs.s); } + + bool operator<(value_type const& lhs, value_type const& rhs) { return std::tie(lhs.i, lhs.s) < std::tie(rhs.i, rhs.s); } + bool + operator>(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) > std::tie(rhs.i, rhs.s); } + + bool + operator<=(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) <= std::tie(rhs.i, rhs.s); } + + bool + operator>=(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) >= std::tie(rhs.i, rhs.s); } + } // namespace ns int main() diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/4.cc b/libstdc++-v3/testsuite/20_util/optional/relops/4.cc index 363e633..78d0eb8 100644 --- a/libstdc++-v3/testsuite/20_util/optional/relops/4.cc +++ b/libstdc++-v3/testsuite/20_util/optional/relops/4.cc @@ -37,9 +37,25 @@ namespace ns { return std::tie(lhs.i, lhs.s) == std::tie(rhs.i, rhs.s); } bool + operator!=(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) != std::tie(rhs.i, rhs.s); } + + bool operator<(value_type const& lhs, value_type const& rhs) { return std::tie(lhs.i, lhs.s) < std::tie(rhs.i, rhs.s); } + bool + operator>(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) > std::tie(rhs.i, rhs.s); } + + bool + operator<=(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) <= std::tie(rhs.i, rhs.s); } + + bool + operator>=(value_type const& lhs, value_type const& rhs) + { return std::tie(lhs.i, lhs.s) >= std::tie(rhs.i, rhs.s); } + } // namespace ns int main() diff --git a/libstdc++-v3/testsuite/20_util/optional/requirements.cc b/libstdc++-v3/testsuite/20_util/optional/requirements.cc index aab572f..d0f3ab6 100644 --- a/libstdc++-v3/testsuite/20_util/optional/requirements.cc +++ b/libstdc++-v3/testsuite/20_util/optional/requirements.cc @@ -257,3 +257,82 @@ int main() static_assert( *o == 33, "" ); } } + +using std::void_t; +using std::declval; +using std::true_type; +using std::false_type; + +template <class T, class = void> +struct is_eq_comparable : false_type {}; +template <class T> +struct is_eq_comparable<T, void_t<decltype(declval<T>() == declval<T>())>> +: true_type {}; + +template <class T, class = void> +struct is_neq_comparable : false_type {}; +template <class T> +struct is_neq_comparable<T, void_t<decltype(declval<T>() != declval<T>())>> +: true_type {}; + +template <class T, class = void> +struct is_lt_comparable : false_type {}; +template <class T> +struct is_lt_comparable<T, void_t<decltype(declval<T>() < declval<T>())>> +: true_type {}; + +template <class T, class = void> +struct is_gt_comparable : false_type {}; +template <class T> +struct is_gt_comparable<T, void_t<decltype(declval<T>() > declval<T>())>> +: true_type {}; + +template <class T, class = void> +struct is_le_comparable : false_type {}; +template <class T> +struct is_le_comparable<T, void_t<decltype(declval<T>() <= declval<T>())>> +: true_type {}; + +template <class T, class = void> +struct is_ge_comparable : false_type {}; +template <class T> +struct is_ge_comparable<T, void_t<decltype(declval<T>() >= declval<T>())>> +: true_type {}; + +using std::optional; + +static_assert(is_eq_comparable<optional<int>>::value, ""); +static_assert(is_neq_comparable<optional<int>>::value, ""); +static_assert(is_lt_comparable<optional<int>>::value, ""); +static_assert(is_gt_comparable<optional<int>>::value, ""); +static_assert(is_le_comparable<optional<int>>::value, ""); +static_assert(is_ge_comparable<optional<int>>::value, ""); + +struct JustEq {}; +bool operator==(const JustEq&, const JustEq&); + +static_assert(is_eq_comparable<optional<JustEq>>::value, ""); +static_assert(!is_neq_comparable<optional<JustEq>>::value, ""); +static_assert(!is_lt_comparable<optional<JustEq>>::value, ""); +static_assert(!is_gt_comparable<optional<JustEq>>::value, ""); +static_assert(!is_le_comparable<optional<JustEq>>::value, ""); +static_assert(!is_ge_comparable<optional<JustEq>>::value, ""); + +struct JustLt {}; +bool operator<(const JustLt&, const JustLt&); + +static_assert(!is_eq_comparable<optional<JustLt>>::value, ""); +static_assert(!is_neq_comparable<optional<JustLt>>::value, ""); +static_assert(is_lt_comparable<optional<JustLt>>::value, ""); +static_assert(!is_gt_comparable<optional<JustLt>>::value, ""); +static_assert(!is_le_comparable<optional<JustLt>>::value, ""); +static_assert(!is_ge_comparable<optional<JustLt>>::value, ""); + +static_assert(!std::is_assignable<optional<JustEq>&, + optional<JustLt>>::value, ""); +static_assert(!std::is_assignable<optional<JustEq>&, + JustLt>::value, ""); +static_assert(!std::is_assignable<optional<JustEq>&, + optional<JustLt>&>::value, ""); +static_assert(!std::is_assignable<optional<JustEq>&, + JustLt&>::value, ""); |