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.
---

Tested x86_64-linux and powerpc64le-linux.

 libstdc++-v3/include/bits/cpp_type_traits.h   | 17 +++----
 libstdc++-v3/include/bits/iterator_concepts.h | 34 -------------
 libstdc++-v3/include/bits/max_size_type.h     | 48 +++++++++----------
 libstdc++-v3/include/bits/ranges_base.h       | 15 ------
 libstdc++-v3/include/bits/stl_algobase.h      |  7 +++
 libstdc++-v3/include/ext/numeric_traits.h     |  6 ---
 libstdc++-v3/include/std/charconv             |  4 ++
 libstdc++-v3/include/std/format               | 14 ------
 libstdc++-v3/include/std/limits               |  3 +-
 libstdc++-v3/include/std/type_traits          | 25 ++++++++++
 10 files changed, 67 insertions(+), 106 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h 
b/libstdc++-v3/include/bits/cpp_type_traits.h
index b1a6206ce1eb..770ad94b3b4d 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -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 }; };
diff --git a/libstdc++-v3/include/bits/iterator_concepts.h 
b/libstdc++-v3/include/bits/iterator_concepts.h
index d31e4f145107..979039e7da53 100644
--- a/libstdc++-v3/include/bits/iterator_concepts.h
+++ b/libstdc++-v3/include/bits/iterator_concepts.h
@@ -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
diff --git a/libstdc++-v3/include/bits/max_size_type.h 
b/libstdc++-v3/include/bits/max_size_type.h
index 30c5b1247679..a34b91a04f1e 100644
--- a/libstdc++-v3/include/bits/max_size_type.h
+++ b/libstdc++-v3/include/bits/max_size_type.h
@@ -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)); }
diff --git a/libstdc++-v3/include/bits/ranges_base.h 
b/libstdc++-v3/include/bits/ranges_base.h
index c09f7292067d..0251e5d0928a 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -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);
        }
diff --git a/libstdc++-v3/include/bits/stl_algobase.h 
b/libstdc++-v3/include/bits/stl_algobase.h
index 4d5662ca45bf..71ef2335a311 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -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
diff --git a/libstdc++-v3/include/ext/numeric_traits.h 
b/libstdc++-v3/include/ext/numeric_traits.h
index 2cd89430f51c..6786dc6a71bc 100644
--- a/libstdc++-v3/include/ext/numeric_traits.h
+++ b/libstdc++-v3/include/ext/numeric_traits.h
@@ -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
diff --git a/libstdc++-v3/include/std/charconv 
b/libstdc++-v3/include/std/charconv
index dda49ce72d0b..8cf2c0b01d7c 100644
--- a/libstdc++-v3/include/std/charconv
+++ b/libstdc++-v3/include/std/charconv
@@ -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
diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index d584b81c78a1..d63c6fc9efd5 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -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{};
     };
 
diff --git a/libstdc++-v3/include/std/limits b/libstdc++-v3/include/std/limits
index 2331c25599a0..3567a3284006 100644
--- a/libstdc++-v3/include/std/limits
+++ b/libstdc++-v3/include/std/limits
@@ -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))
diff --git a/libstdc++-v3/include/std/type_traits 
b/libstdc++-v3/include/std/type_traits
index 055411195f17..e88d04e44d76 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -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,
-- 
2.50.0

Reply via email to