https://gcc.gnu.org/g:44ecf86ff9d0fc07a6b8676a38097a1124e0b314
commit r17-4776-g44ecf86ff9d0fc07a6b8676a38097a1124e0b314 Author: Tomasz KamiĆski <[email protected]> Date: Tue Sep 29 18:50:59 2026 +0200 libstdc++: Handle integer-class types as bound of repeat_view As iter_difference_t is not defined for integer-class types, the unsigned integer-class types are rejected (they are not weekly_incrementable) and difference_type definition is updated to not instantiate __iota_diff_t for all signed integer-like types. This implements LWG3875, "std::ranges::repeat_view<T, IntegerClass>::iterator may be ill-formed". The standard uses integer-like-with-usable-difference-type helper concept, but I do not think it provides enough improvement to justify adding a namespace level symbol. libstdc++-v3/ChangeLog: * include/std/ranges (std::repeat_view, repeat_view::_Iterator): Update constrains. (repeat_view::_Iterator::_S_difference_type): Define. (repeat_view::_Iterator::difference_type): Define in terms of _S_difference_type. * testsuite/std/ranges/repeat/1.cc: New test case. Reviewed-by: Jonathan Wakely <[email protected]> Diff: --- libstdc++-v3/include/std/ranges | 21 ++++++++++---- libstdc++-v3/testsuite/std/ranges/repeat/1.cc | 42 +++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index a7fb2312fe88..1c0991cae138 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -7976,7 +7976,9 @@ namespace views::__adaptor #ifdef __cpp_lib_ranges_repeat // C++ >= 23 template<move_constructible _Tp, semiregular _Bound = unreachable_sentinel_t> requires is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>> - && (__detail::__is_integer_like<_Bound> || same_as<_Bound, unreachable_sentinel_t>) + && (__detail::__is_signed_integer_like<_Bound> + || (__detail::__is_integer_like<_Bound> && weakly_incrementable<_Bound>) + || same_as<_Bound, unreachable_sentinel_t>) class repeat_view : public view_interface<repeat_view<_Tp, _Bound>> { [[no_unique_address]] __detail::__box<_Tp> _M_value; @@ -8050,12 +8052,23 @@ namespace views::__adaptor template<move_constructible _Tp, semiregular _Bound> requires is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>> - && (__detail::__is_integer_like<_Bound> || same_as<_Bound, unreachable_sentinel_t>) + && (__detail::__is_signed_integer_like<_Bound> + || (__detail::__is_integer_like<_Bound> && weakly_incrementable<_Bound>) + || same_as<_Bound, unreachable_sentinel_t>) class repeat_view<_Tp, _Bound>::_Iterator { using __index_type = __conditional_t<same_as<_Bound, unreachable_sentinel_t>, ptrdiff_t, _Bound>; + static auto + _S_difference_type() + { + if constexpr (__detail::__is_signed_integer_like<__index_type>) + return __index_type{}; + else + return __detail::__iota_diff_t<__index_type>{}; + } + const _Tp* _M_value = nullptr; __index_type _M_current = __index_type(); @@ -8073,9 +8086,7 @@ namespace views::__adaptor using iterator_concept = random_access_iterator_tag; using iterator_category = random_access_iterator_tag; using value_type = _Tp; - using difference_type = __conditional_t<__detail::__is_signed_integer_like<__index_type>, - __index_type, - __detail::__iota_diff_t<__index_type>>; + using difference_type = decltype(_S_difference_type()); _Iterator() = default; diff --git a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc index eb0c848e9ce3..3b81e5283106 100644 --- a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc +++ b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc @@ -172,6 +172,47 @@ test09() VERIFY( v[0][0] == 5 ); } +template<typename T, typename B> +concept can_repeat = requires (T t, B b) { + typename ranges::repeat_view<T, B>; + views::repeat(t, b); +}; + +void +test10() +{ + // LWG 3875. std::ranges::repeat_view<T, IntegerClass>::iterator may be ill-formed +#ifdef __SIZEOF_INT128__ + using max_sint = __int128; + using max_uint = unsigned __int128; +#else + using max_sint = long long; + using max_uint = unsigned long long; +#endif + + static_assert( can_repeat<int, max_sint> ); + ranges::repeat_view<int, max_sint> r1(1, 10); + VERIFY( ranges::count(r1, 1) == 10 ); + + static_assert( can_repeat<int, max_uint> ); + ranges::repeat_view<int, max_uint> r2(2, 11); + VERIFY( ranges::count(r2, 2) == 11 ); + + using iotav = ranges::iota_view<max_sint, max_sint>; + using sint_class = ranges::range_difference_t<iotav>; + static_assert( !std::is_integral_v<sint_class> ); + + static_assert( can_repeat<int, sint_class> ); + ranges::repeat_view<int, sint_class> r3(3, 12); + VERIFY( ranges::count(r3, 3) == 12 ); + + using iotas = ranges::subrange<ranges::iterator_t<iotav>>; + using uint_class = ranges::range_size_t<iotas>; + static_assert( !std::is_integral_v<uint_class> ); + + static_assert( !can_repeat<int, uint_class> ); +} + int main() { @@ -184,4 +225,5 @@ main() test07(); test08(); test09(); + test10(); }
