[committed] libstdc++: Add lightweight replacement for std::numeric_limits (PR 92546)

Message ID 20200217153234.GA1535248@redhat.com
State New
Headers show
Series
  • [committed] libstdc++: Add lightweight replacement for std::numeric_limits (PR 92546)
Related show

Commit Message

Jonathan Wakely Feb. 17, 2020, 3:32 p.m.
Many uses of std::numeric_limits in C++17 and C++20 features only really
need the min(), max() and digits constants for integral types. By adding
__detail::__int_limits we can avoid including the whole <limits> header.

The <limits> header isn't especially large, but avoiding it still gives
small savings in compilation time and memory usage for the compiler.

There are also C++11 features that could benefit from this change (e.g.
<bits/hashtable_policy.h> and <bits/uniform_int_dist.h>) but I won't
change those until stage 1.

The implementation of __int_limits assumes two's complement integers,
which is true for all targets supported by GCC.

	PR libstdc++/92546 (partial)
	* include/Makefile.am: Add new header.
	* include/Makefile.in: Regenerate.
	* include/bits/int_limits.h: New header.
	* include/bits/parse_numbers.h (__select_int::_Select_int): Replace
	numeric_limits with __detail::__int_limits.
	* include/std/bit (__rotl, __rotr, __countl_zero, __countl_one)
	(__countr_zero, __countr_one, __popcount, __ceil2, __floor2, __log2p1):
	Likewise.
	* include/std/charconv (__to_chars_8, __from_chars_binary)
	(__from_chars_alpha_to_num, from_chars): Likewise.
	* include/std/memory_resource (polymorphic_allocator::allocate)
	(polymorphic_allocator::allocate_object): Likewise.
	* include/std/string_view (basic_string_view::_S_compare): Likewise.
	* include/std/utility (in_range): Likewise.
	* testsuite/20_util/integer_comparisons/in_range_neg.cc: Adjust for
	extra error about incomplete type __int_limits<bool>.
	* testsuite/26_numerics/bit/bit.count/countl_one.cc: Include <limits>.
	* testsuite/26_numerics/bit/bit.count/countl_zero.cc: Likewise.
	* testsuite/26_numerics/bit/bit.count/countr_one.cc: Likewise.
	* testsuite/26_numerics/bit/bit.count/countr_zero.cc: Likewise.
	* testsuite/26_numerics/bit/bit.count/popcount.cc: Likewise.
	* testsuite/26_numerics/bit/bit.pow.two/ceil2_neg.cc: Likewise.
	* testsuite/26_numerics/bit/bit.pow.two/ceil2.cc: Likewise.
	* testsuite/26_numerics/bit/bit.pow.two/floor2.cc: Likewise.
	* testsuite/26_numerics/bit/bit.pow.two/ispow2.cc: Likewise.
	* testsuite/26_numerics/bit/bit.pow.two/log2p1.cc: Likewise.
	* testsuite/26_numerics/bit/bit.rotate/rotl.cc: Likewise.
	* testsuite/26_numerics/bit/bit.rotate/rotr.cc: Likewise.

