diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2020-04-14 21:54:55 +0100 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2020-04-14 21:54:55 +0100 |
commit | f5fa62ed19a1c85cda920bbe05eb075d8f2a0b42 (patch) | |
tree | 902220d77e6fcfdebc238796ecb183448a03250a /libstdc++-v3 | |
parent | a126a1577ffcbf62d97723b35d343bdff014bb40 (diff) | |
download | gcc-f5fa62ed19a1c85cda920bbe05eb075d8f2a0b42.zip gcc-f5fa62ed19a1c85cda920bbe05eb075d8f2a0b42.tar.gz gcc-f5fa62ed19a1c85cda920bbe05eb075d8f2a0b42.tar.bz2 |
libstdc++: Add comparison operators to std::shared_ptr (PR 94562)
This also implements the proposed resolution to LWG issue 3247, so that
the ill-formed <=> expression with nullptr is not used.
PR libstdc++/94562
* include/bits/shared_ptr.h (operator<=>): Define for C++20.
* include/bits/shared_ptr_base.h (operator<=>): Likewise.
* include/bits/unique_ptr.h (operator<=>): Add inline specifier.
* testsuite/20_util/shared_ptr/comparison/cmp_c++20.cc: New test.
* testsuite/20_util/shared_ptr/comparison/less.cc: Do not expect
std::less<A*> to be used when comparing std::shared_ptr<A> objects in
C++20.
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/ChangeLog | 9 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/shared_ptr.h | 16 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/shared_ptr_base.h | 19 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/unique_ptr.h | 4 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/shared_ptr/comparison/cmp_c++20.cc | 106 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/shared_ptr/comparison/less.cc | 6 |
6 files changed, 158 insertions, 2 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 085ca6a..417c8c4 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,14 @@ 2020-04-14 Jonathan Wakely <jwakely@redhat.com> + PR libstdc++/94562 + * include/bits/shared_ptr.h (operator<=>): Define for C++20. + * include/bits/shared_ptr_base.h (operator<=>): Likewise. + * include/bits/unique_ptr.h (operator<=>): Add inline specifier. + * testsuite/20_util/shared_ptr/comparison/cmp_c++20.cc: New test. + * testsuite/20_util/shared_ptr/comparison/less.cc: Do not expect + std::less<A*> to be used when comparing std::shared_ptr<A> objects in + C++20. + PR libstdc++/94565 * libsupc++/compare (__unspec): Add noexcept-specifier to constructor. * testsuite/18_support/comparisons/categories/94565.cc: New test. diff --git a/libstdc++-v3/include/bits/shared_ptr.h b/libstdc++-v3/include/bits/shared_ptr.h index c4df358..0c393e2 100644 --- a/libstdc++-v3/include/bits/shared_ptr.h +++ b/libstdc++-v3/include/bits/shared_ptr.h @@ -442,6 +442,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator==(const shared_ptr<_Tp>& __a, nullptr_t) noexcept { return !__a; } +#ifdef __cpp_lib_three_way_comparison + template<typename _Tp, typename _Up> + inline strong_ordering + operator<=>(const shared_ptr<_Tp>& __a, + const shared_ptr<_Up>& __b) noexcept + { return compare_three_way()(__a.get(), __b.get()); } + + template<typename _Tp> + inline strong_ordering + operator<=>(const shared_ptr<_Tp>& __a, nullptr_t) noexcept + { + using pointer = typename shared_ptr<_Tp>::element_type*; + return compare_three_way()(__a.get(), static_cast<pointer>(nullptr)); + } +#else /// shared_ptr comparison with nullptr template<typename _Tp> _GLIBCXX_NODISCARD inline bool @@ -548,6 +563,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_NODISCARD inline bool operator>=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept { return !(nullptr < __a); } +#endif // 20.7.2.2.8 shared_ptr specialized algorithms. diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h index c9017ed..ff578e6 100644 --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -54,6 +54,9 @@ #include <bits/refwrap.h> #include <bits/stl_function.h> #include <ext/aligned_buffer.h> +#if __cplusplus > 201703L +# include <compare> +#endif namespace std _GLIBCXX_VISIBILITY(default) { @@ -1442,6 +1445,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator==(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept { return !__a; } +#ifdef __cpp_lib_three_way_comparison + template<typename _Tp, typename _Up, _Lock_policy _Lp> + inline strong_ordering + operator<=>(const __shared_ptr<_Tp, _Lp>& __a, + const __shared_ptr<_Up, _Lp>& __b) noexcept + { return compare_three_way()(__a.get(), __b.get()); } + + template<typename _Tp, _Lock_policy _Lp> + inline strong_ordering + operator<=>(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept + { + using pointer = typename __shared_ptr<_Tp, _Lp>::element_type*; + return compare_three_way()(__a.get(), static_cast<pointer>(nullptr)); + } +#else template<typename _Tp, _Lock_policy _Lp> inline bool operator==(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept @@ -1537,6 +1555,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline bool operator>=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept { return !(nullptr < __a); } +#endif // three-way comparison // 20.7.2.2.8 shared_ptr specialized algorithms. template<typename _Tp, _Lock_policy _Lp> diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h index 53c8def..3695214 100644 --- a/libstdc++-v3/include/bits/unique_ptr.h +++ b/libstdc++-v3/include/bits/unique_ptr.h @@ -888,6 +888,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Dp, typename _Up, typename _Ep> requires three_way_comparable_with<typename unique_ptr<_Tp, _Dp>::pointer, typename unique_ptr<_Up, _Ep>::pointer> + inline compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer, typename unique_ptr<_Up, _Ep>::pointer> operator<=>(const unique_ptr<_Tp, _Dp>& __x, @@ -896,11 +897,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Dp> requires three_way_comparable<typename unique_ptr<_Tp, _Dp>::pointer> + inline compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer> operator<=>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) { using pointer = typename unique_ptr<_Tp, _Dp>::pointer; - return compare_three_way()(__x.get(), pointer(nullptr)); + return compare_three_way()(__x.get(), static_cast<pointer>(nullptr)); } #endif // @} relates unique_ptr diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/comparison/cmp_c++20.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/comparison/cmp_c++20.cc new file mode 100644 index 0000000..5600bbf --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/comparison/cmp_c++20.cc @@ -0,0 +1,106 @@ +// Copyright (C) 2020 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/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <memory> +#include <testsuite_hooks.h> + +void +test01() +{ + std::shared_ptr<int> p0, p00; + VERIFY( p0 == p00 ); + VERIFY( !(p0 < p00) ); + VERIFY( !(p0 > p00) ); + VERIFY( p0 <= p00 ); + VERIFY( p0 >= p00 ); + VERIFY( std::is_eq(p0 <=> p00) ); + + std::shared_ptr<int> p1(new int(1)); + VERIFY( p1 == p1 ); + VERIFY( !(p1 < p1) ); + VERIFY( !(p1 > p1) ); + VERIFY( p1 <= p1 ); + VERIFY( p1 >= p1 ); + VERIFY( std::is_eq(p1 <=> p1) ); + + std::shared_ptr<int> p11 = p1; + VERIFY( p11 == p1 ); + VERIFY( !(p11 < p1) ); + VERIFY( !(p11 > p1) ); + VERIFY( p11 <= p1 ); + VERIFY( p11 >= p1 ); + VERIFY( std::is_eq(p11 <=> p1) ); + + std::shared_ptr<const int> p2(new int(1)); + VERIFY( p1 >= p1 ); + VERIFY( p1 != p2 ); + VERIFY( (p1 < p2) || (p1 > p2) ); + VERIFY( (p1 <= p2) || (p1 >= p2) ); + VERIFY( std::is_neq(p1 <=> p2) ); + + VERIFY( p1 != p0 ); + VERIFY( !(p1 < p0) ); + VERIFY( p1 > p0 ); + VERIFY( !(p1 <= p0) ); + VERIFY( p1 >= p0 ); + VERIFY( std::is_gt(p1 <=> p0) ); + VERIFY( std::is_lt(p0 <=> p1) ); +} + +void +test02() +{ + std::shared_ptr<int> p0; + VERIFY( p0 == nullptr ); + VERIFY( !(p0 < nullptr) ); + VERIFY( !(p0 > nullptr) ); + VERIFY( p0 <= nullptr ); + VERIFY( p0 >= nullptr ); + VERIFY( std::is_eq(p0 <=> nullptr) ); + + VERIFY( nullptr == p0 ); + VERIFY( !(nullptr < p0) ); + VERIFY( !(nullptr > p0) ); + VERIFY( nullptr <= p0 ); + VERIFY( nullptr >= p0 ); + VERIFY( std::is_eq(nullptr <=> p0) ); + + std::shared_ptr<int> p1(new int(1)); + VERIFY( p1 != nullptr ); + VERIFY( !(p1 < nullptr) ); + VERIFY( p1 > nullptr ); + VERIFY( !(p1 <= nullptr) ); + VERIFY( p1 >= nullptr ); + VERIFY( std::is_gt(p1 <=> nullptr) ); + + VERIFY( nullptr != p1 ); + VERIFY( nullptr < p1 ); + VERIFY( !(nullptr > p1) ); + VERIFY( nullptr <= p1 ); + VERIFY( !(nullptr >= p1) ); + VERIFY( std::is_lt(nullptr <=> p1) ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/comparison/less.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/comparison/less.cc index 8b42b3a..9ee65ff 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/comparison/less.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/comparison/less.cc @@ -46,7 +46,11 @@ test01() std::shared_ptr<A> p1; std::shared_ptr<A> p2; VERIFY( !less(p1, p2) && !less(p2, p1) ); +#ifndef __cpp_lib_three_way_comparison +// In C++20 std::less<std::shared_ptr<A>> uses the operator< synthesized +// from operator<=>, which uses std::compare_three_way not std::less<A*>. VERIFY( std::less<A*>::count == 2 ); +#endif return 0; } @@ -86,7 +90,7 @@ test03() return 0; } -int +int main() { test01(); |