[libcxx-commits] [libcxx] f73050e - [libc++] Fix several double-moves in the code base (#104616)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Aug 20 11:36:14 PDT 2024


Author: Louis Dionne
Date: 2024-08-20T14:36:11-04:00
New Revision: f73050e722dd2e484358d03674eb186f3a2f4799

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

LOG: [libc++] Fix several double-moves in the code base (#104616)

This patch hardens the "test iterators" we use to test algorithms by
ensuring that they don't get double-moved. As a result of this
hardening, the tests started reporting multiple failures where we would
double-move iterators, which are being fixed in this patch.

In particular:
- Fixed a double-move in pstl.partition
- Add coverage for begin()/end() in subrange tests
- Fix tests for ranges::ends_with and ranges::contains, which were
  incorrectly calling begin() twice on the same subrange containing
  non-copyable input iterators.

Fixes #100709

Added: 
    libcxx/test/std/ranges/range.utility/range.subrange/begin_end.pass.cpp
    libcxx/test/support/double_move_tracker.h

Modified: 
    libcxx/include/__algorithm/partition.h
    libcxx/include/__pstl/backends/default.h
    libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/partition.pass.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.contains/ranges.contains.pass.cpp
    libcxx/test/std/algorithms/alg.nonmodifying/alg.ends_with/ranges.ends_with.pass.cpp
    libcxx/test/std/containers/associative/from_range_associative_containers.h
    libcxx/test/std/containers/container.adaptors/from_range_container_adaptors.h
    libcxx/test/std/containers/sequences/from_range_sequence_containers.h
    libcxx/test/std/containers/unord/from_range_unordered_containers.h
    libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/iterator_sentinel.pass.cpp
    libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/range.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.elements/iterator/increment.pass.cpp
    libcxx/test/std/ranges/range.adaptors/range.split/begin.pass.cpp
    libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp
    libcxx/test/std/utilities/format/format.range/format.range.formatter/format.functions.tests.h
    libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp
    libcxx/test/support/test_iterators.h

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__algorithm/partition.h b/libcxx/include/__algorithm/partition.h
index 824e49b9ec2149..bd0dccfaf92abe 100644
--- a/libcxx/include/__algorithm/partition.h
+++ b/libcxx/include/__algorithm/partition.h
@@ -29,7 +29,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_ForwardIterator, _Forw
 __partition_impl(_ForwardIterator __first, _Sentinel __last, _Predicate __pred, forward_iterator_tag) {
   while (true) {
     if (__first == __last)
-      return std::make_pair(std::move(__first), std::move(__first));
+      return std::make_pair(__first, __first);
     if (!__pred(*__first))
       break;
     ++__first;

diff  --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index 61a128805f8549..b655da51fe340b 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -163,7 +163,7 @@ struct __is_partitioned<__default_backend_tag, _ExecutionPolicy> {
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
   operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred) const noexcept {
     using _FindIfNot   = __dispatch<__find_if_not, __current_configuration, _ExecutionPolicy>;
-    auto __maybe_first = _FindIfNot()(__policy, std::move(__first), std::move(__last), __pred);
+    auto __maybe_first = _FindIfNot()(__policy, std::move(__first), __last, __pred);
     if (__maybe_first == nullopt)
       return nullopt;
 

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/partition.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/partition.pass.cpp
index 3eaeaa432c490f..87beba183a2842 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/partition.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/partition.pass.cpp
@@ -98,11 +98,13 @@ test()
 
 int main(int, char**)
 {
+    test<forward_iterator<int*> >();
     test<bidirectional_iterator<int*> >();
     test<random_access_iterator<int*> >();
     test<int*>();
 
 #if TEST_STD_VER >= 20
+    static_assert(test<forward_iterator<int*>>());
     static_assert(test<bidirectional_iterator<int*>>());
     static_assert(test<random_access_iterator<int*>>());
     static_assert(test<int*>());

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.contains/ranges.contains.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.contains/ranges.contains.pass.cpp
index f710ca2c319dd6..08d8e119a4d24b 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.contains/ranges.contains.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.contains/ranges.contains.pass.cpp
@@ -65,12 +65,12 @@ constexpr void test_iterators() {
   using ValueT = std::iter_value_t<Iter>;
   { // simple tests
     ValueT a[] = {1, 2, 3, 4, 5, 6};
-    auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 6)));
     {
-      std::same_as<bool> decltype(auto) ret = std::ranges::contains(whole.begin(), whole.end(), 3);
+      std::same_as<bool> decltype(auto) ret = std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3);
       assert(ret);
     }
     {
+      auto whole                            = std::ranges::subrange(Iter(a), Sent(Iter(a + 6)));
       std::same_as<bool> decltype(auto) ret = std::ranges::contains(whole, 3);
       assert(ret);
     }
@@ -78,65 +78,65 @@ constexpr void test_iterators() {
 
   { // check that a range with a single element works
     ValueT a[] = {32};
-    auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 1)));
     {
-      bool ret = std::ranges::contains(whole.begin(), whole.end(), 32);
+      bool ret = std::ranges::contains(Iter(a), Sent(Iter(a + 1)), 32);
       assert(ret);
     }
     {
-      bool ret = std::ranges::contains(whole, 32);
+      auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 1)));
+      bool ret   = std::ranges::contains(whole, 32);
       assert(ret);
     }
   }
 
   { // check that an empty range works
     std::array<ValueT, 0> a = {};
-    auto whole              = std::ranges::subrange(Iter(a.data()), Sent(Iter(a.data())));
     {
-      bool ret = std::ranges::contains(whole.begin(), whole.end(), 1);
+      bool ret = std::ranges::contains(Iter(a.data()), Sent(Iter(a.data())), 1);
       assert(!ret);
     }
     {
-      bool ret = std::ranges::contains(whole, 1);
+      auto whole = std::ranges::subrange(Iter(a.data()), Sent(Iter(a.data())));
+      bool ret   = std::ranges::contains(whole, 1);
       assert(!ret);
     }
   }
 
   { // check that the first element matches
     ValueT a[] = {32, 3, 2, 1, 0, 23, 21, 9, 40, 100};
-    auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 10)));
     {
-      bool ret = std::ranges::contains(whole.begin(), whole.end(), 32);
+      bool ret = std::ranges::contains(Iter(a), Sent(Iter(a + 10)), 32);
       assert(ret);
     }
     {
-      bool ret = std::ranges::contains(whole, 32);
+      auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 10)));
+      bool ret   = std::ranges::contains(whole, 32);
       assert(ret);
     }
   }
 
   { // check that the last element matches
     ValueT a[] = {3, 22, 1, 43, 99, 0, 56, 100, 32};
-    auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 9)));
     {
-      bool ret = std::ranges::contains(whole.begin(), whole.end(), 32);
+      bool ret = std::ranges::contains(Iter(a), Sent(Iter(a + 9)), 32);
       assert(ret);
     }
     {
-      bool ret = std::ranges::contains(whole, 32);
+      auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 9)));
+      bool ret   = std::ranges::contains(whole, 32);
       assert(ret);
     }
   }
 
   { // no match
     ValueT a[] = {13, 1, 21, 4, 5};
-    auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 5)));
     {
-      bool ret = std::ranges::contains(whole.begin(), whole.end(), 10);
+      bool ret = std::ranges::contains(Iter(a), Sent(Iter(a + 5)), 10);
       assert(!ret);
     }
     {
-      bool ret = std::ranges::contains(whole, 10);
+      auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 5)));
+      bool ret   = std::ranges::contains(whole, 10);
       assert(!ret);
     }
   }

diff  --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.ends_with/ranges.ends_with.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.ends_with/ranges.ends_with.pass.cpp
index 685bd692422ac8..199e6a786e5ba3 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.ends_with/ranges.ends_with.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.ends_with/ranges.ends_with.pass.cpp
@@ -49,7 +49,8 @@ static_assert(!HasEndsWithIt<int*, int*, int*, SentinelForNotWeaklyEqualityCompa
 
 template <class Range1, class Range2 = UncheckedRange<int*>>
 concept HasEndsWithR = requires(Range1&& range1, Range2&& range2) {
-    std::ranges::ends_with(std::forward<Range1>(range1), std::forward<Range2>(range2)); };
+  std::ranges::ends_with(std::forward<Range1>(range1), std::forward<Range2>(range2));
+};
 
 static_assert(HasEndsWithR<UncheckedRange<int*>>);
 static_assert(!HasEndsWithR<ForwardRangeNotDerivedFrom>);
@@ -61,19 +62,21 @@ static_assert(!HasEndsWithR<UncheckedRange<int*>, UncheckedRange<int**>>); // no
 static_assert(!HasEndsWithR<UncheckedRange<int*>, ForwardRangeNotDerivedFrom>);
 static_assert(!HasEndsWithR<UncheckedRange<int*>, ForwardRangeNotSentinelSemiregular>);
 
-// clang-format off
 template <class Iter1, class Sent1 = Iter1, class Iter2, class Sent2 = Iter2>
 constexpr void test_iterators() {
   { // simple tests
-    int a[]          = {1, 2, 3, 4, 5, 6};
-    int p[]          = {4, 5, 6};
-    auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
-    auto suffix  = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3)));
+    int a[] = {1, 2, 3, 4, 5, 6};
+    int p[] = {4, 5, 6};
     {
-      [[maybe_unused]] std::same_as<bool> decltype(auto) ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3)));
+      [[maybe_unused]] std::same_as<bool> decltype(auto) ret =
+          std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
       assert(ret);
     }
     {
+      auto whole                                             = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
+      auto suffix                                            = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3)));
       [[maybe_unused]] std::same_as<bool> decltype(auto) ret = std::ranges::ends_with(whole, suffix);
       assert(ret);
     }