Tested powerpc64le-linux, committed to master.
commit c03b53da9129ae2d5ac9629c4b874d0981a7d418
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Feb 17 14:30:02 2020 +0000

    libstdc++: Add lightweight replacement for std::numeric_limits (PR 92546)
    
    Many uses of std::numeric_limits in C++17 and C++20 features only really
    need the min(), max() and digits constants for integral types. By adding
    __detail::__int_limits we can avoid including the whole <limits> header.
    
    The <limits> header isn't especially large, but avoiding it still gives
    small savings in compilation time and memory usage for the compiler.
    
    There are also C++11 features that could benefit from this change (e.g.
    <bits/hashtable_policy.h> and <bits/uniform_int_dist.h>) but I won't
    change those until stage 1.
    
    The implementation of __int_limits assumes two's complement integers,
    which is true for all targets supported by GCC.
    
            PR libstdc++/92546 (partial)
            * include/Makefile.am: Add new header.
            * include/Makefile.in: Regenerate.
            * include/bits/int_limits.h: New header.
            * include/bits/parse_numbers.h (__select_int::_Select_int): Replace
            numeric_limits with __detail::__int_limits.
            * include/std/bit (__rotl, __rotr, __countl_zero, __countl_one)
            (__countr_zero, __countr_one, __popcount, __ceil2, __floor2, __log2p1):
            Likewise.
            * include/std/charconv (__to_chars_8, __from_chars_binary)
            (__from_chars_alpha_to_num, from_chars): Likewise.
            * include/std/memory_resource (polymorphic_allocator::allocate)
            (polymorphic_allocator::allocate_object): Likewise.
            * include/std/string_view (basic_string_view::_S_compare): Likewise.
            * include/std/utility (in_range): Likewise.
            * testsuite/20_util/integer_comparisons/in_range_neg.cc: Adjust for
            extra error about incomplete type __int_limits<bool>.
            * testsuite/26_numerics/bit/bit.count/countl_one.cc: Include <limits>.
            * testsuite/26_numerics/bit/bit.count/countl_zero.cc: Likewise.
            * testsuite/26_numerics/bit/bit.count/countr_one.cc: Likewise.
            * testsuite/26_numerics/bit/bit.count/countr_zero.cc: Likewise.
            * testsuite/26_numerics/bit/bit.count/popcount.cc: Likewise.
            * testsuite/26_numerics/bit/bit.pow.two/ceil2_neg.cc: Likewise.
            * testsuite/26_numerics/bit/bit.pow.two/ceil2.cc: Likewise.
            * testsuite/26_numerics/bit/bit.pow.two/floor2.cc: Likewise.
            * testsuite/26_numerics/bit/bit.pow.two/ispow2.cc: Likewise.
            * testsuite/26_numerics/bit/bit.pow.two/log2p1.cc: Likewise.
            * testsuite/26_numerics/bit/bit.rotate/rotl.cc: Likewise.
            * testsuite/26_numerics/bit/bit.rotate/rotr.cc: Likewise.

Comments

Daniel Krügler Feb. 17, 2020, 4:26 p.m. | #1
Am Mo., 17. Feb. 2020 um 16:33 Uhr schrieb Jonathan Wakely <jwakely@redhat.com>:
>

> Many uses of std::numeric_limits in C++17 and C++20 features only really

> need the min(), max() and digits constants for integral types. By adding

> __detail::__int_limits we can avoid including the whole <limits> header.


numeric_limits has specializations for cv-qualified types, but for
__ini_limits there is only an undefined specialization for bool.
Shouldn't the same undefined specialization be provided for cv bool?
It may be that currently all usages of that trait apply on already
unqualified types, but this might be a fragile assumption.

- Daniel
Jonathan Wakely Feb. 17, 2020, 5:18 p.m. | #2
On 17/02/20 17:26 +0100, Daniel Krügler wrote:
>Am Mo., 17. Feb. 2020 um 16:33 Uhr schrieb Jonathan Wakely <jwakely@redhat.com>:

>>

>> Many uses of std::numeric_limits in C++17 and C++20 features only really

>> need the min(), max() and digits constants for integral types. By adding

>> __detail::__int_limits we can avoid including the whole <limits> header.

>

>numeric_limits has specializations for cv-qualified types, but for

>__ini_limits there is only an undefined specialization for bool.

>Shouldn't the same undefined specialization be provided for cv bool?

>It may be that currently all usages of that trait apply on already

>unqualified types, but this might be a fragile assumption.


The specialization for bool is only there to catch misuses by the
library, it's not really necessary. But I agree that also catching
errors for const bool makes sense. I don't think we need to care about
volatile.

I'm tempted to make __int_limits<const T> an error though, it's not
needed.
Jonathan Wakely Feb. 28, 2020, 9:56 p.m. | #3
On 17/02/20 15:32 +0000, Jonathan Wakely wrote:
>Many uses of std::numeric_limits in C++17 and C++20 features only really

>need the min(), max() and digits constants for integral types. By adding

>__detail::__int_limits we can avoid including the whole <limits> header.

>

>The <limits> header isn't especially large, but avoiding it still gives

>small savings in compilation time and memory usage for the compiler.

>

>There are also C++11 features that could benefit from this change (e.g.

><bits/hashtable_policy.h> and <bits/uniform_int_dist.h>) but I won't

>change those until stage 1.

>

>The implementation of __int_limits assumes two's complement integers,

