[PATCH] libstdc++: Fix up all_pedantic_errors.cc [PR119739]

Jakub Jelinek jakub@redhat.com
Wed Dec 17 12:57:47 GMT 2025


Hi!

Here is an updated patch.
In
make check -j32 -k RUNTESTFLAGS="--target_board=unix\{-m32,-m64\} conformance.exp='114359.cc 58302.cc 64351.cc 83833.cc 91371.cc call-default.cc equal.cc gencanon.cc generate.cc pr60037-neg.cc serialize.cc 93978.cc'"
testing I still see
FAIL: 26_numerics/random/pr60037-neg.cc  -std=gnu++20  (test for errors, line 3650)
FAIL: 26_numerics/random/pr60037-neg.cc  -std=gnu++20 (test for excess errors)
FAIL: 26_numerics/random/uniform_real_distribution/operators/64351.cc  -std=gnu++20 execution test
FAIL: 26_numerics/random/uniform_real_distribution/operators/gencanon.cc  -std=gnu++20 execution test
FAIL: 26_numerics/random/pr60037-neg.cc  -std=gnu++20  (test for errors, line 3650)
FAIL: 26_numerics/random/pr60037-neg.cc  -std=gnu++20 (test for excess errors)
I think Tomasz dealt with pr60037-neg.cc, and the 2 FAILs are -m32 only
/usr/src/gcc/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/64351.cc:42: void test02(): Assertion 'rng == rng2' failed.
and
/usr/src/gcc/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc:152: void test00(): Assertion 'deviation == 7032' failed.
so guess I need to still debug that.

--- libstdc++-v3/include/bits/random.tcc.jj	2025-12-17 11:22:03.823493462 +0100
+++ libstdc++-v3/include/bits/random.tcc	2025-12-17 13:44:24.571984415 +0100
@@ -3481,6 +3481,211 @@ namespace __detail
 #pragma GCC diagnostic ignored "-Wc++14-extensions" // for variable templates
 #pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
 
