commit 5e9ad288eb6fb366142b166e7985d16727b398e1 Author: Jonathan Wakely Date: Thu Aug 20 19:41:15 2020 libstdc++: Make incrementable<__int128> satisfied in strict mode This adds specializations of std::incrementable_traits so that 128-bit integers are always considered incrementable (and therefore usable with std::ranges::iota_view) even when they don't satisfy std::integral. libstdc++-v3/ChangeLog: * include/bits/iterator_concepts.h [__STRICT_ANSI__] (incrementable_traits<__int128>): Define specialization. (incrementable_traits): Likewise. * testsuite/std/ranges/iota/96042.cc: Test iota_view with __int128. diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h index 5033f2bddc3..bd6660c5f22 100644 --- a/libstdc++-v3/include/bits/iterator_concepts.h +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -173,6 +173,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION = make_signed_t() - std::declval<_Tp>())>; }; +#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ + // __int128 is incrementable even if !integral<__int128> + template<> + struct incrementable_traits<__int128> + { using difference_type = __int128; }; + + template<> + struct incrementable_traits + { using difference_type = __int128; }; +#endif + namespace __detail { // An iterator such that iterator_traits<_Iter> names a specialization diff --git a/libstdc++-v3/testsuite/std/ranges/iota/96042.cc b/libstdc++-v3/testsuite/std/ranges/iota/96042.cc index 6f5c8f61fd2..911663bc413 100644 --- a/libstdc++-v3/testsuite/std/ranges/iota/96042.cc +++ b/libstdc++-v3/testsuite/std/ranges/iota/96042.cc @@ -24,8 +24,13 @@ void test01() { // PR libstdc++/96042 - using V = std::ranges::iota_view; + using V = std::ranges::iota_view; + + // In strict -std=c++20 mode there is no integer wider than long long, + // so V's difference type is an integer-class type, [iterator.concept.winc]. + // In practice this is either __int128 or __detail::__max_diff_type. using D = std::ranges::range_difference_t; + // Ensure that numeric_limits is correctly specialized for the type. using L = std::numeric_limits; static_assert( L::is_specialized ); static_assert( L::is_signed ); @@ -37,3 +42,24 @@ test01() static_assert( L::max() == ~L::min() ); static_assert( L::lowest() == L::min() ); } + +#ifdef __SIZEOF_INT128__ +void +test02() +{ + // When the target supports __int128 it can be used in iota_view + // even in strict mode where !integral<__int128>. + using V = std::ranges::iota_view<__int128, __int128>; + using D = std::ranges::range_difference_t; // __detail::__max_diff_type + using L = std::numeric_limits; + static_assert( L::is_specialized ); + static_assert( L::is_signed ); + static_assert( L::is_integer ); + static_assert( L::is_exact ); + static_assert( L::digits > std::numeric_limits::digits ); + static_assert( L::digits10 == static_cast(L::digits * 0.30103) ); + static_assert( L::min() == (D(1) << L::digits) ); + static_assert( L::max() == ~L::min() ); + static_assert( L::lowest() == L::min() ); +} +#endif