[libcxx-commits] [libcxx] [libc++][ranges][enumerate_view] Update sentinel `equal` test (PR #222331)

Lucas Mellone via libcxx-commits libcxx-commits at lists.llvm.org
Fri Oct 2 05:34:47 PDT 2026


https://github.com/lknknm updated https://github.com/llvm/llvm-project/pull/222331

>From 0f30945d5de035b6108d9ff0cfb976ccb3b9a3ea Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Wed, 9 Sep 2026 15:30:53 +0200
Subject: [PATCH 1/8] add: OtherConst test case

---
 .../range.enumerate/sentinel/equal.pass.cpp     | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
index 7bf2898bcd1580..b7058ee359c152 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
@@ -37,20 +37,31 @@ constexpr void test() {
   std::array array{0, 1, 2, 3, 84};
 
   View mv{Iterator(std::to_address(base(array.begin()))), Sentinel(Iterator(std::to_address(base(array.end()))))};
-  std::ranges::enumerate_view view(std::move(mv));
+  std::ranges::enumerate_view v(std::move(mv));
 
-  auto const it = view.begin();
-  auto const s  = view.end();
+  auto const it   = v.begin();
+  auto const c_it = std::as_const(v).begin();
+  auto const s    = v.end();
 
   std::same_as<bool> decltype(auto) eqItSResult = (it == s);
   assert(!eqItSResult);
   std::same_as<bool> decltype(auto) eqSItResult = (s == it);
   assert(!eqSItResult);
 
+  std::same_as<bool> decltype(auto) eqConstItSResult = (c_it == s);
+  assert(!eqConstItSResult);
+  std::same_as<bool> decltype(auto) eqSConstItResult = (s == c_it);
+  assert(!eqSConstItResult);
+
   std::same_as<bool> decltype(auto) neqItSResult = (it != s);
   assert(neqItSResult);
   std::same_as<bool> decltype(auto) neqSItResult = (s != it);
   assert(neqSItResult);
+
+  std::same_as<bool> decltype(auto) neqConstItSResult = (c_it != s);
+  assert(neqConstItSResult);
+  std::same_as<bool> decltype(auto) neqSConstItResult = (s != c_it);
+  assert(neqSConstItResult);
 }
 
 constexpr bool tests() {

>From 3564d10138235cfc2404a28aaba9b258502fc3f6 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Mon, 14 Sep 2026 15:14:05 +0200
Subject: [PATCH 2/8] Update
 libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp

Co-authored-by: Hristo Hristov <zingam at outlook.com>
---
 .../range.adaptors/range.enumerate/sentinel/equal.pass.cpp      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
index b7058ee359c152..f8197dfb7a9d9e 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
@@ -37,7 +37,7 @@ constexpr void test() {
   std::array array{0, 1, 2, 3, 84};
 
   View mv{Iterator(std::to_address(base(array.begin()))), Sentinel(Iterator(std::to_address(base(array.end()))))};
-  std::ranges::enumerate_view v(std::move(mv));
+  std::ranges::enumerate_view ev(std::move(mv));
 
   auto const it   = v.begin();
   auto const c_it = std::as_const(v).begin();

>From 278b8a31e09e08726d6051dea91f816e20365e8d Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Mon, 14 Sep 2026 15:14:23 +0200
Subject: [PATCH 3/8] Apply batched suggestions from code review

Co-authored-by: Hristo Hristov <zingam at outlook.com>
---
 .../range.adaptors/range.enumerate/sentinel/equal.pass.cpp    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
index f8197dfb7a9d9e..1264f8d99a2db6 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
@@ -41,7 +41,7 @@ constexpr void test() {
 
   auto const it   = v.begin();
   auto const c_it = std::as_const(v).begin();
-  auto const s    = v.end();
+  auto const st    = v.end();
 
   std::same_as<bool> decltype(auto) eqItSResult = (it == s);
   assert(!eqItSResult);
@@ -64,7 +64,7 @@ constexpr void test() {
   assert(neqSConstItResult);
 }
 
-constexpr bool tests() {
+constexpr bool test() {
   test<cpp17_input_iterator<int*>>();
   test<cpp20_input_iterator<int*>>();
   test<forward_iterator<int*>>();

>From e4229e1db5b6b3dbb355d72564163548ca8e58f8 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Thu, 1 Oct 2026 18:36:19 +0200
Subject: [PATCH 4/8] wip: fixes just in order for the tests to run

---
 .../range.enumerate/sentinel/equal.pass.cpp   | 24 +++++++++----------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
index 1264f8d99a2db6..cccdb7d0c95b65 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
@@ -39,32 +39,32 @@ constexpr void test() {
   View mv{Iterator(std::to_address(base(array.begin()))), Sentinel(Iterator(std::to_address(base(array.end()))))};
   std::ranges::enumerate_view ev(std::move(mv));
 
-  auto const it   = v.begin();
-  auto const c_it = std::as_const(v).begin();
-  auto const st    = v.end();
+  auto const it   = ev.begin();
+  auto const c_it = std::as_const(ev).begin();
+  auto const st   = ev.end();
 
-  std::same_as<bool> decltype(auto) eqItSResult = (it == s);
+  std::same_as<bool> decltype(auto) eqItSResult = (it == st);
   assert(!eqItSResult);
-  std::same_as<bool> decltype(auto) eqSItResult = (s == it);
+  std::same_as<bool> decltype(auto) eqSItResult = (st == it);
   assert(!eqSItResult);
 
-  std::same_as<bool> decltype(auto) eqConstItSResult = (c_it == s);
+  std::same_as<bool> decltype(auto) eqConstItSResult = (c_it == st);
   assert(!eqConstItSResult);
-  std::same_as<bool> decltype(auto) eqSConstItResult = (s == c_it);
+  std::same_as<bool> decltype(auto) eqSConstItResult = (st == c_it);
   assert(!eqSConstItResult);
 
-  std::same_as<bool> decltype(auto) neqItSResult = (it != s);
+  std::same_as<bool> decltype(auto) neqItSResult = (it != st);
   assert(neqItSResult);
-  std::same_as<bool> decltype(auto) neqSItResult = (s != it);
+  std::same_as<bool> decltype(auto) neqSItResult = (st != it);
   assert(neqSItResult);
 
-  std::same_as<bool> decltype(auto) neqConstItSResult = (c_it != s);
+  std::same_as<bool> decltype(auto) neqConstItSResult = (c_it != st);
   assert(neqConstItSResult);
-  std::same_as<bool> decltype(auto) neqSConstItResult = (s != c_it);
+  std::same_as<bool> decltype(auto) neqSConstItResult = (st != c_it);
   assert(neqSConstItResult);
 }
 
-constexpr bool test() {
+constexpr bool tests() {
   test<cpp17_input_iterator<int*>>();
   test<cpp20_input_iterator<int*>>();
   test<forward_iterator<int*>>();

>From 3ed50414d61d004e11255ef82580de9f2d1446a1 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Thu, 1 Oct 2026 21:08:17 +0200
Subject: [PATCH 5/8] rework: add simple view test

---
 .../range.enumerate/sentinel/equal.pass.cpp   | 116 ++++++++++--------
 1 file changed, 64 insertions(+), 52 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
index cccdb7d0c95b65..e619c7a51851c3 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
@@ -18,67 +18,79 @@
 //   requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
 // friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
 
-#include <ranges>
-
-#include <array>
 #include <cassert>
-#include <concepts>
-#include <memory>
+#include <compare>
+#include <ranges>
+#include <tuple>
 #include <utility>
 
+#include "../../range_adaptor_types.h"
 #include "test_iterators.h"
-
-#include "../types.h"
-
-template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
-constexpr void test() {
-  using View = MinimalView<Iterator, Sentinel>;
-
-  std::array array{0, 1, 2, 3, 84};
-
-  View mv{Iterator(std::to_address(base(array.begin()))), Sentinel(Iterator(std::to_address(base(array.end()))))};
-  std::ranges::enumerate_view ev(std::move(mv));
-
-  auto const it   = ev.begin();
-  auto const c_it = std::as_const(ev).begin();
-  auto const st   = ev.end();
-
-  std::same_as<bool> decltype(auto) eqItSResult = (it == st);
-  assert(!eqItSResult);
-  std::same_as<bool> decltype(auto) eqSItResult = (st == it);
-  assert(!eqSItResult);
-
-  std::same_as<bool> decltype(auto) eqConstItSResult = (c_it == st);
-  assert(!eqConstItSResult);
-  std::same_as<bool> decltype(auto) eqSConstItResult = (st == c_it);
-  assert(!eqSConstItResult);
-
-  std::same_as<bool> decltype(auto) neqItSResult = (it != st);
-  assert(neqItSResult);
-  std::same_as<bool> decltype(auto) neqSItResult = (st != it);
-  assert(neqSItResult);
-
-  std::same_as<bool> decltype(auto) neqConstItSResult = (c_it != st);
-  assert(neqConstItSResult);
-  std::same_as<bool> decltype(auto) neqSConstItResult = (st != c_it);
-  assert(neqSConstItResult);
-}
-
-constexpr bool tests() {
-  test<cpp17_input_iterator<int*>>();
-  test<cpp20_input_iterator<int*>>();
-  test<forward_iterator<int*>>();
-  test<bidirectional_iterator<int*>>();
-  test<random_access_iterator<int*>>();
-  test<contiguous_iterator<int*>>();
-  test<int*>();
+#include "test_range.h"
+
+using Iterator      = random_access_iterator<int*>;
+using ConstIterator = contiguous_iterator<const int*>;
+
+template <bool Const>
+struct ComparableSentinel {
+  using Iter = std::conditional_t<Const, ConstIterator, Iterator>;
+  Iter iter_;
+
+  explicit ComparableSentinel() = default;
+  constexpr explicit ComparableSentinel(const Iter& it) : iter_(it) {}
+
+  constexpr friend bool operator==(const Iterator& i, const ComparableSentinel& s) { return base(i) == base(s.iter_); }
+
+  constexpr friend bool operator==(const ConstIterator& i, const ComparableSentinel& s) {
+    return base(i) == base(s.iter_);
+  }
+};
+
+struct ComparableView : IntBufferView {
+  using IntBufferView::IntBufferView;
+
+  constexpr auto begin() { return Iterator(buffer_); }
+  constexpr auto begin() const { return ConstIterator(buffer_); }
+  constexpr auto end() { return ComparableSentinel<false>(Iterator(buffer_ + size_)); }
+  constexpr auto end() const { return ComparableSentinel<true>(ConstIterator(buffer_ + size_)); }
+};
+
+struct ConstIncompatibleView : IntBufferView {
+  using IntBufferView::IntBufferView;
+
+  constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>(buffer_); }
+  constexpr contiguous_iterator<const int*> begin() const { return contiguous_iterator<const int*>(buffer_); }
+  constexpr sentinel_wrapper<random_access_iterator<int*>> end() {
+    return sentinel_wrapper<random_access_iterator<int*>>(random_access_iterator<int*>(buffer_ + size_));
+  }
+  constexpr sentinel_wrapper<contiguous_iterator<const int*>> end() const {
+    return sentinel_wrapper<contiguous_iterator<const int*>>(contiguous_iterator<const int*>(buffer_ + size_));
+  }
+};
+
+constexpr bool test() {
+  int buffer[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+  {
+    // simple-view: const and non-const have the same iterator/sentinel type
+    using View = std::ranges::enumerate_view<SimpleNonCommon>;
+    static_assert(!std::ranges::common_range<View>);
+    static_assert(simple_view<View>);
+
+    View ev{SimpleNonCommon(buffer)};
+
+    assert(ev.begin() != ev.end());
+    assert(ev.begin() + 1 != ev.end());
+    assert(ev.begin() + 2 != ev.end());
+    assert(ev.begin() + 3 != ev.end());
+    assert(ev.begin() + 10 == ev.end());
+  }
 
   return true;
 }
 
 int main(int, char**) {
-  tests();
-  static_assert(tests());
+  test();
+  static_assert(test());
 
   return 0;
 }

>From 0326d3db10a4c090efd0df6eb1ea70fccb0cca7a Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Thu, 1 Oct 2026 22:37:58 +0200
Subject: [PATCH 6/8] WIP: input_iterator test still to be fixed

---
 .../range.enumerate/sentinel/equal.pass.cpp   | 117 +++++++++++++++++-
 1 file changed, 115 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
index e619c7a51851c3..478324af48d0d6 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
@@ -19,12 +19,13 @@
 // friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
 
 #include <cassert>
-#include <compare>
+#include <concepts>
 #include <ranges>
-#include <tuple>
+#include <type_traits>
 #include <utility>
 
 #include "../../range_adaptor_types.h"
+#include "../types.h"
 #include "test_iterators.h"
 #include "test_range.h"
 
@@ -76,6 +77,8 @@ constexpr bool test() {
     static_assert(!std::ranges::common_range<View>);
     static_assert(simple_view<View>);
 
+    static_assert(weakly_equality_comparable_with<std::ranges::iterator_t<View>, std::ranges::sentinel_t<View>>);
+
     View ev{SimpleNonCommon(buffer)};
 
     assert(ev.begin() != ev.end());
@@ -85,6 +88,116 @@ constexpr bool test() {
     assert(ev.begin() + 10 == ev.end());
   }
 
+  {
+    // !simple-view: const and non-const have different iterator/sentinel types
+    using View = std::ranges::enumerate_view<NonSimpleNonCommon>;
+    static_assert(!std::ranges::common_range<View>);
+    static_assert(!simple_view<View>);
+
+    using Iter      = std::ranges::iterator_t<View>;
+    using ConstIter = std::ranges::iterator_t<const View>;
+    static_assert(!std::is_same_v<Iter, ConstIter>);
+
+    using Sentinel      = std::ranges::sentinel_t<View>;
+    using ConstSentinel = std::ranges::sentinel_t<const View>;
+    static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
+
+    static_assert(weakly_equality_comparable_with<Iter, Sentinel>);
+    static_assert(!weakly_equality_comparable_with<ConstIter, Sentinel>);
+    static_assert(weakly_equality_comparable_with<Iter, ConstSentinel>);
+    static_assert(weakly_equality_comparable_with<ConstIter, ConstSentinel>);
+
+    View ev{NonSimpleNonCommon(buffer)};
+
+    assert(ev.begin() != ev.end());
+    assert(ev.begin() + 10 == ev.end());
+
+    assert(ev.begin() != std::as_const(ev).end());
+    assert(ev.begin() + 10 == std::as_const(ev).end());
+    // the above works because
+    static_assert(std::convertible_to<Iter, ConstIter>);
+
+    assert(std::as_const(ev).begin() != std::as_const(ev).end());
+    assert(std::as_const(ev).begin() + 10 == std::as_const(ev).end());
+  }
+
+  {
+    // underlying const/non-const sentinel can be compared with both const/non-const iterator
+    using View = std::ranges::enumerate_view<ComparableView>;
+    static_assert(!std::ranges::common_range<View>);
+    static_assert(!simple_view<View>);
+
+    using Iter      = std::ranges::iterator_t<View>;
+    using ConstIter = std::ranges::iterator_t<const View>;
+    static_assert(!std::is_same_v<Iter, ConstIter>);
+
+    using Sentinel      = std::ranges::sentinel_t<View>;
+    using ConstSentinel = std::ranges::sentinel_t<const View>;
+    static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
+
+    static_assert(weakly_equality_comparable_with<Iter, Sentinel>);
+    static_assert(weakly_equality_comparable_with<ConstIter, Sentinel>);
+    static_assert(weakly_equality_comparable_with<Iter, ConstSentinel>);
+    static_assert(weakly_equality_comparable_with<ConstIter, ConstSentinel>);
+
+    View ev{ComparableView(buffer)};
+
+    assert(ev.begin() != ev.end());
+    assert(ev.begin() + 10 == ev.end());
+
+    static_assert(!std::convertible_to<Iter, ConstIter>);
+
+    assert(ev.begin() != std::as_const(ev).end());
+    assert(ev.begin() + 10 == std::as_const(ev).end());
+
+    assert(std::as_const(ev).begin() != ev.end());
+    assert(std::as_const(ev).begin() + 10 == ev.end());
+
+    assert(std::as_const(ev).begin() != std::as_const(ev).end());
+    assert(std::as_const(ev).begin() + 10 == std::as_const(ev).end());
+  }
+
+  {
+    // underlying const/non-const sentinel cannot be compared with non-const/const iterator
+
+    using View = std::ranges::enumerate_view<ComparableView>;
+    static_assert(!std::ranges::common_range<View>);
+    static_assert(!simple_view<View>);
+
+    using Iter      = std::ranges::iterator_t<View>;
+    using ConstIter = std::ranges::iterator_t<const View>;
+    static_assert(!std::is_same_v<Iter, ConstIter>);
+
+    using Sentinel      = std::ranges::sentinel_t<View>;
+    using ConstSentinel = std::ranges::sentinel_t<const View>;
+    static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
+
+    static_assert(weakly_equality_comparable_with<Iter, Sentinel>);
+    static_assert(weakly_equality_comparable_with<ConstIter, Sentinel>);
+    static_assert(weakly_equality_comparable_with<Iter, ConstSentinel>);
+    static_assert(weakly_equality_comparable_with<ConstIter, ConstSentinel>);
+
+    View ev{ComparableView(buffer)};
+
+    assert(ev.begin() != ev.end());
+    assert(ev.begin() + 10 == ev.end());
+
+    assert(std::as_const(ev).begin() != std::as_const(ev).end());
+    assert(std::as_const(ev).begin() + 10 == std::as_const(ev).end());
+  }
+
+  {
+    // input_iterator
+
+    using InputIterator = cpp20_input_iterator<int*>;
+    using View          = MinimalView<InputIterator>;
+    View mv{InputIterator(std::to_address(base(buffer.begin()))), Sentinel(InputIterator(std::to_address(base(buffer.end()))))};
+    std::ranges::enumerate_view ev(std::move(mv));
+
+    assert(ev.begin() != ev.end());
+    assert(ev.begin() + 10 == ev.end());
+  }
+
   return true;
 }
 

>From 8464810f60865a2cd7fe9f6d3b7c129c17f7d6ca Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Fri, 2 Oct 2026 14:05:46 +0200
Subject: [PATCH 7/8] fix: clang-format

---
 .../range.adaptors/range.enumerate/sentinel/equal.pass.cpp     | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
index 478324af48d0d6..58987f14593202 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
@@ -191,7 +191,8 @@ constexpr bool test() {
 
     using InputIterator = cpp20_input_iterator<int*>;
     using View          = MinimalView<InputIterator>;
-    View mv{InputIterator(std::to_address(base(buffer.begin()))), Sentinel(InputIterator(std::to_address(base(buffer.end()))))};
+    View mv{InputIterator(std::to_address(base(buffer.begin()))),
+            Sentinel(InputIterator(std::to_address(base(buffer.end()))))};
     std::ranges::enumerate_view ev(std::move(mv));
 
     assert(ev.begin() != ev.end());

>From a83398b26cc56bcada855ba7a70711c58f8664e8 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Fri, 2 Oct 2026 14:33:32 +0200
Subject: [PATCH 8/8] fix: input_iterator test

---
 .../range.enumerate/sentinel/equal.pass.cpp   | 25 +++++++++++++------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
index 58987f14593202..99f921a897c24c 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/equal.pass.cpp
@@ -159,7 +159,6 @@ constexpr bool test() {
 
   {
     // underlying const/non-const sentinel cannot be compared with non-const/const iterator
-
     using View = std::ranges::enumerate_view<ComparableView>;
     static_assert(!std::ranges::common_range<View>);
     static_assert(!simple_view<View>);
@@ -187,16 +186,26 @@ constexpr bool test() {
   }
 
   {
-    // input_iterator
-
+    // sentinel comparison with input move-only iterator must work without copying the iterator
     using InputIterator = cpp20_input_iterator<int*>;
-    using View          = MinimalView<InputIterator>;
-    View mv{InputIterator(std::to_address(base(buffer.begin()))),
-            Sentinel(InputIterator(std::to_address(base(buffer.end()))))};
+    using Sentinel      = sentinel_wrapper<InputIterator>;
+    using View          = MinimalView<InputIterator, Sentinel>;
+    static_assert(simple_view<View>);
+
+    View mv{InputIterator(buffer), Sentinel(InputIterator(buffer + 10))};
     std::ranges::enumerate_view ev(std::move(mv));
 
-    assert(ev.begin() != ev.end());
-    assert(ev.begin() + 10 == ev.end());
+    auto it = ev.begin();
+    assert(it != ev.end());
+    assert(ev.end() != it);
+
+    // enumerate_view iterator only has operator+ when the underlying range is random-access.
+    // for input_iterator we increment it explicitly.
+    for (int i = 0; i != 10; ++i)
+      ++it;
+
+    assert(it == ev.end());
+    assert(ev.end() == it);
   }
 
   return true;



More information about the libcxx-commits mailing list