@@ -82,14 +85,16 @@ constexpr void test_iterators() {
   { // suffix doesn't match
     int a[] = {1, 2, 3, 4, 5, 6};
     int p[] = {1, 2, 3};
-    auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
-    auto suffix  = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3)));
     {
-      bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3)));
+      bool ret    = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
       assert(!ret);
     }
     {
-      bool ret = std::ranges::ends_with(whole, suffix);
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3)));
+      bool ret    = std::ranges::ends_with(whole, suffix);
       assert(!ret);
     }
   }
@@ -97,14 +102,16 @@ constexpr void test_iterators() {
   { // range consists of just one element
     int a[] = {1};
     int p[] = {1};
-    auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 1)));
-    auto suffix  = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1)));
     {
-      bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 1)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1)));
+      bool ret    = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
       assert(ret);
     }
     {
-      bool ret = std::ranges::ends_with(whole, suffix);
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 1)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1)));
+      bool ret    = std::ranges::ends_with(whole, suffix);
       assert(ret);
     }
   }
@@ -112,14 +119,16 @@ constexpr void test_iterators() {
   { // suffix consists of just one element
     int a[] = {5, 1, 2, 4, 3};
     int p[] = {3};
-    auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5)));
-    auto suffix  = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1)));
     {
-      bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1)));
+      bool ret    = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
       assert(ret);
     }
     {
-      bool ret = std::ranges::ends_with(whole, suffix);
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1)));
+      bool ret    = std::ranges::ends_with(whole, suffix);
       assert(ret);
     }
   }
@@ -127,14 +136,16 @@ constexpr void test_iterators() {
   { // range and suffix are identical
     int a[] = {1, 2, 3, 4, 5, 6};
     int p[] = {1, 2, 3, 4, 5, 6};
-    auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
-    auto suffix  = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 6)));
     {
-      bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 6)));
+      bool ret    = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
       assert(ret);
     }
     {
-      bool ret = std::ranges::ends_with(whole, suffix);
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 6)));
+      bool ret    = std::ranges::ends_with(whole, suffix);
       assert(ret);
     }
   }
@@ -142,111 +153,128 @@ constexpr void test_iterators() {
   { // suffix is longer than range
     int a[] = {3, 4, 5, 6, 7, 8};
     int p[] = {1, 2, 3, 4, 5, 6, 7, 8};
-    auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
-    auto suffix  = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8)));
     {
-      bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8)));
+      bool ret    = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
       assert(!ret);
     }
     {
-      bool ret = std::ranges::ends_with(whole, suffix);
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8)));
+      bool ret    = std::ranges::ends_with(whole, suffix);
       assert(!ret);
     }
- }
+  }
 
- { // suffix has zero length
-   int a[] = {1, 2, 3, 4, 5, 6};
-   std::array<int, 0> p = {};
-   auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
-   auto suffix  = std::ranges::subrange(Iter2(p.data()), Sent2(Iter2(p.data())));
-   {
-     bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
-     assert(ret);
-   }
-   {
-     bool ret = std::ranges::ends_with(whole, suffix);
-     assert(ret);
-   }
- }
+  { // suffix has zero length
+    int a[]              = {1, 2, 3, 4, 5, 6};
+    std::array<int, 0> p = {};
+    {
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
+      auto suffix = std::ranges::subrange(Iter2(p.data()), Sent2(Iter2(p.data())));
+      bool ret    = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
+      assert(ret);
+    }
+    {
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
+      auto suffix = std::ranges::subrange(Iter2(p.data()), Sent2(Iter2(p.data())));
+      bool ret    = std::ranges::ends_with(whole, suffix);
+      assert(ret);
+    }
+  }
 
- { // range has zero length
-   std::array<int, 0> a = {};
-   int p[] = {1, 2, 3, 4, 5, 6, 7, 8};
-   auto whole = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data())));
-   auto suffix  = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8)));
-   {
-     bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
-     assert(!ret);
-   }
-   {
-     bool ret = std::ranges::ends_with(whole, suffix);
-     assert(!ret);
-   }
- }
+  { // range has zero length
+    std::array<int, 0> a = {};
+    int p[]              = {1, 2, 3, 4, 5, 6, 7, 8};
+    {
+      auto whole  = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data())));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8)));
+      bool ret    = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
+      assert(!ret);
+    }
+    {
+      auto whole  = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data())));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8)));
+      bool ret    = std::ranges::ends_with(whole, suffix);
+      assert(!ret);
+    }
+  }
 
- { // subarray
-   int a[] = {0, 3, 5, 10, 7, 3, 5, 89, 3, 5, 2, 1, 8, 6};
-   int p[] = {3, 5};
-   auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 13)));
-   auto suffix  = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2)));
-   {
-     bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
-     assert(!ret);
-   }
-   {
-     bool ret = std::ranges::ends_with(whole, suffix);
-     assert(!ret);
-   }
- }
+  { // subarray
+    int a[] = {0, 3, 5, 10, 7, 3, 5, 89, 3, 5, 2, 1, 8, 6};
+    int p[] = {3, 5};
+    {
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 13)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2)));
+      bool ret    = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
+      assert(!ret);
+    }
+    {
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 13)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2)));
+      bool ret    = std::ranges::ends_with(whole, suffix);
+      assert(!ret);
+    }
+  }
 
- { // repeated suffix
-   int a[] = {8, 6, 3, 5, 1, 2};
-   int p[] = {1, 2, 1, 2};
-   auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
-   auto suffix  = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 4)));
-   {
-     bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
-     assert(!ret);
-   }
-   {
-     bool ret = std::ranges::ends_with(whole, suffix);
-     assert(!ret);
-   }
- }
+  { // repeated suffix
+    int a[] = {8, 6, 3, 5, 1, 2};
+    int p[] = {1, 2, 1, 2};
+    {
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 4)));
+      bool ret    = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end());
+      assert(!ret);
+    }
+    {
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 4)));
+      bool ret    = std::ranges::ends_with(whole, suffix);
+      assert(!ret);
+    }
+  }
 
- { // check that the predicate is used
-   int a[] = {5, 1, 3, 2, 7};
-   int p[] = {-2, -7};
-   auto pred = [](int l, int r) { return l * -1 == r; };
-   auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5)));
-   auto suffix  = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2)));
-   {
-     bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end(), pred);
-     assert(ret);
-   }
-   {
-     bool ret = std::ranges::ends_with(whole, suffix, pred);
-     assert(ret);
-   }
- }
+  { // check that the predicate is used
+    int a[]   = {5, 1, 3, 2, 7};
+    int p[]   = {-2, -7};
+    auto pred = [](int l, int r) { return l * -1 == r; };
+    {
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2)));
+      bool ret    = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end(), pred);
+      assert(ret);
+    }
+    {
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2)));
+      bool ret    = std::ranges::ends_with(whole, suffix, pred);
+      assert(ret);
+    }
+  }
 
- { // check that the projections are used
-   int a[] = {1, 3, 15, 1, 2, 1};
-   int p[] = {2, 1, 2};
-   auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
-   auto suffix  = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3)));
-   {
-     bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end(), {},
-         [](int i) { return i - 3; },
-         [](int i) { return i * -1; });
-     assert(ret);
-   }
-   {
-     bool ret = std::ranges::ends_with(whole, suffix, {},
-         [](int i) { return i - 3; },
-         [](int i) { return i * -1; });
-     assert(ret);
-   }
+  { // check that the projections are used
+    int a[] = {1, 3, 15, 1, 2, 1};
+    int p[] = {2, 1, 2};
+    {
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3)));
+      bool ret    = std::ranges::ends_with(
+          whole.begin(),
+          whole.end(),
+          suffix.begin(),
+          suffix.end(),
+          {},
+          [](int i) { return i - 3; },
+          [](int i) { return i * -1; });
+      assert(ret);
+    }
+    {
+      auto whole  = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6)));
+      auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3)));
+      bool ret = std::ranges::ends_with(whole, suffix, {}, [](int i) { return i - 3; }, [](int i) { return i * -1; });
+      assert(ret);
+    }
   }
 }
 