+#ifndef __SIZEOF_INT128__
+  namespace __detail
+  {
+    // Note, this is not a full unsigned __int128 emulation, just
+    // enough for __generate_* purposes below.
+    struct __rng_uint128 {
+      uint64_t _M_l, _M_h;
+
+      constexpr __rng_uint128(uint64_t __x) noexcept
+      : _M_l (__x), _M_h (0) {}
+
+      constexpr __rng_uint128(const __rng_uint128& __x) noexcept = default;
+
+      constexpr __rng_uint128(uint64_t __h, uint64_t __l) noexcept
+      : _M_l (__l), _M_h (__h) {}
+
+      template<typename _RealT>
+      constexpr operator _RealT() const noexcept {
+	static_assert(std::is_floating_point<_RealT>::value,
+	  "template argument must be a floating point type");
+	return _M_h == 0 ? _RealT(_M_l)
+			 : _RealT(_M_h) * _RealT(18446744073709551616.0)
+			   + _RealT(_M_l);
+      }
+
+      __rng_uint128& operator*=(const __rng_uint128& __x) noexcept
+      {
+	uint64_t __a[12] = {
+	  uint32_t(_M_l), _M_l >> 32,
+	  uint32_t(_M_h), _M_h >> 32,
+	  uint32_t(__x._M_l), __x._M_l >> 32,
+	  uint32_t(__x._M_h), __x._M_h >> 32,
+	  0, 0,
+	  0, 0 };
+	for (int __i = 0; __i < 4; ++__i)
+	  {
+	    uint64_t __c = 0;
+	    for (int __j = __i; __j < 4; ++__j)
+	      {
+		__c += __a[__i] * __a[4 + __j - __i] + __a[8 + __j];
+		__a[8 + __j] = uint32_t(__c);
+		__c >>= 32;
+	      }
+	  }
+	_M_l = __a[8] + (__a[9] << 32);
+	_M_h = __a[10] + (__a[11] << 32);
+	return *this;
+      }
+    };
+
+    constexpr __rng_uint128
+    operator+(const __rng_uint128& __x, const __rng_uint128& __y) noexcept
+    {
+      return __rng_uint128(__x._M_h + __y._M_h
+			   + (__x._M_l + __y._M_l < __x._M_l),
+			   __x._M_l + __y._M_l);
+    }
+
+    constexpr __rng_uint128
+    operator<<(const __rng_uint128& __x, size_t __y) noexcept
+    {
+      return (__y >= 64
+	      ? __rng_uint128(__x._M_l << (__y - 64), 0)
+	      : __y
+	      ? __rng_uint128((__x._M_h << __y) | (__x._M_l >> (64 - __y)),
+			      __x._M_l << __y)
+	      : __x);
+    }
+
+    constexpr __rng_uint128
+    operator>>(const __rng_uint128& __x, size_t __y) noexcept
+    {
+      return (__y >= 64
+	      ? __rng_uint128(0, __x._M_h >> (__y - 64))
+	      : __y
+	      ? __rng_uint128(__x._M_h >> __y,
+			      (__x._M_l >> __y) | (__x._M_h << (64 - __y)))
+	      : __x);
+    }
+
+    constexpr __rng_uint128
+    operator|(const __rng_uint128& __x, const __rng_uint128& __y) noexcept
+    {
+      return __rng_uint128(__x._M_h | __y._M_h, __x._M_l | __y._M_l);
+    }
+
+    __rng_uint128
+    operator*(const __rng_uint128& __x, const __rng_uint128& __y) noexcept
+    {
+      __rng_uint128 __ret(__x);
+      __ret *= __y;
+      return __ret;
+    }
+
+    __rng_uint128
+    operator/(const __rng_uint128& __x, const __rng_uint128& __y) noexcept
+    {
+      uint64_t __l, __h;
+      if (!__x._M_h)
+	{
+	  if (!__y._M_h)
+	    __l = __x._M_l / __y._M_l;
+	  else
+	    __l = 0;
+	  __h = 0;
+	}
+      else
+	{
+	  uint64_t __a[13] = {
+	    uint32_t(__x._M_l), __x._M_l >> 32,
+	    uint32_t(__x._M_h), __x._M_h >> 32,
+	    0,
+	    uint32_t(__y._M_l), __y._M_l >> 32,
+	    uint32_t(__y._M_h), __y._M_h >> 32,
+	    0, 0,
+	    0, 0 };
+	  uint64_t __c = 0, __w = 0;
+	  if (!__y._M_h && __y._M_l <= ~uint32_t(0))
+	    for (int __i = 3; ; --__i)
+	      {
+		__w = __a[__i] + (__c << 32);
+		__a[9 + __i] = __w / __y._M_l;
+		if (__i == 0)
+		  break;
+		__c = __w % __y._M_l;
+	      }
+	  else
+	    {
+	      // See Donald E. Knuth's "Seminumerical Algorithms".
+	      int __n = 0, __d = 0;
+	      uint64_t __q = 0, __s = 0;
+	      for (__d = 3; __a[5 + __d] == 0; --__d)
+		;
+	      __s = (uint64_t(1) << 32) / (__a[5 + __d] + 1);
+	      if (__s > 1)
+		{
+		  for (int __i = 0; __i <= 3; ++__i)
+		    {
+		      __w = __a[__i] * __s + __c;
+		      __a[__i] = uint32_t(__w);
+		      __c = __w >> 32;
+		    }
+		  __a[4] = __c;
+		  __c = 0;
+		  for (int __i = 0; __i <= 3; ++__i)
+		    {
+		      __w = __a[5 + __i] * __s + __c;
+		      __a[5 + __i] = uint32_t(__w);
+		      __c = __w >> 32;
+		      if (__a[5 + __i])
+			__d = __i;
+		    }
+		}
+	      __n = 4;
+	      for (int __i = __n - __d - 1; __i >= 0; --__i)
+		{
+		  __n = __i + __d + 1;
+		  __w = (__a[__n] << 32) + __a[__n - 1];
+		  if (__a[__n] != __a[5 + __d])
+		    __q = __w / __a[5 + __d];
+		  else
+		    __q = ~uint32_t(0);
+		  uint64_t __t = __w - __q * __a[5 + __d];
+		  if (__t <= ~uint32_t(0)
+		      && __a[4 + __d] * __q > (__t << 32) + __a[__n - 2])
+		    --__q;
+		  __c = 0;
+		  for (int __j = 0; __j <= __d; ++__j)
+		    {
+		      __w = __q * __a[5 + __j] + __c;
+		      __c = __w >> 32;
+		      __w = __a[__i + __j] - uint32_t(__w);
+		      __a[__i + __j] = uint32_t(__w);
+		      __c += (__w >> 32) != 0;
+		    }
+		  if (int64_t(__a[__n]) < int64_t(__c))
+		    {
+		      --__q;
+		      __c = 0;
+		      for (int __j = 0; __j <= __d; ++__j)
+			{
+			  __w = __a[__i + __j] + __a[5 + __j] + __c;
+			  __c = __w >> 32;
+			  __a[__i + __j] = uint32_t(__w);
+			}
+		      __a[__n] += __c;
+		    }
+		  __a[9 + __i] = __q;
+		}
+	    }
+	  __l = __a[9] + (__a[10] << 32);
+	  __h = __a[11] + (__a[12] << 32);
+	}
+      return __rng_uint128(__h, __l);
+    }
+
+    constexpr bool
+    operator<(const __rng_uint128 __x, const __rng_uint128 __y)
+    {
+      return (__x._M_h < __y._M_h
+	      || (__x._M_h == __y._M_h && __x._M_l < __y._M_l));
+    }
+  }
+#endif  
+
   // This version is used when Urbg::max()-Urbg::min() is a power of
   // two less 1, the norm in real programs. It works by calling urng()
   // as many times as needed to fill the target mantissa, accumulating
