From 5b074864f8c593fd4bccee788a023a37b446b2ed Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Thu, 9 Apr 2020 21:10:32 +0100 Subject: [PATCH] libstdc++: Add comparison operators to std::unique_ptr Some more C++20 changes from P1614R2, "The Mothership has Landed". This includes the proposed resolution for LWG 3426 to fix the three-way comparison with nullptr_t. The existing tests for unique_ptr comparisons don't actually check the results, only that the expressions compile and are convertible to bool. This also adds a test for the results of those comparisons for C++11 and up. * include/bits/unique_ptr.h (operator<=>): Define for C++20. * testsuite/20_util/default_delete/48631_neg.cc: Adjust dg-error line. * testsuite/20_util/default_delete/void_neg.cc: Likewise. * testsuite/20_util/unique_ptr/comparison/compare.cc: New test. * testsuite/20_util/unique_ptr/comparison/compare_c++20.cc: New test. --- libstdc++-v3/ChangeLog | 8 ++ libstdc++-v3/include/bits/unique_ptr.h | 25 +++++ .../20_util/default_delete/48631_neg.cc | 2 +- .../20_util/default_delete/void_neg.cc | 2 +- .../20_util/unique_ptr/comparison/compare.cc | 88 +++++++++++++++++ .../unique_ptr/comparison/compare_c++20.cc | 98 +++++++++++++++++++ 6 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/comparison/compare.cc create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/comparison/compare_c++20.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 37ffbcf7b95..98812f0faae 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,11 @@ +2020-04-09 Jonathan Wakely + + * include/bits/unique_ptr.h (operator<=>): Define for C++20. + * testsuite/20_util/default_delete/48631_neg.cc: Adjust dg-error line. + * testsuite/20_util/default_delete/void_neg.cc: Likewise. + * testsuite/20_util/unique_ptr/comparison/compare.cc: New test. + * testsuite/20_util/unique_ptr/comparison/compare_c++20.cc: New test. + 2020-04-08 Jonathan Wakely * include/bits/slice_array.h (operator==(const slice&, const slice&)): diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h index d03266c1878..53c8def627d 100644 --- a/libstdc++-v3/include/bits/unique_ptr.h +++ b/libstdc++-v3/include/bits/unique_ptr.h @@ -37,6 +37,9 @@ #include #include #include +#if __cplusplus > 201703L +# include +#endif namespace std _GLIBCXX_VISIBILITY(default) { @@ -756,6 +759,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator==(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept { return !__x; } +#ifndef __cpp_lib_three_way_comparison /// unique_ptr comparison with nullptr template _GLIBCXX_NODISCARD inline bool @@ -781,6 +785,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_NODISCARD inline bool operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept { return (bool)__x; } +#endif // three way comparison /// Relational operator for unique_ptr objects, compares the owned pointers template=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) { return !(nullptr < __x); } + +#ifdef __cpp_lib_three_way_comparison + template + requires three_way_comparable_with::pointer, + typename unique_ptr<_Up, _Ep>::pointer> + compare_three_way_result_t::pointer, + typename unique_ptr<_Up, _Ep>::pointer> + operator<=>(const unique_ptr<_Tp, _Dp>& __x, + const unique_ptr<_Up, _Ep>& __y) + { return compare_three_way()(__x.get(), __y.get()); } + + template + requires three_way_comparable::pointer> + compare_three_way_result_t::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)); + } +#endif // @} relates unique_ptr /// @cond undocumented diff --git a/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc b/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc index 57d7e62c310..6da5a52e28b 100644 --- a/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc +++ b/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc @@ -26,4 +26,4 @@ struct D : B { }; D d; std::default_delete db; typedef decltype(db(&d)) type; // { dg-error "no match" } -// { dg-error "no type" "" { target *-*-* } 112 } +// { dg-error "no type" "" { target *-*-* } 115 } diff --git a/libstdc++-v3/testsuite/20_util/default_delete/void_neg.cc b/libstdc++-v3/testsuite/20_util/default_delete/void_neg.cc index 0c5a09e1e9d..149b699d106 100644 --- a/libstdc++-v3/testsuite/20_util/default_delete/void_neg.cc +++ b/libstdc++-v3/testsuite/20_util/default_delete/void_neg.cc @@ -25,5 +25,5 @@ void test01() { std::default_delete d; d(nullptr); // { dg-error "here" } - // { dg-error "incomplete" "" { target *-*-* } 77 } + // { dg-error "incomplete" "" { target *-*-* } 80 } } diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/comparison/compare.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/comparison/compare.cc new file mode 100644 index 00000000000..e293b27904e --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/comparison/compare.cc @@ -0,0 +1,88 @@ +// 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 +// . + +// { dg-do run { target c++11 } } + +#include +#include + +void +test01() +{ + std::unique_ptr p0, p00; + VERIFY( p0 == p00 ); + VERIFY( !(p0 < p00) ); + VERIFY( !(p0 > p00) ); + VERIFY( p0 <= p00 ); + VERIFY( p0 >= p00 ); + + std::unique_ptr p1(new int(1)); + VERIFY( p1 == p1 ); + VERIFY( !(p1 < p1) ); + VERIFY( !(p1 > p1) ); + VERIFY( p1 <= p1 ); + VERIFY( p1 >= p1 ); + + std::unique_ptr p2(new int(1)); + VERIFY( p1 >= p1 ); + VERIFY( p1 != p2 ); + VERIFY( (p1 < p2) || (p1 > p2) ); + VERIFY( (p1 <= p2) || (p1 >= p2) ); + + VERIFY( p1 != p0 ); + VERIFY( !(p1 < p0) ); + VERIFY( p1 > p0 ); + VERIFY( !(p1 <= p0) ); + VERIFY( p1 >= p0 ); +} + +void +test02() +{ + std::unique_ptr p0; + VERIFY( p0 == nullptr ); + VERIFY( !(p0 < nullptr) ); + VERIFY( !(p0 > nullptr) ); + VERIFY( p0 <= nullptr ); + VERIFY( p0 >= nullptr ); + + VERIFY( nullptr == p0 ); + VERIFY( !(nullptr < p0) ); + VERIFY( !(nullptr > p0) ); + VERIFY( nullptr <= p0 ); + VERIFY( nullptr >= p0 ); + + std::unique_ptr p1(new int(1)); + VERIFY( p1 != nullptr ); + VERIFY( !(p1 < nullptr) ); + VERIFY( p1 > nullptr ); + VERIFY( !(p1 <= nullptr) ); + VERIFY( p1 >= nullptr ); + + VERIFY( nullptr != p1 ); + VERIFY( nullptr < p1 ); + VERIFY( !(nullptr > p1) ); + VERIFY( nullptr <= p1 ); + VERIFY( !(nullptr >= p1) ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/comparison/compare_c++20.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/comparison/compare_c++20.cc new file mode 100644 index 00000000000..be9819f8de1 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/comparison/compare_c++20.cc @@ -0,0 +1,98 @@ +// 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 +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +void +test01() +{ + std::unique_ptr p0, p00; + VERIFY( p0 == p00 ); + VERIFY( !(p0 < p00) ); + VERIFY( !(p0 > p00) ); + VERIFY( p0 <= p00 ); + VERIFY( p0 >= p00 ); + VERIFY( std::is_eq(p0 <=> p00) ); + + std::unique_ptr 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::unique_ptr 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::unique_ptr 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::unique_ptr 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(); +} -- 2.30.2