>which is true for all targets supported by GCC.

>

>	PR libstdc++/92546 (partial)

>	* include/Makefile.am: Add new header.

>	* include/Makefile.in: Regenerate.

>	* include/bits/int_limits.h: New header.

>	* include/bits/parse_numbers.h (__select_int::_Select_int): Replace

>	numeric_limits with __detail::__int_limits.

>	* include/std/bit (__rotl, __rotr, __countl_zero, __countl_one)

>	(__countr_zero, __countr_one, __popcount, __ceil2, __floor2, __log2p1):

>	Likewise.

>	* include/std/charconv (__to_chars_8, __from_chars_binary)

>	(__from_chars_alpha_to_num, from_chars): Likewise.

>	* include/std/memory_resource (polymorphic_allocator::allocate)

>	(polymorphic_allocator::allocate_object): Likewise.

>	* include/std/string_view (basic_string_view::_S_compare): Likewise.

>	* include/std/utility (in_range): Likewise.

>	* testsuite/20_util/integer_comparisons/in_range_neg.cc: Adjust for

>	extra error about incomplete type __int_limits<bool>.

>	* testsuite/26_numerics/bit/bit.count/countl_one.cc: Include <limits>.

>	* testsuite/26_numerics/bit/bit.count/countl_zero.cc: Likewise.

>	* testsuite/26_numerics/bit/bit.count/countr_one.cc: Likewise.

>	* testsuite/26_numerics/bit/bit.count/countr_zero.cc: Likewise.

>	* testsuite/26_numerics/bit/bit.count/popcount.cc: Likewise.

>	* testsuite/26_numerics/bit/bit.pow.two/ceil2_neg.cc: Likewise.

>	* testsuite/26_numerics/bit/bit.pow.two/ceil2.cc: Likewise.

>	* testsuite/26_numerics/bit/bit.pow.two/floor2.cc: Likewise.

>	* testsuite/26_numerics/bit/bit.pow.two/ispow2.cc: Likewise.

>	* testsuite/26_numerics/bit/bit.pow.two/log2p1.cc: Likewise.

>	* testsuite/26_numerics/bit/bit.rotate/rotl.cc: Likewise.

>	* testsuite/26_numerics/bit/bit.rotate/rotr.cc: Likewise.

>

>Tested powerpc64le-linux, committed to master.


I think I probably should have just used __gnu_cxx::__numeric_traits
instead of adding a new trait. That already has min, max and digits
and is much smaller than the whole of <limits>.

Patch

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index e131ce04f8c..80aeb3f8959 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -129,6 +129,7 @@  bits_headers = \
 	${bits_srcdir}/hashtable.h \
 	${bits_srcdir}/hashtable_policy.h \
 	${bits_srcdir}/indirect_array.h \
+	${bits_srcdir}/int_limits.h \
 	${bits_srcdir}/invoke.h \
 	${bits_srcdir}/ios_base.h \
 	${bits_srcdir}/istream.tcc \
