libstdc++: Make __int128 meet integer-class requirements [PR 96042]

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.
This commit is contained in:
Jonathan Wakely 2020-08-19 16:27:25 +01:00
parent 4432066509
commit 386fd16c55
3 changed files with 62 additions and 5 deletions

View File

@ -51,11 +51,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
(__glibcxx_signed(_Tp) ? \
(((((_Tp)1 << (__glibcxx_digits(_Tp) - 1)) - 1) << 1) + 1) : ~(_Tp)0)
template<typename _Tp>
struct __is_integer_nonstrict
: public std::__is_integer<_Tp>
{ };
#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
// __is_integer<__int128> is false, but we still want to allow it here.
template<> struct __is_integer_nonstrict<__int128>
{ enum { __value = 1 }; typedef std::__true_type __type; };
template<> struct __is_integer_nonstrict<unsigned __int128>
{ enum { __value = 1 }; typedef std::__true_type __type; };
#endif
template<typename _Value>
struct __numeric_traits_integer
{
#if __cplusplus >= 201103L
static_assert(std::__is_integer<_Value>::__value,
static_assert(__is_integer_nonstrict<_Value>::__value,
"invalid specialization");
#endif
@ -132,7 +146,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Value>
struct __numeric_traits
: public __conditional_type<std::__is_integer<_Value>::__value,
: public __conditional_type<__is_integer_nonstrict<_Value>::__value,
__numeric_traits_integer<_Value>,
__numeric_traits_floating<_Value> >::__type
{ };

View File

@ -1477,8 +1477,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
= round_toward_zero;
};
#if !defined(__STRICT_ANSI__)
#define __INT_N(TYPE, BITSIZE, EXT, UEXT) \
template<> \
struct numeric_limits<TYPE> \
@ -1632,6 +1630,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#define __INT_N_U201103(TYPE)
#endif
#if !defined(__STRICT_ANSI__)
#ifdef __GLIBCXX_TYPE_INT_N_0
__INT_N(__GLIBCXX_TYPE_INT_N_0, __GLIBCXX_BITSIZE_INT_N_0,
__INT_N_201103 (__GLIBCXX_TYPE_INT_N_0),
@ -1653,11 +1652,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__INT_N_U201103 (__GLIBCXX_TYPE_INT_N_3))
#endif
#elif defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
__INT_N(__int128, 128,
__INT_N_201103 (__int128),
__INT_N_U201103 (__int128))
#endif
#undef __INT_N
#undef __INT_N_201103
#undef __INT_N_U201103
#endif
/// numeric_limits<float> specialization.
template<>

View File

@ -0,0 +1,39 @@
// Copyright (C) 2020 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=c++2a" }
// { dg-do compile { target c++2a } }
#include <ranges>
void
test01()
{
// PR libstdc++/96042
using V = std::ranges::iota_view<long long, int>;
using D = std::ranges::range_difference_t<V>;
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() );
}