From fcc71b513bfa4d2d18d37b144651683b99356019 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Wed, 17 Jul 2024 17:38:41 +0200 Subject: [PATCH 1/6] [libc++][spaceship] Implements X::iterator container requirements. This implements the requirements for the container iterator requirements for array, deque, vector, and vector. Implements: - LWG3352 strong_equality isn't a thing Implements parts of: - P1614R2 The Mothership has Landed Fixes: https://github.com/llvm/llvm-project/issues/62486 --- libcxx/docs/Status/Cxx20Issues.csv | 2 +- libcxx/docs/Status/SpaceshipProjects.csv | 2 +- libcxx/include/__bit_reference | 14 ++++++++++++++ libcxx/include/__iterator/wrap_iter.h | 19 +++++++++++++++++++ libcxx/include/deque | 15 +++++++++++++-- .../sequences/array/iterators.pass.cpp | 18 ++++++++++++++++++ .../sequences/deque/iterators.pass.cpp | 9 +++++++++ .../sequences/vector.bool/iterators.pass.cpp | 9 +++++++++ .../sequences/vector/iterators.pass.cpp | 10 +++++++++- 9 files changed, 93 insertions(+), 5 deletions(-) diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv index 1a40a4472a405..8a431c922a2d9 100644 --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -264,7 +264,7 @@ "`3349 `__","Missing ``__cpp_lib_constexpr_complex``\ for P0415R1","Prague","|Complete|","16.0" "`3350 `__","Simplify return type of ``lexicographical_compare_three_way``\ ","Prague","|Complete|","17.0","|spaceship|" "`3351 `__","``ranges::enable_safe_range``\ should not be constrained","Prague","|Complete|","15.0","|ranges|" -"`3352 `__","``strong_equality``\ isn't a thing","Prague","|Nothing To Do|","","|spaceship|" +"`3352 `__","``strong_equality``\ isn't a thing","Prague","|Complete|","19.0","|spaceship|" "`3354 `__","``has_strong_structural_equality``\ has a meaningless definition","Prague","|Nothing To Do|","","|spaceship|" "`3355 `__","The memory algorithms should support move-only input iterators introduced by P1207","Prague","|Complete|","15.0","|ranges|" "`3356 `__","``__cpp_lib_nothrow_convertible``\ should be ``__cpp_lib_is_nothrow_convertible``\ ","Prague","|Complete|","12.0" diff --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv index e1cf2044cfd78..4dc43cdbbd08f 100644 --- a/libcxx/docs/Status/SpaceshipProjects.csv +++ b/libcxx/docs/Status/SpaceshipProjects.csv @@ -83,7 +83,7 @@ Section,Description,Dependencies,Assignee,Complete "| `[string.view.synop] `_ | `[string.view.comparison] `_",| `basic_string_view `_,None,Mark de Wever,|Complete| - `5.7 Clause 22: Containers library `_,,,, -| `[container.requirements.general] `_,|,None,Unassigned,|Not Started| +| `[container.requirements.general] `_,|,None,Mark de Wever,|Complete| | `[array.syn] `_ (`general `_),| `array `_,[expos.only.func],"| Adrian Vogelsgesang | Hristo Hristov",|Complete| | `[deque.syn] `_ (`general `_),| `deque `_,[expos.only.func],Hristo Hristov,|Complete| diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index 606069d98be72..22637d4397412 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -16,6 +16,7 @@ #include <__bit/countr.h> #include <__bit/invert_if.h> #include <__bit/popcount.h> +#include <__compare/ordering.h> #include <__config> #include <__fwd/bit_reference.h> #include <__iterator/iterator_traits.h> @@ -913,6 +914,7 @@ public: return __x.__seg_ == __y.__seg_ && __x.__ctz_ == __y.__ctz_; } +#if _LIBCPP_STD_VER <= 17 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool operator!=(const __bit_iterator& __x, const __bit_iterator& __y) { return !(__x == __y); @@ -937,6 +939,18 @@ public: operator>=(const __bit_iterator& __x, const __bit_iterator& __y) { return !(__x < __y); } +#else // _LIBCPP_STD_VER <= 17 + _LIBCPP_HIDE_FROM_ABI constexpr friend strong_ordering + operator<=>(const __bit_iterator& __x, const __bit_iterator& __y) { + if (__x.__seg_ < __y.__seg_) + return strong_ordering::less; + + if (__x.__seg_ == __y.__seg_) + return __x.__ctz_ <=> __y.__ctz_; + + return strong_ordering::greater; + } +#endif // _LIBCPP_STD_VER <= 17 private: _LIBCPP_HIDE_FROM_ABI diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h index 252d13b26c9e2..a181cbd7c726e 100644 --- a/libcxx/include/__iterator/wrap_iter.h +++ b/libcxx/include/__iterator/wrap_iter.h @@ -10,6 +10,7 @@ #ifndef _LIBCPP___ITERATOR_WRAP_ITER_H #define _LIBCPP___ITERATOR_WRAP_ITER_H +#include <__compare/ordering.h> #include <__config> #include <__iterator/iterator_traits.h> #include <__memory/addressof.h> @@ -119,6 +120,8 @@ operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX return __x.base() == __y.base(); } +#if _LIBCPP_STD_VER <= 17 + template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { @@ -179,6 +182,22 @@ operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX return !(__y < __x); } +#else // _LIBCPP_STD_VER <= 17 + +template +_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering +operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) noexcept { + return __x.base() <=> __y.base(); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering +operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) noexcept { + return __x.base() <=> __y.base(); +} + +#endif // _LIBCPP_STD_VER <= 17 + template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 #ifndef _LIBCPP_CXX03_LANG diff --git a/libcxx/include/deque b/libcxx/include/deque index 4fc994a6e229b..ff4c93dae6147 100644 --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -376,6 +376,7 @@ public: return __x.__ptr_ == __y.__ptr_; } +#if _LIBCPP_STD_VER <= 17 _LIBCPP_HIDE_FROM_ABI friend bool operator!=(const __deque_iterator& __x, const __deque_iterator& __y) { return !(__x == __y); } @@ -395,6 +396,17 @@ public: _LIBCPP_HIDE_FROM_ABI friend bool operator>=(const __deque_iterator& __x, const __deque_iterator& __y) { return !(__x < __y); } +#else // _LIBCPP_STD_VER <= 17 + _LIBCPP_HIDE_FROM_ABI friend strong_ordering operator<=>(const __deque_iterator& __x, const __deque_iterator& __y) { + if (__x.__m_iter_ < __y.__m_iter_) + return strong_ordering::less; + + if (__x.__m_iter_ == __y.__m_iter_) + return __x.__ptr_ <=> __y.__ptr_; + + return strong_ordering::greater; + } +#endif // _LIBCPP_STD_VER <= 17 private: _LIBCPP_HIDE_FROM_ABI explicit __deque_iterator(__map_iterator __m, pointer __p) _NOEXCEPT @@ -2530,8 +2542,7 @@ inline _LIBCPP_HIDE_FROM_ABI bool operator<=(const deque<_Tp, _Allocator>& __x, template _LIBCPP_HIDE_FROM_ABI __synth_three_way_result<_Tp> operator<=>(const deque<_Tp, _Allocator>& __x, const deque<_Tp, _Allocator>& __y) { - return std::lexicographical_compare_three_way( - __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); + return std::lexicographical_compare_three_way(__x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); } #endif // _LIBCPP_STD_VER <= 17 diff --git a/libcxx/test/std/containers/sequences/array/iterators.pass.cpp b/libcxx/test/std/containers/sequences/array/iterators.pass.cpp index 106bc45c70998..9cbe3cb396c9a 100644 --- a/libcxx/test/std/containers/sequences/array/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/iterators.pass.cpp @@ -148,6 +148,15 @@ TEST_CONSTEXPR_CXX17 bool tests() assert(std::rbegin(c) != std::rend(c)); assert(std::cbegin(c) != std::cend(c)); assert(std::crbegin(c) != std::crend(c)); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r1 = ii1 <=> ii2; + assert(r1 == std::strong_ordering::equal); + + std::same_as decltype(auto) r2 = ii1 <=> ii2; + assert(r2 == std::strong_ordering::equal); +# endif } { typedef std::array C; @@ -189,6 +198,15 @@ TEST_CONSTEXPR_CXX17 bool tests() assert(std::rbegin(c) == std::rend(c)); assert(std::cbegin(c) == std::cend(c)); assert(std::crbegin(c) == std::crend(c)); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r1 = ii1 <=> ii2; + assert(r1 == std::strong_ordering::equal); + + std::same_as decltype(auto) r2 = ii1 <=> ii2; + assert(r2 == std::strong_ordering::equal); +# endif } } #endif diff --git a/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp b/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp index 1f06ffde41ac2..a8b5db656b205 100644 --- a/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp @@ -74,6 +74,15 @@ int main(int, char**) // assert ( cii != c.begin()); // assert ( cii != c.cend()); // assert ( ii1 != c.end()); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r1 = ii1 <=> ii2; + assert(r1 == std::strong_ordering::equal); + + std::same_as decltype(auto) r2 = ii1 <=> ii2; + assert(r2 == std::strong_ordering::equal); +# endif // TEST_STD_VER > 20 } #endif diff --git a/libcxx/test/std/containers/sequences/vector.bool/iterators.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/iterators.pass.cpp index 9aaaac7a5557f..2a701cc4ad19f 100644 --- a/libcxx/test/std/containers/sequences/vector.bool/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector.bool/iterators.pass.cpp @@ -131,6 +131,15 @@ TEST_CONSTEXPR_CXX20 bool tests() assert ( (cii >= ii1 )); assert (cii - ii1 == 0); assert (ii1 - cii == 0); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r1 = ii1 <=> ii2; + assert(r1 == std::strong_ordering::equal); + + std::same_as decltype(auto) r2 = ii1 <=> ii2; + assert(r2 == std::strong_ordering::equal); +# endif // TEST_STD_VER > 20 } #endif diff --git a/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp b/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp index 70e0e35767e09..457791b8ee6af 100644 --- a/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp @@ -164,8 +164,16 @@ TEST_CONSTEXPR_CXX20 bool tests() assert ( (cii >= ii1 )); assert (cii - ii1 == 0); assert (ii1 - cii == 0); +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r1 = ii1 <=> ii2; + assert(r1 == std::strong_ordering::equal); + + std::same_as decltype(auto) r2 = ii1 <=> ii2; + assert(r2 == std::strong_ordering::equal); +# endif // TEST_STD_VER > 20 } -#endif +#endif // TEST_STD_VER > 11 return true; } From 2dc8392f7882e3b1e135d18c14fee585ee6f0685 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sat, 20 Jul 2024 12:45:41 +0200 Subject: [PATCH 2/6] bounded_iterator --- libcxx/include/__iterator/bounded_iter.h | 11 +++ .../span.iterators/iterator.pass.cpp | 89 +++++++++++++++++++ .../string.view.iterators/iterators.pass.cpp | 84 +++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp create mode 100644 libcxx/test/std/strings/string.view/string.view.iterators/iterators.pass.cpp diff --git a/libcxx/include/__iterator/bounded_iter.h b/libcxx/include/__iterator/bounded_iter.h index a8f66f4a0126f..b8a72c73b0a32 100644 --- a/libcxx/include/__iterator/bounded_iter.h +++ b/libcxx/include/__iterator/bounded_iter.h @@ -11,6 +11,7 @@ #define _LIBCPP___ITERATOR_BOUNDED_ITER_H #include <__assert> +#include <__compare/ordering.h> #include <__config> #include <__iterator/iterator_traits.h> #include <__memory/pointer_traits.h> @@ -201,6 +202,7 @@ struct __bounded_iter { operator==(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { return __x.__current_ == __y.__current_; } +#if _LIBCPP_STD_VER <= 17 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool operator!=(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { return __x.__current_ != __y.__current_; @@ -222,6 +224,15 @@ struct __bounded_iter { return __x.__current_ >= __y.__current_; } +#else // _LIBCPP_STD_VER <= 17 + + _LIBCPP_HIDE_FROM_ABI constexpr friend strong_ordering + operator<=>(__bounded_iter const& __x, __bounded_iter const& __y) noexcept { + return __x.__current_ <=> __y.__current_; + } + +#endif // _LIBCPP_STD_VER <= 17 + private: template friend struct pointer_traits; diff --git a/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp b/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp new file mode 100644 index 0000000000000..cd834fe5fb4fc --- /dev/null +++ b/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// class iterator + +#include +#include +#include +#include // __cpp_lib_ranges_as_const is not defined in span. + +#include "test_macros.h" + +template +TEST_CONSTEXPR void test_type() { +# + + using C = std::span; + typename C::iterator ii1{}, ii2{}; + typename C::iterator ii4 = ii1; + // TODO Test against C++23 after implementing + // P2278R4 cbegin should always return a constant iterator +#ifdef __cpp_lib_ranges_as_const + typename C::const_iterator cii{}; +#endif + assert(ii1 == ii2); + assert(ii1 == ii4); +#ifdef __cpp_lib_ranges_as_const + assert(ii1 == cii); +#endif + + assert(!(ii1 != ii2)); +#ifdef __cpp_lib_ranges_as_const + assert(!(ii1 != cii)); +#endif + + T v; + C c{&v, 1}; + assert(c.begin() == std::begin(c)); + assert(c.rbegin() == std::rbegin(c)); +#ifdef __cpp_lib_ranges_as_const + assert(c.cbegin() == std::cbegin(c)); + assert(c.crbegin() == std::crbegin(c)); +#endif + + assert(c.end() == std::end(c)); + assert(c.rend() == std::rend(c)); +#ifdef __cpp_lib_ranges_as_const + assert(c.cend() == std::cend(c)); + assert(c.crend() == std::crend(c)); +#endif + + assert(std::begin(c) != std::end(c)); + assert(std::rbegin(c) != std::rend(c)); +#ifdef __cpp_lib_ranges_as_const + assert(std::cbegin(c) != std::cend(c)); + assert(std::crbegin(c) != std::crend(c)); +#endif + + // P1614 + LWG3352 + std::same_as decltype(auto) r1 = ii1 <=> ii2; + assert(r1 == std::strong_ordering::equal); + + std::same_as decltype(auto) r2 = ii1 <=> ii2; + assert(r2 == std::strong_ordering::equal); +} + +TEST_CONSTEXPR bool test() { + test_type(); + test_type(); + test_type(); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test(), ""); + + return 0; +} diff --git a/libcxx/test/std/strings/string.view/string.view.iterators/iterators.pass.cpp b/libcxx/test/std/strings/string.view/string.view.iterators/iterators.pass.cpp new file mode 100644 index 0000000000000..6a2cd046a2b68 --- /dev/null +++ b/libcxx/test/std/strings/string.view/string.view.iterators/iterators.pass.cpp @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: !stdlib=libc++ && (c++03 || c++11 || c++14) + +// + +// class iterator + +#include +#include +#include + +#include "test_macros.h" +#include "make_string.h" + +template +TEST_CONSTEXPR_CXX14 void test_type() { + using C = std::basic_string_view; + typename C::iterator ii1 = typename C::iterator(), ii2 = typename C::iterator(); + typename C::iterator ii4 = ii1; + typename C::const_iterator cii = typename C::const_iterator(); + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(ii1 == cii); + + assert(!(ii1 != ii2)); + assert(!(ii1 != cii)); + +#if TEST_STD_VER >= 11 + C c = MAKE_STRING_VIEW(CharT, "abc"); + assert(c.begin() == std::begin(c)); + assert(c.rbegin() == std::rbegin(c)); + assert(c.cbegin() == std::cbegin(c)); + assert(c.crbegin() == std::crbegin(c)); + + assert(c.end() == std::end(c)); + assert(c.rend() == std::rend(c)); + assert(c.cend() == std::cend(c)); + assert(c.crend() == std::crend(c)); + + assert(std::begin(c) != std::end(c)); + assert(std::rbegin(c) != std::rend(c)); + assert(std::cbegin(c) != std::cend(c)); + assert(std::crbegin(c) != std::crend(c)); +#endif + +#if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r1 = ii1 <=> ii2; + assert(r1 == std::strong_ordering::equal); + + std::same_as decltype(auto) r2 = ii1 <=> ii2; + assert(r2 == std::strong_ordering::equal); +#endif +} + +TEST_CONSTEXPR_CXX14 bool test() { + test_type(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test_type(); +#endif +#ifndef TEST_HAS_NO_CHAR8_T + test_type(); +#endif + test_type(); + test_type(); + + return true; +} + +int main(int, char**) { + test(); +#if TEST_STD_VER >= 14 + static_assert(test(), ""); +#endif + + return 0; +} From cd9e497a3ad2e0693dd4800258ec42f3927cf58f Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sat, 20 Jul 2024 13:55:32 +0200 Subject: [PATCH 3/6] CI fixes. --- libcxx/include/__iterator/bounded_iter.h | 16 +++++++++++----- .../iterators/bounded_iter/comparison.pass.cpp | 18 ++++++++++++++++-- .../span.iterators/iterator.pass.cpp | 4 +++- .../string.view.iterators/iterators.pass.cpp | 5 +++-- libcxx/test/support/test_iterators.h | 2 ++ 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/libcxx/include/__iterator/bounded_iter.h b/libcxx/include/__iterator/bounded_iter.h index b8a72c73b0a32..10825043bf3bb 100644 --- a/libcxx/include/__iterator/bounded_iter.h +++ b/libcxx/include/__iterator/bounded_iter.h @@ -12,6 +12,7 @@ #include <__assert> #include <__compare/ordering.h> +#include <__concepts/same_as.h> #include <__config> #include <__iterator/iterator_traits.h> #include <__memory/pointer_traits.h> @@ -202,7 +203,7 @@ struct __bounded_iter { operator==(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { return __x.__current_ == __y.__current_; } -#if _LIBCPP_STD_VER <= 17 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool operator!=(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { return __x.__current_ != __y.__current_; @@ -224,14 +225,19 @@ struct __bounded_iter { return __x.__current_ >= __y.__current_; } -#else // _LIBCPP_STD_VER <= 17 - +#if _LIBCPP_STD_VER >= 20 + // It is not required that the underlying iterator supports operator<=>. + // Therefore this operator is only conditionally provided, which requires a + // templated function. + template + requires requires(_Iterator const& __i) { + { __i <=> __i } -> same_as; + } _LIBCPP_HIDE_FROM_ABI constexpr friend strong_ordering operator<=>(__bounded_iter const& __x, __bounded_iter const& __y) noexcept { return __x.__current_ <=> __y.__current_; } - -#endif // _LIBCPP_STD_VER <= 17 +#endif // _LIBCPP_STD_VER >= 20 private: template diff --git a/libcxx/test/libcxx/iterators/bounded_iter/comparison.pass.cpp b/libcxx/test/libcxx/iterators/bounded_iter/comparison.pass.cpp index 9c5df5da55b9c..071a67fce9332 100644 --- a/libcxx/test/libcxx/iterators/bounded_iter/comparison.pass.cpp +++ b/libcxx/test/libcxx/iterators/bounded_iter/comparison.pass.cpp @@ -11,6 +11,7 @@ // // Comparison operators +#include #include <__iterator/bounded_iter.h> #include "test_iterators.h" @@ -59,6 +60,16 @@ TEST_CONSTEXPR_CXX14 bool tests() { assert(iter1 >= iter1); } +#if TEST_STD_VER >= 20 + if constexpr (requires(std::__bounded_iter const iter) { + { iter <=> iter } -> std::same_as; + }) { + // P1614 + std::same_as decltype(auto) r1 = iter1 <=> iter2; + assert(r1 == std::strong_ordering::less); + } +#endif + return true; } @@ -69,8 +80,11 @@ int main(int, char**) { #endif #if TEST_STD_VER > 17 - tests >(); - static_assert(tests >(), ""); + tests>(); + static_assert(tests>()); + + tests>(); + static_assert(tests>()); #endif return 0; diff --git a/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp b/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp index cd834fe5fb4fc..3d37267d61d63 100644 --- a/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp @@ -12,8 +12,10 @@ // class iterator -#include #include +#include +#include +#include #include #include // __cpp_lib_ranges_as_const is not defined in span. diff --git a/libcxx/test/std/strings/string.view/string.view.iterators/iterators.pass.cpp b/libcxx/test/std/strings/string.view/string.view.iterators/iterators.pass.cpp index 6a2cd046a2b68..75d492bf7b3c6 100644 --- a/libcxx/test/std/strings/string.view/string.view.iterators/iterators.pass.cpp +++ b/libcxx/test/std/strings/string.view/string.view.iterators/iterators.pass.cpp @@ -12,9 +12,10 @@ // class iterator -#include #include +#include #include +#include #include "test_macros.h" #include "make_string.h" @@ -32,7 +33,7 @@ TEST_CONSTEXPR_CXX14 void test_type() { assert(!(ii1 != ii2)); assert(!(ii1 != cii)); -#if TEST_STD_VER >= 11 +#if TEST_STD_VER >= 17 C c = MAKE_STRING_VIEW(CharT, "abc"); assert(c.begin() == std::begin(c)); assert(c.rbegin() == std::rbegin(c)); diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index 31564a3977317..95d1b7df0007c 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -389,6 +389,8 @@ class contiguous_iterator friend TEST_CONSTEXPR bool operator> (const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ > y.it_;} friend TEST_CONSTEXPR bool operator>=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ >= y.it_;} + // Note no operator<=>, use three_way_contiguous_iterator for testing operator<=> + friend TEST_CONSTEXPR It base(const contiguous_iterator& i) { return i.it_; } template From 0739782f26319457bf389425df918a27db08398f Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sat, 20 Jul 2024 20:09:59 +0200 Subject: [PATCH 4/6] CI fixes and improvements Note the code is not yet conforming. --- libcxx/include/__iterator/bounded_iter.h | 13 +++---- libcxx/include/__iterator/wrap_iter.h | 15 ++++---- libcxx/include/deque | 11 +++--- .../sequences/array/iterators.pass.cpp | 4 +-- .../sequences/deque/iterators.pass.cpp | 18 +++++++++- .../sequences/vector.bool/iterators.pass.cpp | 30 +++++++++++++++- .../sequences/vector/iterators.pass.cpp | 34 ++++++++++++++++++- .../span.iterators/iterator.pass.cpp | 4 ++- 8 files changed, 104 insertions(+), 25 deletions(-) diff --git a/libcxx/include/__iterator/bounded_iter.h b/libcxx/include/__iterator/bounded_iter.h index 10825043bf3bb..805730f5b5042 100644 --- a/libcxx/include/__iterator/bounded_iter.h +++ b/libcxx/include/__iterator/bounded_iter.h @@ -12,7 +12,7 @@ #include <__assert> #include <__compare/ordering.h> -#include <__concepts/same_as.h> +#include <__compare/three_way_comparable.h> #include <__config> #include <__iterator/iterator_traits.h> #include <__memory/pointer_traits.h> @@ -226,15 +226,10 @@ struct __bounded_iter { } #if _LIBCPP_STD_VER >= 20 - // It is not required that the underlying iterator supports operator<=>. - // Therefore this operator is only conditionally provided, which requires a - // templated function. - template - requires requires(_Iterator const& __i) { - { __i <=> __i } -> same_as; - } _LIBCPP_HIDE_FROM_ABI constexpr friend strong_ordering - operator<=>(__bounded_iter const& __x, __bounded_iter const& __y) noexcept { + operator<=>(__bounded_iter const& __x, __bounded_iter const& __y) noexcept + requires three_way_comparable<_Iterator, strong_ordering> + { return __x.__current_ <=> __y.__current_; } #endif // _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h index a181cbd7c726e..8462b0c823700 100644 --- a/libcxx/include/__iterator/wrap_iter.h +++ b/libcxx/include/__iterator/wrap_iter.h @@ -11,6 +11,7 @@ #define _LIBCPP___ITERATOR_WRAP_ITER_H #include <__compare/ordering.h> +#include <__compare/three_way_comparable.h> #include <__config> #include <__iterator/iterator_traits.h> #include <__memory/addressof.h> @@ -120,8 +121,6 @@ operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX return __x.base() == __y.base(); } -#if _LIBCPP_STD_VER <= 17 - template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { @@ -182,21 +181,25 @@ operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX return !(__y < __x); } -#else // _LIBCPP_STD_VER <= 17 +#if _LIBCPP_STD_VER >= 20 template _LIBCPP_HIDE_FROM_ABI constexpr strong_ordering -operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) noexcept { +operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) noexcept + requires three_way_comparable<_Iter1, strong_ordering> +{ return __x.base() <=> __y.base(); } template _LIBCPP_HIDE_FROM_ABI constexpr strong_ordering -operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) noexcept { +operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) noexcept + requires three_way_comparable_with<_Iter1, _Iter2, strong_ordering> +{ return __x.base() <=> __y.base(); } -#endif // _LIBCPP_STD_VER <= 17 +#endif // _LIBCPP_STD_VER >= 20 template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 diff --git a/libcxx/include/deque b/libcxx/include/deque index ff4c93dae6147..782a9db79c7ae 100644 --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -376,7 +376,6 @@ public: return __x.__ptr_ == __y.__ptr_; } -#if _LIBCPP_STD_VER <= 17 _LIBCPP_HIDE_FROM_ABI friend bool operator!=(const __deque_iterator& __x, const __deque_iterator& __y) { return !(__x == __y); } @@ -396,8 +395,12 @@ public: _LIBCPP_HIDE_FROM_ABI friend bool operator>=(const __deque_iterator& __x, const __deque_iterator& __y) { return !(__x < __y); } -#else // _LIBCPP_STD_VER <= 17 - _LIBCPP_HIDE_FROM_ABI friend strong_ordering operator<=>(const __deque_iterator& __x, const __deque_iterator& __y) { + +#if _LIBCPP_STD_VER >= 20 + // template + _LIBCPP_HIDE_FROM_ABI friend strong_ordering operator<=>(const __deque_iterator& __x, const __deque_iterator& __y) + requires three_way_comparable + { if (__x.__m_iter_ < __y.__m_iter_) return strong_ordering::less; @@ -406,7 +409,7 @@ public: return strong_ordering::greater; } -#endif // _LIBCPP_STD_VER <= 17 +#endif // _LIBCPP_STD_VER >= 20 private: _LIBCPP_HIDE_FROM_ABI explicit __deque_iterator(__map_iterator __m, pointer __p) _NOEXCEPT diff --git a/libcxx/test/std/containers/sequences/array/iterators.pass.cpp b/libcxx/test/std/containers/sequences/array/iterators.pass.cpp index 9cbe3cb396c9a..710994c68295e 100644 --- a/libcxx/test/std/containers/sequences/array/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/iterators.pass.cpp @@ -154,7 +154,7 @@ TEST_CONSTEXPR_CXX17 bool tests() std::same_as decltype(auto) r1 = ii1 <=> ii2; assert(r1 == std::strong_ordering::equal); - std::same_as decltype(auto) r2 = ii1 <=> ii2; + std::same_as decltype(auto) r2 = cii <=> ii2; assert(r2 == std::strong_ordering::equal); # endif } @@ -204,7 +204,7 @@ TEST_CONSTEXPR_CXX17 bool tests() std::same_as decltype(auto) r1 = ii1 <=> ii2; assert(r1 == std::strong_ordering::equal); - std::same_as decltype(auto) r2 = ii1 <=> ii2; + std::same_as decltype(auto) r2 = cii <=> ii2; assert(r2 == std::strong_ordering::equal); # endif } diff --git a/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp b/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp index a8b5db656b205..396fd56dc6413 100644 --- a/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp @@ -41,7 +41,23 @@ int main(int, char**) i = c.begin(); C::const_iterator j; j = c.cbegin(); + assert(i == j); + assert(!(i != j)); + + assert(!(i < j)); + assert((i <= j)); + + assert(!(i > j)); + assert((i >= j)); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + // When the allocator does not have operator<=> then neither does the iterator. + // Make sure to test with an allocator that does not have operator<=>. + static_assert(!std::three_way_comparable, std::strong_ordering>); + static_assert(!std::three_way_comparable); +# endif } #endif #if TEST_STD_VER > 11 @@ -80,7 +96,7 @@ int main(int, char**) std::same_as decltype(auto) r1 = ii1 <=> ii2; assert(r1 == std::strong_ordering::equal); - std::same_as decltype(auto) r2 = ii1 <=> ii2; + std::same_as decltype(auto) r2 = cii <=> ii2; assert(r2 == std::strong_ordering::equal); # endif // TEST_STD_VER > 20 } diff --git a/libcxx/test/std/containers/sequences/vector.bool/iterators.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/iterators.pass.cpp index 2a701cc4ad19f..1e4877e8d2443 100644 --- a/libcxx/test/std/containers/sequences/vector.bool/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector.bool/iterators.pass.cpp @@ -77,7 +77,21 @@ TEST_CONSTEXPR_CXX20 bool tests() C::iterator i = c.begin(); C::iterator j = c.end(); assert(std::distance(i, j) == 0); + assert(i == j); + assert(!(i != j)); + + assert(!(i < j)); + assert((i <= j)); + + assert(!(i > j)); + assert((i >= j)); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r = i <=> j; + assert(r == std::strong_ordering::equal); +# endif } { typedef bool T; @@ -86,7 +100,21 @@ TEST_CONSTEXPR_CXX20 bool tests() C::const_iterator i = c.begin(); C::const_iterator j = c.end(); assert(std::distance(i, j) == 0); + assert(i == j); + assert(!(i != j)); + + assert(!(i < j)); + assert((i <= j)); + + assert(!(i > j)); + assert((i >= j)); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r = i <=> j; + assert(r == std::strong_ordering::equal); +# endif } { typedef bool T; @@ -137,7 +165,7 @@ TEST_CONSTEXPR_CXX20 bool tests() std::same_as decltype(auto) r1 = ii1 <=> ii2; assert(r1 == std::strong_ordering::equal); - std::same_as decltype(auto) r2 = ii1 <=> ii2; + std::same_as decltype(auto) r2 = cii <=> ii2; assert(r2 == std::strong_ordering::equal); # endif // TEST_STD_VER > 20 } diff --git a/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp b/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp index 457791b8ee6af..1d750cb1110f9 100644 --- a/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp @@ -87,7 +87,23 @@ TEST_CONSTEXPR_CXX20 bool tests() C::iterator i = c.begin(); C::iterator j = c.end(); assert(std::distance(i, j) == 0); + assert(i == j); + assert(!(i != j)); + + assert(!(i < j)); + assert((i <= j)); + + assert(!(i > j)); + assert((i >= j)); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + // When the allocator does not have operator<=> then neither does the iterator. + // Make sure to test with an allocator that does not have operator<=>. + static_assert(!std::three_way_comparable, std::strong_ordering>); + static_assert(!std::three_way_comparable); +# endif } { typedef int T; @@ -96,7 +112,23 @@ TEST_CONSTEXPR_CXX20 bool tests() C::const_iterator i = c.begin(); C::const_iterator j = c.end(); assert(std::distance(i, j) == 0); + assert(i == j); + assert(!(i != j)); + + assert(!(i < j)); + assert((i <= j)); + + assert(!(i > j)); + assert((i >= j)); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + // When the allocator does not have operator<=> then neither does the iterator. + // Make sure to test with an allocator that does not have operator<=>. + static_assert(!std::three_way_comparable, std::strong_ordering>); + static_assert(!std::three_way_comparable); +# endif } { typedef int T; @@ -169,7 +201,7 @@ TEST_CONSTEXPR_CXX20 bool tests() std::same_as decltype(auto) r1 = ii1 <=> ii2; assert(r1 == std::strong_ordering::equal); - std::same_as decltype(auto) r2 = ii1 <=> ii2; + std::same_as decltype(auto) r2 = cii <=> ii2; assert(r2 == std::strong_ordering::equal); # endif // TEST_STD_VER > 20 } diff --git a/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp b/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp index 3d37267d61d63..b097e4dc994a7 100644 --- a/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp @@ -71,8 +71,10 @@ TEST_CONSTEXPR void test_type() { std::same_as decltype(auto) r1 = ii1 <=> ii2; assert(r1 == std::strong_ordering::equal); - std::same_as decltype(auto) r2 = ii1 <=> ii2; +#ifdef __cpp_lib_ranges_as_const + std::same_as decltype(auto) r2 = cii <=> ii2; assert(r2 == std::strong_ordering::equal); +#endif } TEST_CONSTEXPR bool test() { From ecd6887bec874200a5c4167b464630d192d012ed Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sun, 21 Jul 2024 17:36:49 +0200 Subject: [PATCH 5/6] Polish the patch. --- libcxx/include/__iterator/bounded_iter.h | 19 ++++++++--- libcxx/include/__iterator/wrap_iter.h | 34 ++++++++++++++----- libcxx/include/deque | 21 +++++++++--- .../sequences/deque/iterators.pass.cpp | 8 +++-- .../sequences/vector/iterators.pass.cpp | 17 +++++++--- 5 files changed, 75 insertions(+), 24 deletions(-) diff --git a/libcxx/include/__iterator/bounded_iter.h b/libcxx/include/__iterator/bounded_iter.h index 805730f5b5042..78a4e46cd4281 100644 --- a/libcxx/include/__iterator/bounded_iter.h +++ b/libcxx/include/__iterator/bounded_iter.h @@ -204,10 +204,13 @@ struct __bounded_iter { return __x.__current_ == __y.__current_; } +#if _LIBCPP_STD_VER <= 17 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool operator!=(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { return __x.__current_ != __y.__current_; } +#endif + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool operator<(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { return __x.__current_ < __y.__current_; @@ -227,10 +230,18 @@ struct __bounded_iter { #if _LIBCPP_STD_VER >= 20 _LIBCPP_HIDE_FROM_ABI constexpr friend strong_ordering - operator<=>(__bounded_iter const& __x, __bounded_iter const& __y) noexcept - requires three_way_comparable<_Iterator, strong_ordering> - { - return __x.__current_ <=> __y.__current_; + operator<=>(__bounded_iter const& __x, __bounded_iter const& __y) noexcept { + if constexpr (three_way_comparable<_Iterator, strong_ordering>) { + return __x.__current_ <=> __y.__current_; + } else { + if (__x.__current_ < __y.__current_) + return strong_ordering::less; + + if (__x.__current_ == __y.__current_) + return strong_ordering::equal; + + return strong_ordering::greater; + } } #endif // _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h index 8462b0c823700..2598ed4544345 100644 --- a/libcxx/include/__iterator/wrap_iter.h +++ b/libcxx/include/__iterator/wrap_iter.h @@ -133,6 +133,7 @@ operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXC return __x.base() < __y.base(); } +#if _LIBCPP_STD_VER <= 17 template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { @@ -144,6 +145,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { return !(__x == __y); } +#endif template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool @@ -185,18 +187,34 @@ operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX template _LIBCPP_HIDE_FROM_ABI constexpr strong_ordering -operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) noexcept - requires three_way_comparable<_Iter1, strong_ordering> -{ - return __x.base() <=> __y.base(); +operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) noexcept { + if constexpr (three_way_comparable<_Iter1, strong_ordering>) { + return __x.base() <=> __y.base(); + } else { + if (__x.base() < __y.base()) + return strong_ordering::less; + + if (__x.base() == __y.base()) + return strong_ordering::equal; + + return strong_ordering::greater; + } } template _LIBCPP_HIDE_FROM_ABI constexpr strong_ordering -operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) noexcept - requires three_way_comparable_with<_Iter1, _Iter2, strong_ordering> -{ - return __x.base() <=> __y.base(); +operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) noexcept { + if constexpr (three_way_comparable_with<_Iter1, _Iter2, strong_ordering>) { + return __x.base() <=> __y.base(); + } else { + if (__x.base() < __y.base()) + return strong_ordering::less; + + if (__x.base() == __y.base()) + return strong_ordering::equal; + + return strong_ordering::greater; + } } #endif // _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/deque b/libcxx/include/deque index 782a9db79c7ae..a5b3ee298fb51 100644 --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -376,9 +376,11 @@ public: return __x.__ptr_ == __y.__ptr_; } +#if _LIBCPP_STD_VER <= 17 _LIBCPP_HIDE_FROM_ABI friend bool operator!=(const __deque_iterator& __x, const __deque_iterator& __y) { return !(__x == __y); } +#endif _LIBCPP_HIDE_FROM_ABI friend bool operator<(const __deque_iterator& __x, const __deque_iterator& __y) { return __x.__m_iter_ < __y.__m_iter_ || (__x.__m_iter_ == __y.__m_iter_ && __x.__ptr_ < __y.__ptr_); @@ -398,14 +400,23 @@ public: #if _LIBCPP_STD_VER >= 20 // template - _LIBCPP_HIDE_FROM_ABI friend strong_ordering operator<=>(const __deque_iterator& __x, const __deque_iterator& __y) - requires three_way_comparable - { + _LIBCPP_HIDE_FROM_ABI friend strong_ordering operator<=>(const __deque_iterator& __x, const __deque_iterator& __y) { if (__x.__m_iter_ < __y.__m_iter_) return strong_ordering::less; - if (__x.__m_iter_ == __y.__m_iter_) - return __x.__ptr_ <=> __y.__ptr_; + if (__x.__m_iter_ == __y.__m_iter_) { + if constexpr (three_way_comparable) { + return __x.__ptr_ <=> __y.__ptr_; + } else { + if (__x.__ptr_ < __y.__ptr_) + return strong_ordering::less; + + if (__x.__ptr_ == __y.__ptr_) + return strong_ordering::equal; + + return strong_ordering::greater; + } + } return strong_ordering::greater; } diff --git a/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp b/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp index 396fd56dc6413..484a2961fdb0c 100644 --- a/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp @@ -53,10 +53,14 @@ int main(int, char**) # if TEST_STD_VER >= 20 // P1614 + LWG3352 - // When the allocator does not have operator<=> then neither does the iterator. + // When the allocator does not have operator<=> then the iterator uses a + // fallback to provide operator<=>. // Make sure to test with an allocator that does not have operator<=>. static_assert(!std::three_way_comparable, std::strong_ordering>); - static_assert(!std::three_way_comparable); + static_assert(std::three_way_comparable); + + std::same_as decltype(auto) r1 = i <=> j; + assert(r1 == std::strong_ordering::equal); # endif } #endif diff --git a/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp b/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp index 1d750cb1110f9..0aa7ad0d42ed7 100644 --- a/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp @@ -99,10 +99,14 @@ TEST_CONSTEXPR_CXX20 bool tests() # if TEST_STD_VER >= 20 // P1614 + LWG3352 - // When the allocator does not have operator<=> then neither does the iterator. + // When the allocator does not have operator<=> then the iterator uses a + // fallback to provide operator<=>. // Make sure to test with an allocator that does not have operator<=>. static_assert(!std::three_way_comparable, std::strong_ordering>); - static_assert(!std::three_way_comparable); + static_assert(std::three_way_comparable); + + std::same_as decltype(auto) r1 = i <=> j; + assert(r1 == std::strong_ordering::equal); # endif } { @@ -123,11 +127,14 @@ TEST_CONSTEXPR_CXX20 bool tests() assert((i >= j)); # if TEST_STD_VER >= 20 - // P1614 + LWG3352 - // When the allocator does not have operator<=> then neither does the iterator. + // When the allocator does not have operator<=> then the iterator uses a + // fallback to provide operator<=>. // Make sure to test with an allocator that does not have operator<=>. static_assert(!std::three_way_comparable, std::strong_ordering>); - static_assert(!std::three_way_comparable); + static_assert(std::three_way_comparable); + + std::same_as decltype(auto) r1 = i <=> j; + assert(r1 == std::strong_ordering::equal); # endif } { From e94dc78e3bf19cc6504ed1238038c4c3d02dc781 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Tue, 23 Jul 2024 18:56:36 +0200 Subject: [PATCH 6/6] Addresses review comments. --- libcxx/include/__iterator/bounded_iter.h | 1 + libcxx/include/__iterator/wrap_iter.h | 19 +------------------ libcxx/include/deque | 2 +- .../bounded_iter/comparison.pass.cpp | 10 +++------- .../span.iterators/iterator.pass.cpp | 9 ++++----- 5 files changed, 10 insertions(+), 31 deletions(-) diff --git a/libcxx/include/__iterator/bounded_iter.h b/libcxx/include/__iterator/bounded_iter.h index 78a4e46cd4281..76647dcaaf02c 100644 --- a/libcxx/include/__iterator/bounded_iter.h +++ b/libcxx/include/__iterator/bounded_iter.h @@ -211,6 +211,7 @@ struct __bounded_iter { } #endif + // TODO(mordante) disable these overloads in the LLVM 20 release. _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool operator<(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { return __x.__current_ < __y.__current_; diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h index 2598ed4544345..56183c0ee794d 100644 --- a/libcxx/include/__iterator/wrap_iter.h +++ b/libcxx/include/__iterator/wrap_iter.h @@ -147,6 +147,7 @@ operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX } #endif +// TODO(mordante) disable these overloads in the LLVM 20 release. template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { @@ -184,23 +185,6 @@ operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX } #if _LIBCPP_STD_VER >= 20 - -template -_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering -operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) noexcept { - if constexpr (three_way_comparable<_Iter1, strong_ordering>) { - return __x.base() <=> __y.base(); - } else { - if (__x.base() < __y.base()) - return strong_ordering::less; - - if (__x.base() == __y.base()) - return strong_ordering::equal; - - return strong_ordering::greater; - } -} - template _LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) noexcept { @@ -216,7 +200,6 @@ operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) noex return strong_ordering::greater; } } - #endif // _LIBCPP_STD_VER >= 20 template diff --git a/libcxx/include/deque b/libcxx/include/deque index a5b3ee298fb51..e73135a8647b9 100644 --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -382,6 +382,7 @@ public: } #endif + // TODO(mordante) disable these overloads in the LLVM 20 release. _LIBCPP_HIDE_FROM_ABI friend bool operator<(const __deque_iterator& __x, const __deque_iterator& __y) { return __x.__m_iter_ < __y.__m_iter_ || (__x.__m_iter_ == __y.__m_iter_ && __x.__ptr_ < __y.__ptr_); } @@ -399,7 +400,6 @@ public: } #if _LIBCPP_STD_VER >= 20 - // template _LIBCPP_HIDE_FROM_ABI friend strong_ordering operator<=>(const __deque_iterator& __x, const __deque_iterator& __y) { if (__x.__m_iter_ < __y.__m_iter_) return strong_ordering::less; diff --git a/libcxx/test/libcxx/iterators/bounded_iter/comparison.pass.cpp b/libcxx/test/libcxx/iterators/bounded_iter/comparison.pass.cpp index 071a67fce9332..cef2157469c8f 100644 --- a/libcxx/test/libcxx/iterators/bounded_iter/comparison.pass.cpp +++ b/libcxx/test/libcxx/iterators/bounded_iter/comparison.pass.cpp @@ -61,13 +61,9 @@ TEST_CONSTEXPR_CXX14 bool tests() { } #if TEST_STD_VER >= 20 - if constexpr (requires(std::__bounded_iter const iter) { - { iter <=> iter } -> std::same_as; - }) { - // P1614 - std::same_as decltype(auto) r1 = iter1 <=> iter2; - assert(r1 == std::strong_ordering::less); - } + // P1614 + std::same_as decltype(auto) r1 = iter1 <=> iter2; + assert(r1 == std::strong_ordering::less); #endif return true; diff --git a/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp b/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp index b097e4dc994a7..13a7628e6043d 100644 --- a/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp @@ -22,14 +22,13 @@ #include "test_macros.h" template -TEST_CONSTEXPR void test_type() { -# - +constexpr void test_type() { using C = std::span; typename C::iterator ii1{}, ii2{}; typename C::iterator ii4 = ii1; // TODO Test against C++23 after implementing - // P2278R4 cbegin should always return a constant iterator + // P2278R4 cbegin should always return a constant iterator + // The means adjusting the #ifdef to guard against C++23. #ifdef __cpp_lib_ranges_as_const typename C::const_iterator cii{}; #endif @@ -77,7 +76,7 @@ TEST_CONSTEXPR void test_type() { #endif } -TEST_CONSTEXPR bool test() { +constexpr bool test() { test_type(); test_type(); test_type();