diff  --git a/libcxx/test/std/containers/associative/from_range_associative_containers.h b/libcxx/test/std/containers/associative/from_range_associative_containers.h
index 6d2d6e6874aaa2..d227c41f6d84a8 100644
--- a/libcxx/test/std/containers/associative/from_range_associative_containers.h
+++ b/libcxx/test/std/containers/associative/from_range_associative_containers.h
@@ -59,9 +59,8 @@ template <template <class ...> class Container,
           class Alloc,
           class ValueType = std::pair<const K, V>>
 void test_associative_map_with_input(std::vector<ValueType>&& input) {
-  auto in = wrap_input<Iter, Sent>(input);
-
   { // (range)
+    auto in = wrap_input<Iter, Sent>(input);
     Container<K, V> c(std::from_range, in);
 
     assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
@@ -69,6 +68,7 @@ void test_associative_map_with_input(std::vector<ValueType>&& input) {
   }
 
   { // (range, comp)
+    auto in = wrap_input<Iter, Sent>(input);
     Comp comp;
     Container<K, V, Comp> c(std::from_range, in, comp);
 
@@ -78,6 +78,7 @@ void test_associative_map_with_input(std::vector<ValueType>&& input) {
   }
 
   { // (range, allocator)
+    auto in = wrap_input<Iter, Sent>(input);
     Alloc alloc;
     Container<K, V, std::less<K>, Alloc> c(std::from_range, in, alloc);
 
@@ -87,6 +88,7 @@ void test_associative_map_with_input(std::vector<ValueType>&& input) {
   }
 
   { // (range, comp, allocator)
+    auto in = wrap_input<Iter, Sent>(input);
     Comp comp;
     Alloc alloc;
     Container<K, V, Comp, Alloc> c(std::from_range, in, comp, alloc);
@@ -199,11 +201,8 @@ template <template <class ...> class Container,
           class Comp,
           class Alloc>
 void test_associative_set_with_input(std::vector<T>&& input) {
-  auto b = Iter(input.data());
-  auto e = Iter(input.data() + input.size());
-  std::ranges::subrange in(std::move(b), Sent(std::move(e)));
-
   { // (range)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     Container<T> c(std::from_range, in);
 
     assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
@@ -211,6 +210,7 @@ void test_associative_set_with_input(std::vector<T>&& input) {
   }
 
   { // (range, comp)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     Comp comp;
     Container<T, Comp> c(std::from_range, in, comp);
 
@@ -220,6 +220,7 @@ void test_associative_set_with_input(std::vector<T>&& input) {
   }
 
   { // (range, allocator)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     Alloc alloc;
     Container<T, std::less<T>, Alloc> c(std::from_range, in, alloc);
 
@@ -229,6 +230,7 @@ void test_associative_set_with_input(std::vector<T>&& input) {
   }
 
   { // (range, comp, allocator)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     Comp comp;
     Alloc alloc;
     Container<T, Comp, Alloc> c(std::from_range, in, comp, alloc);

diff  --git a/libcxx/test/std/containers/container.adaptors/from_range_container_adaptors.h b/libcxx/test/std/containers/container.adaptors/from_range_container_adaptors.h
index 8bd3ac632cfc95..1bb34fb5425221 100644
--- a/libcxx/test/std/containers/container.adaptors/from_range_container_adaptors.h
+++ b/libcxx/test/std/containers/container.adaptors/from_range_container_adaptors.h
@@ -54,21 +54,19 @@ template <template <class ...> class Adaptor,
           class Sent,
           class Alloc>
 constexpr void test_container_adaptor_with_input(std::vector<T>&& input) {
-  auto b = Iter(input.data());
-  auto e = Iter(input.data() + input.size());
-  std::ranges::subrange in(std::move(b), Sent(std::move(e)));
-
   { // (range)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     Adaptor<T> adaptor(std::from_range, in);
     UnwrapAdaptor<Adaptor<T>> unwrap_adaptor(std::move(adaptor));
     auto& c = unwrap_adaptor.get_container();
 
     assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
-    assert(std::ranges::equal(in, c));
+    assert(std::ranges::equal(input, c));
     LIBCPP_ASSERT(c.__invariants());
   }
 
   { // (range, allocator)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     using C = UnderlyingContainer<T, Alloc>;
     Alloc alloc;
     Adaptor<T, C> adaptor(std::from_range, in, alloc);
@@ -77,7 +75,7 @@ constexpr void test_container_adaptor_with_input(std::vector<T>&& input) {
 
     assert(c.get_allocator() == alloc);
     assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
-    assert(std::ranges::equal(in, c));
+    assert(std::ranges::equal(input, c));
     LIBCPP_ASSERT(c.__invariants());
   }
 }
@@ -89,11 +87,8 @@ template <template <class ...> class UnderlyingContainer,
           class Comp,
           class Alloc>
 constexpr void test_priority_queue_with_input(std::vector<T>&& input) {
-  auto b = Iter(input.data());
-  auto e = Iter(input.data() + input.size());
-  std::ranges::subrange in(std::move(b), Sent(std::move(e)));
-
   { // (range)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     std::priority_queue<T> adaptor(std::from_range, in);
     UnwrapAdaptor<std::priority_queue<T>> unwrap_adaptor(std::move(adaptor));
     auto& c = unwrap_adaptor.get_container();
@@ -104,6 +99,7 @@ constexpr void test_priority_queue_with_input(std::vector<T>&& input) {
   }
 
   { // (range, comp)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     using C = UnderlyingContainer<T>;
     Comp comp;
 
@@ -118,6 +114,7 @@ constexpr void test_priority_queue_with_input(std::vector<T>&& input) {
   }
 
   { // (range, allocator)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     using C = UnderlyingContainer<T, Alloc>;
     Alloc alloc;
 
@@ -132,6 +129,7 @@ constexpr void test_priority_queue_with_input(std::vector<T>&& input) {
   }
 
   { // (range, comp, alloc)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     using C = UnderlyingContainer<T, Alloc>;
     Comp comp;
     Alloc alloc;

diff  --git a/libcxx/test/std/containers/sequences/from_range_sequence_containers.h b/libcxx/test/std/containers/sequences/from_range_sequence_containers.h
index 859b9c535f7ba3..df66bc91808078 100644
--- a/libcxx/test/std/containers/sequences/from_range_sequence_containers.h
+++ b/libcxx/test/std/containers/sequences/from_range_sequence_containers.h
@@ -61,19 +61,19 @@ template <template <class ...> class Container,
           std::size_t N,
           class ValidateFunc>
 constexpr void test_sequence_container_with_input(std::array<T, N>&& input, ValidateFunc validate) {
-  auto in = wrap_input<Iter, Sent>(input);
-
   { // (range)
+    auto in = wrap_input<Iter, Sent>(input);
     Container<T> c(std::from_range, in);
 
     if constexpr (HasSize<Container<T>>) {
       assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
     }
-    assert(std::ranges::equal(in, c));
+    assert(std::ranges::equal(input, c));
     validate(c);
   }
 
   { // (range, allocator)
+    auto in = wrap_input<Iter, Sent>(input);
     Alloc alloc;
     Container<T, Alloc> c(std::from_range, in, alloc);
 
@@ -81,7 +81,7 @@ constexpr void test_sequence_container_with_input(std::array<T, N>&& input, Vali
     if constexpr (HasSize<Container<T, Alloc>>) {
       assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
     }
-    assert(std::ranges::equal(in, c));
+    assert(std::ranges::equal(input, c));
     validate(c);
   }
 }

diff  --git a/libcxx/test/std/containers/unord/from_range_unordered_containers.h b/libcxx/test/std/containers/unord/from_range_unordered_containers.h
index 763dd3e423f320..7eb2a07e499c71 100644
--- a/libcxx/test/std/containers/unord/from_range_unordered_containers.h
+++ b/libcxx/test/std/containers/unord/from_range_unordered_containers.h
@@ -99,9 +99,8 @@ void test_unordered_map_with_input(std::vector<ValueType>&& input) {
     assert(c.max_load_factor() == 1);
   };
 
-  auto in = wrap_input<Iter, Sent>(input);
-
   { // (range)
+    auto in = wrap_input<Iter, Sent>(input);
     Container<K, V> c(std::from_range, in);
 
     assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
@@ -110,6 +109,7 @@ void test_unordered_map_with_input(std::vector<ValueType>&& input) {
   }
 
   { // (range, n)
+    auto in = wrap_input<Iter, Sent>(input);
     Container<K, V> c(std::from_range, in, 123);
 
     assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
@@ -118,6 +118,7 @@ void test_unordered_map_with_input(std::vector<ValueType>&& input) {
   }
 
   { // (range, n, hasher)
+    auto in = wrap_input<Iter, Sent>(input);
     Container<K, V, Hash> c(std::from_range, in, 123, Hash());
 
     assert(c.hash_function() == Hash());
@@ -127,6 +128,7 @@ void test_unordered_map_with_input(std::vector<ValueType>&& input) {
   }
 
   { // (range, n, hasher, key_equal)
+    auto in = wrap_input<Iter, Sent>(input);
     Container<K, V, Hash, Equal> c(std::from_range, in, 123, Hash(), Equal());
 
     assert(c.hash_function() == Hash());
@@ -137,6 +139,7 @@ void test_unordered_map_with_input(std::vector<ValueType>&& input) {
   }
 
   { // (range, n, hasher, key_equal, allocator)
+    auto in = wrap_input<Iter, Sent>(input);
     Alloc alloc;
     Container<K, V, Hash, Equal, Alloc> c(std::from_range, in, 123, Hash(), Equal(), alloc);
 
@@ -149,6 +152,7 @@ void test_unordered_map_with_input(std::vector<ValueType>&& input) {
   }
 
   { // (range, n, allocator)
+    auto in = wrap_input<Iter, Sent>(input);
     Alloc alloc;
     Container<K, V, DefaultHash, DefaultEqual, Alloc> c(std::from_range, in, 123, alloc);
 
@@ -159,6 +163,7 @@ void test_unordered_map_with_input(std::vector<ValueType>&& input) {
   }
 
   { // (range, n, hasher, allocator)
+    auto in = wrap_input<Iter, Sent>(input);
     Alloc alloc;
     Container<K, V, Hash, DefaultEqual, Alloc> c(std::from_range, in, 123, Hash(), alloc);
 
@@ -297,11 +302,8 @@ void test_unordered_set_with_input(std::vector<T>&& input) {
     assert(c.max_load_factor() == 1);
   };
 
-  auto b = Iter(input.data());
-  auto e = Iter(input.data() + input.size());
-  std::ranges::subrange in(std::move(b), Sent(std::move(e)));
-
   { // (range)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     Container<T> c(std::from_range, in);
 
     assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
@@ -310,6 +312,7 @@ void test_unordered_set_with_input(std::vector<T>&& input) {
   }
 
   { // (range, n)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     Container<T> c(std::from_range, in, 123);
 
     assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
@@ -318,6 +321,7 @@ void test_unordered_set_with_input(std::vector<T>&& input) {
   }
 
   { // (range, n, hasher)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     Container<T, Hash> c(std::from_range, in, 123, Hash());
 
     assert(c.hash_function() == Hash());
@@ -327,6 +331,7 @@ void test_unordered_set_with_input(std::vector<T>&& input) {
   }
 
   { // (range, n, hasher, key_equal)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     Container<T, Hash, Equal> c(std::from_range, in, 123, Hash(), Equal());
 
     assert(c.hash_function() == Hash());
@@ -337,6 +342,7 @@ void test_unordered_set_with_input(std::vector<T>&& input) {
   }
 
   { // (range, n, hasher, key_equal, allocator)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     Alloc alloc;
     Container<T, Hash, Equal, Alloc> c(std::from_range, in, 123, Hash(), Equal(), alloc);
 
@@ -349,6 +355,7 @@ void test_unordered_set_with_input(std::vector<T>&& input) {
   }
 
   { // (range, n, allocator)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     Alloc alloc;
     Container<T, DefaultHash, DefaultEqual, Alloc> c(std::from_range, in, 123, alloc);
 
@@ -359,6 +366,7 @@ void test_unordered_set_with_input(std::vector<T>&& input) {
   }
 
   { // (range, n, hasher, allocator)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     Alloc alloc;
     Container<T, Hash, DefaultEqual, Alloc> c(std::from_range, in, 123, Hash(), alloc);
 

diff  --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/iterator_sentinel.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/iterator_sentinel.pass.cpp
index aa63f3ff3b6f68..b4199b73ad76a5 100644
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/iterator_sentinel.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/iterator_sentinel.pass.cpp
@@ -35,27 +35,29 @@ constexpr void test_unsized() {
     ASSERT_SAME_TYPE(decltype(std::ranges::distance(It(a), Sent(It(a)))), std::iter_
diff erence_t<It>);
   }
   {
-    It first = It(a);
-    auto last = Sent(It(a + 3));
-    assert(std::ranges::distance(first, last) == 3);
+    auto check = [&a]<class ItQual, class SentQual> {
+      It first = It(a);
+      Sent last = Sent(It(a + 3));
+      assert(std::ranges::distance(static_cast<ItQual>(first), static_cast<SentQual>(last)) == 3);
+    };
 
     // Test all const/ref-qualifications of both operands.
-    assert(std::ranges::distance(static_cast<It&>(first), static_cast<Sent&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<It&>(first), static_cast<Sent&&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<It&>(first), static_cast<const Sent&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<It&>(first), static_cast<const Sent&&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<It&&>(first), static_cast<Sent&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<It&&>(first), static_cast<Sent&&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<It&&>(first), static_cast<const Sent&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<It&&>(first), static_cast<const Sent&&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<const It&>(first), static_cast<Sent&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<const It&>(first), static_cast<Sent&&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<const It&>(first), static_cast<const Sent&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<const It&>(first), static_cast<const Sent&&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<const It&&>(first), static_cast<Sent&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<const It&&>(first), static_cast<Sent&&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<const It&&>(first), static_cast<const Sent&>(last)) == 3);
-    assert(std::ranges::distance(static_cast<const It&&>(first), static_cast<const Sent&&>(last)) == 3);
+    check.template operator()<It&, Sent&>();
+    check.template operator()<It&, Sent&&>();
+    check.template operator()<It&, const Sent&>();
+    check.template operator()<It&, const Sent&&>();
+    check.template operator()<It&&, Sent&>();
+    check.template operator()<It&&, Sent&&>();
+    check.template operator()<It&&, const Sent&>();
+    check.template operator()<It&&, const Sent&&>();
+    check.template operator()<const It&, Sent&>();
+    check.template operator()<const It&, Sent&&>();
+    check.template operator()<const It&, const Sent&>();
+    check.template operator()<const It&, const Sent&&>();
+    check.template operator()<const It&&, Sent&>();
+    check.template operator()<const It&&, Sent&&>();
+    check.template operator()<const It&&, const Sent&>();
+    check.template operator()<const It&&, const Sent&&>();
   }
 }
 
@@ -64,27 +66,29 @@ constexpr void test_sized() {
   static_assert(std::sized_sentinel_for<Sent, It>);
   int a[] = {1,2,3};
   {
-    It first = It(a + 3);
-    auto last = Sent(It(a));
-    assert(std::ranges::distance(first, last) == -3);
+    auto check = [&a]<class ItQual, class SentQual> {
+      It first = It(a + 3);
+      Sent last = Sent(It(a));
+      assert(std::ranges::distance(static_cast<ItQual>(first), static_cast<SentQual>(last)) == -3);
+    };
 
     // Test all const/ref-qualifications of both operands.
-    assert(std::ranges::distance(static_cast<It&>(first), static_cast<Sent&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<It&>(first), static_cast<Sent&&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<It&>(first), static_cast<const Sent&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<It&>(first), static_cast<const Sent&&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<It&&>(first), static_cast<Sent&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<It&&>(first), static_cast<Sent&&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<It&&>(first), static_cast<const Sent&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<It&&>(first), static_cast<const Sent&&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<const It&>(first), static_cast<Sent&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<const It&>(first), static_cast<Sent&&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<const It&>(first), static_cast<const Sent&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<const It&>(first), static_cast<const Sent&&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<const It&&>(first), static_cast<Sent&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<const It&&>(first), static_cast<Sent&&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<const It&&>(first), static_cast<const Sent&>(last)) == -3);
-    assert(std::ranges::distance(static_cast<const It&&>(first), static_cast<const Sent&&>(last)) == -3);
+    check.template operator()<It&, Sent&>();
+    check.template operator()<It&, Sent&&>();
+    check.template operator()<It&, const Sent&>();
+    check.template operator()<It&, const Sent&&>();
+    check.template operator()<It&&, Sent&>();
+    check.template operator()<It&&, Sent&&>();
+    check.template operator()<It&&, const Sent&>();
+    check.template operator()<It&&, const Sent&&>();
+    check.template operator()<const It&, Sent&>();
+    check.template operator()<const It&, Sent&&>();
+    check.template operator()<const It&, const Sent&>();
+    check.template operator()<const It&, const Sent&&>();
+    check.template operator()<const It&&, Sent&>();
+    check.template operator()<const It&&, Sent&&>();
+    check.template operator()<const It&&, const Sent&>();
+    check.template operator()<const It&&, const Sent&&>();
   }
   {
     It first = It(a);

diff  --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/range.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/range.pass.cpp
index 1d5ec94198abea..db1be748334841 100644
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/range.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/range.pass.cpp
@@ -51,9 +51,14 @@ constexpr bool test() {
     using R = std::ranges::subrange<It, Sent, std::ranges::subrange_kind::unsized>;
 
     int a[] = {1, 2, 3};
-    auto r = R(It(a), Sent(It(a + 3)));
-    assert(std::ranges::distance(r) == 3);
-    assert(std::ranges::distance(static_cast<R&&>(r)) == 3);
+    {
+      auto r = R(It(a), Sent(It(a + 3)));
+      assert(std::ranges::distance(r) == 3);
+    }
+    {
+      auto r = R(It(a), Sent(It(a + 3)));
+      assert(std::ranges::distance(static_cast<R&&>(r)) == 3);
+    }
     static_assert(!std::is_invocable_v<decltype(std::ranges::distance), const R&>);
     static_assert(!std::is_invocable_v<decltype(std::ranges::distance), const R&&>);
   }
@@ -64,9 +69,14 @@ constexpr bool test() {
     using R = std::ranges::subrange<It, Sent, std::ranges::subrange_kind::sized>;
 
     int a[] = {1, 2, 3};
-    auto r = R(It(a), Sent(It(a + 3)), 3);
-    assert(std::ranges::distance(r) == 3);
-    assert(std::ranges::distance(static_cast<R&&>(r)) == 3);
+    {
+      auto r = R(It(a), Sent(It(a + 3)), 3);
+      assert(std::ranges::distance(r) == 3);
+    }
+    {
+      auto r = R(It(a), Sent(It(a + 3)), 3);
+      assert(std::ranges::distance(static_cast<R&&>(r)) == 3);
+    }
     static_assert(!std::is_invocable_v<decltype(std::ranges::distance), const R&>);
     static_assert(!std::is_invocable_v<decltype(std::ranges::distance), const R&&>);
   }

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp
index e55121f95e7c2e..4265a3acdba5c5 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp
@@ -104,14 +104,16 @@ constexpr bool test() {
   {
     auto it = random_access_iterator<int*>(buffer);
     auto cit = random_access_iterator<const int*>(buffer);
+    auto it_copy = it;
+    auto cit_copy = cit;
 
     auto c1 = std::views::counted(it, 3);
     auto c2 = std::views::counted(std::as_const(it), 3);
-    auto c3 = std::views::counted(std::move(it), 3);
+    auto c3 = std::views::counted(std::move(it_copy), 3);
     auto c4 = std::views::counted(random_access_iterator<int*>(buffer), 3);
     auto c5 = std::views::counted(cit, 3);
     auto c6 = std::views::counted(std::as_const(cit), 3);
-    auto c7 = std::views::counted(std::move(cit), 3);
+    auto c7 = std::views::counted(std::move(cit_copy), 3);
     auto c8 = std::views::counted(random_access_iterator<const int*>(buffer), 3);
 
     ASSERT_SAME_TYPE(decltype(c1), std::ranges::subrange<random_access_iterator<int*>>);
@@ -136,14 +138,16 @@ constexpr bool test() {
   {
     auto it = bidirectional_iterator<int*>(buffer);
     auto cit = bidirectional_iterator<const int*>(buffer);
+    auto it_copy = it;
+    auto cit_copy = cit;
 
     auto c1 = std::views::counted(it, 3);
     auto c2 = std::views::counted(std::as_const(it), 3);
-    auto c3 = std::views::counted(std::move(it), 3);
+    auto c3 = std::views::counted(std::move(it_copy), 3);
     auto c4 = std::views::counted(bidirectional_iterator<int*>(buffer), 3);
     auto c5 = std::views::counted(cit, 3);
     auto c6 = std::views::counted(std::as_const(cit), 3);
-    auto c7 = std::views::counted(std::move(cit), 3);
+    auto c7 = std::views::counted(std::move(cit_copy), 3);
     auto c8 = std::views::counted(bidirectional_iterator<const int*>(buffer), 3);
 
     using Expected = std::ranges::subrange<std::counted_iterator<decltype(it)>, std::default_sentinel_t>;
@@ -170,10 +174,11 @@ constexpr bool test() {
 
   {
     auto it = cpp17_output_iterator<int*>(buffer);
+    auto it_copy = it;
 
     auto c1 = std::views::counted(it, 3);
     auto c2 = std::views::counted(std::as_const(it), 3);
-    auto c3 = std::views::counted(std::move(it), 3);
+    auto c3 = std::views::counted(std::move(it_copy), 3);
     auto c4 = std::views::counted(cpp17_output_iterator<int*>(buffer), 3);
 
     using Expected = std::ranges::subrange<std::counted_iterator<decltype(it)>, std::default_sentinel_t>;
@@ -191,10 +196,11 @@ constexpr bool test() {
 
   {
     auto it = cpp17_input_iterator<int*>(buffer);
+    auto it_copy = it;
 
     auto c1 = std::views::counted(it, 3);
     auto c2 = std::views::counted(std::as_const(it), 3);
-    auto c3 = std::views::counted(std::move(it), 3);
+    auto c3 = std::views::counted(std::move(it_copy), 3);
     auto c4 = std::views::counted(cpp17_input_iterator<int*>(buffer), 3);
 
     using Expected = std::ranges::subrange<std::counted_iterator<decltype(it)>, std::default_sentinel_t>;

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/increment.pass.cpp
index 6b29ba0239e564..2ba6d96c43757d 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/increment.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/increment.pass.cpp
@@ -14,6 +14,7 @@
 
 #include <array>
 #include <cassert>
+#include <iterator>
 #include <ranges>
 #include <tuple>
 
@@ -23,15 +24,14 @@ template <class Iter, class Sent = sentinel_wrapper<Iter>>
 constexpr void testOne() {
   using Range          = std::ranges::subrange<Iter, Sent>;
   std::tuple<int> ts[] = {{1}, {2}, {3}};
-  auto ev              = Range{Iter{&ts[0]}, Sent{Iter{&ts[0] + 3}}} | std::views::elements<0>;
-
-  using ElementIter = std::ranges::iterator_t<decltype(ev)>;
 
   // ++i
   {
+    auto ev               = Range{Iter{std::begin(ts)}, Sent{Iter{std::end(ts)}}} | std::views::elements<0>;
     auto it               = ev.begin();
     decltype(auto) result = ++it;
 
+    using ElementIter = std::ranges::iterator_t<decltype(ev)>;
     static_assert(std::is_same_v<decltype(result), ElementIter&>);
     assert(&result == &it);
 
@@ -40,10 +40,12 @@ constexpr void testOne() {
 
   // i++
   {
+    auto ev = Range{Iter{std::begin(ts)}, Sent{Iter{std::end(ts)}}} | std::views::elements<0>;
     if constexpr (std::forward_iterator<Iter>) {
       auto it               = ev.begin();
       decltype(auto) result = it++;
 
+      using ElementIter = std::ranges::iterator_t<decltype(ev)>;
       static_assert(std::is_same_v<decltype(result), ElementIter>);
 
       assert(base(it.base()) == &ts[1]);

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.split/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.split/begin.pass.cpp
index 15df4d0da65c17..203b237d98fe10 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.split/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.split/begin.pass.cpp
@@ -49,8 +49,8 @@ constexpr void testOne() {
     std::ranges::split_view sv{std::move(range), 1};
     auto it         = sv.begin();
     auto firstRange = *it;
-    assert(firstRange.begin() == range.begin());
-    assert(firstRange.end() == range.end());
+    assert(firstRange.begin() == Iter(a.data()));
+    assert(firstRange.end() == Sent(Iter(a.data())));
   }
 
   // empty pattern
@@ -60,8 +60,8 @@ constexpr void testOne() {
     std::ranges::split_view sv{std::move(range), std::views::empty<int>};
     auto it         = sv.begin();
     auto firstRange = *it;
-    assert(firstRange.begin() == range.begin());
-    assert(firstRange.end() == std::next(range.begin()));
+    assert(firstRange.begin() == Iter(buffer));
+    assert(firstRange.end() == Sent(Iter(buffer + 1)));
   }
 
   // empty view and empty pattern
@@ -71,8 +71,8 @@ constexpr void testOne() {
     std::ranges::split_view sv{std::move(range), std::views::empty<int>};
     auto it         = sv.begin();
     auto firstRange = *it;
-    assert(firstRange.begin() == range.begin());
-    assert(firstRange.end() == range.end());
+    assert(firstRange.begin() == Iter(a.data()));
+    assert(firstRange.end() == Sent(Iter(a.data())));
   }
 
   // pattern found at the beginning
@@ -84,8 +84,8 @@ constexpr void testOne() {
 
     auto it         = sv.begin();
     auto firstRange = *it;
-    assert(firstRange.begin() == range.begin());
-    assert(firstRange.end() == range.begin());
+    assert(firstRange.begin() == Iter(buffer));
+    assert(firstRange.end() == Sent(Iter(buffer)));
   }
 
   // pattern found in the middle
@@ -97,8 +97,8 @@ constexpr void testOne() {
 
     auto it         = sv.begin();
     auto firstRange = *it;
-    assert(firstRange.begin() == range.begin());
-    assert(firstRange.end() == std::next(range.begin()));
+    assert(firstRange.begin() == Iter(buffer));
+    assert(firstRange.end() == Sent(Iter(buffer + 1)));
   }
 
   // pattern found at the end
@@ -110,8 +110,8 @@ constexpr void testOne() {
 
     auto it         = sv.begin();
     auto firstRange = *it;
-    assert(firstRange.begin() == range.begin());
-    assert(firstRange.end() == std::next(range.begin()));
+    assert(firstRange.begin() == Iter(buffer));
+    assert(firstRange.end() == Sent(Iter(buffer + 1)));
   }
 
   // pattern not found
@@ -123,8 +123,8 @@ constexpr void testOne() {
 
     auto it         = sv.begin();
     auto firstRange = *it;
-    assert(firstRange.begin() == range.begin());
-    assert(firstRange.end() == range.end());
+    assert(firstRange.begin() == Iter(buffer));
+    assert(firstRange.end() == Sent(Iter(buffer + 3)));
   }
 
   // Make sure that we cache the result of begin() on subsequent calls

diff  --git a/libcxx/test/std/ranges/range.utility/range.subrange/begin_end.pass.cpp b/libcxx/test/std/ranges/range.utility/range.subrange/begin_end.pass.cpp
new file mode 100644
index 00000000000000..db3f3722422d6b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.utility/range.subrange/begin_end.pass.cpp
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 std::ranges::subrange;
+
+#include <ranges>
+#include <cassert>
+#include <iterator>
+
+#include "test_iterators.h"
+#include "type_algorithms.h"
+
+template <class Iterator, class Sentinel>
+constexpr bool test() {
+  using Subrange = std::ranges::subrange<Iterator, Sentinel>;
+
+  // Empty subrange
+  {
+    int array[10] = {};
+    Subrange rng(Iterator(std::begin(array)), Sentinel(Iterator(std::begin(array))));
+    std::same_as<Iterator> decltype(auto) beg = rng.begin();
+    std::same_as<Sentinel> decltype(auto) end = rng.end();
+    assert(beg == Iterator(std::begin(array)));
+    assert(end == Iterator(std::begin(array)));
+  }
+
+  // Non-empty subrange
+  {
+    int array[10] = {};
+    Subrange rng(Iterator(std::begin(array)), Sentinel(Iterator(std::end(array) - 3)));
+    std::same_as<Iterator> decltype(auto) beg = rng.begin();
+    std::same_as<Sentinel> decltype(auto) end = rng.end();
+    assert(beg == Iterator(std::begin(array)));
+    assert(end == Iterator(std::end(array) - 3));
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  types::for_each(types::forward_iterator_list<int*>{}, []<class Iterator> {
+    test<Iterator, sentinel_wrapper<Iterator>>();
+    static_assert(test<Iterator, sentinel_wrapper<Iterator>>());
+  });
+
+  return 0;
+}

diff  --git a/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp
index 7f33237de4631d..6a1b45b25ef032 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp
@@ -61,27 +61,25 @@ constexpr bool test_constraints() {
 
 template <class Iter, class Sent, class Alloc>
 constexpr void test_with_input(std::vector<char> input) {
-  auto b = Iter(input.data());
-  auto e = Iter(input.data() + input.size());
-  std::ranges::subrange in(std::move(b), Sent(std::move(e)));
-
   { // (range)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     std::string c(std::from_range, in);
 
     LIBCPP_ASSERT(c.__invariants());
     assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
-    assert(std::ranges::equal(in, c));
+    assert(std::ranges::equal(input, c));
     LIBCPP_ASSERT(is_string_asan_correct(c));
   }
 
   { // (range, allocator)
+    std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size())));
     Alloc alloc;
     std::basic_string<char, std::char_traits<char>, Alloc> c(std::from_range, in, alloc);
 
     LIBCPP_ASSERT(c.__invariants());
     assert(c.get_allocator() == alloc);
     assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
-    assert(std::ranges::equal(in, c));
+    assert(std::ranges::equal(input, c));
     LIBCPP_ASSERT(is_string_asan_correct(c));
   }
 }

diff  --git a/libcxx/test/std/utilities/format/format.range/format.range.formatter/format.functions.tests.h b/libcxx/test/std/utilities/format/format.range/format.range.formatter/format.functions.tests.h
index 06bac9b673709a..d0469e11f3040a 100644
--- a/libcxx/test/std/utilities/format/format.range/format.range.formatter/format.functions.tests.h
+++ b/libcxx/test/std/utilities/format/format.range/format.range.formatter/format.functions.tests.h
@@ -15,10 +15,12 @@
 #include <concepts>
 #include <deque>
 #include <format>
+#include <functional> // std::identity
 #include <list>
 #include <ranges>
 #include <span>
 #include <tuple>
+#include <utility>
 #include <vector>
 
 #include "format.functions.common.h"
@@ -404,109 +406,113 @@ void test_bool(TestFunction check, ExceptionTest check_exception) {
 //
 
 template <class CharT, class TestFunction, class ExceptionTest>
-void test_int(TestFunction check, ExceptionTest check_exception, auto&& input) {
-  check(SV("[1, 2, 42, -42]"), SV("{}"), input);
-  check(SV("[1, 2, 42, -42]^42"), SV("{}^42"), input);
-  check(SV("[1, 2, 42, -42]^42"), SV("{:}^42"), input);
+void test_int(TestFunction check, ExceptionTest check_exception, auto&& input, auto make_range) {
+  check(SV("[1, 2, 42, -42]"), SV("{}"), make_range(input));
+  check(SV("[1, 2, 42, -42]^42"), SV("{}^42"), make_range(input));
+  check(SV("[1, 2, 42, -42]^42"), SV("{:}^42"), make_range(input));
 
   // ***** underlying has no format-spec
 
   // *** align-fill & width ***
-  check(SV("[1, 2, 42, -42]     "), SV("{:20}"), input);
-  check(SV("[1, 2, 42, -42]*****"), SV("{:*<20}"), input);
-  check(SV("__[1, 2, 42, -42]___"), SV("{:_^20}"), input);
-  check(SV("#####[1, 2, 42, -42]"), SV("{:#>20}"), input);
+  check(SV("[1, 2, 42, -42]     "), SV("{:20}"), make_range(input));
+  check(SV("[1, 2, 42, -42]*****"), SV("{:*<20}"), make_range(input));
+  check(SV("__[1, 2, 42, -42]___"), SV("{:_^20}"), make_range(input));
+  check(SV("#####[1, 2, 42, -42]"), SV("{:#>20}"), make_range(input));
 
-  check(SV("[1, 2, 42, -42]     "), SV("{:{}}"), input, 20);
-  check(SV("[1, 2, 42, -42]*****"), SV("{:*<{}}"), input, 20);
-  check(SV("__[1, 2, 42, -42]___"), SV("{:_^{}}"), input, 20);
-  check(SV("#####[1, 2, 42, -42]"), SV("{:#>{}}"), input, 20);
+  check(SV("[1, 2, 42, -42]     "), SV("{:{}}"), make_range(input), 20);
+  check(SV("[1, 2, 42, -42]*****"), SV("{:*<{}}"), make_range(input), 20);
+  check(SV("__[1, 2, 42, -42]___"), SV("{:_^{}}"), make_range(input), 20);
+  check(SV("#####[1, 2, 42, -42]"), SV("{:#>{}}"), make_range(input), 20);
 
-  check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input);
-  check_exception("The fill option contains an invalid value", SV("{:{<}"), input);
+  check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), make_range(input));
+  check_exception("The fill option contains an invalid value", SV("{:{<}"), make_range(input));
 
   // *** sign ***
-  check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), input);
-  check_exception("The format specifier should consume the input or end with a '}'", SV("{:+}"), input);
-  check_exception("The format specifier should consume the input or end with a '}'", SV("{: }"), input);
+  check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), make_range(input));
+  check_exception("The format specifier should consume the input or end with a '}'", SV("{:+}"), make_range(input));
+  check_exception("The format specifier should consume the input or end with a '}'", SV("{: }"), make_range(input));
 
   // *** alternate form ***
-  check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
+  check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), make_range(input));
 
   // *** zero-padding ***
-  check_exception("The width option should not have a leading zero", SV("{:0}"), input);
+  check_exception("The width option should not have a leading zero", SV("{:0}"), make_range(input));
 
   // *** precision ***
-  check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input);
+  check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), make_range(input));
 
   // *** locale-specific form ***
-  check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
+  check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), make_range(input));
 
   // *** n
-  check(SV("__1, 2, 42, -42___"), SV("{:_^18n}"), input);
+  check(SV("__1, 2, 42, -42___"), SV("{:_^18n}"), make_range(input));
 
   // *** type ***
-  check_exception("Type m requires a pair or a tuple with two elements", SV("{:m}"), input);
-  check_exception("Type s requires character type as formatting argument", SV("{:s}"), input);
-  check_exception("Type ?s requires character type as formatting argument", SV("{:?s}"), input);
+  check_exception("Type m requires a pair or a tuple with two elements", SV("{:m}"), make_range(input));
+  check_exception("Type s requires character type as formatting argument", SV("{:s}"), make_range(input));
+  check_exception("Type ?s requires character type as formatting argument", SV("{:?s}"), make_range(input));
   for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s"))
-    check_exception("The format specifier should consume the input or end with a '}'", fmt, input);
+    check_exception("The format specifier should consume the input or end with a '}'", fmt, make_range(input));
 
   // ***** Only underlying has a format-spec
-  check(SV("[    1,     2,    42,   -42]"), SV("{::5}"), input);
-  check(SV("[1****, 2****, 42***, -42**]"), SV("{::*<5}"), input);
-  check(SV("[__1__, __2__, _42__, _-42_]"), SV("{::_^5}"), input);
-  check(SV("[::::1, ::::2, :::42, ::-42]"), SV("{:::>5}"), input);
+  check(SV("[    1,     2,    42,   -42]"), SV("{::5}"), make_range(input));
+  check(SV("[1****, 2****, 42***, -42**]"), SV("{::*<5}"), make_range(input));
+  check(SV("[__1__, __2__, _42__, _-42_]"), SV("{::_^5}"), make_range(input));
+  check(SV("[::::1, ::::2, :::42, ::-42]"), SV("{:::>5}"), make_range(input));
 
-  check(SV("[    1,     2,    42,   -42]"), SV("{::{}}"), input, 5);
-  check(SV("[1****, 2****, 42***, -42**]"), SV("{::*<{}}"), input, 5);
-  check(SV("[__1__, __2__, _42__, _-42_]"), SV("{::_^{}}"), input, 5);
-  check(SV("[::::1, ::::2, :::42, ::-42]"), SV("{:::>{}}"), input, 5);
+  check(SV("[    1,     2,    42,   -42]"), SV("{::{}}"), make_range(input), 5);
+  check(SV("[1****, 2****, 42***, -42**]"), SV("{::*<{}}"), make_range(input), 5);
+  check(SV("[__1__, __2__, _42__, _-42_]"), SV("{::_^{}}"), make_range(input), 5);
+  check(SV("[::::1, ::::2, :::42, ::-42]"), SV("{:::>{}}"), make_range(input), 5);
 
-  check_exception("The format string contains an invalid escape sequence", SV("{::}<}"), input);
-  check_exception("The fill option contains an invalid value", SV("{::{<}"), input);
+  check_exception("The format string contains an invalid escape sequence", SV("{::}<}"), make_range(input));
+  check_exception("The fill option contains an invalid value", SV("{::{<}"), make_range(input));
 
   // *** sign ***
-  check(SV("[1, 2, 42, -42]"), SV("{::-}"), input);
-  check(SV("[+1, +2, +42, -42]"), SV("{::+}"), input);
-  check(SV("[ 1,  2,  42, -42]"), SV("{:: }"), input);
+  check(SV("[1, 2, 42, -42]"), SV("{::-}"), make_range(input));
+  check(SV("[+1, +2, +42, -42]"), SV("{::+}"), make_range(input));
+  check(SV("[ 1,  2,  42, -42]"), SV("{:: }"), make_range(input));
 
   // *** alternate form ***
-  check(SV("[0x1, 0x2, 0x2a, -0x2a]"), SV("{::#x}"), input);
+  check(SV("[0x1, 0x2, 0x2a, -0x2a]"), SV("{::#x}"), make_range(input));
 
   // *** zero-padding ***
-  check(SV("[00001, 00002, 00042, -0042]"), SV("{::05}"), input);
-  check(SV("[00001, 00002, 0002a, -002a]"), SV("{::05x}"), input);
-  check(SV("[0x001, 0x002, 0x02a, -0x2a]"), SV("{::#05x}"), input);
+  check(SV("[00001, 00002, 00042, -0042]"), SV("{::05}"), make_range(input));
+  check(SV("[00001, 00002, 0002a, -002a]"), SV("{::05x}"), make_range(input));
+  check(SV("[0x001, 0x002, 0x02a, -0x2a]"), SV("{::#05x}"), make_range(input));
 
   // *** precision ***
-  check_exception("The format specifier should consume the input or end with a '}'", SV("{::.}"), input);
+  check_exception("The format specifier should consume the input or end with a '}'", SV("{::.}"), make_range(input));
 
   // *** locale-specific form ***
-  check(SV("[1, 2, 42, -42]"), SV("{::L}"), input); // does nothing in this test, but is accepted.
+  check(SV("[1, 2, 42, -42]"), SV("{::L}"), make_range(input)); // does nothing in this test, but is accepted.
 
   // *** type ***
   for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("bBcdoxX"))
-    check_exception("The type option contains an invalid value for an integer formatting argument", fmt, input);
+    check_exception(
+        "The type option contains an invalid value for an integer formatting argument", fmt, make_range(input));
 
   // ***** Both have a format-spec
-  check(SV("^^[::::1, ::::2, :::42, ::-42]^^^"), SV("{:^^33::>5}"), input);
-  check(SV("^^[::::1, ::::2, :::42, ::-42]^^^"), SV("{:^^{}::>5}"), input, 33);
-  check(SV("^^[::::1, ::::2, :::42, ::-42]^^^"), SV("{:^^{}::>{}}"), input, 33, 5);
-
-  check_exception(
-      "The argument index value is too large for the number of arguments supplied", SV("{:^^{}::>5}"), input);
-  check_exception(
-      "The argument index value is too large for the number of arguments supplied", SV("{:^^{}::>{}}"), input, 33);
+  check(SV("^^[::::1, ::::2, :::42, ::-42]^^^"), SV("{:^^33::>5}"), make_range(input));
+  check(SV("^^[::::1, ::::2, :::42, ::-42]^^^"), SV("{:^^{}::>5}"), make_range(input), 33);
+  check(SV("^^[::::1, ::::2, :::42, ::-42]^^^"), SV("{:^^{}::>{}}"), make_range(input), 33, 5);
+
+  check_exception("The argument index value is too large for the number of arguments supplied",
+                  SV("{:^^{}::>5}"),
+                  make_range(input));
+  check_exception("The argument index value is too large for the number of arguments supplied",
+                  SV("{:^^{}::>{}}"),
+                  make_range(input),
+                  33);
 }
 
 template <class CharT, class TestFunction, class ExceptionTest>
 void test_int(TestFunction check, ExceptionTest check_exception) {
-  test_int<CharT>(check, check_exception, std::array{1, 2, 42, -42});
-  test_int<CharT>(check, check_exception, std::list{1, 2, 42, -42});
-  test_int<CharT>(check, check_exception, std::vector{1, 2, 42, -42});
+  test_int<CharT>(check, check_exception, std::array{1, 2, 42, -42}, std::identity());
+  test_int<CharT>(check, check_exception, std::list{1, 2, 42, -42}, std::identity());
+  test_int<CharT>(check, check_exception, std::vector{1, 2, 42, -42}, std::identity());
   std::array input{1, 2, 42, -42};
-  test_int<CharT>(check, check_exception, std::span{input});
+  test_int<CharT>(check, check_exception, std::span{input}, std::identity());
 }
 
 //
@@ -1275,25 +1281,24 @@ void test_tuple_int_int_int(TestFunction check, ExceptionTest check_exception) {
 // Ranges
 //
 
-template <class CharT, class TestFunction, class ExceptionTest>
-void test_with_ranges(TestFunction check, ExceptionTest check_exception, auto&& iter) {
-  std::ranges::subrange range{std::move(iter), std::default_sentinel};
-  test_int<CharT>(check, check_exception, std::move(range));
+template <class CharT, class Iterator, class TestFunction, class ExceptionTest, class Array>
+void test_with_ranges_impl(TestFunction check, ExceptionTest check_exception, Array input) {
+  auto make_range = [](auto& in) {
+    std::counted_iterator it(Iterator(in.data()), in.size());
+    std::ranges::subrange range{std::move(it), std::default_sentinel};
+    return range;
+  };
+  test_int<CharT>(check, check_exception, input, make_range);
 }
 
 template <class CharT, class TestFunction, class ExceptionTest>
 void test_with_ranges(TestFunction check, ExceptionTest check_exception) {
   std::array input{1, 2, 42, -42};
-  test_with_ranges<CharT>(
-      check, check_exception, std::counted_iterator{cpp20_input_iterator<int*>(input.data()), input.size()});
-  test_with_ranges<CharT>(
-      check, check_exception, std::counted_iterator{forward_iterator<int*>(input.data()), input.size()});
-  test_with_ranges<CharT>(
-      check, check_exception, std::counted_iterator{bidirectional_iterator<int*>(input.data()), input.size()});
-  test_with_ranges<CharT>(
-      check, check_exception, std::counted_iterator{random_access_iterator<int*>(input.data()), input.size()});
-  test_with_ranges<CharT>(
-      check, check_exception, std::counted_iterator{contiguous_iterator<int*>(input.data()), input.size()});
+  test_with_ranges_impl<CharT, cpp20_input_iterator<int*>>(check, check_exception, input);
+  test_with_ranges_impl<CharT, forward_iterator<int*>>(check, check_exception, input);
+  test_with_ranges_impl<CharT, bidirectional_iterator<int*>>(check, check_exception, input);
+  test_with_ranges_impl<CharT, random_access_iterator<int*>>(check, check_exception, input);
+  test_with_ranges_impl<CharT, contiguous_iterator<int*>>(check, check_exception, input);
 }
 
 //

diff  --git a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp
index 334517861e7b35..13442df9db3ae5 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp
@@ -98,26 +98,24 @@ constexpr bool test()
     return true;
 }
 
-template <class ...Args, class = decltype(std::construct_at(std::declval<Args>()...))>
-constexpr bool can_construct_at(Args&&...) { return true; }
-
 template <class ...Args>
-constexpr bool can_construct_at(...) { return false; }
+constexpr bool can_construct_at = requires {
+    std::construct_at(std::declval<Args>()...);
+};
 
 // Check that SFINAE works.
-static_assert( can_construct_at((int*)nullptr, 42));
-static_assert( can_construct_at((Foo*)nullptr, 1, '2', 3.0));
-static_assert(!can_construct_at((Foo*)nullptr, 1, '2'));
-static_assert(!can_construct_at((Foo*)nullptr, 1, '2', 3.0, 4));
-static_assert(!can_construct_at(nullptr, 1, '2', 3.0));
-static_assert(!can_construct_at((int*)nullptr, 1, '2', 3.0));
-static_assert(!can_construct_at(contiguous_iterator<Foo*>(), 1, '2', 3.0));
+static_assert( can_construct_at<int*, int>);
+static_assert( can_construct_at<Foo*, int, char, double>);
+static_assert(!can_construct_at<Foo*, int, char>);
+static_assert(!can_construct_at<Foo*, int, char, double, int>);
+static_assert(!can_construct_at<std::nullptr_t, int, char, double>);
+static_assert(!can_construct_at<int*, int, char, double>);
+static_assert(!can_construct_at<contiguous_iterator<Foo*>, int, char, double>);
 // Can't construct function pointers.
-static_assert(!can_construct_at((int(*)())nullptr));
-static_assert(!can_construct_at((int(*)())nullptr, nullptr));
+static_assert(!can_construct_at<int(*)()>);
+static_assert(!can_construct_at<int(*)(), std::nullptr_t>);
 
-int main(int, char**)
-{
+int main(int, char**) {
     test();
     static_assert(test());
     return 0;

diff  --git a/libcxx/test/support/double_move_tracker.h b/libcxx/test/support/double_move_tracker.h
new file mode 100644
index 00000000000000..fac575d9df08fb
--- /dev/null
+++ b/libcxx/test/support/double_move_tracker.h
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_SUPPORT_DOUBLE_MOVE_TRACKER_H
+#define TEST_SUPPORT_DOUBLE_MOVE_TRACKER_H
+
+#include <cassert>
+
+#include "test_macros.h"
+
+namespace support {
+
+struct double_move_tracker {
+  TEST_CONSTEXPR double_move_tracker() : moved_from_(false) {}
+
+  double_move_tracker(double_move_tracker const&) = default;
+
+  TEST_CONSTEXPR_CXX14 double_move_tracker(double_move_tracker&& other) : moved_from_(false) {
+    assert(!other.moved_from_);
+    other.moved_from_ = true;
+  }
+
+  double_move_tracker& operator=(double_move_tracker const&) = default;
+
+  TEST_CONSTEXPR_CXX14 double_move_tracker& operator=(double_move_tracker&& other) {
+    assert(!other.moved_from_);
+    other.moved_from_ = true;
+    moved_from_       = false;
+    return *this;
+  }
+
+private:
+  bool moved_from_;
+};
+
+} // namespace support
+
+#endif // TEST_SUPPORT_DOUBLE_MOVE_TRACKER_H

diff  --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h
index 44bd4a597539de..419f1d86730b85 100644
--- a/libcxx/test/support/test_iterators.h
+++ b/libcxx/test/support/test_iterators.h
@@ -18,6 +18,7 @@
 #include <type_traits>
 #include <utility>
 
+#include "double_move_tracker.h"
 #include "test_macros.h"
 #include "type_algorithms.h"
 
@@ -28,6 +29,7 @@ template <class It>
 class cpp17_output_iterator
 {
     It it_;
+    support::double_move_tracker tracker_;
 
     template <class U> friend class cpp17_output_iterator;
 public:
@@ -40,10 +42,13 @@ class cpp17_output_iterator
     TEST_CONSTEXPR explicit cpp17_output_iterator(It it) : it_(std::move(it)) {}
 
     template <class U>
-    TEST_CONSTEXPR cpp17_output_iterator(const cpp17_output_iterator<U>& u) : it_(u.it_) {}
+    TEST_CONSTEXPR cpp17_output_iterator(const cpp17_output_iterator<U>& u) : it_(u.it_), tracker_(u.tracker_) {}
 
     template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
-    TEST_CONSTEXPR_CXX14 cpp17_output_iterator(cpp17_output_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
+    TEST_CONSTEXPR_CXX14 cpp17_output_iterator(cpp17_output_iterator<U>&& u)
+        : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) {
+      u.it_ = U();
+    }
 
     TEST_CONSTEXPR reference operator*() const {return *it_;}
 
@@ -71,6 +76,7 @@ class cpp17_input_iterator
 {
     typedef std::iterator_traits<ItTraits> Traits;
     It it_;
+    support::double_move_tracker tracker_;
 
     template <class U, class T> friend class cpp17_input_iterator;
 public:
@@ -83,10 +89,13 @@ class cpp17_input_iterator
     TEST_CONSTEXPR explicit cpp17_input_iterator(It it) : it_(it) {}
 
     template <class U, class T>
-    TEST_CONSTEXPR cpp17_input_iterator(const cpp17_input_iterator<U, T>& u) : it_(u.it_) {}
+    TEST_CONSTEXPR cpp17_input_iterator(const cpp17_input_iterator<U, T>& u) : it_(u.it_), tracker_(u.tracker_) {}
 
     template <class U, class T, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
-    TEST_CONSTEXPR_CXX14 cpp17_input_iterator(cpp17_input_iterator<U, T>&& u) : it_(u.it_) { u.it_ = U(); }
+    TEST_CONSTEXPR_CXX14 cpp17_input_iterator(cpp17_input_iterator<U, T>&& u)
+        : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) {
+      u.it_ = U();
+    }
 
     TEST_CONSTEXPR reference operator*() const {return *it_;}
 
@@ -114,6 +123,7 @@ template <class It>
 class forward_iterator
 {
     It it_;
+    support::double_move_tracker tracker_;
 
     template <class U> friend class forward_iterator;
 public:
@@ -127,10 +137,13 @@ class forward_iterator
     TEST_CONSTEXPR explicit forward_iterator(It it) : it_(it) {}
 
     template <class U>
-    TEST_CONSTEXPR forward_iterator(const forward_iterator<U>& u) : it_(u.it_) {}
+    TEST_CONSTEXPR forward_iterator(const forward_iterator<U>& u) : it_(u.it_), tracker_(u.tracker_) {}
 
     template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
-    TEST_CONSTEXPR_CXX14 forward_iterator(forward_iterator<U>&& other) : it_(other.it_) { other.it_ = U(); }
+    TEST_CONSTEXPR_CXX14 forward_iterator(forward_iterator<U>&& other)
+        : it_(std::move(other.it_)), tracker_(std::move(other.tracker_)) {
+      other.it_ = U();
+    }
 
     TEST_CONSTEXPR reference operator*() const {return *it_;}
 
@@ -154,6 +167,7 @@ template <class It>
 class bidirectional_iterator
 {
     It it_;
+    support::double_move_tracker tracker_;
 
     template <class U> friend class bidirectional_iterator;
 public:
@@ -167,10 +181,13 @@ class bidirectional_iterator
     TEST_CONSTEXPR explicit bidirectional_iterator(It it) : it_(it) {}
 
     template <class U>
-    TEST_CONSTEXPR bidirectional_iterator(const bidirectional_iterator<U>& u) : it_(u.it_) {}
+    TEST_CONSTEXPR bidirectional_iterator(const bidirectional_iterator<U>& u) : it_(u.it_), tracker_(u.tracker_) {}
 
     template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
-    TEST_CONSTEXPR_CXX14 bidirectional_iterator(bidirectional_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
+    TEST_CONSTEXPR_CXX14 bidirectional_iterator(bidirectional_iterator<U>&& u)
+        : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) {
+      u.it_ = U();
+    }
 
     TEST_CONSTEXPR reference operator*() const {return *it_;}
 
@@ -196,6 +213,7 @@ template <class It>
 class random_access_iterator
 {
     It it_;
+    support::double_move_tracker tracker_;
 
     template <class U> friend class random_access_iterator;
 public:
@@ -209,10 +227,13 @@ class random_access_iterator
     TEST_CONSTEXPR explicit random_access_iterator(It it) : it_(it) {}
 
     template <class U>
-    TEST_CONSTEXPR random_access_iterator(const random_access_iterator<U>& u) : it_(u.it_) {}
+    TEST_CONSTEXPR random_access_iterator(const random_access_iterator<U>& u) : it_(u.it_), tracker_(u.tracker_) {}
 
     template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
-    TEST_CONSTEXPR_CXX14 random_access_iterator(random_access_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
+    TEST_CONSTEXPR_CXX14 random_access_iterator(random_access_iterator<U>&& u)
+        : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) {
+      u.it_ = U();
+    }
 
     TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;}
     TEST_CONSTEXPR_CXX14 reference operator[](
diff erence_type n) const {return it_[n];}
@@ -251,6 +272,7 @@ random_access_iterator(It) -> random_access_iterator<It>;
 template <std::random_access_iterator It>
 class cpp20_random_access_iterator {
   It it_;
+  support::double_move_tracker tracker_;
 
   template <std::random_access_iterator>
   friend class cpp20_random_access_iterator;
@@ -265,10 +287,11 @@ class cpp20_random_access_iterator {
   constexpr explicit cpp20_random_access_iterator(It it) : it_(it) {}
 
   template <class U>
-  constexpr cpp20_random_access_iterator(const cpp20_random_access_iterator<U>& u) : it_(u.it_) {}
+  constexpr cpp20_random_access_iterator(const cpp20_random_access_iterator<U>& u) : it_(u.it_), tracker_(u.tracker_) {}
 
   template <class U>
-  constexpr cpp20_random_access_iterator(cpp20_random_access_iterator<U>&& u) : it_(u.it_) {
+  constexpr cpp20_random_access_iterator(cpp20_random_access_iterator<U>&& u)
+      : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) {
     u.it_ = U();
   }
 
@@ -342,6 +365,7 @@ static_assert(std::random_access_iterator<cpp20_random_access_iterator<int*>>);
 template <std::contiguous_iterator It>
 class contiguous_iterator {
   It it_;
+  support::double_move_tracker tracker_;
 
   template <std::contiguous_iterator U>
   friend class contiguous_iterator;
@@ -360,10 +384,10 @@ class contiguous_iterator {
   constexpr explicit contiguous_iterator(It it) : it_(it) {}
 
   template <class U>
-  constexpr contiguous_iterator(const contiguous_iterator<U>& u) : it_(u.it_) {}
+  constexpr contiguous_iterator(const contiguous_iterator<U>& u) : it_(u.it_), tracker_(u.tracker_) {}
 
   template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
-  constexpr contiguous_iterator(contiguous_iterator<U>&& u) : it_(u.it_) {
+  constexpr contiguous_iterator(contiguous_iterator<U>&& u) : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) {
     u.it_ = U();
   }
 
@@ -435,6 +459,7 @@ class three_way_contiguous_iterator
     static_assert(std::is_pointer_v<It>, "Things probably break in this case");
 
     It it_;
+    support::double_move_tracker tracker_;
 
     template <class U> friend class three_way_contiguous_iterator;
 public:
@@ -451,10 +476,14 @@ class three_way_contiguous_iterator
     constexpr explicit three_way_contiguous_iterator(It it) : it_(it) {}
 
     template <class U>
-    constexpr three_way_contiguous_iterator(const three_way_contiguous_iterator<U>& u) : it_(u.it_) {}
+    constexpr three_way_contiguous_iterator(const three_way_contiguous_iterator<U>& u)
+        : it_(u.it_), tracker_(u.tracker_) {}
 
     template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
-    constexpr three_way_contiguous_iterator(three_way_contiguous_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
+    constexpr three_way_contiguous_iterator(three_way_contiguous_iterator<U>&& u)
+        : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) {
+      u.it_ = U();
+    }
 
     constexpr reference operator*() const {return *it_;}
     constexpr pointer operator->() const {return it_;}
@@ -671,6 +700,7 @@ template <class It>
 class cpp20_input_iterator
 {
     It it_;
+    support::double_move_tracker tracker_;
 
 public:
     using value_type = std::iter_value_t<It>;
@@ -705,6 +735,7 @@ struct iter_value_or_void<I> {
 template <class It>
 class cpp20_output_iterator {
   It it_;
+  support::double_move_tracker tracker_;
 
 public:
   using 
diff erence_type = std::iter_
diff erence_t<It>;


        


More information about the libcxx-commits mailing list