diff --git a/libstdc++-v3/include/bits/int_limits.h b/libstdc++-v3/include/bits/int_limits.h
new file mode 100644
index 00000000000..7ae34377331
--- /dev/null
+++ b/libstdc++-v3/include/bits/int_limits.h
@@ -0,0 +1,74 @@ 
+// Minimal replacement for numeric_limits of integers. -*- C++ -*-
+
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/int_limits.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{limits}
+ */
+
+#ifndef _GLIBCXX_INT_LIMITS_H
+#define _GLIBCXX_INT_LIMITS_H 1
+
+#pragma GCC system_header
+
+#if __cplusplus >= 201103L
+#include <bits/c++config.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace __detail
+{
+  // This template is used for arbitrary signed and unsigned integer types
+  // (by headers <bit> and <charconv>) and for specific integer types
+  // (by <memory_resource> and <string_view>) but also for char (<charconv>).
+  // For simplicity's sake, all integral types except bool are supported.
+
+  // Lightweight alternative to numeric_limits<signed integer type>.
+  template<typename _Tp, bool = is_signed<_Tp>::value>
+    struct __int_limits
+    {
+      static_assert(is_integral<_Tp>::value, "unsupported specialization");
+      using _Up = typename make_unsigned<_Tp>::type;
+      static constexpr int digits = sizeof(_Tp) * __CHAR_BIT__ - 1;
+      static constexpr _Tp min() noexcept { return _Tp(_Up(1) << digits); }
+      static constexpr _Tp max() noexcept { return _Tp(_Up(~_Up(0)) >> 1); }
+    };
+
+  // Lightweight alternative to numeric_limits<unsigned integer type>.
+  template<typename _Tp>
+    struct __int_limits<_Tp, false>
+    {
+      static_assert(is_integral<_Tp>::value, "unsupported specialization");
+      static constexpr int digits = sizeof(_Tp) * __CHAR_BIT__;
+      static constexpr _Tp min() noexcept { return 0; }
+      static constexpr _Tp max() noexcept { return _Tp(-1); }
+    };
+
+  template<> struct __int_limits<bool>; // not defined
+}
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // C++11
+#endif // _GLIBCXX_INT_LIMITS_H
diff --git a/libstdc++-v3/include/bits/parse_numbers.h b/libstdc++-v3/include/bits/parse_numbers.h
index d7a81e55182..6a75d002774 100644
--- a/libstdc++-v3/include/bits/parse_numbers.h
+++ b/libstdc++-v3/include/bits/parse_numbers.h
@@ -34,9 +34,9 @@ 
 
 // From n3642.pdf except I added binary literals and digit separator '\''.
 
-#if __cplusplus > 201103L
+#if __cplusplus >= 201402L
 
-#include <limits>
+#include <bits/int_limits.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -265,7 +265,7 @@  namespace __select_int
 
   template<unsigned long long _Val, typename _IntType, typename... _Ints>
     struct _Select_int_base<_Val, _IntType, _Ints...>
-    : conditional_t<(_Val <= std::numeric_limits<_IntType>::max()),
+    : conditional_t<(_Val <= __detail::__int_limits<_IntType>::max()),
 		    integral_constant<_IntType, _Val>,
 		    _Select_int_base<_Val, _Ints...>>
     { };
@@ -289,6 +289,6 @@  namespace __select_int
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
-#endif // __cplusplus > 201103L
+#endif // C++14
 
 #endif // _GLIBCXX_PARSE_NUMBERS_H
diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit
index 0203546d1d2..dc0a77e1a5f 100644
--- a/libstdc++-v3/include/std/bit
+++ b/libstdc++-v3/include/std/bit
@@ -34,7 +34,7 @@ 
 #if __cplusplus >= 201402L
 
 #include <type_traits>