@@ -3511,7 +3716,8 @@ namespace __detail
   // This implementation works with std::bfloat16, which can exactly
   // represent 2^32, but not with std::float16_t, limited to 2^15.
 
-  template<typename _RealT, typename _UInt, size_t __d, typename _Urbg>
+  template<typename _RealT, typename _UInt, size_t __d, int __log2_uint_max,
+	   typename _Urbg>
     _RealT
     __generate_canonical_pow2(_Urbg& __urng)
     {
@@ -3521,10 +3727,8 @@ namespace __detail
       // r = 2;  // Redundant, we only support radix 2.
       using _Rng = decltype(_Urbg::max());
       const _Rng __rng_range_less_1 = _Urbg::max() - _Urbg::min();
-      const _UInt __uint_range_less_1 = ~_UInt(0);
       // R = _UInt(__rng_range_less_1) + 1;  // May wrap to 0.
       const auto __log2_R = __builtin_popcountg(__rng_range_less_1);
-      const auto __log2_uint_max = __builtin_popcountg(__uint_range_less_1);
       // rd = _UInt(1) << __d;  // Could overflow, UB.
       const unsigned __k = (__d + __log2_R - 1) / __log2_R;
       const unsigned __log2_Rk_max = __k * __log2_R;
@@ -3532,7 +3736,8 @@ namespace __detail
 	__log2_uint_max < __log2_Rk_max ? __log2_uint_max : __log2_Rk_max;
       static_assert(__log2_Rk >= __d);
       // Rk = _UInt(1) << __log2_Rk;  // Likely overflows, UB.
-      constexpr _RealT __Rk = _RealT(_UInt(1) << (__log2_Rk - 1)) * 2.0;
+      constexpr _RealT __Rk
+	= _RealT(_UInt(1) << (__log2_Rk - 1)) * _RealT(2.0);
 #if defined(_GLIBCXX_GENERATE_CANONICAL_STRICT)
       const unsigned __log2_x = __log2_Rk - __d; // # of spare entropy bits.
 #else
@@ -3585,7 +3790,6 @@ namespace __detail
     _RealT
     __generate_canonical_any(_Urbg& __urng)
     {
-      static_assert(__d < __builtin_popcountg(~_UInt(0)));
       // Names below are chosen to match the description in the Standard.
       // Parameter d is the actual target number of bits.
       const _UInt __r = 2;
@@ -3593,7 +3797,7 @@ namespace __detail
       const _UInt __rd = _UInt(1) << __d;
       const unsigned __k = __gen_can_rng_calls_needed(__R, __rd);
       const _UInt __Rk = __gen_can_pow(__R, __k);
-      const _UInt __x =  __Rk/__rd;
+      const _UInt __x =  __Rk / __rd;
 
       while (true)
 	{
@@ -3601,9 +3805,9 @@ namespace __detail
 	  for (int __i = __k - 1; __i > 0; --__i)
 	    {
 	      __Ri *= __R;
-	      __sum += (__urng() - _Urbg::min()) * __Ri;
+	      __sum = __sum + (__urng() - _Urbg::min()) * __Ri;
 	    }
-	  const _RealT __ret = _RealT(__sum / __x) / __rd;
+	  const _RealT __ret = _RealT(__sum / __x) / _RealT(__rd);
 	  if (__ret < _RealT(1.0))
 	    return __ret;
 	}
@@ -3658,7 +3862,6 @@ namespace __detail
 	"float16_t type is not supported, consider using bfloat16_t");
 #endif
 
-      using _Rng = decltype(_Urbg::max());
       const unsigned __d_max = std::numeric_limits<_RealT>::digits;
       const unsigned __d = __digits > __d_max ? __d_max : __digits;
 
@@ -3667,18 +3870,20 @@ namespace __detail
       if constexpr (__is_power_of_2_less_1(_Urbg::max() - _Urbg::min()))
 	{
 	  if constexpr (__d <= 32)
-	    return __generate_canonical_pow2<_RealT, uint32_t, __d>(__urng);
+	    return __generate_canonical_pow2<_RealT, uint32_t, __d,
+					     32>(__urng);
 	  else if constexpr (__d <= 64)
-	    return __generate_canonical_pow2<_RealT, uint64_t, __d>(__urng);
+	    return __generate_canonical_pow2<_RealT, uint64_t, __d,
+					     64>(__urng);
 	  else
 	    {
-#if defined(__SIZEOF_INT128__)
 	      // Accommodate double double or float128.
+#if defined(__SIZEOF_INT128__)
 	      return __extension__ __generate_canonical_pow2<
-		_RealT, unsigned __int128, __d>(__urng);
+		_RealT, unsigned __int128, __d, 128>(__urng);
 #else
-	      static_assert(false,
-		"float precision >64 requires __int128 support");
+	      return __extension__ __generate_canonical_pow2<
+		_RealT, __detail::__rng_uint128, __d, 128>(__urng);
 #endif
 	    }
 	}
@@ -3688,14 +3893,14 @@ namespace __detail
 	    return __generate_canonical_any<_RealT, uint64_t, __d>(__urng);
 	  else
 	    {
-#if defined(__SIZEOF_INT128__)
 	      static_assert(__d <= 64,
 		"irregular RNG with float precision >64 is not supported");
+#if defined(__SIZEOF_INT128__)
 	      return __extension__ __generate_canonical_any<
 		_RealT, unsigned __int128, __d>(__urng);
 #else
-	      static_assert(false, "irregular RNG with float precision"
-		 " >32 requires __int128 support");
+	      return __extension__ __generate_canonical_any<
+		_RealT, __detail::__rng_uint128, __d>(__urng);
 #endif
 	    }
 	}


	Jakub



More information about the Libstdc++ mailing list