mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
libstdc++: Treat __int128 as a real integral type [PR96710]
Since LWG 3828 (included in C++23) implementations are allowed to have extended integer types that are wider than intmax_t. This means we no longer have to make is_integral_v<__int128> false for strict -std=c++23 mode, removing the confusing inconsistency with -std=gnu++23 (where is_integral_v<__int128> is true). This change makes __int128 a true integral type for all modes, treating LWG 3828 as a DR for previous standards. Most of the change just involves removing special cases where we wanted to treat __int128 and unsigned __int128 as integral types even when is_integral_v was false. There are still some preprocessor conditionals needed, because on some targets the compiler defines the macro __GLIBCXX_TYPE_INT_N_0 as __int128 in non-strict modes. Because we define explicit specializations of templates such as is_integral for all the INT_N types, we already have a specialization of is_integral<__int128> in non-strict modes, and so to avoid a redefinition we only must only define is_integral<__int128> for strict modes. libstdc++-v3/ChangeLog: PR libstdc++/96710 * include/bits/cpp_type_traits.h (__is_integer): Define explicit specializations for __int128. (__memcpyable_integer): Remove explicit specializations for __int128. * include/bits/iterator_concepts.h (incrementable_traits): Likewise. (__is_signed_int128, __is_unsigned_int128, __is_int128): Remove. (__is_integer_like, __is_signed_integer_like): Remove check for __int128. * include/bits/max_size_type.h: Remove all uses of __is_int128 in constraints. * include/bits/ranges_base.h (__to_unsigned_like): Remove overloads for __int128. (ranges::ssize): Remove special case for __int128. * include/bits/stl_algobase.h (__size_to_integer): Define __int128 overloads for strict modes. * include/ext/numeric_traits.h (__is_integer_nonstrict): Remove explicit specializations for __int128. * include/std/charconv (to_chars): Define overloads for __int128. * include/std/format (__format::make_unsigned_t): Remove. (__format::to_chars): Remove. * include/std/limits (numeric_limits): Define explicit specializations for __int128. * include/std/type_traits (__is_integral_helper): Likewise. (__make_unsigned, __make_signed): Likewise. Reviewed-by: Patrick Palka <ppalka@redhat.com>
This commit is contained in:
committed by
Jonathan Wakely
parent
743c04db2f
commit
4faa42ac0d
@@ -273,6 +273,12 @@ __INT_N(__GLIBCXX_TYPE_INT_N_2)
|
||||
__INT_N(__GLIBCXX_TYPE_INT_N_3)
|
||||
#endif
|
||||
|
||||
#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
|
||||
// In strict modes __GLIBCXX_TYPE_INT_N_0 is not defined for __int128,
|
||||
// but we want to always treat signed/unsigned __int128 as integral types.
|
||||
__INT_N(__int128)
|
||||
#endif
|
||||
|
||||
#undef __INT_N
|
||||
|
||||
//
|
||||
@@ -545,17 +551,6 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
|
||||
{ enum { __width = __GLIBCXX_BITSIZE_INT_N_3 }; };
|
||||
#endif
|
||||
|
||||
#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
|
||||
// In strict modes __is_integer<__int128> is false,
|
||||
// but we want to allow memcpy between signed/unsigned __int128.
|
||||
__extension__
|
||||
template<>
|
||||
struct __memcpyable_integer<__int128> { enum { __width = 128 }; };
|
||||
__extension__
|
||||
template<>
|
||||
struct __memcpyable_integer<unsigned __int128> { enum { __width = 128 }; };
|
||||
#endif
|
||||
|
||||
#if _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 && _GLIBCXX_LDOUBLE_IS_IEEE_BINARY64
|
||||
template<>
|
||||
struct __memcpyable<double*, long double*> { enum { __value = true }; };
|
||||
|
||||
@@ -214,17 +214,6 @@ _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
|
||||
@@ -611,41 +600,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
class __max_diff_type;
|
||||
class __max_size_type;
|
||||
|
||||
__extension__
|
||||
template<typename _Tp>
|
||||
concept __is_signed_int128
|
||||
#if __SIZEOF_INT128__
|
||||
= same_as<_Tp, __int128>;
|
||||
#else
|
||||
= false;
|
||||
#endif
|
||||
|
||||
__extension__
|
||||
template<typename _Tp>
|
||||
concept __is_unsigned_int128
|
||||
#if __SIZEOF_INT128__
|
||||
= same_as<_Tp, unsigned __int128>;
|
||||
#else
|
||||
= false;
|
||||
#endif
|
||||
|
||||
template<typename _Tp>
|
||||
concept __cv_bool = same_as<const volatile _Tp, const volatile bool>;
|
||||
|
||||
template<typename _Tp>
|
||||
concept __integral_nonbool = integral<_Tp> && !__cv_bool<_Tp>;
|
||||
|
||||
template<typename _Tp>
|
||||
concept __is_int128 = __is_signed_int128<_Tp> || __is_unsigned_int128<_Tp>;
|
||||
|
||||
template<typename _Tp>
|
||||
concept __is_integer_like = __integral_nonbool<_Tp>
|
||||
|| __is_int128<_Tp>
|
||||
|| same_as<_Tp, __max_diff_type> || same_as<_Tp, __max_size_type>;
|
||||
|
||||
template<typename _Tp>
|
||||
concept __is_signed_integer_like = signed_integral<_Tp>
|
||||
|| __is_signed_int128<_Tp>
|
||||
|| same_as<_Tp, __max_diff_type>;
|
||||
|
||||
} // namespace ranges::__detail
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace ranges
|
||||
public:
|
||||
__max_size_type() = default;
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
constexpr
|
||||
__max_size_type(_Tp __i) noexcept
|
||||
: _M_val(__i), _M_msb(__i < 0)
|
||||
@@ -74,7 +74,7 @@ namespace ranges
|
||||
constexpr explicit
|
||||
__max_size_type(const __max_diff_type& __d) noexcept;
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
constexpr explicit
|
||||
operator _Tp() const noexcept
|
||||
{ return _M_val; }
|
||||
@@ -260,52 +260,52 @@ namespace ranges
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator+=(_Tp& __a, const __max_size_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a + __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator-=(_Tp& __a, const __max_size_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a - __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator*=(_Tp& __a, const __max_size_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a * __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator/=(_Tp& __a, const __max_size_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a / __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator%=(_Tp& __a, const __max_size_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a % __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator&=(_Tp& __a, const __max_size_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a & __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator|=(_Tp& __a, const __max_size_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a | __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator^=(_Tp& __a, const __max_size_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a ^ __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator<<=(_Tp& __a, const __max_size_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a << __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator>>=(_Tp& __a, const __max_size_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a >> __b)); }
|
||||
@@ -447,7 +447,7 @@ namespace ranges
|
||||
public:
|
||||
__max_diff_type() = default;
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
constexpr
|
||||
__max_diff_type(_Tp __i) noexcept
|
||||
: _M_rep(__i)
|
||||
@@ -458,7 +458,7 @@ namespace ranges
|
||||
: _M_rep(__d)
|
||||
{ }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
constexpr explicit
|
||||
operator _Tp() const noexcept
|
||||
{ return static_cast<_Tp>(_M_rep); }
|
||||
@@ -591,52 +591,52 @@ namespace ranges
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator+=(_Tp& __a, const __max_diff_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a + __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator-=(_Tp& __a, const __max_diff_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a - __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator*=(_Tp& __a, const __max_diff_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a * __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator/=(_Tp& __a, const __max_diff_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a / __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator%=(_Tp& __a, const __max_diff_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a % __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator&=(_Tp& __a, const __max_diff_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a & __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator|=(_Tp& __a, const __max_diff_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a | __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator^=(_Tp& __a, const __max_diff_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a ^ __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator<<=(_Tp& __a, const __max_diff_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a << __b)); }
|
||||
|
||||
template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
|
||||
template<typename _Tp> requires integral<_Tp>
|
||||
friend constexpr _Tp&
|
||||
operator>>=(_Tp& __a, const __max_diff_type& __b) noexcept
|
||||
{ return (__a = static_cast<_Tp>(__a >> __b)); }
|
||||
|
||||
@@ -81,16 +81,6 @@ namespace ranges
|
||||
__to_unsigned_like(_Tp __t) noexcept
|
||||
{ return static_cast<make_unsigned_t<_Tp>>(__t); }
|
||||
|
||||
#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
|
||||
constexpr unsigned __int128
|
||||
__to_unsigned_like(__int128 __t) noexcept
|
||||
{ return __t; }
|
||||
|
||||
constexpr unsigned __int128
|
||||
__to_unsigned_like(unsigned __int128 __t) noexcept
|
||||
{ return __t; }
|
||||
#endif
|
||||
|
||||
template<typename _Tp>
|
||||
using __make_unsigned_like_t
|
||||
= decltype(__detail::__to_unsigned_like(std::declval<_Tp>()));
|
||||
@@ -398,11 +388,6 @@ namespace ranges
|
||||
else
|
||||
return static_cast<make_signed_t<__size_type>>(__size);
|
||||
}
|
||||
#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
|
||||
// For strict-ansi modes integral<__int128> is false
|
||||
else if constexpr (__detail::__is_int128<__size_type>)
|
||||
return static_cast<__int128>(__size);
|
||||
#endif
|
||||
else // Must be one of __max_diff_type or __max_size_type.
|
||||
return __detail::__max_diff_type(__size);
|
||||
}
|
||||
|
||||
@@ -1052,6 +1052,13 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
|
||||
__size_to_integer(unsigned __GLIBCXX_TYPE_INT_N_3 __n) { return __n; }
|
||||
#endif
|
||||
|
||||
#if defined(__STRICT_ANSI__) && defined(__SIZEOF_INT128__)
|
||||
__extension__ inline _GLIBCXX_CONSTEXPR __int128
|
||||
__size_to_integer(__int128 __n) { return __n; }
|
||||
__extension__ inline _GLIBCXX_CONSTEXPR unsigned __int128
|
||||
__size_to_integer(unsigned __int128 __n) { return __n; }
|
||||
#endif
|
||||
|
||||
inline _GLIBCXX_CONSTEXPR long long
|
||||
__size_to_integer(float __n) { return (long long)__n; }
|
||||
inline _GLIBCXX_CONSTEXPR long long
|
||||
|
||||
@@ -126,12 +126,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
_GLIBCXX_INT_N_TRAITS(__GLIBCXX_TYPE_INT_N_3, __GLIBCXX_BITSIZE_INT_N_3)
|
||||
#endif
|
||||
|
||||
#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
|
||||
// In strict modes __is_integer<__int128> is false,
|
||||
// but we still want to define __numeric_traits_integer<__int128>.
|
||||
_GLIBCXX_INT_N_TRAITS(__int128, 128)
|
||||
#endif
|
||||
|
||||
#undef _GLIBCXX_INT_N_TRAITS
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
|
||||
@@ -390,6 +390,10 @@ _GLIBCXX_TO_CHARS(unsigned __GLIBCXX_TYPE_INT_N_2)
|
||||
_GLIBCXX_TO_CHARS(signed __GLIBCXX_TYPE_INT_N_3)
|
||||
_GLIBCXX_TO_CHARS(unsigned __GLIBCXX_TYPE_INT_N_3)
|
||||
#endif
|
||||
#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
|
||||
_GLIBCXX_TO_CHARS(signed __int128)
|
||||
_GLIBCXX_TO_CHARS(unsigned __int128)
|
||||
#endif
|
||||
#undef _GLIBCXX_TO_CHARS
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
|
||||
@@ -1854,20 +1854,6 @@ namespace __format
|
||||
__align, __nfill, __fill_char);
|
||||
}
|
||||
|
||||
#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
|
||||
template<typename _Tp>
|
||||
using make_unsigned_t
|
||||
= typename __conditional_t<(sizeof(_Tp) <= sizeof(long long)),
|
||||
std::make_unsigned<_Tp>,
|
||||
type_identity<unsigned __int128>>::type;
|
||||
|
||||
// std::to_chars is not overloaded for int128 in strict mode.
|
||||
template<typename _Int>
|
||||
static to_chars_result
|
||||
to_chars(char* __first, char* __last, _Int __value, int __base)
|
||||
{ return std::__to_chars_i<_Int>(__first, __last, __value, __base); }
|
||||
#endif
|
||||
|
||||
_Spec<_CharT> _M_spec{};
|
||||
};
|
||||
|
||||
|
||||
@@ -1639,7 +1639,6 @@ _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),
|
||||
@@ -1661,7 +1660,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
__INT_N_U201103 (__GLIBCXX_TYPE_INT_N_3))
|
||||
#endif
|
||||
|
||||
#elif defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
|
||||
#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
|
||||
__INT_N(__int128, 128,
|
||||
__INT_N_201103 (__int128),
|
||||
__INT_N_U201103 (__int128))
|
||||
|
||||
@@ -464,6 +464,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_3>
|
||||
: public true_type { };
|
||||
#endif
|
||||
|
||||
#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
|
||||
__extension__
|
||||
template<>
|
||||
struct __is_integral_helper<__int128>
|
||||
: public true_type { };
|
||||
|
||||
__extension__
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned __int128>
|
||||
: public true_type { };
|
||||
#endif
|
||||
|
||||
/// @endcond
|
||||
|
||||
/// is_integral
|
||||
@@ -1927,6 +1940,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
struct __make_unsigned<__GLIBCXX_TYPE_INT_N_3>
|
||||
{ using __type = unsigned __GLIBCXX_TYPE_INT_N_3; };
|
||||
#endif
|
||||
#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
|
||||
__extension__
|
||||
template<>
|
||||
struct __make_unsigned<__int128>
|
||||
{ using __type = unsigned __int128; };
|
||||
#endif
|
||||
|
||||
// Select between integral and enum: not possible to be both.
|
||||
template<typename _Tp,
|
||||
@@ -2087,6 +2106,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
struct __make_signed<unsigned __GLIBCXX_TYPE_INT_N_3>
|
||||
{ using __type = __GLIBCXX_TYPE_INT_N_3; };
|
||||
#endif
|
||||
#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
|
||||
__extension__
|
||||
template<>
|
||||
struct __make_signed<unsigned __int128>
|
||||
{ using __type = __int128; };
|
||||
#endif
|
||||
|
||||
// Select between integral and enum: not possible to be both.
|
||||
template<typename _Tp,
|
||||
|
||||
Reference in New Issue
Block a user