-#include <limits>
+#include <bits/int_limits.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -55,7 +55,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     constexpr _Tp
     __rotl(_Tp __x, int __s) noexcept
     {
-      constexpr auto _Nd = numeric_limits<_Tp>::digits;
+      constexpr auto _Nd = __detail::__int_limits<_Tp>::digits;
       const int __r = __s % _Nd;
       if (__r == 0)
 	return __x;
@@ -69,7 +69,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     constexpr _Tp
     __rotr(_Tp __x, int __s) noexcept
     {
-      constexpr auto _Nd = numeric_limits<_Tp>::digits;
+      constexpr auto _Nd = __detail::__int_limits<_Tp>::digits;
       const int __r = __s % _Nd;
       if (__r == 0)
 	return __x;
@@ -83,14 +83,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     constexpr int
     __countl_zero(_Tp __x) noexcept
     {
-      constexpr auto _Nd = numeric_limits<_Tp>::digits;
+      using std::__detail::__int_limits;
+      constexpr auto _Nd = __int_limits<_Tp>::digits;
 
       if (__x == 0)
         return _Nd;
 
-      constexpr auto _Nd_ull = numeric_limits<unsigned long long>::digits;
-      constexpr auto _Nd_ul = numeric_limits<unsigned long>::digits;
-      constexpr auto _Nd_u = numeric_limits<unsigned>::digits;
+      constexpr auto _Nd_ull = __int_limits<unsigned long long>::digits;
+      constexpr auto _Nd_ul = __int_limits<unsigned long>::digits;
+      constexpr auto _Nd_u = __int_limits<unsigned>::digits;
 
       if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_u)
 	{
@@ -118,7 +119,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	      constexpr int __diff = (2 * _Nd_ull) - _Nd;
 	      return __builtin_clzll(__high) - __diff;
 	    }
-	  constexpr auto __max_ull = numeric_limits<unsigned long long>::max();
+	  constexpr auto __max_ull = __int_limits<unsigned long long>::max();
 	  unsigned long long __low = __x & __max_ull;
 	  return (_Nd - _Nd_ull) + __builtin_clzll(__low);
 	}
@@ -128,8 +129,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     constexpr int
     __countl_one(_Tp __x) noexcept
     {
-      if (__x == numeric_limits<_Tp>::max())
-        return numeric_limits<_Tp>::digits;
+      if (__x == __detail::__int_limits<_Tp>::max())
+	return __detail::__int_limits<_Tp>::digits;
       return std::__countl_zero<_Tp>((_Tp)~__x);
     }
 
@@ -137,14 +138,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     constexpr int
     __countr_zero(_Tp __x) noexcept
     {
-      constexpr auto _Nd = numeric_limits<_Tp>::digits;
+      using std::__detail::__int_limits;
+      constexpr auto _Nd = __int_limits<_Tp>::digits;
 
       if (__x == 0)
         return _Nd;
 
-      constexpr auto _Nd_ull = numeric_limits<unsigned long long>::digits;
-      constexpr auto _Nd_ul = numeric_limits<unsigned long>::digits;
-      constexpr auto _Nd_u = numeric_limits<unsigned>::digits;
+      constexpr auto _Nd_ull = __int_limits<unsigned long long>::digits;
+      constexpr auto _Nd_ul = __int_limits<unsigned long>::digits;
+      constexpr auto _Nd_u = __int_limits<unsigned>::digits;
 
       if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_u)
 	return __builtin_ctz(__x);
@@ -157,7 +159,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  static_assert(_Nd <= (2 * _Nd_ull),
 			"Maximum supported integer size is 128-bit");
 
-	  constexpr auto __max_ull = numeric_limits<unsigned long long>::max();
+	  constexpr auto __max_ull = __int_limits<unsigned long long>::max();
 	  unsigned long long __low = __x & __max_ull;
 	  if (__low != 0)
 	    return __builtin_ctzll(__low);
@@ -170,8 +172,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     constexpr int
     __countr_one(_Tp __x) noexcept
     {
-      if (__x == numeric_limits<_Tp>::max())
-        return numeric_limits<_Tp>::digits;
+      if (__x == __detail::__int_limits<_Tp>::max())
+	return __detail::__int_limits<_Tp>::digits;
       return std::__countr_zero((_Tp)~__x);
     }
 
@@ -179,14 +181,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     constexpr int
     __popcount(_Tp __x) noexcept
     {
-      constexpr auto _Nd = numeric_limits<_Tp>::digits;
+      using std::__detail::__int_limits;
+      constexpr auto _Nd = __int_limits<_Tp>::digits;
 
       if (__x == 0)
         return 0;
 
-      constexpr auto _Nd_ull = numeric_limits<unsigned long long>::digits;
-      constexpr auto _Nd_ul = numeric_limits<unsigned long>::digits;
-      constexpr auto _Nd_u = numeric_limits<unsigned>::digits;
+      constexpr auto _Nd_ull = __int_limits<unsigned long long>::digits;
+      constexpr auto _Nd_ul = __int_limits<unsigned long>::digits;
+      constexpr auto _Nd_u = __int_limits<unsigned>::digits;
 
       if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_u)
 	return __builtin_popcount(__x);
@@ -199,7 +202,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  static_assert(_Nd <= (2 * _Nd_ull),
 			"Maximum supported integer size is 128-bit");
 
-	  constexpr auto __max_ull = numeric_limits<unsigned long long>::max();
+	  constexpr auto __max_ull = __int_limits<unsigned long long>::max();
 	  unsigned long long __low = __x & __max_ull;
 	  unsigned long long __high = __x >> _Nd_ull;
 	  return __builtin_popcountll(__low) + __builtin_popcountll(__high);
@@ -215,7 +218,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     constexpr _Tp
     __ceil2(_Tp __x) noexcept
     {
-      constexpr auto _Nd = numeric_limits<_Tp>::digits;
+      using std::__detail::__int_limits;
+      constexpr auto _Nd = __int_limits<_Tp>::digits;
       if (__x == 0 || __x == 1)
         return 1;
       auto __shift_exponent = _Nd - std::__countl_zero((_Tp)(__x - 1u));
@@ -226,7 +230,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifdef _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED
       if (!__builtin_is_constant_evaluated())
 	{
-	  __glibcxx_assert( __shift_exponent != numeric_limits<_Tp>::digits );
+	  __glibcxx_assert( __shift_exponent != __int_limits<_Tp>::digits );
 	}
 #endif
       using __promoted_type = decltype(__x << 1);
@@ -247,7 +251,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     constexpr _Tp
     __floor2(_Tp __x) noexcept
     {
-      constexpr auto _Nd = numeric_limits<_Tp>::digits;
+      constexpr auto _Nd = __detail::__int_limits<_Tp>::digits;
       if (__x == 0)
         return 0;
       return (_Tp)1u << (_Nd - std::__countl_zero((_Tp)(__x >> 1)));
@@ -257,7 +261,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     constexpr _Tp
     __log2p1(_Tp __x) noexcept
     {
-      constexpr auto _Nd = numeric_limits<_Tp>::digits;
+      constexpr auto _Nd = __detail::__int_limits<_Tp>::digits;
       return _Nd - std::__countl_zero(__x);
     }
 
diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv
index 1fd84a8f449..9b5a1f7cab8 100644
--- a/libstdc++-v3/include/std/charconv
+++ b/libstdc++-v3/include/std/charconv
@@ -34,11 +34,11 @@ 
 #if __cplusplus >= 201402L
 
 #include <type_traits>
-#include <limits>
 #include <bit>			// for __log2p1
 #include <cctype>		// for isdigit
 #include <bits/charconv.h>	// for __to_chars_len, __to_chars_10_impl
 #include <bits/error_constants.h> // for std::errc
+#include <bits/int_limits.h>
 
 // Define when floating point is supported: #define __cpp_lib_to_chars 201611L
 
@@ -222,7 +222,7 @@  namespace __detail
       to_chars_result __res;
       unsigned __len;
 
-      if _GLIBCXX17_CONSTEXPR (numeric_limits<_Tp>::digits <= 16)
+      if _GLIBCXX17_CONSTEXPR (__detail::__int_limits<_Tp>::digits <= 16)
 	{
 	  __len = __val > 077777u ? 6u
 	    : __val > 07777u ? 5u
@@ -410,7 +410,7 @@  namespace __detail
 	  __i++;
 	}
       __first += __i;
-      return __i <= numeric_limits<_Tp>::digits;
+      return __i <= __detail::__int_limits<_Tp>::digits;
     }
 
   /// std::from_chars implementation for integers in bases 3 to 10.
@@ -529,7 +529,7 @@  namespace __detail
     case 'Z':
       return 35;
     }
-    return std::numeric_limits<unsigned char>::max();
+    return __detail::__int_limits<unsigned char>::max();
   }
 
   /// std::from_chars implementation for integers in bases 11 to 26.
