[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