diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h index 6cfa6fb6afe..519927f5613 100644 --- a/libstdc++-v3/include/bits/ranges_base.h +++ b/libstdc++-v3/include/bits/ranges_base.h @@ -969,8 +969,6 @@ namespace ranges struct __distance_fn final { - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 3664. LWG 3392 broke std::ranges::distance(a, a+3) template _Sent> requires (!sized_sentinel_for<_Sent, _It>) constexpr iter_difference_t<_It> @@ -985,11 +983,20 @@ namespace ranges return __n; } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3392. cannot be used on a move-only iterator with a sized sentinel + // 3664. LWG 3392 broke std::ranges::distance(a, a+3) + // 4242. ranges::distance does not work with volatile iterators template> _Sent> [[nodiscard, __gnu__::__always_inline__]] constexpr iter_difference_t> operator()(_It&& __first, _Sent __last) const - { return __last - static_cast&>(__first); } + { + if constexpr (!is_array_v>) + return __last - __first; + else + return __last - static_cast>(__first); + } template [[nodiscard, __gnu__::__always_inline__]] diff --git a/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc b/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc index 46e33a2aa70..65edeb8ab02 100644 --- a/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc +++ b/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc @@ -154,6 +154,23 @@ test06() VERIFY( std::ranges::distance(a+3, a) == -3 ); } +void +test_lwg4242() +{ + // LWG 4242. ranges::distance does not work with volatile iterators + int arr[] = {1, 2, 3}; + int* volatile ptr = arr; + auto d1 = std::distance(ptr, arr + 3); + auto d2 = std::ranges::distance(ptr, arr + 3); + VERIFY( d1 == d2 ); + + // This is not part of LWG 4242 but it doesn't hurt to check it anyway: + volatile int vol_arr[1]{}; + auto d3 = std::distance(vol_arr, vol_arr + 1); + auto d4 = std::ranges::distance(vol_arr, vol_arr + 1); + VERIFY( d3 == d4 ); +} + int main() { @@ -163,4 +180,5 @@ main() test04(); test05(); test06(); + test_lwg4242(); }