@@ -616,10 +616,10 @@  namespace __detail
 		}
 	      else
 		{
-		  if _GLIBCXX17_CONSTEXPR
-		    (numeric_limits<_Up>::max() > numeric_limits<_Tp>::max())
+		  if _GLIBCXX17_CONSTEXPR (__detail::__int_limits<_Up>::max()
+		      > __detail::__int_limits<_Tp>::max())
 		    {
-		      if (__val > numeric_limits<_Tp>::max())
+		      if (__val > __detail::__int_limits<_Tp>::max())
 			__res.ec = errc::result_out_of_range;
 		      else
 			__value = __val;
diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource
index 13be3e9dc75..70c56d1d7e6 100644
--- a/libstdc++-v3/include/std/memory_resource
+++ b/libstdc++-v3/include/std/memory_resource
@@ -33,13 +33,13 @@ 
 
 #if __cplusplus >= 201703L
 
-#include <limits>			// numeric_limits
 #include <memory>			// align, allocator_arg_t, __uses_alloc
 #include <utility>			// pair, index_sequence
 #include <vector>			// vector
 #include <cstddef>			// size_t, max_align_t, byte
 #include <shared_mutex>			// shared_mutex
 #include <bits/functexcept.h>
+#include <bits/int_limits.h>
 #include <debug/assertions.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -166,7 +166,7 @@  namespace pmr
       allocate(size_t __n)
       __attribute__((__returns_nonnull__))
       {
-	if (__n > (numeric_limits<size_t>::max() / sizeof(_Tp)))
+	if (__n > (__detail::__int_limits<size_t>::max() / sizeof(_Tp)))
 	  std::__throw_bad_alloc();
 	return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp),
 						       alignof(_Tp)));
