[libcxx-commits] [libcxx] [libc++][ranges] Resolve LWG4242 (PR #211568)

Lucas Mellone via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jul 23 07:43:23 PDT 2026


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

>From 8e3559129e89e81f7b8bf0d195222363898ef654 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Thu, 23 Jul 2026 15:38:21 +0200
Subject: [PATCH 1/2] resolve: LWG4242

---
 libcxx/docs/Status/Cxx26Issues.csv   | 2 +-
 libcxx/include/__iterator/distance.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/docs/Status/Cxx26Issues.csv b/libcxx/docs/Status/Cxx26Issues.csv
index 5b046b69d14bd..83ad46827ca18 100644
--- a/libcxx/docs/Status/Cxx26Issues.csv
+++ b/libcxx/docs/Status/Cxx26Issues.csv
@@ -142,7 +142,7 @@
 "`LWG4235 <https://wg21.link/LWG4235>`__","``cache_latest_view`` and ``to_input_view`` miss ``reserve_hint``","2025-06 (Sofia)","","","`#148219 <https://github.com/llvm/llvm-project/issues/148219>`__",""
 "`LWG4236 <https://wg21.link/LWG4236>`__","``chunk_view::outer-iterator::value_type`` should provide ``reserve_hint``","2025-06 (Sofia)","","","`#148220 <https://github.com/llvm/llvm-project/issues/148220>`__",""
 "`LWG4239 <https://wg21.link/LWG4239>`__","``flat_map``'s transparent comparator no longer works for string literals","2025-06 (Sofia)","","","`#148223 <https://github.com/llvm/llvm-project/issues/148223>`__",""
-"`LWG4242 <https://wg21.link/LWG4242>`__","``ranges::distance`` does not work with volatile iterators","2025-06 (Sofia)","","","`#148224 <https://github.com/llvm/llvm-project/issues/148224>`__",""
+"`LWG4242 <https://wg21.link/LWG4242>`__","``ranges::distance`` does not work with volatile iterators","2025-06 (Sofia)","|Complete|","24","`#148224 <https://github.com/llvm/llvm-project/issues/148224>`__",""
 "`LWG4245 <https://wg21.link/LWG4245>`__","Operators that interact with ``counted_iterator`` and ``default_sentinel_t`` should be ``noexcept``","2025-06 (Sofia)","","","`#148226 <https://github.com/llvm/llvm-project/issues/148226>`__",""
 "`LWG4247 <https://wg21.link/LWG4247>`__","Header ``<stdbit.h>`` is not yet freestanding","2025-06 (Sofia)","","","`#148227 <https://github.com/llvm/llvm-project/issues/148227>`__",""
 "","","","","","",""
diff --git a/libcxx/include/__iterator/distance.h b/libcxx/include/__iterator/distance.h
index c7c4ff22d6e9f..029117e2ff5cc 100644
--- a/libcxx/include/__iterator/distance.h
+++ b/libcxx/include/__iterator/distance.h
@@ -87,7 +87,7 @@ struct __distance {
 
   template <class _Ip, sized_sentinel_for<decay_t<_Ip>> _Sp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Ip> operator()(_Ip&& __first, _Sp __last) const {
-    if constexpr (sized_sentinel_for<_Sp, __remove_cvref_t<_Ip>>) {
+    if constexpr (!is_array_v<remove_reference_t<_Ip>>) {
       return __last - __first;
     } else {
       return __last - decay_t<_Ip>(__first);

>From 654370a5f26aed08caebe4fbc98f09417e272517 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Thu, 23 Jul 2026 15:56:59 +0200
Subject: [PATCH 2/2] add: lwg4242 test case and refactor lwg3664 test case

---
 .../iterator_sentinel.pass.cpp                | 63 ++++++++++++-------
 1 file changed, 40 insertions(+), 23 deletions(-)

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 30507c59495ea..37ee37a0e5876 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
@@ -199,6 +199,41 @@ static_assert(!std::sized_sentinel_for<EvilSentinel<int*>, const int*>);
 static_assert(std::sized_sentinel_for<EvilSentinel<const int*>, int*>);
 static_assert(std::sized_sentinel_for<EvilSentinel<const int*>, const int*>);
 
+// LWG3664: "LWG3392 broke std::ranges::distance(a, a+3)" tests.
+constexpr void test_lwg3664() {
+  {
+    int a[] = {1, 2, 3};
+    assert(std::ranges::distance(a, a + 3) == 3);
+    assert(std::ranges::distance(a, a) == 0);
+    assert(std::ranges::distance(a + 3, a) == -3);
+  }
+  {
+    int a[] = {1, 2, 3};
+    assert(std::ranges::distance(a, EvilSentinel<int*>{a + 3}) == 3);
+    assert(std::ranges::distance(a, EvilSentinel<int*>{a}) == 0);
+    assert(std::ranges::distance(a + 3, EvilSentinel<int*>{a}) == -3);
+    assert(std::ranges::distance(std::move(a), EvilSentinel<int*>{a + 3}) == 3);
+  }
+  {
+    const int a[] = {1, 2, 3};
+    assert(std::ranges::distance(a, EvilSentinel<const int*>{a + 3}) == 3);
+    assert(std::ranges::distance(a, EvilSentinel<const int*>{a}) == 0);
+    assert(std::ranges::distance(a + 3, EvilSentinel<const int*>{a}) == -3);
+    assert(std::ranges::distance(std::move(a), EvilSentinel<const int*>{a + 3}) == 3);
+    static_assert(!std::is_invocable_v<decltype(std::ranges::distance), const int (&)[3], EvilSentinel<int*>>);
+    static_assert(!std::is_invocable_v<decltype(std::ranges::distance), const int (&&)[3], EvilSentinel<int*>>);
+  }
+}
+
+// LWG4242: "ranges::distance does not work with volatile iterators" tests.
+void test_lwg4242() {
+  int arr[]         = {1, 2, 3};
+  int* volatile ptr = arr;
+  auto dist         = std::distance(ptr, arr + 3);
+  auto r_dist       = std::ranges::distance(ptr, arr + 3);
+  assert(dist == r_dist);
+}
+
 constexpr bool test() {
   {
     int a[] = {1, 2, 3};
@@ -284,30 +319,12 @@ constexpr bool test() {
     auto view = c | std::views::join;
     assert(std::ranges::distance(view.begin(), view.end()) == 30);
   }
-  if (!TEST_IS_CONSTANT_EVALUATED) // TODO: Use TEST_STD_AT_LEAST_26_OR_RUNTIME_EVALUATED when std::deque is made constexpr
-    test_deque();
 
-  {
-    int a[] = {1, 2, 3};
-    assert(std::ranges::distance(a, a + 3) == 3);
-    assert(std::ranges::distance(a, a) == 0);
-    assert(std::ranges::distance(a + 3, a) == -3);
-  }
-  {
-    int a[] = {1, 2, 3};
-    assert(std::ranges::distance(a, EvilSentinel<int*>{a + 3}) == 3);
-    assert(std::ranges::distance(a, EvilSentinel<int*>{a}) == 0);
-    assert(std::ranges::distance(a + 3, EvilSentinel<int*>{a}) == -3);
-    assert(std::ranges::distance(std::move(a), EvilSentinel<int*>{a + 3}) == 3);
-  }
-  {
-    const int a[] = {1, 2, 3};
-    assert(std::ranges::distance(a, EvilSentinel<const int*>{a + 3}) == 3);
-    assert(std::ranges::distance(a, EvilSentinel<const int*>{a}) == 0);
-    assert(std::ranges::distance(a + 3, EvilSentinel<const int*>{a}) == -3);
-    assert(std::ranges::distance(std::move(a), EvilSentinel<const int*>{a + 3}) == 3);
-    static_assert(!std::is_invocable_v<decltype(std::ranges::distance), const int (&)[3], EvilSentinel<int*>>);
-    static_assert(!std::is_invocable_v<decltype(std::ranges::distance), const int (&&)[3], EvilSentinel<int*>>);
+  test_lwg3664();
+
+  if (!TEST_IS_CONSTANT_EVALUATED) {
+    test_deque(); // TODO: Use TEST_STD_AT_LEAST_26_OR_RUNTIME_EVALUATED when std::deque is made constexpr
+    test_lwg4242();
   }
 
   return true;



More information about the libcxx-commits mailing list