[libcxx-commits] [libcxx] b06049b - [libc++][NFC] Add more tests to `move_{iterator, sentinel}`.

via libcxx-commits libcxx-commits at lists.llvm.org
Tue May 24 19:56:42 PDT 2022


Author: Konstantin Varlamov
Date: 2022-05-24T19:56:12-07:00
New Revision: b06049bc3b79be4a037a60dec4ad19a68e196a8f

URL: https://github.com/llvm/llvm-project/commit/b06049bc3b79be4a037a60dec4ad19a68e196a8f
DIFF: https://github.com/llvm/llvm-project/commit/b06049bc3b79be4a037a60dec4ad19a68e196a8f.diff

LOG: [libc++][NFC] Add more tests to `move_{iterator,sentinel}`.

More test coverage for the parts added by the One Ranges Proposal.

Differential Revision: https://reviews.llvm.org/D124906

Added: 
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_move.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_swap.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.-/sentinel.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/base.pass.cpp

Modified: 
    libcxx/include/__iterator/move_iterator.h
    libcxx/include/__iterator/move_sentinel.h
    libcxx/include/iterator
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.incr/post.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.index/difference_type.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.star/op_star.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/types.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/assign.converting.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/base.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/concept_conformance.compile.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.converting.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.default.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.sentinel.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/op_eq.pass.cpp
    libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_move.pass.cpp
    libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_swap.pass.cpp
    libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.compile.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_move.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_swap.pass.cpp
    libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp
    libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp
    libcxx/test/support/test_iterators.h

Removed: 
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/tested_elsewhere.pass.cpp


################################################################################
diff  --git a/libcxx/include/__iterator/move_iterator.h b/libcxx/include/__iterator/move_iterator.h
index 5beb8319d172..e0c7e73a9cc3 100644
--- a/libcxx/include/__iterator/move_iterator.h
+++ b/libcxx/include/__iterator/move_iterator.h
@@ -87,10 +87,13 @@ class _LIBCPP_TEMPLATE_VIS move_iterator
         >::type reference;
 #endif // _LIBCPP_STD_VER > 17
 
-#if _LIBCPP_STD_VER > 17
-    _LIBCPP_HIDE_FROM_ABI constexpr
+    _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
     explicit move_iterator(_Iter __i) : __current_(std::move(__i)) {}
 
+    _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
+    move_iterator& operator++() { ++__current_; return *this; }
+
+#if _LIBCPP_STD_VER > 17
     _LIBCPP_HIDE_FROM_ABI constexpr
     move_iterator() requires is_constructible_v<_Iter> : __current_() {}
 
@@ -117,9 +120,6 @@ class _LIBCPP_TEMPLATE_VIS move_iterator
     _LIBCPP_HIDE_FROM_ABI constexpr
     reference operator[](
diff erence_type __n) const { return ranges::iter_move(__current_ + __n); }
 
-    _LIBCPP_HIDE_FROM_ABI constexpr
-    move_iterator& operator++() { ++__current_; return *this; }
-
     _LIBCPP_HIDE_FROM_ABI constexpr
     auto operator++(int)
         requires forward_iterator<_Iter>
@@ -130,9 +130,6 @@ class _LIBCPP_TEMPLATE_VIS move_iterator
     _LIBCPP_HIDE_FROM_ABI constexpr
     void operator++(int) { ++__current_; }
 #else
-    _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
-    explicit move_iterator(_Iter __i) : __current_(std::move(__i)) {}
-
     _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
     move_iterator() : __current_() {}
 
@@ -163,8 +160,6 @@ class _LIBCPP_TEMPLATE_VIS move_iterator
     _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
     reference operator[](
diff erence_type __n) const { return static_cast<reference>(__current_[__n]); }
 
-    _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
-    move_iterator& operator++() { ++__current_; return *this; }
     _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
     move_iterator operator++(int) { move_iterator __tmp(*this); ++__current_; return __tmp; }
 #endif // _LIBCPP_STD_VER > 17

diff  --git a/libcxx/include/__iterator/move_sentinel.h b/libcxx/include/__iterator/move_sentinel.h
index abacc91be842..5adf877b3490 100644
--- a/libcxx/include/__iterator/move_sentinel.h
+++ b/libcxx/include/__iterator/move_sentinel.h
@@ -31,7 +31,7 @@ class _LIBCPP_TEMPLATE_VIS move_sentinel
   move_sentinel() = default;
 
   _LIBCPP_HIDE_FROM_ABI constexpr
-  explicit move_sentinel(_Sent __s) : __last_(_VSTD::move(__s)) {}
+  explicit move_sentinel(_Sent __s) : __last_(std::move(__s)) {}
 
   template <class _S2>
     requires convertible_to<const _S2&, _Sent>