@@ -192,7 +192,7 @@  namespace pmr
 	_Up*
 	allocate_object(size_t __n = 1)
 	{
-	  if ((std::numeric_limits<size_t>::max() / sizeof(_Up)) < __n)
+	  if ((__detail::__int_limits<size_t>::max() / sizeof(_Up)) < __n)
 	    __throw_length_error("polymorphic_allocator::allocate_object");
 	  return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up),
 						  alignof(_Up)));
diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view
index 798cb89a621..bedad24979e 100644
--- a/libstdc++-v3/include/std/string_view
+++ b/libstdc++-v3/include/std/string_view
@@ -37,10 +37,10 @@ 
 
 #if __cplusplus >= 201703L
 
-#include <limits>
 #include <iosfwd>
 #include <bits/char_traits.h>
 #include <bits/functional_hash.h>
+#include <bits/int_limits.h>
 #include <bits/range_access.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -456,10 +456,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _S_compare(size_type __n1, size_type __n2) noexcept
       {
 	const difference_type __diff = __n1 - __n2;
-	if (__diff > std::numeric_limits<int>::max())
-	  return std::numeric_limits<int>::max();
-	if (__diff < std::numeric_limits<int>::min())
-	  return std::numeric_limits<int>::min();
+	if (__diff > __detail::__int_limits<int>::max())
+	  return __detail::__int_limits<int>::max();
+	if (__diff < __detail::__int_limits<int>::min())
+	  return __detail::__int_limits<int>::min();
 	return static_cast<int>(__diff);
       }
 
diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility
index 380c059395c..dc6e8468af5 100644
--- a/libstdc++-v3/include/std/utility
+++ b/libstdc++-v3/include/std/utility
@@ -76,7 +76,7 @@ 
 #include <initializer_list>
 
 #if __cplusplus > 201703L
-#include <limits>
+#include <bits/int_limits.h>
 #endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -460,15 +460,16 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       static_assert(__is_standard_integer<_Up>::value);
       static_assert(__is_standard_integer<_Tp>::value);
+      using std::__detail::__int_limits;
 
       if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
-	return numeric_limits<_Up>::min() <= __t
-	  && __t <= numeric_limits<_Up>::max();
+	return __int_limits<_Up>::min() <= __t
+	  && __t <= __int_limits<_Up>::max();
       else if constexpr (is_signed_v<_Tp>)
 	return __t >= 0
-	  && make_unsigned_t<_Tp>(__t) <= numeric_limits<_Up>::max();
+	  && make_unsigned_t<_Tp>(__t) <= __int_limits<_Up>::max();
       else
-	return __t <= make_unsigned_t<_Up>(numeric_limits<_Up>::max());
+	return __t <= make_unsigned_t<_Up>(__int_limits<_Up>::max());
     }
 #endif // C++20
 #endif // C++17
diff --git a/libstdc++-v3/testsuite/20_util/integer_comparisons/in_range_neg.cc b/libstdc++-v3/testsuite/20_util/integer_comparisons/in_range_neg.cc
index 13e2bf75a8a..077d9818dc8 100644
--- a/libstdc++-v3/testsuite/20_util/integer_comparisons/in_range_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/integer_comparisons/in_range_neg.cc
@@ -34,3 +34,4 @@  bool k = std::in_range<int>(U'a'); // { dg-error "here" }
 bool l = std::in_range<char32_t>(97); // { dg-error "here" }
 
 // { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-prune-output "incomplete type" }
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countl_one.cc b/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countl_one.cc
index 7fdb6ed53bb..1e9b8983ed6 100644
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countl_one.cc
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countl_one.cc
@@ -19,6 +19,7 @@ 
 // { dg-do compile { target c++2a } }
 
 #include <bit>
