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
This commit is contained in:
parent
6fb3d28f13
commit
7f397e4519
@ -1,5 +1,20 @@
|
|||||||
2019-12-03 Jonathan Wakely <jwakely@redhat.com>
|
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.
|
* include/bits/stl_pair.h (pair): Remove stray Doxygen closing marker.
|
||||||
|
|
||||||
* testsuite/util/slow_clock.h: Fix copyright date.
|
* testsuite/util/slow_clock.h: Fix copyright date.
|
||||||
|
@ -59,7 +59,10 @@
|
|||||||
#include <bits/move.h> // for std::move / std::forward, and std::swap
|
#include <bits/move.h> // for std::move / std::forward, and std::swap
|
||||||
|
|
||||||
#if __cplusplus >= 201103L
|
#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
|
#endif
|
||||||
|
|
||||||
namespace std _GLIBCXX_VISIBILITY(default)
|
namespace std _GLIBCXX_VISIBILITY(default)
|
||||||
@ -447,7 +450,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||||||
_GLIBCXX20_CONSTEXPR
|
_GLIBCXX20_CONSTEXPR
|
||||||
pair(tuple<_Args1...>&, tuple<_Args2...>&,
|
pair(tuple<_Args1...>&, tuple<_Args2...>&,
|
||||||
_Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>);
|
_Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>);
|
||||||
#endif
|
#endif // C++11
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @relates pair @{
|
/// @relates pair @{
|
||||||
@ -462,6 +465,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||||||
operator==(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
|
operator==(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
|
||||||
{ return __x.first == __y.first && __x.second == __y.second; }
|
{ 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.
|
/** Defines a lexicographical order for pairs.
|
||||||
*
|
*
|
||||||
* For two pairs of the same type, `P` is ordered before `Q` if
|
* 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
|
inline _GLIBCXX_CONSTEXPR bool
|
||||||
operator>=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
|
operator>=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
|
||||||
{ return !(__x < __y); }
|
{ return !(__x < __y); }
|
||||||
|
#endif // !(three_way_comparison && concepts)
|
||||||
|
|
||||||
#if __cplusplus >= 201103L
|
#if __cplusplus >= 201103L
|
||||||
/** Swap overload for pairs. Calls std::pair::swap().
|
/** Swap overload for pairs. Calls std::pair::swap().
|
||||||
|
@ -509,34 +509,41 @@ namespace std
|
|||||||
{ __t <=> __u } -> __detail::__compares_as<_Cat>;
|
{ __t <=> __u } -> __detail::__compares_as<_Cat>;
|
||||||
{ __u <=> __t } -> __detail::__compares_as<_Cat>;
|
{ __u <=> __t } -> __detail::__compares_as<_Cat>;
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
template<typename _Tp, typename _Up>
|
namespace __detail
|
||||||
using __cmp2way_res_t
|
{
|
||||||
= decltype(std::declval<_Tp&>() <=> std::declval<_Up&>());
|
template<typename _Tp, typename _Up>
|
||||||
|
using __cmp3way_res_t
|
||||||
|
= decltype(std::declval<_Tp>() <=> std::declval<_Up>());
|
||||||
|
|
||||||
template<typename _Tp, typename _Up = _Tp, typename = void>
|
// Implementation of std::compare_three_way_result.
|
||||||
struct __cmp3way_helper
|
// 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>
|
template<typename _Tp, typename _Up>
|
||||||
struct __cmp3way_helper<_Tp, _Up, void_t<__cmp2way_res_t<_Tp, _Up>>>
|
requires requires { typename __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; }
|
||||||
{
|
struct __cmp3way_res_impl<_Tp, _Up>
|
||||||
using type = __cmp2way_res_t<_Tp, _Up>;
|
{
|
||||||
using __type = type;
|
using type = __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>;
|
||||||
};
|
};
|
||||||
|
} // namespace __detail
|
||||||
|
|
||||||
/// [cmp.result], result of three-way comparison
|
/// [cmp.result], result of three-way comparison
|
||||||
template<typename _Tp, typename _Up = _Tp>
|
template<typename _Tp, typename _Up = _Tp>
|
||||||
struct compare_three_way_result
|
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>
|
template<typename _Tp, typename _Up = _Tp>
|
||||||
using compare_three_way_result_t
|
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
|
namespace __detail
|
||||||
{
|
{
|
||||||
// BUILTIN-PTR-THREE-WAY(T, U)
|
// BUILTIN-PTR-THREE-WAY(T, U)
|
||||||
@ -548,13 +555,17 @@ namespace std
|
|||||||
{ operator<=>(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }
|
{ operator<=>(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }
|
||||||
&& ! requires(_Tp&& __t, _Up&& __u)
|
&& ! requires(_Tp&& __t, _Up&& __u)
|
||||||
{ static_cast<_Tp&&>(__t).operator<=>(static_cast<_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
|
} // namespace __detail
|
||||||
|
|
||||||
// [cmp.object], typename compare_three_way
|
// [cmp.object], typename compare_three_way
|
||||||
struct compare_three_way
|
struct compare_three_way
|
||||||
{
|
{
|
||||||
template<typename _Tp, typename _Up>
|
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>)
|
|| __detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
|
||||||
constexpr auto
|
constexpr auto
|
||||||
operator()(_Tp&& __t, _Up&& __u) const noexcept
|
operator()(_Tp&& __t, _Up&& __u) const noexcept
|
||||||
@ -915,6 +926,40 @@ namespace std
|
|||||||
inline constexpr __cmp_cust::_Partial_fallback
|
inline constexpr __cmp_cust::_Partial_fallback
|
||||||
compare_partial_order_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
|
#endif // concepts
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
||||||
|
@ -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 );
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user