On 19/08/20 20:36 +0100, Jonathan Wakely wrote:
On 19/08/20 17:00 +0100, Jonathan Wakely wrote:
Because __int128 can be used as the difference type for iota_view, we
need to ensure that it meets the requirements of an integer-class type.
The requirements in [iterator.concept.winc] p10 include numeric_limits
being specialized and giving meaningful answers. Currently we only
specialize numeric_limits for non-standard integer types in non-strict
modes. However, nothing prevents us from defining an explicit
specialization for any implementation-defined type, so it doesn't matter
whether std::is_integral<__int128> is true or not.
This patch ensures that the numeric_limits specializations for signed
and unsigned __int128 are defined whenever __int128 is available. It
also makes the __numeric_traits and __int_limits helpers work for
__int128, via a new __gnu_cxx::__is_integer_nonstrict trait.
libstdc++-v3/ChangeLog:
PR libstdc++/96042
* include/ext/numeric_traits.h (__is_integer_nonstrict): New
trait which is true for 128-bit integers even in strict modes.
(__numeric_traits_integer, __numeric_traits): Use
__is_integer_nonstrict instead of __is_integer.
* include/std/limits [__STRICT_ANSI__ && __SIZEOF_INT128__]
(numeric_limits<__int128>, (numeric_limits<unsigned __int128>):
Define.
* testsuite/std/ranges/iota/96042.cc: New test.
The attached patch is another change needed to support __int128 as an
integer-like type in strict mode.
And one more piece of __int128 support.
Tested x86_64-linux, -m32 and -m64. Committed to trunk.
I'll backport this to gcc-10 too.
commit 5e9ad288eb6fb366142b166e7985d16727b398e1
Author: Jonathan Wakely <jwak...@redhat.com>
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<unsigned __int128>): 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<decltype(std::declval<_Tp>() - 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<unsigned __int128>
+ { 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<long long, int>;
+ using V = std::ranges::iota_view<long long, long long>;
+
+ // 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<V>;
+ // Ensure that numeric_limits is correctly specialized for the type.
using L = std::numeric_limits<D>;
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<V>; // __detail::__max_diff_type
+ using L = std::numeric_limits<D>;
+ 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<long long>::digits );
+ static_assert( L::digits10 == static_cast<int>(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