On Tue, Mar 11, 2025 at 10:28 PM Jonathan Wakely <jwak...@redhat.com> wrote:
> 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. > --- > > Tested x86_64-linux. > LGTM > > libstdc++-v3/include/bits/ranges_util.h | 5 ++- > .../testsuite/std/ranges/adaptors/lwg4112.cc | 41 +++++++++++++++++++ > 2 files changed, 45 insertions(+), 1 deletion(-) > create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/lwg4112.cc > > diff --git a/libstdc++-v3/include/bits/ranges_util.h > b/libstdc++-v3/include/bits/ranges_util.h > index 54e4f6261b0..53b7f5c17f1 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 00000000000..a283504b636 > --- /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&> ); > -- > 2.48.1 > >