+#include <limits>
 
 template<typename UInt>
 constexpr auto
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countl_zero.cc b/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countl_zero.cc
index 1a056bf7dd4..8e2f42ab6ba 100644
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countl_zero.cc
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countl_zero.cc
@@ -19,6 +19,7 @@ 
 // { dg-do compile { target c++2a } }
 
 #include <bit>
+#include <limits>
 
 template<typename UInt>
 constexpr auto
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countr_one.cc b/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countr_one.cc
index d6fffa95445..7f53b7116d1 100644
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countr_one.cc
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countr_one.cc
@@ -19,6 +19,7 @@ 
 // { dg-do compile { target c++2a } }
 
 #include <bit>
+#include <limits>
 
 template<typename UInt>
 constexpr auto
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countr_zero.cc b/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countr_zero.cc
index 004272c9cce..132722f037b 100644
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countr_zero.cc
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.count/countr_zero.cc
@@ -19,6 +19,7 @@ 
 // { dg-do compile { target c++2a } }
 
 #include <bit>
+#include <limits>
 
 template<typename UInt>
 constexpr auto
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.count/popcount.cc b/libstdc++-v3/testsuite/26_numerics/bit/bit.count/popcount.cc
index e2f5e9829ea..62007ed6aeb 100644
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.count/popcount.cc
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.count/popcount.cc
@@ -19,6 +19,7 @@ 
 // { dg-do compile { target c++2a } }
 
 #include <bit>
+#include <limits>
 
 template<typename UInt>
 constexpr auto
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/ceil2.cc b/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/ceil2.cc
index e8bc0bba6f8..f917efb5ef3 100644
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/ceil2.cc
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/ceil2.cc
@@ -19,6 +19,7 @@ 
 // { dg-do compile { target c++2a } }
 
 #include <bit>
+#include <limits>
 
 template<typename T>
   constexpr T max = std::numeric_limits<T>::max();
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/ceil2_neg.cc b/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/ceil2_neg.cc
index 54b194bb9df..b5391936e3d 100644
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/ceil2_neg.cc
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/ceil2_neg.cc
@@ -20,6 +20,7 @@ 
 // { dg-xfail-run-if "__glibcxx_assert in ceil2 should fail" { *-*-* } }
 
 #include <bit>
+#include <limits>
 
 // P1355R2: not a constant expression if the result is not representable
 
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/floor2.cc b/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/floor2.cc
index 4d439bd2a19..7d2321d6acf 100644
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/floor2.cc
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/floor2.cc
@@ -19,6 +19,7 @@ 
 // { dg-do compile { target c++2a } }
 
 #include <bit>
+#include <limits>
 
 template<typename UInt>
 constexpr auto
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/ispow2.cc b/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/ispow2.cc
index 3362d40c6dc..a0a4d89a54f 100644
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/ispow2.cc
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/ispow2.cc
@@ -19,6 +19,7 @@ 
 // { dg-do compile { target c++2a } }
 
 #include <bit>
+#include <limits>
 
 template<typename UInt>
 constexpr auto
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/log2p1.cc b/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/log2p1.cc
index 4fea5805228..6f32d4afc1b 100644
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/log2p1.cc
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.pow.two/log2p1.cc
@@ -19,6 +19,7 @@ 
 // { dg-do compile { target c++2a } }
 
 #include <bit>
+#include <limits>
 
 template<typename UInt>
 constexpr auto
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.rotate/rotl.cc b/libstdc++-v3/testsuite/26_numerics/bit/bit.rotate/rotl.cc
index 802495f20d8..b2525050e09 100644
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.rotate/rotl.cc
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.rotate/rotl.cc
@@ -19,6 +19,7 @@ 
 // { dg-do compile { target c++2a } }
 
 #include <bit>
+#include <limits>
 
 template<typename UInt>
 constexpr bool
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.rotate/rotr.cc b/libstdc++-v3/testsuite/26_numerics/bit/bit.rotate/rotr.cc
index 84a86c03149..bebf79d5d96 100644
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.rotate/rotr.cc
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.rotate/rotr.cc
@@ -19,6 +19,7 @@ 
 // { dg-do compile { target c++2a } }
 
 #include <bit>
+#include <limits>
 
 template<typename UInt>
 constexpr bool