[PATCH] libstdc++: Handle integer-class types as bound of repeat_view

Tomasz Kamiński tkaminsk@redhat.com
Fri Sep 18 11:22:11 GMT 2026


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 LWG4581, "constant_of(^^v) for variable v of reference
to array/function type produces reflection of pointer constant".

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.
---
It took me some time to reffer unsigned integer-class, without using
to std::__detail::__max_size_type directly.

Tested on x86_64-linux. *repeat* test also passed in all standard modes,
debug, assertions, -m32. OK for trunk?


 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 a7fb2312fe8..1c0991cae13 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 eb0c848e9ce..3b81e528310 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();
 }
-- 
2.55.0



More information about the Libstdc++ mailing list