https://gcc.gnu.org/g:04815ae0a2b27895411506813db3a8b460be1d6d

commit r15-7989-g04815ae0a2b27895411506813db3a8b460be1d6d
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Tue Mar 11 15:47:21 2025 +0000

    libstdc++: Make range adaptor __has_arrow helper use a const type
    
    LWG 4112 (approved in Wrocław, November 2024) changes the has-arrow
    helper to require operator-> to be valid on a const-qualified lvalue.
    This affects the constraints for filter_view::_Iterator::operator-> and
    join_view::_Iterator::operator-> so that they can only be used if the
    underlying iterator supports operator-> on const.
    
    The change also adds semantic (i.e. not checkable and not enforced)
    requirements that operator-> must have the same semantics whether called
    on a const or non-const value, and on an lvalue or rvalue (due to the
    implicit expression variation rules in [concepts.equality]).
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/ranges_util.h (ranges::_detail::__has_arrow):
            Require operator->() to be valid on const-qualified type, as per
            LWG 4112.
            * testsuite/std/ranges/adaptors/lwg4112.cc: New test.
    
    Reviewed-by: Tomasz Kamiński <tkami...@redhat.com>

Diff:
---
 libstdc++-v3/include/bits/ranges_util.h            |  5 ++-
 .../testsuite/std/ranges/adaptors/lwg4112.cc       | 41 ++++++++++++++++++++++
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/bits/ranges_util.h 
b/libstdc++-v3/include/bits/ranges_util.h
index 54e4f6261b05..53b7f5c17f1c 100644
--- a/libstdc++-v3/include/bits/ranges_util.h
+++ b/libstdc++-v3/include/bits/ranges_util.h
@@ -54,9 +54,12 @@ namespace ranges
        && same_as<iterator_t<_Range>, iterator_t<const _Range>>
        && same_as<sentinel_t<_Range>, sentinel_t<const _Range>>;
 
+    // _GLIBCXX_RESOLVE_LIB_DEFECTS
+    // 4112. has-arrow should required operator->() to be const-qualified
     template<typename _It>
       concept __has_arrow = input_iterator<_It>
-       && (is_pointer_v<_It> || requires(_It __it) { __it.operator->(); });
+       && (is_pointer_v<_It>
+             || requires(const _It __it) { __it.operator->(); });
 
     using std::__detail::__different_from;
   } // namespace __detail
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/lwg4112.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/lwg4112.cc
new file mode 100644
index 000000000000..a283504b636d
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/lwg4112.cc
@@ -0,0 +1,41 @@
+// { dg-do compile { target c++20 } }
+
+// LWG 4112. has-arrow should required operator->() to be const-qualified
+
+// The issue resolution means that range adaptors which use has-arrow to
+// constrain their iterator's operator-> should require a const-qualified
+// operator-> on the underlying view's iterator.
+
+#include <ranges>
+
+struct Int { int i = 0; };
+
+struct Iter
+{
+  using value_type = Int;
+  using difference_type = int;
+
+  mutable Int val;
+
+  Int& operator*() const { return val; }
+  Int* operator->() /* non-const */ { return &val; }
+  Iter& operator++() { ++val.i; return *this; }
+  void operator++(int) { ++val.i; }
+  bool operator==(const Iter& j) const { return val.i == j.val.i; }
+};
+
+template<typename T>
+concept has_op_arrow = requires (T t) { t.operator->(); };
+
+static_assert( has_op_arrow<Iter> );
+static_assert( ! has_op_arrow<const Iter> );
+
+using Range = std::ranges::subrange<Iter>;
+using Pred = bool(*)(Int);
+using FilterView = std::ranges::filter_view<Range, Pred>;
+using FilterIterator = std::ranges::iterator_t<FilterView>;
+
+static_assert( ! has_op_arrow<FilterIterator> );
+static_assert( ! has_op_arrow<FilterIterator&> );
+static_assert( ! has_op_arrow<FilterIterator const> );
+static_assert( ! has_op_arrow<FilterIterator const&> );

Reply via email to