diff  --git a/libcxx/include/iterator b/libcxx/include/iterator
index 1f0390e83a59..e98372527cc0 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -386,12 +386,13 @@ constexpr insert_iterator<Container> inserter(Container& x, ranges::iterator_t<C
 template <class Iterator>
 class move_iterator {
 public:
-    typedef Iterator                                              iterator_type;
-    typedef typename iterator_traits<Iterator>::
diff erence_type   
diff erence_type;
-    typedef Iterator                                              pointer;
-    typedef typename iterator_traits<Iterator>::value_type        value_type;
-    typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
-    typedef value_type&&                                          reference;
+    using iterator_type     = Iterator;
+    using iterator_concept  = input_iterator_tag; // From C++20
+    using iterator_category = see below; // not always present starting from C++20
+    using value_type        = iter_value_t<Iterator>; // Until C++20, iterator_traits<Iterator>::value_type
+    using 
diff erence_type   = iter_
diff erence_t<Iterator>; // Until C++20, iterator_traits<Iterator>::
diff erence_type;
+    using pointer           = Iterator;
+    using reference         = iter_rvalue_reference_t<Iterator>; // Until C++20, value_type&&
 
     constexpr move_iterator();  // all the constexprs are in C++17
     constexpr explicit move_iterator(Iterator i);
@@ -399,18 +400,40 @@ public:
       constexpr move_iterator(const move_iterator<U>& u);
     template <class U>
       constexpr move_iterator& operator=(const move_iterator<U>& u);
-    constexpr iterator_type base() const;
+
+    constexpr iterator_type base() const; // Until C++20
+    constexpr const Iterator& base() const & noexcept; // From C++20
+    constexpr Iterator base() &&; // From C++20
+
     constexpr reference operator*() const;
-    constexpr pointer operator->() const;
+    constexpr pointer operator->() const; // Removed in C++20
     constexpr move_iterator& operator++();
-    constexpr move_iterator operator++(int);
+    constexpr auto operator++(int); // Return type was move_iterator until C++20
     constexpr move_iterator& operator--();
     constexpr move_iterator operator--(int);
     constexpr move_iterator operator+(
diff erence_type n) const;
     constexpr move_iterator& operator+=(
diff erence_type n);
     constexpr move_iterator operator-(
diff erence_type n) const;
     constexpr move_iterator& operator-=(
diff erence_type n);
-    constexpr unspecified operator[](
diff erence_type n) const;
+    constexpr reference operator[](
diff erence_type n) const; // Return type unspecified until C++20
+
+    template<sentinel_for<Iterator> S>
+      friend constexpr bool
+        operator==(const move_iterator& x, const move_sentinel<S>& y); // Since C++20
+    template<sized_sentinel_for<Iterator> S>
+      friend constexpr iter_
diff erence_t<Iterator>
+        operator-(const move_sentinel<S>& x, const move_iterator& y); // Since C++20
+    template<sized_sentinel_for<Iterator> S>
+      friend constexpr iter_
diff erence_t<Iterator>
+        operator-(const move_iterator& x, const move_sentinel<S>& y); // Since C++20
+    friend constexpr iter_rvalue_reference_t<Iterator>
+      iter_move(const move_iterator& i)
+        noexcept(noexcept(ranges::iter_move(i.current))); // Since C++20
+    template<indirectly_swappable<Iterator> Iterator2>
+      friend constexpr void
+        iter_swap(const move_iterator& x, const move_iterator<Iterator2>& y)
+          noexcept(noexcept(ranges::iter_swap(x.current, y.current))); // Since C++20
+
 private:
     Iterator current; // exposition only
 };
@@ -452,6 +475,23 @@ constexpr move_iterator<Iterator> operator+(   // constexpr in C++17
 template <class Iterator>   // constexpr in C++17
 constexpr  move_iterator<Iterator> make_move_iterator(const Iterator& i);
 
+template<semiregular S>
+class move_sentinel {
+public:
+  constexpr move_sentinel();
+  constexpr explicit move_sentinel(S s);
+  template<class S2>
+    requires convertible_to<const S2&, S>
+      constexpr move_sentinel(const move_sentinel<S2>& s);
+  template<class S2>
+    requires assignable_from<S&, const S2&>
+      constexpr move_sentinel& operator=(const move_sentinel<S2>& s);
+
+  constexpr S base() const;
+private:
+  S last;     // exposition only
+};
+
 // [default.sentinel], default sentinel
 struct default_sentinel_t;
 inline constexpr default_sentinel_t default_sentinel{};

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_move.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_move.pass.cpp
new file mode 100644
index 000000000000..a9e6d17720ab
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_move.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
+
+// <iterator>
+//
+// friend constexpr iter_rvalue_reference_t<Iterator>
+//   iter_move(const move_iterator& i)
+//     noexcept(noexcept(ranges::iter_move(i.current))); // Since C++20
+
+#include <iterator>
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+#include "test_iterators.h"
+#include "test_macros.h"
+
+int global;
+
+template <bool IsNoexcept>
+struct MaybeNoexceptMove {
+  int x;
+  using value_type = int;
+  using 
diff erence_type = ptr
diff _t;
+
+  constexpr friend value_type&& iter_move(MaybeNoexceptMove) noexcept(IsNoexcept) {
+    return std::move(global);
+  }
+
+  int& operator*() const { static int a; return a; }
+
+  MaybeNoexceptMove& operator++();
+  MaybeNoexceptMove operator++(int);
+};
+using ThrowingBase = MaybeNoexceptMove<false>;
+using NoexceptBase = MaybeNoexceptMove<true>;
+static_assert(std::input_iterator<ThrowingBase>);
+ASSERT_NOT_NOEXCEPT(std::ranges::iter_move(std::declval<ThrowingBase>()));
+ASSERT_NOEXCEPT(std::ranges::iter_move(std::declval<NoexceptBase>()));
+
+constexpr bool test() {
+  // Can use `iter_move` with a regular array.
+  {
+    int a[] = {0, 1, 2};
+
+    std::move_iterator<int*> i(a);
+    static_assert(std::same_as<decltype(iter_move(i)), int&&>);
+    assert(iter_move(i) == 0);
+
+    ++i;
+    assert(iter_move(i) == 1);
+  }
+
+  // Check that the `iter_move` customization point is being used.
+  {
+    int a[] = {0, 1, 2};
+
+    int iter_move_invocations = 0;
+    adl::Iterator base = adl::Iterator::TrackMoves(a, iter_move_invocations);
+    std::move_iterator<adl::Iterator> i(base);
+    int x = iter_move(i);
+    assert(x == 0);
+    assert(iter_move_invocations == 1);
+  }
+
+  // Check the `noexcept` specification.
+  {
+    using ThrowingIter = std::move_iterator<ThrowingBase>;
+    ASSERT_NOT_NOEXCEPT(iter_move(std::declval<ThrowingIter>()));
+    using NoexceptIter = std::move_iterator<NoexceptBase>;
+    ASSERT_NOEXCEPT(iter_move(std::declval<NoexceptIter>()));
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_swap.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_swap.pass.cpp
new file mode 100644
index 000000000000..075930dcb0a0
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_swap.pass.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <iterator>
+//
+// template<indirectly_swappable<Iterator> Iterator2>
+//   friend constexpr void
+//     iter_swap(const move_iterator& x, const move_iterator<Iterator2>& y)
+//       noexcept(noexcept(ranges::iter_swap(x.current, y.current))); // Since C++20
+
+#include <iterator>
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <bool IsNoexcept>
+struct MaybeNoexceptSwap {
+  using value_type = int;
+  using 
diff erence_type = ptr
diff _t;
+
+  constexpr friend void iter_swap(MaybeNoexceptSwap, MaybeNoexceptSwap) noexcept(IsNoexcept) {
+  }
+
+  int& operator*() const { static int x; return x; }
+
+  MaybeNoexceptSwap& operator++();
+  MaybeNoexceptSwap operator++(int);
+};
+using ThrowingBase = MaybeNoexceptSwap<false>;
+using NoexceptBase = MaybeNoexceptSwap<true>;
+static_assert(std::input_iterator<ThrowingBase>);
+ASSERT_NOT_NOEXCEPT(std::ranges::iter_swap(std::declval<ThrowingBase>(), std::declval<ThrowingBase>()));
+ASSERT_NOEXCEPT(std::ranges::iter_swap(std::declval<NoexceptBase>(), std::declval<NoexceptBase>()));
+
+constexpr bool test() {
+  // Can use `iter_swap` with a regular array.
+  {
+    int a[] = {0, 1, 2};
+
+    std::move_iterator b(a);
+    std::move_iterator e(a + 2);
+    assert(a[0] == 0);
+    assert(a[2] == 2);
+
+    static_assert(std::same_as<decltype(iter_swap(b, e)), void>);
+    iter_swap(b, e);
+    assert(a[0] == 2);
+    assert(a[2] == 0);
+  }
+
+  // Check that the `iter_swap` customization point is being used.
+  {
+    int iter_swap_invocations = 0;
+    adl::Iterator base1 = adl::Iterator::TrackSwaps(iter_swap_invocations);
+    adl::Iterator base2 = adl::Iterator::TrackSwaps(iter_swap_invocations);
+    std::move_iterator<adl::Iterator> i1(base1), i2(base2);
+    iter_swap(i1, i2);
+    assert(iter_swap_invocations == 1);
+
+    iter_swap(i2, i1);
+    assert(iter_swap_invocations == 2);
+  }
+
+  // Check the `noexcept` specification.
+  {
+    using ThrowingIter = std::move_iterator<ThrowingBase>;
+    ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<ThrowingIter>(), std::declval<ThrowingIter>()));
+    using NoexceptIter = std::move_iterator<NoexceptBase>;
+    ASSERT_NOEXCEPT(iter_swap(std::declval<NoexceptIter>(), std::declval<NoexceptIter>()));
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.-/sentinel.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.-/sentinel.pass.cpp
new file mode 100644
index 000000000000..d84a38c8c6e0
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.-/sentinel.pass.cpp
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <iterator>
+
+// move_iterator
+
+// template<sized_sentinel_for<Iterator> S>
+//   friend constexpr iter_
diff erence_t<Iterator>
+//     operator-(const move_sentinel<S>& x, const move_iterator& y); // Since C++20
+// template<sized_sentinel_for<Iterator> S>
+//   friend constexpr iter_
diff erence_t<Iterator>
+//     operator-(const move_iterator& x, const move_sentinel<S>& y); // Since C++20
+
+#include <iterator>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+
+// The `operator-` calls the underlying iterator and sentinel's `operator-`.
+
+struct CustomIt {
+  using value_type = int;
+  using 
diff erence_type = int;
+  using reference = int&;
+  using pointer = int*;
+  using iterator_category = std::input_iterator_tag;
+
+  CustomIt() = default;
+  TEST_CONSTEXPR_CXX17 explicit CustomIt(int* p) : p_(p) {}
+  int& operator*() const;
+  CustomIt& operator++();
+  CustomIt operator++(int);
+  constexpr friend 
diff erence_type operator-(const CustomIt& a, const CustomIt& b) { return a.p_ - b.p_; }
+  int *p_ = nullptr;
+};
+
+template <class It, class Sent = sized_sentinel<It>>
+constexpr void test_one() {
+  int arr[] = {3, 1, 4};
+
+  const std::move_iterator<It> it_a{It(arr)};
+  const std::move_iterator<It> it_b{It(arr + 1)};
+
+  const std::move_sentinel<Sent> sent_a{Sent(It(arr))};
+  const std::move_sentinel<Sent> sent_b{Sent(It(arr + 1))};
+  const std::move_sentinel<Sent> sent_c{Sent(It(arr + 2))};
+
+  ASSERT_SAME_TYPE(decltype(it_a - sent_a), std::iter_
diff erence_t<It>);
+  ASSERT_SAME_TYPE(decltype(sent_a - it_a), std::iter_
diff erence_t<It>);
+
+  // it_a
+  assert(it_a - sent_a == 0);
+  assert(sent_a - it_a == 0);
+
+  assert(it_a - sent_b == -1);
+  assert(sent_b - it_a == 1);
+
+  assert(it_a - sent_c == -2);
+  assert(sent_c - it_a == 2);
+
+  // it_b
+  assert(it_b - sent_a == 1);
+  assert(sent_a - it_b == -1);
+
+  assert(it_b - sent_b == 0);
+  assert(sent_b - it_b == 0);
+
+  assert(it_b - sent_c == -1);
+  assert(sent_c - it_b == 1);
+}
+
+constexpr bool test() {
+  test_one<CustomIt>();
+  test_one<cpp17_input_iterator<int*>>();
+  test_one<forward_iterator<int*>>();
+  test_one<bidirectional_iterator<int*>>();
+  test_one<random_access_iterator<int*>>();
+  test_one<int*>();
+  test_one<const int*>();
+  test_one<contiguous_iterator<int*>>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
index 04d3d6e1866a..d095182c560d 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
@@ -13,33 +13,42 @@
 // move_iterator();
 //
 //  constexpr in C++17
+//
+//  requires the underlying iterator to be default-constructible (extension).
 
 #include <iterator>
 
+#include <type_traits>
 #include "test_macros.h"
 #include "test_iterators.h"
 
+#if TEST_STD_VER > 17
+struct NoDefaultCtr : forward_iterator<int*> {
+  NoDefaultCtr() = delete;
+};
+
+LIBCPP_STATIC_ASSERT( std::is_default_constructible_v<std::move_iterator<forward_iterator<int*>>>);
+LIBCPP_STATIC_ASSERT(!std::is_default_constructible_v<std::move_iterator<NoDefaultCtr>>);
+#endif
+
 template <class It>
-void
-test()
-{
+void test() {
     std::move_iterator<It> r;
     (void)r;
 }
 
-int main(int, char**)
-{
-    // we don't have a test iterator that is both input and default-constructible, so not testing that case
-    test<forward_iterator<char*> >();
-    test<bidirectional_iterator<char*> >();
-    test<random_access_iterator<char*> >();
-    test<char*>();
+int main(int, char**) {
+  // we don't have a test iterator that is both input and default-constructible, so not testing that case
+  test<forward_iterator<char*> >();
+  test<bidirectional_iterator<char*> >();
+  test<random_access_iterator<char*> >();
+  test<char*>();
 
 #if TEST_STD_VER > 14
-    {
+  {
     constexpr std::move_iterator<const char *> it;
     (void)it;
-    }
+  }
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/base.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/base.pass.cpp
new file mode 100644
index 000000000000..6e348b59be16
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/base.pass.cpp
@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <iterator>
+//
+// constexpr iterator_type base() const; // Until C++20
+// constexpr const Iterator& base() const & noexcept; // From C++20
+// constexpr Iterator base() &&; // From C++20
+
+#include <iterator>
+
+#include <utility>
+#include "test_iterators.h"
+#include "test_macros.h"
+
+struct MoveOnlyIterator {
+  using It = int*;
+
+  It it_;
+
+  using iterator_category = std::input_iterator_tag;
+  using value_type = int;
+  using 
diff erence_type = std::ptr
diff _t;
+  using reference = int&;
+
+  TEST_CONSTEXPR explicit MoveOnlyIterator(It it) : it_(it) {}
+  MoveOnlyIterator(MoveOnlyIterator&&) = default;
+  MoveOnlyIterator& operator=(MoveOnlyIterator&&) = default;
+  MoveOnlyIterator(const MoveOnlyIterator&) = delete;
+  MoveOnlyIterator& operator=(const MoveOnlyIterator&) = delete;
+
+  TEST_CONSTEXPR reference operator*() const { return *it_; }
+
+  TEST_CONSTEXPR_CXX14 MoveOnlyIterator& operator++() { ++it_; return *this; }
+  TEST_CONSTEXPR_CXX14 MoveOnlyIterator operator++(int) { return MoveOnlyIterator(it_++); }
+
+  friend TEST_CONSTEXPR bool operator==(const MoveOnlyIterator& x, const MoveOnlyIterator& y) {return x.it_ == y.it_;}
+  friend TEST_CONSTEXPR bool operator!=(const MoveOnlyIterator& x, const MoveOnlyIterator& y) {return x.it_ != y.it_;}
+
+  friend TEST_CONSTEXPR It base(const MoveOnlyIterator& i) { return i.it_; }
+};
+
+#if TEST_STD_VER > 17
+static_assert( std::input_iterator<MoveOnlyIterator>);
+#endif
+static_assert(!std::is_copy_constructible<MoveOnlyIterator>::value, "");
+
+template <class It>
+TEST_CONSTEXPR_CXX14 void test_one() {
+  // Non-const lvalue.
+  {
+    int a[] = {1, 2, 3};
+
+    auto i = std::move_iterator<It>(It(a));
+#if TEST_STD_VER > 17
+    ASSERT_SAME_TYPE(decltype(i.base()), const It&);
+    ASSERT_NOEXCEPT(i.base());
+#else
+    ASSERT_SAME_TYPE(decltype(i.base()), It);
+#endif
+    assert(i.base() == It(a));
+
+    ++i;
+    assert(i.base() == It(a + 1));
+  }
+
+  // Const lvalue.
+  {
+    int a[] = {1, 2, 3};
+
+    const auto i = std::move_iterator<It>(It(a));
+#if TEST_STD_VER > 17
+    ASSERT_SAME_TYPE(decltype(i.base()), const It&);
+    ASSERT_NOEXCEPT(i.base());
+#else
+    ASSERT_SAME_TYPE(decltype(i.base()), It);
+#endif
+    assert(i.base() == It(a));
+  }
+
+  // Rvalue.
+  {
+    int a[] = {1, 2, 3};
+
+    auto i = std::move_iterator<It>(It(a));
+    ASSERT_SAME_TYPE(decltype(std::move(i).base()), It);
+    assert(std::move(i).base() == It(a));
+  }
+}
+
+TEST_CONSTEXPR_CXX14 bool test() {
+  test_one<cpp17_input_iterator<int*> >();
+  test_one<forward_iterator<int*> >();
+  test_one<bidirectional_iterator<int*> >();
+  test_one<random_access_iterator<int*> >();
+  test_one<int*>();
+  test_one<const int*>();
+#if TEST_STD_VER > 17
+  test_one<contiguous_iterator<int*>>();
+#endif
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER > 14
+  static_assert(test());
+#endif
+
+  return 0;
+}

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/tested_elsewhere.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/tested_elsewhere.pass.cpp
deleted file mode 100644
index 1f764da05d6b..000000000000
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/tested_elsewhere.pass.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-int main(int, char**)
-{
-
-  return 0;
-}

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.incr/post.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.incr/post.pass.cpp
index a33bb08fa097..e2b831b717b9 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.incr/post.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.incr/post.pass.cpp
@@ -10,9 +10,7 @@
 
 // move_iterator
 
-// move_iterator operator++(int);
-//
-//  constexpr in C++17
+// constexpr auto operator++(int); // Return type was move_iterator until C++20
 
 #include <iterator>
 #include <cassert>
@@ -31,30 +29,27 @@ void test_single_pass(It i, It x) {
 #endif
 
 template <class It>
-void
-test(It i, It x)
-{
+void test(It i, It x) {
     std::move_iterator<It> r(i);
     std::move_iterator<It> rr = r++;
     assert(r.base() == x);
     assert(rr.base() == i);
 }
 
-int main(int, char**)
-{
-    char s[] = "123";
+int main(int, char**) {
+  char s[] = "123";
 #if TEST_STD_VER > 17
-    test_single_pass(cpp17_input_iterator<char*>(s), cpp17_input_iterator<char*>(s + 1));
+  test_single_pass(cpp17_input_iterator<char*>(s), cpp17_input_iterator<char*>(s + 1));
 #else
-    test(cpp17_input_iterator<char*>(s), cpp17_input_iterator<char*>(s+1));
+  test(cpp17_input_iterator<char*>(s), cpp17_input_iterator<char*>(s+1));
 #endif
-    test(forward_iterator<char*>(s), forward_iterator<char*>(s+1));
-    test(bidirectional_iterator<char*>(s), bidirectional_iterator<char*>(s+1));
-    test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1));
-    test(s, s+1);
+  test(forward_iterator<char*>(s), forward_iterator<char*>(s+1));
+  test(bidirectional_iterator<char*>(s), bidirectional_iterator<char*>(s+1));
+  test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1));
+  test(s, s+1);
 
 #if TEST_STD_VER > 14
-    {
+  {
     constexpr const char *p = "123456789";
     typedef std::move_iterator<const char *> MI;
     constexpr MI it1 = std::make_move_iterator(p);
@@ -63,7 +58,32 @@ int main(int, char**)
     constexpr MI it3 = std::make_move_iterator(p) ++;
     static_assert(it1 == it3, "");
     static_assert(it2 != it3, "");
-    }
+  }
+#endif
+
+#if TEST_STD_VER > 17
+  // Forward iterators return a copy.
+  {
+    int a[] = {1, 2, 3};
+    using MoveIter = std::move_iterator<forward_iterator<int*>>;
+
+    MoveIter i = MoveIter(forward_iterator<int*>(a));
+    ASSERT_SAME_TYPE(decltype(i++), MoveIter);
+    auto j = i++;
+    assert(base(j.base()) == a);
+    assert(base(i.base()) == a + 1);
+  }
+
+  // Non-forward iterators return void.
+  {
+    int a[] = {1, 2, 3};
+    using MoveIter = std::move_iterator<cpp20_input_iterator<int*>>;
+
+    MoveIter i = MoveIter(cpp20_input_iterator<int*>(a));
+    ASSERT_SAME_TYPE(decltype(i++), void);
+    i++;
+    assert(base(i.base()) == a + 1);
+  }
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.index/
diff erence_type.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.index/
diff erence_type.pass.cpp
index ecf3b61058b7..df199873ffae 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.index/
diff erence_type.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.index/
diff erence_type.pass.cpp
@@ -10,10 +10,7 @@
 
 // move_iterator
 
-// requires RandomAccessIterator<Iter>
-//   unspecified operator[](
diff erence_type n) const;
-//
-//  constexpr in C++17
+// constexpr reference operator[](
diff erence_type n) const; // Return type unspecified until C++20
 
 #include <iterator>
 #include <cassert>
@@ -65,5 +62,20 @@ int main(int, char**)
     }
 #endif
 
+#if TEST_STD_VER > 17
+  // Ensure the `iter_move` customization point is being used.
+  {
+    int a[] = {0, 1, 2};
+
+    int iter_moves = 0;
+    adl::Iterator i = adl::Iterator::TrackMoves(a, iter_moves);
+    std::move_iterator<adl::Iterator> mi(i);
+
+    auto x = mi[0];
+    assert(x == 0);
+    assert(iter_moves == 1);
+  }
+#endif
+
   return 0;
 }

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.star/op_star.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.star/op_star.pass.cpp
index e6e826d83525..22f601e6ca30 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.star/op_star.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.star/op_star.pass.cpp
@@ -18,6 +18,7 @@
 #include <cassert>
 #include <memory>
 
+#include "test_iterators.h"
 #include "test_macros.h"
 
 class A
@@ -47,28 +48,42 @@ struct do_nothing
 };
 
 
-int main(int, char**)
-{
-    {
-        A a;
-        test(&a, A());
-    }
+int main(int, char**) {
+  {
+    A a;
+    test(&a, A());
+  }
 #if TEST_STD_VER >= 11
-    {
-        int i;
-        std::unique_ptr<int, do_nothing> p(&i);
-        test(&p, std::unique_ptr<int, do_nothing>(&i));
-    }
+  {
+    int i;
+    std::unique_ptr<int, do_nothing> p(&i);
+    test(&p, std::unique_ptr<int, do_nothing>(&i));
+  }
 #endif
 #if TEST_STD_VER > 14
-    {
+  {
     constexpr const char *p = "123456789";
     typedef std::move_iterator<const char *> MI;
     constexpr MI it1 = std::make_move_iterator(p);
     constexpr MI it2 = std::make_move_iterator(p+1);
     static_assert(*it1 == p[0], "");
     static_assert(*it2 == p[1], "");
-    }
+  }
+#endif
+
+#if TEST_STD_VER > 17
+  // Ensure the `iter_move` customization point is being used.
+  {
+    int a[] = {0, 1, 2};
+
+    int iter_moves = 0;
+    adl::Iterator i = adl::Iterator::TrackMoves(a, iter_moves);
+    std::move_iterator<adl::Iterator> mi(i);
+
+    auto x = *mi;
+    assert(x == 0);
+    assert(iter_moves == 1);
+  }
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/types.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/types.pass.cpp
index 2d0dadfeec8f..f262b4d29eeb 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/types.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/types.pass.cpp
@@ -15,11 +15,13 @@
 // template <InputIterator Iter>
 // class move_iterator {
 // public:
-//   typedef Iter                  iterator_type;
-//   typedef Iter::
diff erence_type 
diff erence_type;
-//   typedef Iter                  pointer;
-//   typedef Iter::value_type      value_type;
-//   typedef value_type&&          reference;
+//  using iterator_type     = Iterator;
+//  using iterator_concept  = input_iterator_tag; // From C++20
+//  using iterator_category = see below; // not always present starting from C++20
+//  using value_type        = iter_value_t<Iterator>; // Until C++20, iterator_traits<Iterator>::value_type
+//  using 
diff erence_type   = iter_
diff erence_t<Iterator>; // Until C++20, iterator_traits<Iterator>::
diff erence_type;
+//  using pointer           = Iterator;
+//  using reference         = iter_rvalue_reference_t<Iterator>; // Until C++20, value_type&&
 // };
 
 #include <iterator>
@@ -28,6 +30,37 @@
 #include "test_macros.h"
 #include "test_iterators.h"
 
+struct FooIter {
+  using iterator_category = std::bidirectional_iterator_tag;
+  using value_type = void*;
+  using 
diff erence_type = void*;
+  using pointer = void*;
+  using reference = char&;
+  bool& operator*() const;
+};
+
+#if TEST_STD_VER > 17
+template <>
+struct std::indirectly_readable_traits<FooIter> {
+  using value_type = int;
+};
+template <>
+struct std::incrementable_traits<FooIter> {
+  using 
diff erence_type = char;
+};
+#endif
+
+#if TEST_STD_VER > 17
+// Not using `FooIter::value_type`.
+static_assert(std::is_same_v<typename std::move_iterator<FooIter>::value_type, int>);
+// Not using `FooIter::
diff erence_type`.
+static_assert(std::is_same_v<typename std::move_iterator<FooIter>::
diff erence_type, char>);
+static_assert(std::is_same_v<typename std::reverse_iterator<FooIter>::reference, bool&>);
+
+#else
+static_assert(std::is_same<typename std::reverse_iterator<FooIter>::reference, char&>::value, "");
+#endif
+
 template <class ValueType, class Reference>
 struct DummyIt {
   typedef std::forward_iterator_tag iterator_category;
@@ -40,71 +73,79 @@ struct DummyIt {
 };
 
 template <class It>
-void
-test()
-{
-    typedef std::move_iterator<It> R;
-    typedef std::iterator_traits<It> T;
-    static_assert((std::is_same<typename R::iterator_type, It>::value), "");
-    static_assert((std::is_same<typename R::
diff erence_type, typename T::
diff erence_type>::value), "");
-    static_assert((std::is_same<typename R::pointer, It>::value), "");
-    static_assert((std::is_same<typename R::value_type, typename T::value_type>::value), "");
-    static_assert((std::is_same<typename R::reference, typename R::value_type&&>::value), "");
+void test() {
+  typedef std::move_iterator<It> R;
+  typedef std::iterator_traits<It> T;
+  static_assert((std::is_same<typename R::iterator_type, It>::value), "");
+  static_assert((std::is_same<typename R::
diff erence_type, typename T::
diff erence_type>::value), "");
+  static_assert((std::is_same<typename R::pointer, It>::value), "");
+  static_assert((std::is_same<typename R::value_type, typename T::value_type>::value), "");
+
 #if TEST_STD_VER > 17
-    if constexpr (std::is_same_v<typename T::iterator_category, std::contiguous_iterator_tag>) {
-        static_assert((std::is_same<typename R::iterator_category, std::random_access_iterator_tag>::value), "");
-    } else {
-        static_assert((std::is_same<typename R::iterator_category, typename T::iterator_category>::value), "");
-    }
+  static_assert((std::is_same_v<typename R::reference, std::iter_rvalue_reference_t<It>>), "");
 #else
+  static_assert((std::is_same<typename R::reference, typename R::value_type&&>::value), "");
+#endif
+
+#if TEST_STD_VER > 17
+  if constexpr (std::is_same_v<typename T::iterator_category, std::contiguous_iterator_tag>) {
+    static_assert((std::is_same<typename R::iterator_category, std::random_access_iterator_tag>::value), "");
+  } else {
     static_assert((std::is_same<typename R::iterator_category, typename T::iterator_category>::value), "");
+  }
+#else
+  static_assert((std::is_same<typename R::iterator_category, typename T::iterator_category>::value), "");
+#endif
+
+#if TEST_STD_VER > 17
+  static_assert(std::is_same_v<typename R::iterator_concept, std::input_iterator_tag>);
 #endif
 }
 
-int main(int, char**)
-{
-    test<cpp17_input_iterator<char*> >();
-    test<forward_iterator<char*> >();
-    test<bidirectional_iterator<char*> >();
-    test<random_access_iterator<char*> >();
-    test<char*>();
+int main(int, char**) {
+  test<cpp17_input_iterator<char*> >();
+  test<forward_iterator<char*> >();
+  test<bidirectional_iterator<char*> >();
+  test<random_access_iterator<char*> >();
+  test<char*>();
+
 #if TEST_STD_VER >= 11
-    {
-        typedef DummyIt<int, int> T;
-        typedef std::move_iterator<T> It;
-        static_assert(std::is_same<It::reference, int>::value, "");
-    }
-    {
-        typedef DummyIt<int, std::reference_wrapper<int> > T;
-        typedef std::move_iterator<T> It;
-        static_assert(std::is_same<It::reference, std::reference_wrapper<int> >::value, "");
-    }
-    {
-        // Check that move_iterator uses whatever reference type it's given
-        // when it's not a reference.
-        typedef DummyIt<int, long > T;
-        typedef std::move_iterator<T> It;
-        static_assert(std::is_same<It::reference, long>::value, "");
-    }
-    {
-        typedef DummyIt<int, int&> T;
-        typedef std::move_iterator<T> It;
-        static_assert(std::is_same<It::reference, int&&>::value, "");
-    }
-    {
-        typedef DummyIt<int, int&&> T;
-        typedef std::move_iterator<T> It;
-        static_assert(std::is_same<It::reference, int&&>::value, "");
-    }
+  {
+      typedef DummyIt<int, int> T;
+      typedef std::move_iterator<T> It;
+      static_assert(std::is_same<It::reference, int>::value, "");
+  }
+  {
+      typedef DummyIt<int, std::reference_wrapper<int> > T;
+      typedef std::move_iterator<T> It;
+      static_assert(std::is_same<It::reference, std::reference_wrapper<int> >::value, "");
+  }
+  {
+      // Check that move_iterator uses whatever reference type it's given
+      // when it's not a reference.
+      typedef DummyIt<int, long > T;
+      typedef std::move_iterator<T> It;
+      static_assert(std::is_same<It::reference, long>::value, "");
+  }
+  {
+      typedef DummyIt<int, int&> T;
+      typedef std::move_iterator<T> It;
+      static_assert(std::is_same<It::reference, int&&>::value, "");
+  }
+  {
+      typedef DummyIt<int, int&&> T;
+      typedef std::move_iterator<T> It;
+      static_assert(std::is_same<It::reference, int&&>::value, "");
+  }
 #endif
 
 #if TEST_STD_VER > 17
-    test<contiguous_iterator<char*>>();
-    static_assert(std::is_same_v<typename std::move_iterator<forward_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
-    static_assert(std::is_same_v<typename std::move_iterator<bidirectional_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
-    static_assert(std::is_same_v<typename std::move_iterator<random_access_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
-    static_assert(std::is_same_v<typename std::move_iterator<contiguous_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
-    static_assert(std::is_same_v<typename std::move_iterator<char*>::iterator_concept, std::input_iterator_tag>);
+  test<contiguous_iterator<char*>>();
+  static_assert(std::is_same_v<typename std::move_iterator<forward_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
+  static_assert(std::is_same_v<typename std::move_iterator<bidirectional_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
+  static_assert(std::is_same_v<typename std::move_iterator<random_access_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
+  static_assert(std::is_same_v<typename std::move_iterator<contiguous_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
+  static_assert(std::is_same_v<typename std::move_iterator<char*>::iterator_concept, std::input_iterator_tag>);
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/assign.converting.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/assign.converting.pass.cpp
index 03ef6e2b085f..57f9ad70b7ad 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/assign.converting.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/assign.converting.pass.cpp
@@ -21,7 +21,7 @@
 #include <concepts>
 
 struct NonAssignable {
-    NonAssignable& operator=(int i);
+  NonAssignable& operator=(int i);
 };
 static_assert(std::semiregular<NonAssignable>);
 static_assert(std::is_assignable_v<NonAssignable, int>);
@@ -29,17 +29,22 @@ static_assert(!std::assignable_from<NonAssignable, int>);
 
 constexpr bool test()
 {
+  // Assigning from an lvalue.
   {
     std::move_sentinel<int> m(42);
     std::move_sentinel<long> m2;
     m2 = m;
     assert(m2.base() == 42L);
   }
+
+  // Assigning from an rvalue.
   {
     std::move_sentinel<long> m2;
     m2 = std::move_sentinel<int>(43);
     assert(m2.base() == 43L);
   }
+
+  // SFINAE checks.
   {
     static_assert( std::is_assignable_v<std::move_sentinel<int>, std::move_sentinel<long>>);
     static_assert(!std::is_assignable_v<std::move_sentinel<int*>, std::move_sentinel<const int*>>);

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/base.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/base.pass.cpp
index bfb202ac36b6..b3b0293c3d48 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/base.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/base.pass.cpp
@@ -22,6 +22,7 @@
 
 constexpr bool test()
 {
+  // The sentinel type is a value.
   {
     auto m = std::move_sentinel<int>(42);
     const auto& cm = m;
@@ -34,6 +35,8 @@ constexpr bool test()
     ASSERT_SAME_TYPE(decltype(std::move(m).base()), int);
     ASSERT_SAME_TYPE(decltype(std::move(cm).base()), int);
   }
+
+  // The sentinel type is a pointer.
   {
     int a[] = {1, 2, 3};
     auto m = std::move_sentinel<const int*>(a);

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/concept_conformance.compile.pass.cpp
index 88e0f77ea39f..80dc4de73116 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/concept_conformance.compile.pass.cpp
@@ -19,6 +19,7 @@
 
 void test()
 {
+  // Pointer.
   {
     using It = int*;
     static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
@@ -28,6 +29,8 @@ void test()
     static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
     static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
   }
+
+  // `Cpp17InputIterator`.
   {
     using It = cpp17_input_iterator<int*>;
     static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
@@ -35,6 +38,8 @@ void test()
     static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
     static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
   }
+
+  // `std::input_iterator`.
   {
     using It = cpp20_input_iterator<int*>;
     static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
@@ -42,6 +47,8 @@ void test()
     static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
     static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
   }
+
+  // `std::forward_iterator`.
   {
     using It = forward_iterator<int*>;
     static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
@@ -51,6 +58,8 @@ void test()
     static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
     static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
   }
+
+  // `std::bidirectional_iterator`.
   {
     using It = bidirectional_iterator<int*>;
     static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
@@ -60,6 +69,8 @@ void test()
     static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
     static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
   }
+
+  // `std::random_access_iterator`.
   {
     using It = random_access_iterator<int*>;
     static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
@@ -69,6 +80,8 @@ void test()
     static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
     static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
   }
+
+  // `std::contiguous_iterator`.
   {
     using It = contiguous_iterator<int*>;
     static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
@@ -78,6 +91,8 @@ void test()
     static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
     static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
   }
+
+  // `std::contiguous_iterator` with the spaceship operator.
   {
     using It = three_way_contiguous_iterator<int*>;
     static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.converting.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.converting.pass.cpp
index b77d4836cd4e..5f5be0c7f159 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.converting.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.converting.pass.cpp
@@ -31,15 +31,20 @@ static_assert(!std::convertible_to<long, NonConvertible>);
 
 constexpr bool test()
 {
+  // Constructing from an lvalue.
   {
     std::move_sentinel<int> m(42);
     std::move_sentinel<long> m2 = m;
     assert(m2.base() == 42L);
   }
+
+  // Constructing from an rvalue.
   {
     std::move_sentinel<long> m2 = std::move_sentinel<int>(43);
     assert(m2.base() == 43L);
   }
+
+  // SFINAE checks.
   {
     static_assert( std::is_convertible_v<std::move_sentinel<int>, std::move_sentinel<long>>);
     static_assert( std::is_convertible_v<std::move_sentinel<int*>, std::move_sentinel<const int*>>);

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.default.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.default.pass.cpp
index 655825de7d6f..c446373eff2b 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.default.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.default.pass.cpp
@@ -19,14 +19,20 @@
 
 constexpr bool test()
 {
+
+  // The underlying sentinel is an integer.
   {
     std::move_sentinel<int> m;
     assert(m.base() == 0);
   }
+
+  // The underlying sentinel is a pointer.
   {
     std::move_sentinel<int*> m;
     assert(m.base() == nullptr);
   }
+
+  // The underlying sentinel is a user-defined type with an explicit default constructor.
   {
     struct S {
       explicit S() = default;
@@ -35,6 +41,7 @@ constexpr bool test()
     std::move_sentinel<S> m;
     assert(m.base().i == 3);
   }
+
   return true;
 }
 

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.sentinel.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.sentinel.pass.cpp
index 226a24a2bee8..1fc2843f465a 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.sentinel.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.sentinel.pass.cpp
@@ -19,17 +19,22 @@
 
 constexpr bool test()
 {
+  // The underlying sentinel is an integer.
   {
     static_assert(!std::is_convertible_v<int, std::move_sentinel<int>>);
     std::move_sentinel<int> m(42);
     assert(m.base() == 42);
   }
+
+  // The underlying sentinel is a pointer.
   {
     static_assert(!std::is_convertible_v<int*, std::move_sentinel<int*>>);
     int i = 42;
     std::move_sentinel<int*> m(&i);
     assert(m.base() == &i);
   }
+
+  // The underlying sentinel is a user-defined type with an explicit default constructor.
   {
     struct S {
       explicit S() = default;

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/op_eq.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/op_eq.pass.cpp
index fef17c5d188b..9519eb2a9fad 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/op_eq.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/op_eq.pass.cpp
@@ -38,30 +38,25 @@ static_assert( HasNotEquals<std::move_iterator<const int*>, std::move_sentinel<i
 static_assert(!HasLess<std::move_iterator<const int*>, std::move_sentinel<int*>>);
 
 template <class It>
-constexpr bool test_one()
-{
-  {
-    char s[] = "abc";
-    const auto it = std::move_iterator<It>(It(s));
-    const auto sent1 = std::move_sentinel<sentinel_wrapper<It>>(sentinel_wrapper<It>(It(s)));
-    const auto sent2 = std::move_sentinel<sentinel_wrapper<It>>(sentinel_wrapper<It>(It(s + 1)));
-    ASSERT_SAME_TYPE(decltype(it == sent1), bool);
-    assert( (it == sent1));
-    assert(!(it != sent1));
-    assert(!(it == sent2));
-    assert( (it != sent2));
-    assert( (sent1 == it));
-    assert(!(sent1 != it));
-    assert(!(sent2 == it));
-    assert( (sent2 != it));
-    static_assert(!HasEquals<decltype(sent1), decltype(sent1)>);
-    static_assert(!HasLess<decltype(sent1), decltype(sent1)>);
-  }
-  return true;
+constexpr void test_one() {
+  char s[] = "abc";
+  const auto it = std::move_iterator<It>(It(s));
+  const auto sent1 = std::move_sentinel<sentinel_wrapper<It>>(sentinel_wrapper<It>(It(s)));
+  const auto sent2 = std::move_sentinel<sentinel_wrapper<It>>(sentinel_wrapper<It>(It(s + 1)));
+  ASSERT_SAME_TYPE(decltype(it == sent1), bool);
+  assert( (it == sent1));
+  assert(!(it != sent1));
+  assert(!(it == sent2));
+  assert( (it != sent2));
+  assert( (sent1 == it));
+  assert(!(sent1 != it));
+  assert(!(sent2 == it));
+  assert( (sent2 != it));
+  static_assert(!HasEquals<decltype(sent1), decltype(sent1)>);
+  static_assert(!HasLess<decltype(sent1), decltype(sent1)>);
 }
 
-constexpr bool test()
-{
+constexpr bool test() {
   test_one<cpp17_input_iterator<char*>>();
   test_one<cpp20_input_iterator<char*>>();
   test_one<forward_iterator<char*>>();
@@ -75,8 +70,7 @@ constexpr bool test()
   return true;
 }
 
-int main(int, char**)
-{
+int main(int, char**) {
   test();
   static_assert(test());
 

diff  --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_move.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_move.pass.cpp
index acf91784ef9b..712425a0c44f 100644
--- a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_move.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_move.pass.cpp
@@ -20,48 +20,9 @@
 #include <cassert>
 #include <type_traits>
 #include <utility>
+#include "test_iterators.h"
 #include "test_macros.h"
 
-namespace adl {
-
-struct Iterator {
-  using value_type = int;
-  using 
diff erence_type = ptr
diff _t;
-
-  value_type* ptr_ = nullptr;
-  int* iter_move_invocations_ = nullptr;
-
-  constexpr Iterator() = default;
-  constexpr explicit Iterator(int* p, int& iter_moves) : ptr_(p), iter_move_invocations_(&iter_moves) {}
-
-  constexpr value_type& operator*() const { return *ptr_; }
-
-  Iterator& operator++() { ++ptr_; return *this; }
-  Iterator operator++(int) {
-    Iterator prev = *this;
-    ++ptr_;
-    return prev;
-  }
-
-  constexpr Iterator& operator--() { --ptr_; return *this; }
-  constexpr Iterator operator--(int) {
-    Iterator prev = *this;
-    --ptr_;
-    return prev;
-  }
-
-  constexpr friend value_type&& iter_move(Iterator iter) {
-    if (iter.iter_move_invocations_) {
-      ++(*iter.iter_move_invocations_);
-    }
-    return std::move(*iter);
-  }
-
-  friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
-};
-
-} // namespace adl
-
 constexpr bool test() {
   // Can use `iter_move` with a regular array.
   {
@@ -76,13 +37,13 @@ constexpr bool test() {
     assert(iter_move(ri) == 1);
   }
 
-  // Ensure the `iter_move` customization point is being used.
+  // Check that the `iter_move` customization point is being used.
   {
     constexpr int N = 3;
     int a[N] = {0, 1, 2};
 
     int iter_move_invocations = 0;
-    adl::Iterator i(a + N, iter_move_invocations);
+    adl::Iterator i = adl::Iterator::TrackMoves(a + N, iter_move_invocations);
     std::reverse_iterator<adl::Iterator> ri(i);
     int x = iter_move(ri);
     assert(x == 2);

diff  --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_swap.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_swap.pass.cpp
index 3ae27368007a..aaad0eb51e2f 100644
--- a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_swap.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_swap.pass.cpp
@@ -22,47 +22,9 @@
 #include <cassert>
 #include <type_traits>
 #include <utility>
+#include "test_iterators.h"
 #include "test_macros.h"
 
-namespace adl {
-
-struct Iterator {
-  using value_type = int;
-  using 
diff erence_type = ptr
diff _t;
-
-  value_type* ptr_ = nullptr;
-  int* iter_swap_invocations_ = nullptr;
-
-  constexpr Iterator() = default;
-  constexpr explicit Iterator(int& iter_swaps) : iter_swap_invocations_(&iter_swaps) {}
-
-  value_type& operator*() const { return *ptr_; }
-
-  Iterator& operator++() { ++ptr_; return *this; }
-  Iterator operator++(int) {
-    Iterator prev = *this;
-    ++ptr_;
-    return prev;
-  }
-
-  Iterator& operator--() { --ptr_; return *this; }
-  Iterator operator--(int) {
-    Iterator prev = *this;
-    --ptr_;
-    return prev;
-  }
-
-  constexpr friend void iter_swap(Iterator a, Iterator) {
-    if (a.iter_swap_invocations_) {
-      ++(*a.iter_swap_invocations_);
-    }
-  }
-
-  friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
-};
-
-} // namespace adl
-
 constexpr bool test() {
   // Can use `iter_swap` with a regular array.
   {
@@ -80,15 +42,17 @@ constexpr bool test() {
     assert(a[2] == 0);
   }
 
-  // Ensure the `iter_swap` customization point is being used.
+  // Check that the `iter_swap` customization point is being used.
   {
     int iter_swap_invocations = 0;
-    adl::Iterator i1(iter_swap_invocations), i2(iter_swap_invocations);
-    std::reverse_iterator<adl::Iterator> ri1(i1), ri2(i2);
-    iter_swap(i1, i2);
+    int a[] = {0, 1, 2};
+    adl::Iterator base1 = adl::Iterator::TrackSwaps(a + 1, iter_swap_invocations);
+    adl::Iterator base2 = adl::Iterator::TrackSwaps(a + 2, iter_swap_invocations);
+    std::reverse_iterator<adl::Iterator> ri1(base1), ri2(base2);
+    iter_swap(ri1, ri2);
     assert(iter_swap_invocations == 1);
 
-    iter_swap(i2, i1);
+    iter_swap(ri2, ri1);
     assert(iter_swap_invocations == 2);
   }
 

diff  --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.compile.pass.cpp
index 419df883f102..f8c9ce72daa9 100644
--- a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.compile.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.compile.pass.cpp
@@ -82,7 +82,9 @@ struct std::incrementable_traits<FooIter> {
   using 
diff erence_type = char;
 };
 
+// Not using `FooIter::value_type`.
 static_assert(std::is_same_v<typename std::reverse_iterator<FooIter>::value_type, int>);
+// Not using `FooIter::
diff erence_type`.
 static_assert(std::is_same_v<typename std::reverse_iterator<FooIter>::
diff erence_type, char>);
 
 #endif

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_move.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_move.pass.cpp
index 7b648d110a83..39f81a4a5e39 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_move.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_move.pass.cpp
@@ -22,40 +22,40 @@
 namespace adl {
 
 template <bool IsNoexcept = false>
-struct Iterator {
+struct MaybeNoexceptIterator {
   using value_type = int;
   using 
diff erence_type = ptr
diff _t;
 
   value_type* ptr_ = nullptr;
   int* iter_move_invocations_ = nullptr;
 
-  constexpr Iterator() = default;
-  constexpr explicit Iterator(int* p, int& iter_moves) : ptr_(p), iter_move_invocations_(&iter_moves) {}
+  constexpr MaybeNoexceptIterator() = default;
+  constexpr explicit MaybeNoexceptIterator(int* p, int& iter_moves) : ptr_(p), iter_move_invocations_(&iter_moves) {}
 
   constexpr value_type& operator*() const { return *ptr_; }
 
-  Iterator& operator++() { ++ptr_; return *this; }
-  Iterator operator++(int) {
-    Iterator prev = *this;
+  MaybeNoexceptIterator& operator++() { ++ptr_; return *this; }
+  MaybeNoexceptIterator operator++(int) {
+    MaybeNoexceptIterator prev = *this;
     ++ptr_;
     return prev;
   }
 
-  constexpr Iterator& operator--() { --ptr_; return *this; }
-  constexpr Iterator operator--(int) {
-    Iterator prev = *this;
+  constexpr MaybeNoexceptIterator& operator--() { --ptr_; return *this; }
+  constexpr MaybeNoexceptIterator operator--(int) {
+    MaybeNoexceptIterator prev = *this;
     --ptr_;
     return prev;
   }
 
-  constexpr friend value_type&& iter_move(Iterator iter) noexcept(IsNoexcept) {
+  constexpr friend value_type&& iter_move(MaybeNoexceptIterator iter) noexcept(IsNoexcept) {
     if (iter.iter_move_invocations_) {
       ++(*iter.iter_move_invocations_);
     }
     return std::move(*iter);
   }
 
-  friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
+  friend bool operator==(const MaybeNoexceptIterator& lhs, const MaybeNoexceptIterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
 };
 
 template <bool IsNoexcept = false>
@@ -68,8 +68,12 @@ struct View : std::ranges::view_base {
   constexpr View(int& iter_move_invocations) : iter_moves(&iter_move_invocations) {
   }
 
-  constexpr adl::Iterator<IsNoexcept> begin() { return adl::Iterator<IsNoexcept>(a, *iter_moves); }
-  constexpr adl::Iterator<IsNoexcept> end() { return adl::Iterator<IsNoexcept>(a + N, *iter_moves); }
+  constexpr adl::MaybeNoexceptIterator<IsNoexcept> begin() {
+    return adl::MaybeNoexceptIterator<IsNoexcept>(a, *iter_moves);
+  }
+  constexpr adl::MaybeNoexceptIterator<IsNoexcept> end() {
+    return adl::MaybeNoexceptIterator<IsNoexcept>(a + N, *iter_moves);
+  }
 };
 
 } // namespace adl
@@ -134,7 +138,7 @@ constexpr bool test() {
       using ThrowingSplitView = std::ranges::lazy_split_view<adl::View<false>, adl::View<false>>;
       using ThrowingValueType = std::ranges::iterator_t<ThrowingSplitView>::value_type;
       using ThrowingIter = std::ranges::iterator_t<ThrowingValueType>;
-      ASSERT_NOT_NOEXCEPT(std::ranges::iter_move(std::declval<adl::Iterator<false>>()));
+      ASSERT_NOT_NOEXCEPT(std::ranges::iter_move(std::declval<adl::MaybeNoexceptIterator<false>>()));
       ASSERT_NOT_NOEXCEPT(iter_move(std::declval<ThrowingIter>()));
     }
 
@@ -142,7 +146,7 @@ constexpr bool test() {
       using NoexceptSplitView = std::ranges::lazy_split_view<adl::View<true>, adl::View<true>>;
       using NoexceptValueType = std::ranges::iterator_t<NoexceptSplitView>::value_type;
       using NoexceptIter = std::ranges::iterator_t<NoexceptValueType>;
-      ASSERT_NOEXCEPT(std::ranges::iter_move(std::declval<adl::Iterator<true>>()));
+      ASSERT_NOEXCEPT(std::ranges::iter_move(std::declval<adl::MaybeNoexceptIterator<true>>()));
       ASSERT_NOEXCEPT(iter_move(std::declval<NoexceptIter>()));
     }
   }

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_swap.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_swap.pass.cpp
index 52bf8d20fe82..4bcbcafaeab9 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_swap.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_swap.pass.cpp
@@ -23,39 +23,41 @@
 namespace adl {
 
 template <bool IsNoexcept = false>
-struct Iterator {
+struct MaybeNoexceptIterator {
   using value_type = int;
   using 
diff erence_type = ptr
diff _t;
 
   value_type* ptr_ = nullptr;
   int* iter_swap_invocations_ = nullptr;
 
-  constexpr Iterator() = default;
-  constexpr explicit Iterator(int& iter_swaps) : iter_swap_invocations_(&iter_swaps) {}
+  constexpr MaybeNoexceptIterator() = default;
+  constexpr explicit MaybeNoexceptIterator(int& iter_swaps) : iter_swap_invocations_(&iter_swaps) {}
 
   value_type& operator*() const { return *ptr_; }
 
-  Iterator& operator++() { ++ptr_; return *this; }
-  Iterator operator++(int) {
-    Iterator prev = *this;
+  MaybeNoexceptIterator& operator++() { ++ptr_; return *this; }
+  MaybeNoexceptIterator operator++(int) {
+    MaybeNoexceptIterator prev = *this;
     ++ptr_;
     return prev;
   }
 
-  Iterator& operator--() { --ptr_; return *this; }
-  Iterator operator--(int) {
-    Iterator prev = *this;
+  MaybeNoexceptIterator& operator--() { --ptr_; return *this; }
+  MaybeNoexceptIterator operator--(int) {
+    MaybeNoexceptIterator prev = *this;
     --ptr_;
     return prev;
   }
 
-  constexpr friend void iter_swap(Iterator a, Iterator) noexcept(IsNoexcept) {
+  constexpr friend void iter_swap(MaybeNoexceptIterator a, MaybeNoexceptIterator) noexcept(IsNoexcept) {
     if (a.iter_swap_invocations_) {
       ++(*a.iter_swap_invocations_);
     }
   }
 
-  friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
+  friend bool operator==(const MaybeNoexceptIterator& lhs, const MaybeNoexceptIterator& rhs) {
+    return lhs.ptr_ == rhs.ptr_;
+  }
 };
 
 template <bool IsNoexcept = false>
@@ -66,8 +68,12 @@ struct View : std::ranges::view_base {
   constexpr View(int& iter_swap_invocations) : iter_swaps(&iter_swap_invocations) {
   }
 
-  constexpr adl::Iterator<IsNoexcept> begin() { return adl::Iterator<IsNoexcept>(*iter_swaps); }
-  constexpr adl::Iterator<IsNoexcept> end() { return adl::Iterator<IsNoexcept>(*iter_swaps); }
+  constexpr adl::MaybeNoexceptIterator<IsNoexcept> begin() {
+    return adl::MaybeNoexceptIterator<IsNoexcept>(*iter_swaps);
+  }
+  constexpr adl::MaybeNoexceptIterator<IsNoexcept> end() {
+    return adl::MaybeNoexceptIterator<IsNoexcept>(*iter_swaps);
+  }
 };
 
 } // namespace adl
@@ -189,8 +195,9 @@ constexpr bool test() {
       using ThrowingSplitView = std::ranges::lazy_split_view<adl::View<false>, adl::View<false>>;
       using ThrowingValueType = std::ranges::iterator_t<ThrowingSplitView>::value_type;
       using ThrowingIter = std::ranges::iterator_t<ThrowingValueType>;
-      ASSERT_NOT_NOEXCEPT(
-          std::ranges::iter_swap(std::declval<adl::Iterator<false>>(), std::declval<adl::Iterator<false>>()));
+      ASSERT_NOT_NOEXCEPT(std::ranges::iter_swap(
+          std::declval<adl::MaybeNoexceptIterator<false>>(),
+          std::declval<adl::MaybeNoexceptIterator<false>>()));
       ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<ThrowingIter>(), std::declval<ThrowingIter>()));
     }
 
@@ -198,8 +205,9 @@ constexpr bool test() {
       using NoexceptSplitView = std::ranges::lazy_split_view<adl::View<true>, adl::View<true>>;
       using NoexceptValueType = std::ranges::iterator_t<NoexceptSplitView>::value_type;
       using NoexceptIter = std::ranges::iterator_t<NoexceptValueType>;
-      ASSERT_NOEXCEPT(
-          std::ranges::iter_swap(std::declval<adl::Iterator<true>>(), std::declval<adl::Iterator<true>>()));
+      ASSERT_NOEXCEPT(std::ranges::iter_swap(
+          std::declval<adl::MaybeNoexceptIterator<true>>(),
+          std::declval<adl::MaybeNoexceptIterator<true>>()));
       ASSERT_NOEXCEPT(iter_swap(std::declval<NoexceptIter>(), std::declval<NoexceptIter>()));
     }
   }

diff  --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp
index 44317ad9e1bc..c317efca64b2 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp
@@ -41,40 +41,6 @@ struct NotConvertibleFromInt {};
 static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_move), int*, int*, NotConvertibleFromInt*,
                                    NotConvertibleFromInt*>);
 
-namespace adl {
-
-static int iter_move_invocations = 0;
-
-template <class T>
-struct Iterator {
-  using value_type = T;
-  using 
diff erence_type = int;
-  using iterator_concept = std::input_iterator_tag;
-
-  T* ptr = nullptr;
-
-  Iterator() = default;
-  explicit Iterator(int* p) : ptr(p) {}
-
-  T& operator*() const { return *ptr; }
-
-  Iterator& operator++() { ++ptr; return *this; }
-  Iterator operator++(int) {
-    Iterator prev = *this;
-    ++ptr;
-    return prev;
-  }
-
-  friend T&& iter_move(Iterator iter) {
-    ++iter_move_invocations;
-    return std::move(*iter);
-  }
-
-  friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr == rhs.ptr; }
-};
-
-} // namespace adl
-
 int main(int, char**) {
   // An empty range -- no default constructors should be invoked.
   {
@@ -411,17 +377,18 @@ int main(int, char**) {
     constexpr int N = 3;
     int in[N] = {1, 2, 3};
     Buffer<int, N> out;
-    adl::Iterator<int> begin(in);
-    adl::Iterator<int> end(in + N);
+    int iter_moves = 0;
+    adl::Iterator begin = adl::Iterator::TrackMoves(in, iter_moves);
+    adl::Iterator end = adl::Iterator::TrackMoves(in + N, iter_moves);
 
     std::ranges::uninitialized_move(begin, end, out.begin(), out.end());
-    assert(adl::iter_move_invocations == 3);
-    adl::iter_move_invocations = 0;
+    assert(iter_moves == 3);
+    iter_moves = 0;
 
     std::ranges::subrange range(begin, end);
     std::ranges::uninitialized_move(range, out);
-    assert(adl::iter_move_invocations == 3);
-    adl::iter_move_invocations = 0;
+    assert(iter_moves == 3);
+    iter_moves = 0;
   }
 
   return 0;

diff  --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp
index edd0e7811bc8..70a68880e0f4 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp
@@ -24,8 +24,8 @@
 
 #include "../buffer.h"
 #include "../counted.h"
-#include "test_macros.h"
 #include "test_iterators.h"
+#include "test_macros.h"
 
 // TODO(varconst): consolidate the ADL checks into a single file.
 // Because this is a variable and not a function, it's guaranteed that ADL won't be used. However,
@@ -38,40 +38,6 @@ struct NotConvertibleFromInt {};
 static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_move_n), int*, size_t, NotConvertibleFromInt*,
                                    NotConvertibleFromInt*>);
 
-namespace adl {
-
-static int iter_move_invocations = 0;
-
-template <class T>
-struct Iterator {
-  using value_type = T;
-  using 
diff erence_type = int;
-  using iterator_concept = std::input_iterator_tag;
-
-  T* ptr = nullptr;
-
-  Iterator() = default;
-  explicit Iterator(int* p) : ptr(p) {}
-
-  T& operator*() const { return *ptr; }
-
-  Iterator& operator++() { ++ptr; return *this; }
-  Iterator operator++(int) {
-    Iterator prev = *this;
-    ++ptr;
-    return prev;
-  }
-
-  friend T&& iter_move(Iterator iter) {
-    ++iter_move_invocations;
-    return std::move(*iter);
-  }
-
-  friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr == rhs.ptr; }
-};
-
-} // namespace adl
-
 int main(int, char**) {
   // An empty range -- no default constructors should be invoked.
   {
@@ -187,17 +153,18 @@ int main(int, char**) {
     constexpr int N = 3;
     int in[N] = {1, 2, 3};
     Buffer<int, N> out;
-    adl::Iterator<int> begin(in);
-    adl::Iterator<int> end(in + N);
+    int iter_moves = 0;
+    adl::Iterator begin = adl::Iterator::TrackMoves(in, iter_moves);
+    adl::Iterator end = adl::Iterator::TrackMoves(in + N, iter_moves);
 
     std::ranges::uninitialized_move(begin, end, out.begin(), out.end());
-    assert(adl::iter_move_invocations == 3);
-    adl::iter_move_invocations = 0;
+    assert(iter_moves == 3);
+    iter_moves = 0;
 
     std::ranges::subrange range(begin, end);
     std::ranges::uninitialized_move(range, out);
-    assert(adl::iter_move_invocations == 3);
-    adl::iter_move_invocations = 0;
+    assert(iter_moves == 3);
+    iter_moves = 0;
   }
 
   return 0;

diff  --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h
index 9377b5fc5609..6d3a8e2699ed 100644
--- a/libcxx/test/support/test_iterators.h
+++ b/libcxx/test/support/test_iterators.h
@@ -721,6 +721,77 @@ class sized_sentinel {
 private:
     decltype(base(std::declval<It>())) base_;
 };
+
+namespace adl {
+
+class Iterator {
+ public:
+  using value_type = int;
+  using 
diff erence_type = ptr
diff _t;
+
+ private:
+  value_type* ptr_ = nullptr;
+  int* iter_moves_ = nullptr;
+  int* iter_swaps_ = nullptr;
+
+  constexpr Iterator(int* p, int* iter_moves, int* iter_swaps)
+    : ptr_(p)
+    , iter_moves_(iter_moves)
+    , iter_swaps_(iter_swaps) {}
+
+ public:
+  constexpr Iterator() = default;
+  static constexpr Iterator TrackMoves(int* p, int& iter_moves) {
+    return Iterator(p, &iter_moves, /*iter_swaps=*/nullptr);
+  }
+  static constexpr Iterator TrackSwaps(int& iter_swaps) {
+    return Iterator(/*p=*/nullptr, /*iter_moves=*/nullptr, &iter_swaps);
+  }
+  static constexpr Iterator TrackSwaps(int* p, int& iter_swaps) {
+    return Iterator(p, /*iter_moves=*/nullptr, &iter_swaps);
+  }
+
+  constexpr int iter_moves() const { assert(iter_moves_); return *iter_moves_; }
+  constexpr int iter_swaps() const { assert(iter_swaps_); return *iter_swaps_; }
+
+  constexpr value_type& operator*() const { return *ptr_; }
+
+  constexpr Iterator operator+(
diff erence_type n) const {
+    return Iterator(ptr_ + n, iter_moves_, iter_swaps_);
+  }
+
+  constexpr Iterator& operator++() { ++ptr_; return *this; }
+  constexpr Iterator operator++(int) {
+    Iterator prev = *this;
+    ++ptr_;
+    return prev;
+  }
+
+  constexpr Iterator& operator--() { --ptr_; return *this; }
+  constexpr Iterator operator--(int) {
+    Iterator prev = *this;
+    --ptr_;
+    return prev;
+  }
+
+  constexpr friend void iter_swap(Iterator a, Iterator) {
+    if (a.iter_swaps_) {
+      ++(*a.iter_swaps_);
+    }
+  }
+
+  constexpr friend value_type&& iter_move(Iterator iter) {
+    if (iter.iter_moves_) {
+      ++(*iter.iter_moves_);
+    }
+    return std::move(*iter);
+  }
+
+  constexpr friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
+};
+
+} // namespace adl
+
 #endif // TEST_STD_VER > 17
 
 #endif // SUPPORT_TEST_ITERATORS_H


        


More information about the libcxx-commits mailing list