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 `__","``cache_latest_view`` and ``to_input_view`` miss ``reserve_hint``","2025-06 (Sofia)","","","`#148219 `__","" "`LWG4236 `__","``chunk_view::outer-iterator::value_type`` should provide ``reserve_hint``","2025-06 (Sofia)","","","`#148220 `__","" "`LWG4239 `__","``flat_map``'s transparent comparator no longer works for string literals","2025-06 (Sofia)","","","`#148223 `__","" -"`LWG4242 `__","``ranges::distance`` does not work with volatile iterators","2025-06 (Sofia)","","","`#148224 `__","" +"`LWG4242 `__","``ranges::distance`` does not work with volatile iterators","2025-06 (Sofia)","|Complete|","24","`#148224 `__","" "`LWG4245 `__","Operators that interact with ``counted_iterator`` and ``default_sentinel_t`` should be ``noexcept``","2025-06 (Sofia)","","","`#148226 `__","" "`LWG4247 `__","Header ```` is not yet freestanding","2025-06 (Sofia)","","","`#148227 `__","" "","","","","","","" diff --git a/libcxx/include/__iterator/distance.h b/libcxx/include/__iterator/distance.h index c7c4ff22d6e9f..20f186bc89c8a 100644 --- a/libcxx/include/__iterator/distance.h +++ b/libcxx/include/__iterator/distance.h @@ -22,7 +22,8 @@ #include <__ranges/size.h> #include <__type_traits/decay.h> #include <__type_traits/enable_if.h> -#include <__type_traits/remove_cvref.h> +#include <__type_traits/is_array.h> +#include <__type_traits/remove_reference.h> #include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -87,10 +88,10 @@ struct __distance { template > _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>) { return __last - __first; } else { - return __last - decay_t<_Ip>(__first); + return __last - static_cast>(__first); } } 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, const int*>); static_assert(std::sized_sentinel_for, int*>); static_assert(std::sized_sentinel_for, 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{a + 3}) == 3); + assert(std::ranges::distance(a, EvilSentinel{a}) == 0); + assert(std::ranges::distance(a + 3, EvilSentinel{a}) == -3); + assert(std::ranges::distance(std::move(a), EvilSentinel{a + 3}) == 3); + } + { + const int a[] = {1, 2, 3}; + assert(std::ranges::distance(a, EvilSentinel{a + 3}) == 3); + assert(std::ranges::distance(a, EvilSentinel{a}) == 0); + assert(std::ranges::distance(a + 3, EvilSentinel{a}) == -3); + assert(std::ranges::distance(std::move(a), EvilSentinel{a + 3}) == 3); + static_assert(!std::is_invocable_v>); + static_assert(!std::is_invocable_v>); + } +} + +// 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{a + 3}) == 3); - assert(std::ranges::distance(a, EvilSentinel{a}) == 0); - assert(std::ranges::distance(a + 3, EvilSentinel{a}) == -3); - assert(std::ranges::distance(std::move(a), EvilSentinel{a + 3}) == 3); - } - { - const int a[] = {1, 2, 3}; - assert(std::ranges::distance(a, EvilSentinel{a + 3}) == 3); - assert(std::ranges::distance(a, EvilSentinel{a}) == 0); - assert(std::ranges::distance(a + 3, EvilSentinel{a}) == -3); - assert(std::ranges::distance(std::move(a), EvilSentinel{a + 3}) == 3); - static_assert(!std::is_invocable_v>); - static_assert(!std::is_invocable_v>); + 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;