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&> );