[libcxx-commits] [libcxx] [libc++][ranges] Mark LWG3664 as resolved (PR #210550)

Lucas Mellone via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jul 21 02:29:36 PDT 2026


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

>From 23293789342393617472800afc72656011d5334f Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Sat, 18 Jul 2026 23:13:24 +0200
Subject: [PATCH 1/7] apply: changes from proposal and mark as Complete

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

diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index 91c4dc462c0c9..0e13c6dc62bfe 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -249,7 +249,7 @@
 "`LWG2295 <https://wg21.link/LWG2295>`__","Locale name when the provided ``Facet`` is a ``nullptr``","2023-02 (Issaquah)","","","`#105063 <https://github.com/llvm/llvm-project/issues/105063>`__",""
 "`LWG3032 <https://wg21.link/LWG3032>`__","``ValueSwappable`` requirement missing for ``push_heap`` and ``make_heap``","2023-02 (Issaquah)","","","`#105064 <https://github.com/llvm/llvm-project/issues/105064>`__",""
 "`LWG3085 <https://wg21.link/LWG3085>`__","``char_traits::copy`` precondition too weak","2023-02 (Issaquah)","","","`#105065 <https://github.com/llvm/llvm-project/issues/105065>`__",""
-"`LWG3664 <https://wg21.link/LWG3664>`__","`LWG 3392 <https://wg21.link/LWG3392>`__ ``broke std::ranges::distance(a, a+3)``","2023-02 (Issaquah)","","","`#105066 <https://github.com/llvm/llvm-project/issues/105066>`__",""
+"`LWG3664 <https://wg21.link/LWG3664>`__","`LWG 3392 <https://wg21.link/LWG3392>`__ ``broke std::ranges::distance(a, a+3)``","2023-02 (Issaquah)","|Complete|","","`#105066 <https://github.com/llvm/llvm-project/issues/105066>`__",""
 "`LWG3720 <https://wg21.link/LWG3720>`__","Restrict the valid types of ``arg-id`` for width and precision in ``std-format-spec``","2023-02 (Issaquah)","|Complete|","17","`#105067 <https://github.com/llvm/llvm-project/issues/105067>`__",""
 "`LWG3756 <https://wg21.link/LWG3756>`__","Is the ``std::atomic_flag`` class signal-safe?","2023-02 (Issaquah)","","","`#105068 <https://github.com/llvm/llvm-project/issues/105068>`__",""
 "`LWG3769 <https://wg21.link/LWG3769>`__","``basic_const_iterator::operator==`` causes infinite constraint recursion","2023-02 (Issaquah)","","","`#105069 <https://github.com/llvm/llvm-project/issues/105069>`__",""
diff --git a/libcxx/include/__iterator/distance.h b/libcxx/include/__iterator/distance.h
index c7c4ff22d6e9f..bbdd30e56730f 100644
--- a/libcxx/include/__iterator/distance.h
+++ b/libcxx/include/__iterator/distance.h
@@ -86,11 +86,11 @@ 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 {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<decay_t<_Ip>> operator()(_Ip&& __first, _Sp __last) const {
     if constexpr (sized_sentinel_for<_Sp, __remove_cvref_t<_Ip>>) {
       return __last - __first;
     } else {
-      return __last - decay_t<_Ip>(__first);
+      return __last - static_cast<decay_t<_Ip>>(__first);
     }
   }
 

>From cbed72094e96ce8a7756aa588be4dc25f608635b Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Sat, 18 Jul 2026 23:33:56 +0200
Subject: [PATCH 2/7] clang-format

---
 libcxx/include/__iterator/distance.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__iterator/distance.h b/libcxx/include/__iterator/distance.h
index bbdd30e56730f..e0a2590253c71 100644
--- a/libcxx/include/__iterator/distance.h
+++ b/libcxx/include/__iterator/distance.h
@@ -86,7 +86,8 @@ struct __distance {
   }
 
   template <class _Ip, sized_sentinel_for<decay_t<_Ip>> _Sp>
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<decay_t<_Ip>> operator()(_Ip&& __first, _Sp __last) const {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<decay_t<_Ip>>
+  operator()(_Ip&& __first, _Sp __last) const {
     if constexpr (sized_sentinel_for<_Sp, __remove_cvref_t<_Ip>>) {
       return __last - __first;
     } else {

>From a265367976e6651929998984e3284210eab11585 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Sat, 18 Jul 2026 23:58:32 +0200
Subject: [PATCH 3/7] update: comments in tests

---
 .../range.iter.ops.distance/iterator_sentinel.pass.cpp          | 2 +-
 .../range.iter.ops/range.iter.ops.distance/lwg3664.pass.cpp     | 2 +-
 2 files changed, 2 insertions(+), 2 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 c34d59e405a9e..1888f606465b2 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
@@ -13,7 +13,7 @@
 //     constexpr iter_difference_t<I> ranges::distance(I first, S last);
 //
 // template<class I, sized_sentinel_for<decay_t<I>> S>
-//   constexpr iter_difference_t<I> ranges::distance(I&& first, S last); // TODO: update when LWG3664 is resolved
+//   constexpr iter_difference_t<decay_t<I>> ranges::distance(I&& first, S last);
 
 #include <array>
 #include <cassert>
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/lwg3664.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/lwg3664.pass.cpp
index 164101c2bf5a8..bac0ffba1e7f1 100644
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/lwg3664.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/lwg3664.pass.cpp
@@ -13,7 +13,7 @@
 //     constexpr iter_difference_t<I> ranges::distance(I first, S last);
 //
 // template<class I, sized_sentinel_for<decay_t<I>> S>
-//   constexpr iter_difference_t<I> ranges::distance(const I& first, S last);
+//   constexpr iter_difference_t<decay_t<I>> ranges::distance(I&& first, S last);
 
 #include <cassert>
 #include <iterator>

>From 9452d4068636d3a8c8d31b5602b9446ffd7f7fe4 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Sun, 19 Jul 2026 00:11:01 +0200
Subject: [PATCH 4/7] add version number

---
 libcxx/docs/Status/Cxx23Issues.csv | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index 0e13c6dc62bfe..617c89508b7a3 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -249,7 +249,7 @@
 "`LWG2295 <https://wg21.link/LWG2295>`__","Locale name when the provided ``Facet`` is a ``nullptr``","2023-02 (Issaquah)","","","`#105063 <https://github.com/llvm/llvm-project/issues/105063>`__",""
 "`LWG3032 <https://wg21.link/LWG3032>`__","``ValueSwappable`` requirement missing for ``push_heap`` and ``make_heap``","2023-02 (Issaquah)","","","`#105064 <https://github.com/llvm/llvm-project/issues/105064>`__",""
 "`LWG3085 <https://wg21.link/LWG3085>`__","``char_traits::copy`` precondition too weak","2023-02 (Issaquah)","","","`#105065 <https://github.com/llvm/llvm-project/issues/105065>`__",""
-"`LWG3664 <https://wg21.link/LWG3664>`__","`LWG 3392 <https://wg21.link/LWG3392>`__ ``broke std::ranges::distance(a, a+3)``","2023-02 (Issaquah)","|Complete|","","`#105066 <https://github.com/llvm/llvm-project/issues/105066>`__",""
+"`LWG3664 <https://wg21.link/LWG3664>`__","`LWG 3392 <https://wg21.link/LWG3392>`__ ``broke std::ranges::distance(a, a+3)``","2023-02 (Issaquah)","|Complete|","24","`#105066 <https://github.com/llvm/llvm-project/issues/105066>`__",""
 "`LWG3720 <https://wg21.link/LWG3720>`__","Restrict the valid types of ``arg-id`` for width and precision in ``std-format-spec``","2023-02 (Issaquah)","|Complete|","17","`#105067 <https://github.com/llvm/llvm-project/issues/105067>`__",""
 "`LWG3756 <https://wg21.link/LWG3756>`__","Is the ``std::atomic_flag`` class signal-safe?","2023-02 (Issaquah)","","","`#105068 <https://github.com/llvm/llvm-project/issues/105068>`__",""
 "`LWG3769 <https://wg21.link/LWG3769>`__","``basic_const_iterator::operator==`` causes infinite constraint recursion","2023-02 (Issaquah)","","","`#105069 <https://github.com/llvm/llvm-project/issues/105069>`__",""

>From c8e9bf8199acfc396e09077e01eb52c240fa2636 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Sun, 19 Jul 2026 13:01:31 +0200
Subject: [PATCH 5/7] Apply suggestion from @frederick-vs-ja

Co-authored-by: A. Jiang <de34 at live.cn>
---
 libcxx/docs/Status/Cxx23Issues.csv | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index 617c89508b7a3..4b80d5ebf3623 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -249,7 +249,7 @@
 "`LWG2295 <https://wg21.link/LWG2295>`__","Locale name when the provided ``Facet`` is a ``nullptr``","2023-02 (Issaquah)","","","`#105063 <https://github.com/llvm/llvm-project/issues/105063>`__",""
 "`LWG3032 <https://wg21.link/LWG3032>`__","``ValueSwappable`` requirement missing for ``push_heap`` and ``make_heap``","2023-02 (Issaquah)","","","`#105064 <https://github.com/llvm/llvm-project/issues/105064>`__",""
 "`LWG3085 <https://wg21.link/LWG3085>`__","``char_traits::copy`` precondition too weak","2023-02 (Issaquah)","","","`#105065 <https://github.com/llvm/llvm-project/issues/105065>`__",""
-"`LWG3664 <https://wg21.link/LWG3664>`__","`LWG 3392 <https://wg21.link/LWG3392>`__ ``broke std::ranges::distance(a, a+3)``","2023-02 (Issaquah)","|Complete|","24","`#105066 <https://github.com/llvm/llvm-project/issues/105066>`__",""
+"`LWG3664 <https://wg21.link/LWG3664>`__","`LWG 3392 <https://wg21.link/LWG3392>`__ ``broke std::ranges::distance(a, a+3)``","2023-02 (Issaquah)","|Complete|","14","`#105066 <https://github.com/llvm/llvm-project/issues/105066>`__",""
 "`LWG3720 <https://wg21.link/LWG3720>`__","Restrict the valid types of ``arg-id`` for width and precision in ``std-format-spec``","2023-02 (Issaquah)","|Complete|","17","`#105067 <https://github.com/llvm/llvm-project/issues/105067>`__",""
 "`LWG3756 <https://wg21.link/LWG3756>`__","Is the ``std::atomic_flag`` class signal-safe?","2023-02 (Issaquah)","","","`#105068 <https://github.com/llvm/llvm-project/issues/105068>`__",""
 "`LWG3769 <https://wg21.link/LWG3769>`__","``basic_const_iterator::operator==`` causes infinite constraint recursion","2023-02 (Issaquah)","","","`#105069 <https://github.com/llvm/llvm-project/issues/105069>`__",""

>From 934ee224bb2c04a091a0b64c48f1f2c950e597e2 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Sun, 19 Jul 2026 17:53:08 +0200
Subject: [PATCH 6/7] port lwg3664 tests to iterator_sentinel.pass.cpp

---
 .../iterator_sentinel.pass.cpp                | 39 ++++++++++
 .../range.iter.ops.distance/lwg3664.pass.cpp  | 73 -------------------
 2 files changed, 39 insertions(+), 73 deletions(-)
 delete mode 100644 libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/lwg3664.pass.cpp

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 1888f606465b2..30507c59495ea 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
@@ -183,6 +183,22 @@ constexpr void test_stride_counting() {
   assert(std::ranges::distance(view.begin(), view.end()) == n);
 }
 
+template <class It>
+struct EvilSentinel {
+  It p_;
+  friend constexpr bool operator==(EvilSentinel s, It p) { return s.p_ == p; }
+  friend constexpr auto operator-(EvilSentinel s, It p) { return s.p_ - p; }
+  friend constexpr auto operator-(It p, EvilSentinel s) { return p - s.p_; }
+  friend constexpr void operator-(EvilSentinel s, int (&)[3])        = delete;
+  friend constexpr void operator-(EvilSentinel s, int (&&)[3])       = delete;
+  friend constexpr void operator-(EvilSentinel s, const int (&)[3])  = delete;
+  friend constexpr void operator-(EvilSentinel s, const int (&&)[3]) = delete;
+};
+static_assert(std::sized_sentinel_for<EvilSentinel<int*>, int*>);
+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*>);
+
 constexpr bool test() {
   {
     int a[] = {1, 2, 3};
@@ -271,6 +287,29 @@ constexpr bool test() {
   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*>>);
+  }
+
   return true;
 }
 
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/lwg3664.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/lwg3664.pass.cpp
deleted file mode 100644
index bac0ffba1e7f1..0000000000000
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/lwg3664.pass.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17
-
-// template<class I, sentinel_for<I> S>
-//   requires (!sized_sentinel_for<S, I>)
-//     constexpr iter_difference_t<I> ranges::distance(I first, S last);
-//
-// template<class I, sized_sentinel_for<decay_t<I>> S>
-//   constexpr iter_difference_t<decay_t<I>> ranges::distance(I&& first, S last);
-
-#include <cassert>
-#include <iterator>
-#include <type_traits>
-#include <utility>
-
-#include "test_iterators.h"
-
-template<class It>
-struct EvilSentinel {
-  It p_;
-  friend constexpr bool operator==(EvilSentinel s, It p) { return s.p_ == p; }
-  friend constexpr auto operator-(EvilSentinel s, It p) { return s.p_ - p; }
-  friend constexpr auto operator-(It p, EvilSentinel s) { return p - s.p_; }
-  friend constexpr void operator-(EvilSentinel s, int(&)[3]) = delete;
-  friend constexpr void operator-(EvilSentinel s, int(&&)[3]) = delete;
-  friend constexpr void operator-(EvilSentinel s, const int(&)[3]) = delete;
-  friend constexpr void operator-(EvilSentinel s, const int(&&)[3]) = delete;
-};
-static_assert( std::sized_sentinel_for<EvilSentinel<int*>, int*>);
-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*>);
-
-constexpr bool test() {
-  {
-    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*>>);
-  }
-
-  return true;
-}
-
-int main(int, char**) {
-  test();
-  static_assert(test());
-
-  return 0;
-}

>From 09717349d634bce08c26b9e3ca3cb9d927f6a80a Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Tue, 21 Jul 2026 11:29:21 +0200
Subject: [PATCH 7/7] revert: initial changes

---
 libcxx/include/__iterator/distance.h | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__iterator/distance.h b/libcxx/include/__iterator/distance.h
index e0a2590253c71..c7c4ff22d6e9f 100644
--- a/libcxx/include/__iterator/distance.h
+++ b/libcxx/include/__iterator/distance.h
@@ -86,12 +86,11 @@ struct __distance {
   }
 
   template <class _Ip, sized_sentinel_for<decay_t<_Ip>> _Sp>
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<decay_t<_Ip>>
-  operator()(_Ip&& __first, _Sp __last) const {
+  [[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>>) {
       return __last - __first;
     } else {
-      return __last - static_cast<decay_t<_Ip>>(__first);
+      return __last - decay_t<_Ip>(__first);
     }
   }
 



More information about the libcxx-commits mailing list