aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2019-12-03 23:57:46 +0000
committerJonathan Wakely <redi@gcc.gnu.org>2019-12-03 23:57:46 +0000
commit7f397e451905d1ce2b04d56836044b97d71216dd (patch)
treece0d178fc7667c837a673141f0558e50129ff32a /libstdc++-v3
parent6fb3d28f13dfc2591690b6f66d350f651bae6726 (diff)
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/ChangeLog15
-rw-r--r--libstdc++-v3/include/bits/stl_pair.h19
-rw-r--r--libstdc++-v3/libsupc++/compare81
-rw-r--r--libstdc++-v3/testsuite/20_util/pair/comparison_operators/constexpr_c++20.cc31
4 files changed, 126 insertions, 20 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 8baac8e3a14..50f506cc38e 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 1e0e4fe892a..02b1f0ac922 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 289145dea56..412ec6861d3 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 00000000000..127610d8368
--- /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 );
+}