This implements LWG 4242 which was approved in Sofia 2025.

Replace the use of the std::decay_t trait with the C++23 auto(x)
feature, which avoids instantiating the class template.

libstdc++-v3/ChangeLog:

        * include/bits/ranges_base.h (distance(It&&, Sent)): Decay
        arrays to pointers, as per LWG 4242.
        * testsuite/24_iterators/range_operations/lwg4242.cc: New test.
---

Lightly tested on x86_64-linux so far, full tests running now.

 libstdc++-v3/include/bits/ranges_base.h       | 12 ++++++++++-
 .../24_iterators/range_operations/lwg4242.cc  | 21 +++++++++++++++++++
 2 files changed, 32 insertions(+), 1 deletion(-)
 create mode 100644 
libstdc++-v3/testsuite/24_iterators/range_operations/lwg4242.cc

diff --git a/libstdc++-v3/include/bits/ranges_base.h 
b/libstdc++-v3/include/bits/ranges_base.h
index 6cfa6fb6afe6..609e29175f06 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -989,7 +989,17 @@ namespace ranges
       [[nodiscard, __gnu__::__always_inline__]]
       constexpr iter_difference_t<decay_t<_It>>
       operator()(_It&& __first, _Sent __last) const
-      { return __last - static_cast<const decay_t<_It>&>(__first); }
+      {
+       // GLIBCXX_RESOLVE_LIB_DEFECTS
+       // 4242. ranges::distance does not work with volatile iterators
+       if constexpr (!is_array_v<remove_reference_t<_It>>)
+         return __last - __first;
+       else
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++23-extensions" // auto(x)
+         return __last - auto(__first);
+#pragma GCC diagnostic pop
+      }
 
     template<range _Range>
       [[nodiscard, __gnu__::__always_inline__]]
diff --git a/libstdc++-v3/testsuite/24_iterators/range_operations/lwg4242.cc 
b/libstdc++-v3/testsuite/24_iterators/range_operations/lwg4242.cc
new file mode 100644
index 000000000000..ec03be42cbab
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/range_operations/lwg4242.cc
@@ -0,0 +1,21 @@
+// { dg-do run { target c++20 } }
+
+// LWG 4242. ranges::distance does not work with volatile iterators
+
+#include <iterator>
+#include <testsuite_hooks.h>
+
+void
+test_lwg4242()
+{
+  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 );
+}
+
+int main()
+{
+  test_lwg4242();
+}
-- 
2.53.0

Reply via email to