diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2019-12-03 23:57:46 +0000 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2019-12-03 23:57:46 +0000 |
commit | 7f397e451905d1ce2b04d56836044b97d71216dd (patch) | |
tree | ce0d178fc7667c837a673141f0558e50129ff32a /libstdc++-v3 | |
parent | 6fb3d28f13dfc2591690b6f66d350f651bae6726 (diff) | |
download | gcc-7f397e451905d1ce2b04d56836044b97d71216dd.zip gcc-7f397e451905d1ce2b04d56836044b97d71216dd.tar.gz gcc-7f397e451905d1ce2b04d56836044b97d71216dd.tar.bz2 |
libstdc++: Implement spaceship for std::pair (P1614R2)
This defines operator<=> as a non-member function template and does not
alter operator==. This contradicts the changes made by P1614R2, which
specify both as hidden friends, but that specification of operator<=> is
broken and the subject of a soon-to-be-published LWG issue.
* include/bits/stl_pair.h [__cpp_lib_three_way_comparison]
(operator<=>): Define for C++20.
* libsupc++/compare (__cmp2way_res_t): Rename to __cmp3way_res_t,
move into __detail namespace. Do not turn argument types into lvalues.
(__cmp3way_helper): Rename to __cmp3way_res_impl, move into __detail
namespace. Constrain with concepts instead of using void_t.
(compare_three_way_result): Adjust name of base class.
(compare_three_way_result_t): Use __cmp3way_res_impl directly.
(__detail::__3way_cmp_with): Add workaround for PR 91073.
(compare_three_way): Use workaround.
(__detail::__synth3way, __detail::__synth3way_t): Define new helpers
implementing synth-three-way and synth-three-way-result semantics.
* testsuite/20_util/pair/comparison_operators/constexpr_c++20.cc: New
test.
From-SVN: r278951
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/ChangeLog | 15 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/stl_pair.h | 19 | ||||
-rw-r--r-- | libstdc++-v3/libsupc++/compare | 81 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/pair/comparison_operators/constexpr_c++20.cc | 31 |
4 files changed, 126 insertions, 20 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 8baac8e..50f506c 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,20 @@ 2019-12-03 Jonathan Wakely <jwakely@redhat.com> + * include/bits/stl_pair.h [__cpp_lib_three_way_comparison] + (operator<=>): Define for C++20. + * libsupc++/compare (__cmp2way_res_t): Rename to __cmp3way_res_t, + move into __detail namespace. Do not turn argument types into lvalues. + (__cmp3way_helper): Rename to __cmp3way_res_impl, move into __detail + namespace. Constrain with concepts instead of using void_t. + (compare_three_way_result): Adjust name of base class. + (compare_three_way_result_t): Use __cmp3way_res_impl directly. + (__detail::__3way_cmp_with): Add workaround for PR 91073. + (compare_three_way): Use workaround. + (__detail::__synth3way, __detail::__synth3way_t): Define new helpers + implementing synth-three-way and synth-three-way-result semantics. + * testsuite/20_util/pair/comparison_operators/constexpr_c++20.cc: New + test. + * include/bits/stl_pair.h (pair): Remove stray Doxygen closing marker. * testsuite/util/slow_clock.h: Fix copyright date. diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 1e0e4fe..02b1f0a 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -59,7 +59,10 @@ #include <bits/move.h> // for std::move / std::forward, and std::swap #if __cplusplus >= 201103L -#include <type_traits> // for std::__decay_and_strip too +# include <type_traits> // for std::__decay_and_strip, std::is_reference_v +#endif +#if __cplusplus > 201703L +# include <compare> #endif namespace std _GLIBCXX_VISIBILITY(default) @@ -447,7 +450,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX20_CONSTEXPR pair(tuple<_Args1...>&, tuple<_Args2...>&, _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>); -#endif +#endif // C++11 }; /// @relates pair @{ @@ -462,6 +465,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator==(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) { return __x.first == __y.first && __x.second == __y.second; } +#if __cpp_lib_three_way_comparison && __cpp_lib_concepts + template<typename _T1, typename _T2> + constexpr common_comparison_category_t<__detail::__synth3way_t<_T1>, + __detail::__synth3way_t<_T2>> + operator<=>(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) + { + if (auto __c = __detail::__synth3way(__x.first, __y.first); __c != 0) + return __c; + return __detail::__synth3way(__x.second, __y.second); + } +#else /** Defines a lexicographical order for pairs. * * For two pairs of the same type, `P` is ordered before `Q` if @@ -498,6 +512,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline _GLIBCXX_CONSTEXPR bool operator>=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) { return !(__x < __y); } +#endif // !(three_way_comparison && concepts) #if __cplusplus >= 201103L /** Swap overload for pairs. Calls std::pair::swap(). diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare index 289145d..412ec68 100644 --- a/libstdc++-v3/libsupc++/compare +++ b/libstdc++-v3/libsupc++/compare @@ -509,34 +509,41 @@ namespace std { __t <=> __u } -> __detail::__compares_as<_Cat>; { __u <=> __t } -> __detail::__compares_as<_Cat>; }; -#endif - template<typename _Tp, typename _Up> - using __cmp2way_res_t - = decltype(std::declval<_Tp&>() <=> std::declval<_Up&>()); - - template<typename _Tp, typename _Up = _Tp, typename = void> - struct __cmp3way_helper - { }; + namespace __detail + { + template<typename _Tp, typename _Up> + using __cmp3way_res_t + = decltype(std::declval<_Tp>() <=> std::declval<_Up>()); + + // Implementation of std::compare_three_way_result. + // It is undefined for a program to add specializations of + // std::compare_three_way_result, so the std::compare_three_way_result_t + // alias ignores std::compare_three_way_result and uses + // __detail::__cmp3way_res_impl directly instead. + template<typename _Tp, typename _Up> + struct __cmp3way_res_impl + { }; - template<typename _Tp, typename _Up> - struct __cmp3way_helper<_Tp, _Up, void_t<__cmp2way_res_t<_Tp, _Up>>> - { - using type = __cmp2way_res_t<_Tp, _Up>; - using __type = type; - }; + template<typename _Tp, typename _Up> + requires requires { typename __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; } + struct __cmp3way_res_impl<_Tp, _Up> + { + using type = __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; + }; + } // namespace __detail /// [cmp.result], result of three-way comparison template<typename _Tp, typename _Up = _Tp> struct compare_three_way_result - : __cmp3way_helper<_Tp, _Up> + : __detail::__cmp3way_res_impl<_Tp, _Up> { }; + /// [cmp.result], result of three-way comparison template<typename _Tp, typename _Up = _Tp> using compare_three_way_result_t - = typename compare_three_way_result<_Tp, _Up>::__type; + = typename __detail::__cmp3way_res_impl<_Tp, _Up>::type; -#if __cpp_lib_concepts namespace __detail { // BUILTIN-PTR-THREE-WAY(T, U) @@ -548,13 +555,17 @@ namespace std { operator<=>(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); } && ! requires(_Tp&& __t, _Up&& __u) { static_cast<_Tp&&>(__t).operator<=>(static_cast<_Up&&>(__u)); }; + + // FIXME: workaround for PR c++/91073 + template<typename _Tp, typename _Up> + concept __3way_cmp_with = three_way_comparable_with<_Tp, _Up>; } // namespace __detail // [cmp.object], typename compare_three_way struct compare_three_way { template<typename _Tp, typename _Up> - requires (three_way_comparable_with<_Tp, _Up> + requires (__detail::__3way_cmp_with<_Tp, _Up> || __detail::__3way_builtin_ptr_cmp<_Tp, _Up>) constexpr auto operator()(_Tp&& __t, _Up&& __u) const noexcept @@ -915,6 +926,40 @@ namespace std inline constexpr __cmp_cust::_Partial_fallback compare_partial_order_fallback{}; } + + namespace __detail + { + // [expos.only.func] + inline constexpr struct _Synth3way + { + template<typename _Tp, typename _Up> + constexpr auto + operator()(const _Tp& __t, const _Up& __u) const + requires requires + { + { __t < __u } -> convertible_to<bool>; + { __u < __t } -> convertible_to<bool>; + } + { + if constexpr (__3way_cmp_with<_Tp, _Up>) + return __t <=> __u; + else + { + if (__t < __u) + return weak_ordering::less; + else if (__u < __t) + return weak_ordering::greater; + else + return weak_ordering::equivalent; + } + } + } __synth3way = {}; + + template<typename _Tp, typename _Up = _Tp> + using __synth3way_t + = decltype(__detail::__synth3way(std::declval<_Tp&>(), + std::declval<_Up&>())); + } // namespace __detail #endif // concepts } // namespace std diff --git a/libstdc++-v3/testsuite/20_util/pair/comparison_operators/constexpr_c++20.cc b/libstdc++-v3/testsuite/20_util/pair/comparison_operators/constexpr_c++20.cc new file mode 100644 index 0000000..127610d8 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/pair/comparison_operators/constexpr_c++20.cc @@ -0,0 +1,31 @@ +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <utility> +#include <testsuite_common_types.h> + +int main() +{ + __gnu_test::constexpr_comparison_operators test; + test.operator()<std::pair<int, int>>(); + + constexpr std::pair<int, int> p{1, 2}, q{3, 0}; + static_assert( p <=> q == std::strong_ordering::less ); +} |