public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] libstdc++: Allow Lemire's algorithm to be used in more cases
@ 2020-10-29 14:59 Jonathan Wakely
  2020-11-03 21:28 ` Stephan Bergmann
  0 siblings, 1 reply; 7+ messages in thread
From: Jonathan Wakely @ 2020-10-29 14:59 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Daniel Lemire

[-- Attachment #1: Type: text/plain, Size: 1576 bytes --]

This extends the fast path to also work when the URBG's range of
possible values is not the entire range of its result_type. Previously,
the slow path would be used for engines with a uint_fast32_t result type
if that type is actually a typedef for uint64_t rather than uint32_t.
After this change, the generator's result_type is not important, only
the range of possible value that generator can produce. If the
generator's range is exactly UINT64_MAX then the calculation will be
done using 128-bit and 64-bit integers, and if the range is UINT32_MAX
it will be done using 64-bit and 32-bit integers.

In practice, this benefits most of the engines and engine adaptors
defined in [rand.predef] on x86_64-linux and other 64-bit targets. This
is because std::minstd_rand0 and std::mt19937 and others use
uint_fast32_t, which is a typedef for uint64_t.

The code now makes use of the recently-clarified requirement that the
generator's min() and max() functions are usable in constant
expressions (see LWG 2154).

libstdc++-v3/ChangeLog:

	* include/bits/uniform_int_dist.h (_Power_of_two): Add
	constexpr.
	(uniform_int_distribution::_S_nd): Add static_assert to ensure
	the wider type is twice as wide as the result type.
	(uniform_int_distribution::__generate_impl): Add static_assert
	and declare variables as constexpr where appropriate.
	(uniform_int_distribution:operator()): Likewise. Only consider
	the uniform random bit generator's range of possible results
	when deciding whether _S_nd can be used, not the __uctype type.

Tested x86_64-linux. Committed to trunk.


[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 6387 bytes --]

commit 822c1d21a3c710831af65a6e3bc83f558fb39044
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Oct 29 14:47:18 2020

    libstdc++: Allow Lemire's algorithm to be used in more cases
    
    This extends the fast path to also work when the URBG's range of
    possible values is not the entire range of its result_type. Previously,
    the slow path would be used for engines with a uint_fast32_t result type
    if that type is actually a typedef for uint64_t rather than uint32_t.
    After this change, the generator's result_type is not important, only
    the range of possible value that generator can produce. If the
    generator's range is exactly UINT64_MAX then the calculation will be
    done using 128-bit and 64-bit integers, and if the range is UINT32_MAX
    it will be done using 64-bit and 32-bit integers.
    
    In practice, this benefits most of the engines and engine adaptors
    defined in [rand.predef] on x86_64-linux and other 64-bit targets. This
    is because std::minstd_rand0 and std::mt19937 and others use
    uint_fast32_t, which is a typedef for uint64_t.
    
    The code now makes use of the recently-clarified requirement that the
    generator's min() and max() functions are usable in constant
    expressions (see LWG 2154).
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/uniform_int_dist.h (_Power_of_two): Add
            constexpr.
            (uniform_int_distribution::_S_nd): Add static_assert to ensure
            the wider type is twice as wide as the result type.
            (uniform_int_distribution::__generate_impl): Add static_assert
            and declare variables as constexpr where appropriate.
            (uniform_int_distribution:operator()): Likewise. Only consider
            the uniform random bit generator's range of possible results
            when deciding whether _S_nd can be used, not the __uctype type.

diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h
index cf6ba35c675..524593bb984 100644
--- a/libstdc++-v3/include/bits/uniform_int_dist.h
+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
@@ -58,7 +58,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   {
     /* Determine whether number is a power of 2.  */
     template<typename _Tp>
-      inline bool
+      constexpr bool
       _Power_of_2(_Tp __x)
       {
 	return ((__x - 1) & __x) == 0;
@@ -242,9 +242,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	static _Up
 	_S_nd(_Urbg& __g, _Up __range)
 	{
-	  using __gnu_cxx::__int_traits;
-	  static_assert(!__int_traits<_Up>::__is_signed, "U must be unsigned");
-	  static_assert(!__int_traits<_Wp>::__is_signed, "W must be unsigned");
+	  using _Up_traits = __gnu_cxx::__int_traits<_Up>;
+	  using _Wp_traits = __gnu_cxx::__int_traits<_Wp>;
+	  static_assert(!_Up_traits::__is_signed, "U must be unsigned");
+	  static_assert(!_Wp_traits::__is_signed, "W must be unsigned");
+	  static_assert(_Wp_traits::__digits == (2 * _Up_traits::__digits),
+			"W must be twice as wide as U");
 
 	  // reference: Fast Random Integer Generation in an Interval
 	  // ACM Transactions on Modeling and Computer Simulation 29 (1), 2019
@@ -260,7 +263,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		  __low = _Up(__product);
 		}
 	    }
-	  return __product >> __gnu_cxx::__int_traits<_Up>::__digits;
+	  return __product >> _Up_traits::__digits;
 	}
     };
 
@@ -275,9 +278,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	typedef typename make_unsigned<result_type>::type __utype;
 	typedef typename common_type<_Gresult_type, __utype>::type __uctype;
 
-	const __uctype __urngmin = __urng.min();
-	const __uctype __urngmax = __urng.max();
-	const __uctype __urngrange = __urngmax - __urngmin;
+	static_assert( __urng.min() < __urng.max(),
+	    "Uniform random bit generator must define min() < max()");
+
+	constexpr __uctype __urngmin = __urng.min();
+	constexpr __uctype __urngmax = __urng.max();
+	constexpr __uctype __urngrange = __urngmax - __urngmin;
 	const __uctype __urange
 	  = __uctype(__param.b()) - __uctype(__param.a());
 
@@ -288,21 +294,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 	    const __uctype __uerange = __urange + 1; // __urange can be zero
 
-	    using __gnu_cxx::__int_traits;
+#if defined __UINT64_TYPE__ && defined __UINT32_TYPE__
 #if __SIZEOF_INT128__
-	    if (__int_traits<__uctype>::__digits == 64
-		&& __urngrange == __int_traits<__uctype>::__max)
+	    if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT64_MAX__)
 	      {
-		__ret = _S_nd<unsigned __int128>(__urng, __uerange);
+		// __urng produces values that use exactly 64-bits,
+		// so use 128-bit integers to downscale to desired range.
+		__UINT64_TYPE__ __u64erange = __uerange;
+		__ret = _S_nd<unsigned __int128>(__urng, __u64erange);
 	      }
 	    else
 #endif
-	    if (__int_traits<__uctype>::__digits == 32
-		&& __urngrange == __int_traits<__uctype>::__max)
+	    if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT32_MAX__)
 	      {
-		__ret = _S_nd<__UINT64_TYPE__>(__urng, __uerange);
+		// __urng produces values that use exactly 32-bits,
+		// so use 64-bit integers to downscale to desired range.
+		__UINT32_TYPE__ __u32erange = __uerange;
+		__ret = _S_nd<__UINT64_TYPE__>(__urng, __u32erange);
 	      }
 	    else
+#endif
 	      {
 		// fallback case (2 divisions)
 		const __uctype __scaling = __urngrange / __uerange;
@@ -361,9 +372,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	typedef typename make_unsigned<result_type>::type __utype;
 	typedef typename common_type<_Gresult_type, __utype>::type __uctype;
 
-	const __uctype __urngmin = __urng.min();
-	const __uctype __urngmax = __urng.max();
-	const __uctype __urngrange = __urngmax - __urngmin;
+	static_assert( __urng.min() < __urng.max(),
+	    "Uniform random bit generator must define min() < max()");
+
+	constexpr __uctype __urngmin = __urng.min();
+	constexpr __uctype __urngmax = __urng.max();
+	constexpr __uctype __urngrange = __urngmax - __urngmin;
 	const __uctype __urange
 	  = __uctype(__param.b()) - __uctype(__param.a());
 
@@ -417,7 +431,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	      {
 		do
 		  {
-		    const __uctype __uerngrange = __urngrange + 1;
+		    constexpr __uctype __uerngrange = __urngrange + 1;
 		    __tmp = (__uerngrange * operator()
 			     (__urng, param_type(0, __urange / __uerngrange)));
 		    __ret = __tmp + (__uctype(__urng()) - __urngmin);

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [committed] libstdc++: Allow Lemire's algorithm to be used in more cases
  2020-10-29 14:59 [committed] libstdc++: Allow Lemire's algorithm to be used in more cases Jonathan Wakely
@ 2020-11-03 21:28 ` Stephan Bergmann
  2020-11-03 22:25   ` Jonathan Wakely
  0 siblings, 1 reply; 7+ messages in thread
From: Stephan Bergmann @ 2020-11-03 21:28 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

On 29/10/2020 15:59, Jonathan Wakely via Gcc-patches wrote:
> This extends the fast path to also work when the URBG's range of
> possible values is not the entire range of its result_type. Previously,
> the slow path would be used for engines with a uint_fast32_t result type
> if that type is actually a typedef for uint64_t rather than uint32_t.
> After this change, the generator's result_type is not important, only
> the range of possible value that generator can produce. If the
> generator's range is exactly UINT64_MAX then the calculation will be
> done using 128-bit and 64-bit integers, and if the range is UINT32_MAX
> it will be done using 64-bit and 32-bit integers.
> 
> In practice, this benefits most of the engines and engine adaptors
> defined in [rand.predef] on x86_64-linux and other 64-bit targets. This
> is because std::minstd_rand0 and std::mt19937 and others use
> uint_fast32_t, which is a typedef for uint64_t.
> 
> The code now makes use of the recently-clarified requirement that the
> generator's min() and max() functions are usable in constant
> expressions (see LWG 2154).
> 
> libstdc++-v3/ChangeLog:
> 
> 	* include/bits/uniform_int_dist.h (_Power_of_two): Add
> 	constexpr.
> 	(uniform_int_distribution::_S_nd): Add static_assert to ensure
> 	the wider type is twice as wide as the result type.
> 	(uniform_int_distribution::__generate_impl): Add static_assert
> 	and declare variables as constexpr where appropriate.
> 	(uniform_int_distribution:operator()): Likewise. Only consider
> 	the uniform random bit generator's range of possible results
> 	when deciding whether _S_nd can be used, not the __uctype type.
> 
> Tested x86_64-linux. Committed to trunk.

At least with recent Clang trunk, this causes e.g.

> $ cat test.cc
> #include <random>
> void f(std::default_random_engine e) { std::uniform_int_distribution<int>{0, 1}(e); }

to fail with

> $ clang++ --gcc-toolchain=~/gcc/trunk/inst -std=c++17 -fsyntax-only test.cc
> In file included from test.cc:1:
> In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/random:40:
> In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/string:52:
> In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/stl_algo.h:66:
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:281:17: error: static_assert expression is not an integral constant expression
>         static_assert( __urng.min() < __urng.max(),
>                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:190:24: note: in instantiation of function template specialization 'std::uniform_int_distribution<int>::operator()<std::linear_congruential_engine<unsigned long, 16807, 0, 2147483647>>' requested here
>         { return this->operator()(__urng, _M_param); }
>                        ^
> test.cc:2:80: note: in instantiation of function template specialization 'std::uniform_int_distribution<int>::operator()<std::linear_congruential_engine<unsigned long, 16807, 0, 2147483647>>' requested here
> void f(std::default_random_engine e) { std::uniform_int_distribution<int>{0, 1}(e); }
>                                                                                ^
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:281:17: note: function parameter '__urng' with unknown value cannot be used in a constant expression
>         static_assert( __urng.min() < __urng.max(),
>                        ^
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: note: declared here
>         operator()(_UniformRandomBitGenerator& __urng,
>                                                ^
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:284:21: error: constexpr variable '__urngmin' must be initialized by a constant expression
>         constexpr __uctype __urngmin = __urng.min();
>                            ^           ~~~~~~~~~~~~
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:284:33: note: function parameter '__urng' with unknown value cannot be used in a constant expression
>         constexpr __uctype __urngmin = __urng.min();
>                                        ^
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: note: declared here
>         operator()(_UniformRandomBitGenerator& __urng,
>                                                ^
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:21: error: constexpr variable '__urngmax' must be initialized by a constant expression
>         constexpr __uctype __urngmax = __urng.max();
>                            ^           ~~~~~~~~~~~~
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:33: note: function parameter '__urng' with unknown value cannot be used in a constant expression
>         constexpr __uctype __urngmax = __urng.max();
>                                        ^
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: note: declared here
>         operator()(_UniformRandomBitGenerator& __urng,
>                                                ^
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: error: constexpr variable '__urngrange' must be initialized by a constant expression
>         constexpr __uctype __urngrange = __urngmax - __urngmin;
>                            ^             ~~~~~~~~~~~~~~~~~~~~~
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:35: note: initializer of '__urngmax' is not a constant expression
>         constexpr __uctype __urngrange = __urngmax - __urngmin;
>                                          ^
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:21: note: declared here
>         constexpr __uctype __urngmax = __urng.max();
>                            ^
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:299:31: error: constexpr if condition is not a constant expression
>             if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT64_MAX__)
>                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:299:31: note: initializer of '__urngrange' is not a constant expression
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: note: declared here
>         constexpr __uctype __urngrange = __urngmax - __urngmin;
>                            ^
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:308:31: error: constexpr if condition is not a constant expression
>             if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT32_MAX__)
>                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:308:31: note: initializer of '__urngrange' is not a constant expression
> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: note: declared here
>         constexpr __uctype __urngrange = __urngmax - __urngmin;
>                            ^
> 6 errors generated.

which would be fixed by something like

> diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h
> index 524593bb984..d9c7ea96fda 100644
> --- a/libstdc++-v3/include/bits/uniform_int_dist.h
> +++ b/libstdc++-v3/include/bits/uniform_int_dist.h
> @@ -278,11 +278,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         typedef typename make_unsigned<result_type>::type __utype;
>         typedef typename common_type<_Gresult_type, __utype>::type __uctype;
>  
> -       static_assert( __urng.min() < __urng.max(),
> +       static_assert( _UniformRandomBitGenerator::min() < _UniformRandomBitGenerator::max(),
>             "Uniform random bit generator must define min() < max()");
>  
> -       constexpr __uctype __urngmin = __urng.min();
> -       constexpr __uctype __urngmax = __urng.max();
> +       constexpr __uctype __urngmin = _UniformRandomBitGenerator::min();
> +       constexpr __uctype __urngmax = _UniformRandomBitGenerator::max();
>         constexpr __uctype __urngrange = __urngmax - __urngmin;
>         const __uctype __urange
>           = __uctype(__param.b()) - __uctype(__param.a());

(and I think there are further similar issues in this change).


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [committed] libstdc++: Allow Lemire's algorithm to be used in more cases
  2020-11-03 21:28 ` Stephan Bergmann
@ 2020-11-03 22:25   ` Jonathan Wakely
  2020-11-04  8:45     ` Stephan Bergmann
  0 siblings, 1 reply; 7+ messages in thread
From: Jonathan Wakely @ 2020-11-03 22:25 UTC (permalink / raw)
  To: Stephan Bergmann; +Cc: libstdc++, gcc-patches

On 03/11/20 22:28 +0100, Stephan Bergmann via Libstdc++ wrote:
>On 29/10/2020 15:59, Jonathan Wakely via Gcc-patches wrote:
>>This extends the fast path to also work when the URBG's range of
>>possible values is not the entire range of its result_type. Previously,
>>the slow path would be used for engines with a uint_fast32_t result type
>>if that type is actually a typedef for uint64_t rather than uint32_t.
>>After this change, the generator's result_type is not important, only
>>the range of possible value that generator can produce. If the
>>generator's range is exactly UINT64_MAX then the calculation will be
>>done using 128-bit and 64-bit integers, and if the range is UINT32_MAX
>>it will be done using 64-bit and 32-bit integers.
>>
>>In practice, this benefits most of the engines and engine adaptors
>>defined in [rand.predef] on x86_64-linux and other 64-bit targets. This
>>is because std::minstd_rand0 and std::mt19937 and others use
>>uint_fast32_t, which is a typedef for uint64_t.
>>
>>The code now makes use of the recently-clarified requirement that the
>>generator's min() and max() functions are usable in constant
>>expressions (see LWG 2154).
>>
>>libstdc++-v3/ChangeLog:
>>
>>	* include/bits/uniform_int_dist.h (_Power_of_two): Add
>>	constexpr.
>>	(uniform_int_distribution::_S_nd): Add static_assert to ensure
>>	the wider type is twice as wide as the result type.
>>	(uniform_int_distribution::__generate_impl): Add static_assert
>>	and declare variables as constexpr where appropriate.
>>	(uniform_int_distribution:operator()): Likewise. Only consider
>>	the uniform random bit generator's range of possible results
>>	when deciding whether _S_nd can be used, not the __uctype type.
>>
>>Tested x86_64-linux. Committed to trunk.
>
>At least with recent Clang trunk, this causes e.g.
>
>>$ cat test.cc
>>#include <random>
>>void f(std::default_random_engine e) { std::uniform_int_distribution<int>{0, 1}(e); }
>
>to fail with
>
>>$ clang++ --gcc-toolchain=~/gcc/trunk/inst -std=c++17 -fsyntax-only test.cc
>>In file included from test.cc:1:
>>In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/random:40:
>>In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/string:52:
>>In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/stl_algo.h:66:
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:281:17: error: static_assert expression is not an integral constant expression
>>        static_assert( __urng.min() < __urng.max(),
>>                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:190:24: note: in instantiation of function template specialization 'std::uniform_int_distribution<int>::operator()<std::linear_congruential_engine<unsigned long, 16807, 0, 2147483647>>' requested here
>>        { return this->operator()(__urng, _M_param); }
>>                       ^
>>test.cc:2:80: note: in instantiation of function template specialization 'std::uniform_int_distribution<int>::operator()<std::linear_congruential_engine<unsigned long, 16807, 0, 2147483647>>' requested here
>>void f(std::default_random_engine e) { std::uniform_int_distribution<int>{0, 1}(e); }
>>                                                                               ^
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:281:17: note: function parameter '__urng' with unknown value cannot be used in a constant expression
>>        static_assert( __urng.min() < __urng.max(),
>>                       ^
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: note: declared here
>>        operator()(_UniformRandomBitGenerator& __urng,
>>                                               ^
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:284:21: error: constexpr variable '__urngmin' must be initialized by a constant expression
>>        constexpr __uctype __urngmin = __urng.min();
>>                           ^           ~~~~~~~~~~~~
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:284:33: note: function parameter '__urng' with unknown value cannot be used in a constant expression
>>        constexpr __uctype __urngmin = __urng.min();
>>                                       ^
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: note: declared here
>>        operator()(_UniformRandomBitGenerator& __urng,
>>                                               ^
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:21: error: constexpr variable '__urngmax' must be initialized by a constant expression
>>        constexpr __uctype __urngmax = __urng.max();
>>                           ^           ~~~~~~~~~~~~
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:33: note: function parameter '__urng' with unknown value cannot be used in a constant expression
>>        constexpr __uctype __urngmax = __urng.max();
>>                                       ^
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: note: declared here
>>        operator()(_UniformRandomBitGenerator& __urng,
>>                                               ^
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: error: constexpr variable '__urngrange' must be initialized by a constant expression
>>        constexpr __uctype __urngrange = __urngmax - __urngmin;
>>                           ^             ~~~~~~~~~~~~~~~~~~~~~
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:35: note: initializer of '__urngmax' is not a constant expression
>>        constexpr __uctype __urngrange = __urngmax - __urngmin;
>>                                         ^
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:21: note: declared here
>>        constexpr __uctype __urngmax = __urng.max();
>>                           ^
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:299:31: error: constexpr if condition is not a constant expression
>>            if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT64_MAX__)
>>                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:299:31: note: initializer of '__urngrange' is not a constant expression
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: note: declared here
>>        constexpr __uctype __urngrange = __urngmax - __urngmin;
>>                           ^
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:308:31: error: constexpr if condition is not a constant expression
>>            if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT32_MAX__)
>>                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:308:31: note: initializer of '__urngrange' is not a constant expression
>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: note: declared here
>>        constexpr __uctype __urngrange = __urngmax - __urngmin;
>>                           ^
>>6 errors generated.
>
>which would be fixed by something like
>
>>diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h
>>index 524593bb984..d9c7ea96fda 100644
>>--- a/libstdc++-v3/include/bits/uniform_int_dist.h
>>+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
>>@@ -278,11 +278,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>        typedef typename make_unsigned<result_type>::type __utype;
>>        typedef typename common_type<_Gresult_type, __utype>::type __uctype;
>>-       static_assert( __urng.min() < __urng.max(),
>>+       static_assert( _UniformRandomBitGenerator::min() < _UniformRandomBitGenerator::max(),
>>            "Uniform random bit generator must define min() < max()");
>>-       constexpr __uctype __urngmin = __urng.min();
>>-       constexpr __uctype __urngmax = __urng.max();
>>+       constexpr __uctype __urngmin = _UniformRandomBitGenerator::min();
>>+       constexpr __uctype __urngmax = _UniformRandomBitGenerator::max();
>>        constexpr __uctype __urngrange = __urngmax - __urngmin;
>>        const __uctype __urange
>>          = __uctype(__param.b()) - __uctype(__param.a());
>
>(and I think there are further similar issues in this change).

I think this is a Clang bug, but I'll change the code anyway.



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [committed] libstdc++: Allow Lemire's algorithm to be used in more cases
  2020-11-03 22:25   ` Jonathan Wakely
@ 2020-11-04  8:45     ` Stephan Bergmann
  2020-11-04  8:52       ` Ville Voutilainen
  2020-11-04 10:15       ` Jonathan Wakely
  0 siblings, 2 replies; 7+ messages in thread
From: Stephan Bergmann @ 2020-11-04  8:45 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

On 03/11/2020 23:25, Jonathan Wakely wrote:
> On 03/11/20 22:28 +0100, Stephan Bergmann via Libstdc++ wrote:
>> On 29/10/2020 15:59, Jonathan Wakely via Gcc-patches wrote:
>>> This extends the fast path to also work when the URBG's range of
>>> possible values is not the entire range of its result_type. Previously,
>>> the slow path would be used for engines with a uint_fast32_t result type
>>> if that type is actually a typedef for uint64_t rather than uint32_t.
>>> After this change, the generator's result_type is not important, only
>>> the range of possible value that generator can produce. If the
>>> generator's range is exactly UINT64_MAX then the calculation will be
>>> done using 128-bit and 64-bit integers, and if the range is UINT32_MAX
>>> it will be done using 64-bit and 32-bit integers.
>>>
>>> In practice, this benefits most of the engines and engine adaptors
>>> defined in [rand.predef] on x86_64-linux and other 64-bit targets. This
>>> is because std::minstd_rand0 and std::mt19937 and others use
>>> uint_fast32_t, which is a typedef for uint64_t.
>>>
>>> The code now makes use of the recently-clarified requirement that the
>>> generator's min() and max() functions are usable in constant
>>> expressions (see LWG 2154).
>>>
>>> libstdc++-v3/ChangeLog:
>>>
>>>     * include/bits/uniform_int_dist.h (_Power_of_two): Add
>>>     constexpr.
>>>     (uniform_int_distribution::_S_nd): Add static_assert to ensure
>>>     the wider type is twice as wide as the result type.
>>>     (uniform_int_distribution::__generate_impl): Add static_assert
>>>     and declare variables as constexpr where appropriate.
>>>     (uniform_int_distribution:operator()): Likewise. Only consider
>>>     the uniform random bit generator's range of possible results
>>>     when deciding whether _S_nd can be used, not the __uctype type.
>>>
>>> Tested x86_64-linux. Committed to trunk.
>>
>> At least with recent Clang trunk, this causes e.g.
>>
>>> $ cat test.cc
>>> #include <random>
>>> void f(std::default_random_engine e) { 
>>> std::uniform_int_distribution<int>{0, 1}(e); }
>>
>> to fail with
>>
>>> $ clang++ --gcc-toolchain=~/gcc/trunk/inst -std=c++17 -fsyntax-only 
>>> test.cc
>>> In file included from test.cc:1:
>>> In file included from 
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/random:40: 
>>>
>>> In file included from 
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/string:52: 
>>>
>>> In file included from 
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/stl_algo.h:66: 
>>>
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:281:17: 
>>> error: static_assert expression is not an integral constant expression
>>>        static_assert( __urng.min() < __urng.max(),
>>>                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:190:24: 
>>> note: in instantiation of function template specialization 
>>> 'std::uniform_int_distribution<int>::operator()<std::linear_congruential_engine<unsigned 
>>> long, 16807, 0, 2147483647>>' requested here
>>>        { return this->operator()(__urng, _M_param); }
>>>                       ^
>>> test.cc:2:80: note: in instantiation of function template 
>>> specialization 
>>> 'std::uniform_int_distribution<int>::operator()<std::linear_congruential_engine<unsigned 
>>> long, 16807, 0, 2147483647>>' requested here
>>> void f(std::default_random_engine e) { 
>>> std::uniform_int_distribution<int>{0, 1}(e); }
>>>                                                                               
>>> ^
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:281:17: 
>>> note: function parameter '__urng' with unknown value cannot be used 
>>> in a constant expression
>>>        static_assert( __urng.min() < __urng.max(),
>>>                       ^
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: 
>>> note: declared here
>>>        operator()(_UniformRandomBitGenerator& __urng,
>>>                                               ^
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:284:21: 
>>> error: constexpr variable '__urngmin' must be initialized by a 
>>> constant expression
>>>        constexpr __uctype __urngmin = __urng.min();
>>>                           ^           ~~~~~~~~~~~~
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:284:33: 
>>> note: function parameter '__urng' with unknown value cannot be used 
>>> in a constant expression
>>>        constexpr __uctype __urngmin = __urng.min();
>>>                                       ^
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: 
>>> note: declared here
>>>        operator()(_UniformRandomBitGenerator& __urng,
>>>                                               ^
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:21: 
>>> error: constexpr variable '__urngmax' must be initialized by a 
>>> constant expression
>>>        constexpr __uctype __urngmax = __urng.max();
>>>                           ^           ~~~~~~~~~~~~
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:33: 
>>> note: function parameter '__urng' with unknown value cannot be used 
>>> in a constant expression
>>>        constexpr __uctype __urngmax = __urng.max();
>>>                                       ^
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: 
>>> note: declared here
>>>        operator()(_UniformRandomBitGenerator& __urng,
>>>                                               ^
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: 
>>> error: constexpr variable '__urngrange' must be initialized by a 
>>> constant expression
>>>        constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>                           ^             ~~~~~~~~~~~~~~~~~~~~~
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:35: 
>>> note: initializer of '__urngmax' is not a constant expression
>>>        constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>                                         ^
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:21: 
>>> note: declared here
>>>        constexpr __uctype __urngmax = __urng.max();
>>>                           ^
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:299:31: 
>>> error: constexpr if condition is not a constant expression
>>>            if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT64_MAX__)
>>>                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:299:31: 
>>> note: initializer of '__urngrange' is not a constant expression
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: 
>>> note: declared here
>>>        constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>                           ^
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:308:31: 
>>> error: constexpr if condition is not a constant expression
>>>            if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT32_MAX__)
>>>                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:308:31: 
>>> note: initializer of '__urngrange' is not a constant expression
>>> ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: 
>>> note: declared here
>>>        constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>                           ^
>>> 6 errors generated.
>>
>> which would be fixed by something like
>>
>>> diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h 
>>> b/libstdc++-v3/include/bits/uniform_int_dist.h
>>> index 524593bb984..d9c7ea96fda 100644
>>> --- a/libstdc++-v3/include/bits/uniform_int_dist.h
>>> +++ b/libstdc++-v3/include/bits/uniform_int_dist.h
>>> @@ -278,11 +278,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>        typedef typename make_unsigned<result_type>::type __utype;
>>>        typedef typename common_type<_Gresult_type, __utype>::type 
>>> __uctype;
>>> -       static_assert( __urng.min() < __urng.max(),
>>> +       static_assert( _UniformRandomBitGenerator::min() < 
>>> _UniformRandomBitGenerator::max(),
>>>            "Uniform random bit generator must define min() < max()");
>>> -       constexpr __uctype __urngmin = __urng.min();
>>> -       constexpr __uctype __urngmax = __urng.max();
>>> +       constexpr __uctype __urngmin = 
>>> _UniformRandomBitGenerator::min();
>>> +       constexpr __uctype __urngmax = 
>>> _UniformRandomBitGenerator::max();
>>>        constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>        const __uctype __urange
>>>          = __uctype(__param.b()) - __uctype(__param.a());
>>
>> (and I think there are further similar issues in this change).
> 
> I think this is a Clang bug, but I'll change the code anyway.

To me it looks like it boils down to disagreement between g++ and 
clang++ over

> struct S { static constexpr int f() { return 0; } };
> void f(S & s) { static_assert(s.f(), ""); }

where I think Clang might be right in rejecting it based on [expr.const] 
"An expression e is a core constant expression unless [...] an 
id-expression that refers to a variable or data member of reference type 
unless the reference has a preceding initialization [...]"

(By the way, when looking into the original issue, what puzzles me is: 
IIUC, `_UniformRandomBitGenerator& __urng` must meet the uniform random 
big generator requirements, [rand.req.urng]: a table of requirements in 
C++17, concept uniform_random_bit_generator in C++20.  For one, that 
only requires G::min() but not g.min().  What if G::min is defined as 
`using min = result_type`?  For another, what guarantees that G::min() 
is a constant expression?  The C++17 table mentions "Complexity: 
compile-time", and the C++20 concept contains `requires 
bool_constant<(G::min() < G::max())>::value;`.  Is each of those enough 
to imply the constant expression requirement?)


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [committed] libstdc++: Allow Lemire's algorithm to be used in more cases
  2020-11-04  8:45     ` Stephan Bergmann
@ 2020-11-04  8:52       ` Ville Voutilainen
  2020-11-04 10:15       ` Jonathan Wakely
  1 sibling, 0 replies; 7+ messages in thread
From: Ville Voutilainen @ 2020-11-04  8:52 UTC (permalink / raw)
  To: Stephan Bergmann; +Cc: Jonathan Wakely, libstdc++, gcc-patches List

On Wed, 4 Nov 2020 at 10:46, Stephan Bergmann via Libstdc++
<libstdc++@gcc.gnu.org> wrote:
> To me it looks like it boils down to disagreement between g++ and
> clang++ over
>
> > struct S { static constexpr int f() { return 0; } };
> > void f(S & s) { static_assert(s.f(), ""); }
>
> where I think Clang might be right in rejecting it based on [expr.const]
> "An expression e is a core constant expression unless [...] an
> id-expression that refers to a variable or data member of reference type
> unless the reference has a preceding initialization [...]"

There's more to it than that. It's a disagreement over [expr.ref]/1.
For a static
member call, gcc just plain doesn't evaluate the s in s.f(). But [expr.ref]/1
says it's evaluated, and since it's not a constant expression, clang rejects
it, and gcc accepts it. That's why your fix works; it removes the use
of the otherwise-mostly-ignored
object expression for a call to a static member function.

So, I think gcc is accepting-invalid here, and we should just apply
the fix you suggested.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [committed] libstdc++: Allow Lemire's algorithm to be used in more cases
  2020-11-04  8:45     ` Stephan Bergmann
  2020-11-04  8:52       ` Ville Voutilainen
@ 2020-11-04 10:15       ` Jonathan Wakely
  2020-11-04 10:38         ` Jonathan Wakely
  1 sibling, 1 reply; 7+ messages in thread
From: Jonathan Wakely @ 2020-11-04 10:15 UTC (permalink / raw)
  To: Stephan Bergmann; +Cc: libstdc++, gcc-patches

On 04/11/20 09:45 +0100, Stephan Bergmann via Libstdc++ wrote:
>On 03/11/2020 23:25, Jonathan Wakely wrote:
>>On 03/11/20 22:28 +0100, Stephan Bergmann via Libstdc++ wrote:
>>>On 29/10/2020 15:59, Jonathan Wakely via Gcc-patches wrote:
>>>>This extends the fast path to also work when the URBG's range of
>>>>possible values is not the entire range of its result_type. Previously,
>>>>the slow path would be used for engines with a uint_fast32_t result type
>>>>if that type is actually a typedef for uint64_t rather than uint32_t.
>>>>After this change, the generator's result_type is not important, only
>>>>the range of possible value that generator can produce. If the
>>>>generator's range is exactly UINT64_MAX then the calculation will be
>>>>done using 128-bit and 64-bit integers, and if the range is UINT32_MAX
>>>>it will be done using 64-bit and 32-bit integers.
>>>>
>>>>In practice, this benefits most of the engines and engine adaptors
>>>>defined in [rand.predef] on x86_64-linux and other 64-bit targets. This
>>>>is because std::minstd_rand0 and std::mt19937 and others use
>>>>uint_fast32_t, which is a typedef for uint64_t.
>>>>
>>>>The code now makes use of the recently-clarified requirement that the
>>>>generator's min() and max() functions are usable in constant
>>>>expressions (see LWG 2154).
>>>>
>>>>libstdc++-v3/ChangeLog:
>>>>
>>>>    * include/bits/uniform_int_dist.h (_Power_of_two): Add
>>>>    constexpr.
>>>>    (uniform_int_distribution::_S_nd): Add static_assert to ensure
>>>>    the wider type is twice as wide as the result type.
>>>>    (uniform_int_distribution::__generate_impl): Add static_assert
>>>>    and declare variables as constexpr where appropriate.
>>>>    (uniform_int_distribution:operator()): Likewise. Only consider
>>>>    the uniform random bit generator's range of possible results
>>>>    when deciding whether _S_nd can be used, not the __uctype type.
>>>>
>>>>Tested x86_64-linux. Committed to trunk.
>>>
>>>At least with recent Clang trunk, this causes e.g.
>>>
>>>>$ cat test.cc
>>>>#include <random>
>>>>void f(std::default_random_engine e) { 
>>>>std::uniform_int_distribution<int>{0, 1}(e); }
>>>
>>>to fail with
>>>
>>>>$ clang++ --gcc-toolchain=~/gcc/trunk/inst -std=c++17 
>>>>-fsyntax-only test.cc
>>>>In file included from test.cc:1:
>>>>In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/random:40:
>>>>
>>>>In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/string:52:
>>>>
>>>>In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/stl_algo.h:66:
>>>>
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:281:17: 
>>>>error: static_assert expression is not an integral constant 
>>>>expression
>>>>       static_assert( __urng.min() < __urng.max(),
>>>>                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:190:24: 
>>>>note: in instantiation of function template specialization 'std::uniform_int_distribution<int>::operator()<std::linear_congruential_engine<unsigned 
>>>>long, 16807, 0, 2147483647>>' requested here
>>>>       { return this->operator()(__urng, _M_param); }
>>>>                      ^
>>>>test.cc:2:80: note: in instantiation of function template 
>>>>specialization 'std::uniform_int_distribution<int>::operator()<std::linear_congruential_engine<unsigned 
>>>>long, 16807, 0, 2147483647>>' requested here
>>>>void f(std::default_random_engine e) { 
>>>>std::uniform_int_distribution<int>{0, 1}(e); }
>>>>^
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:281:17: 
>>>>note: function parameter '__urng' with unknown value cannot be 
>>>>used in a constant expression
>>>>       static_assert( __urng.min() < __urng.max(),
>>>>                      ^
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: 
>>>>note: declared here
>>>>       operator()(_UniformRandomBitGenerator& __urng,
>>>>                                              ^
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:284:21: 
>>>>error: constexpr variable '__urngmin' must be initialized by a 
>>>>constant expression
>>>>       constexpr __uctype __urngmin = __urng.min();
>>>>                          ^           ~~~~~~~~~~~~
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:284:33: 
>>>>note: function parameter '__urng' with unknown value cannot be 
>>>>used in a constant expression
>>>>       constexpr __uctype __urngmin = __urng.min();
>>>>                                      ^
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: 
>>>>note: declared here
>>>>       operator()(_UniformRandomBitGenerator& __urng,
>>>>                                              ^
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:21: 
>>>>error: constexpr variable '__urngmax' must be initialized by a 
>>>>constant expression
>>>>       constexpr __uctype __urngmax = __urng.max();
>>>>                          ^           ~~~~~~~~~~~~
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:33: 
>>>>note: function parameter '__urng' with unknown value cannot be 
>>>>used in a constant expression
>>>>       constexpr __uctype __urngmax = __urng.max();
>>>>                                      ^
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: 
>>>>note: declared here
>>>>       operator()(_UniformRandomBitGenerator& __urng,
>>>>                                              ^
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: 
>>>>error: constexpr variable '__urngrange' must be initialized by a 
>>>>constant expression
>>>>       constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>                          ^             ~~~~~~~~~~~~~~~~~~~~~
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:35: 
>>>>note: initializer of '__urngmax' is not a constant expression
>>>>       constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>                                        ^
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:21: 
>>>>note: declared here
>>>>       constexpr __uctype __urngmax = __urng.max();
>>>>                          ^
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:299:31: 
>>>>error: constexpr if condition is not a constant expression
>>>>           if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT64_MAX__)
>>>>                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:299:31: 
>>>>note: initializer of '__urngrange' is not a constant expression
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: 
>>>>note: declared here
>>>>       constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>                          ^
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:308:31: 
>>>>error: constexpr if condition is not a constant expression
>>>>           if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT32_MAX__)
>>>>                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:308:31: 
>>>>note: initializer of '__urngrange' is not a constant expression
>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: 
>>>>note: declared here
>>>>       constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>                          ^
>>>>6 errors generated.
>>>
>>>which would be fixed by something like
>>>
>>>>diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h 
>>>>b/libstdc++-v3/include/bits/uniform_int_dist.h
>>>>index 524593bb984..d9c7ea96fda 100644
>>>>--- a/libstdc++-v3/include/bits/uniform_int_dist.h
>>>>+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
>>>>@@ -278,11 +278,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>       typedef typename make_unsigned<result_type>::type __utype;
>>>>       typedef typename common_type<_Gresult_type, 
>>>>__utype>::type __uctype;
>>>>-       static_assert( __urng.min() < __urng.max(),
>>>>+       static_assert( _UniformRandomBitGenerator::min() < 
>>>>_UniformRandomBitGenerator::max(),
>>>>           "Uniform random bit generator must define min() < max()");
>>>>-       constexpr __uctype __urngmin = __urng.min();
>>>>-       constexpr __uctype __urngmax = __urng.max();
>>>>+       constexpr __uctype __urngmin = 
>>>>_UniformRandomBitGenerator::min();
>>>>+       constexpr __uctype __urngmax = 
>>>>_UniformRandomBitGenerator::max();
>>>>       constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>       const __uctype __urange
>>>>         = __uctype(__param.b()) - __uctype(__param.a());
>>>
>>>(and I think there are further similar issues in this change).
>>
>>I think this is a Clang bug, but I'll change the code anyway.
>
>To me it looks like it boils down to disagreement between g++ and 
>clang++ over
>
>>struct S { static constexpr int f() { return 0; } };
>>void f(S & s) { static_assert(s.f(), ""); }
>
>where I think Clang might be right in rejecting it based on 
>[expr.const] "An expression e is a core constant expression unless 
>[...] an id-expression that refers to a variable or data member of 
>reference type unless the reference has a preceding initialization 
>[...]"

GCC, Intel icc and MSVC all accept it:

   https://godbolt.org/z/hTsT96


>(By the way, when looking into the original issue, what puzzles me is: 
>IIUC, `_UniformRandomBitGenerator& __urng` must meet the uniform 
>random big generator requirements, [rand.req.urng]: a table of 
>requirements in C++17, concept uniform_random_bit_generator in C++20.  
>For one, that only requires G::min() but not g.min().  What if G::min 
>is defined as `using min = result_type`?  For another, what guarantees 
>that G::min() is a constant expression?  The C++17 table mentions 
>"Complexity: compile-time", and the C++20 concept contains `requires 
>bool_constant<(G::min() < G::max())>::value;`.  Is each of those 
>enough to imply the constant expression requirement?)

The C++20 requirement is exactly requiring constant expressions,
otherwise you can't use them as template arguments. It wasn't clear in
C++17 but the intent was always to require them to be constant
expressions.

I mentioned this in the commit log of the commit that broke clang:

     The code now makes use of the recently-clarified requirement that the
     generator's min() and max() functions are usable in constant
     expressions (see LWG 2154).

See https://cplusplus.github.io/LWG/issue2154


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [committed] libstdc++: Allow Lemire's algorithm to be used in more cases
  2020-11-04 10:15       ` Jonathan Wakely
@ 2020-11-04 10:38         ` Jonathan Wakely
  0 siblings, 0 replies; 7+ messages in thread
From: Jonathan Wakely @ 2020-11-04 10:38 UTC (permalink / raw)
  To: Stephan Bergmann; +Cc: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 11704 bytes --]

On 04/11/20 10:15 +0000, Jonathan Wakely wrote:
>On 04/11/20 09:45 +0100, Stephan Bergmann via Libstdc++ wrote:
>>On 03/11/2020 23:25, Jonathan Wakely wrote:
>>>On 03/11/20 22:28 +0100, Stephan Bergmann via Libstdc++ wrote:
>>>>On 29/10/2020 15:59, Jonathan Wakely via Gcc-patches wrote:
>>>>>This extends the fast path to also work when the URBG's range of
>>>>>possible values is not the entire range of its result_type. Previously,
>>>>>the slow path would be used for engines with a uint_fast32_t result type
>>>>>if that type is actually a typedef for uint64_t rather than uint32_t.
>>>>>After this change, the generator's result_type is not important, only
>>>>>the range of possible value that generator can produce. If the
>>>>>generator's range is exactly UINT64_MAX then the calculation will be
>>>>>done using 128-bit and 64-bit integers, and if the range is UINT32_MAX
>>>>>it will be done using 64-bit and 32-bit integers.
>>>>>
>>>>>In practice, this benefits most of the engines and engine adaptors
>>>>>defined in [rand.predef] on x86_64-linux and other 64-bit targets. This
>>>>>is because std::minstd_rand0 and std::mt19937 and others use
>>>>>uint_fast32_t, which is a typedef for uint64_t.
>>>>>
>>>>>The code now makes use of the recently-clarified requirement that the
>>>>>generator's min() and max() functions are usable in constant
>>>>>expressions (see LWG 2154).
>>>>>
>>>>>libstdc++-v3/ChangeLog:
>>>>>
>>>>>    * include/bits/uniform_int_dist.h (_Power_of_two): Add
>>>>>    constexpr.
>>>>>    (uniform_int_distribution::_S_nd): Add static_assert to ensure
>>>>>    the wider type is twice as wide as the result type.
>>>>>    (uniform_int_distribution::__generate_impl): Add static_assert
>>>>>    and declare variables as constexpr where appropriate.
>>>>>    (uniform_int_distribution:operator()): Likewise. Only consider
>>>>>    the uniform random bit generator's range of possible results
>>>>>    when deciding whether _S_nd can be used, not the __uctype type.
>>>>>
>>>>>Tested x86_64-linux. Committed to trunk.
>>>>
>>>>At least with recent Clang trunk, this causes e.g.
>>>>
>>>>>$ cat test.cc
>>>>>#include <random>
>>>>>void f(std::default_random_engine e) { 
>>>>>std::uniform_int_distribution<int>{0, 1}(e); }
>>>>
>>>>to fail with
>>>>
>>>>>$ clang++ --gcc-toolchain=~/gcc/trunk/inst -std=c++17 
>>>>>-fsyntax-only test.cc
>>>>>In file included from test.cc:1:
>>>>>In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/random:40:
>>>>>
>>>>>In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/string:52:
>>>>>
>>>>>In file included from ~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/stl_algo.h:66:
>>>>>
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:281:17: 
>>>>>error: static_assert expression is not an integral constant 
>>>>>expression
>>>>>       static_assert( __urng.min() < __urng.max(),
>>>>>                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:190:24: 
>>>>>note: in instantiation of function template specialization 'std::uniform_int_distribution<int>::operator()<std::linear_congruential_engine<unsigned 
>>>>>long, 16807, 0, 2147483647>>' requested here
>>>>>       { return this->operator()(__urng, _M_param); }
>>>>>                      ^
>>>>>test.cc:2:80: note: in instantiation of function template 
>>>>>specialization 'std::uniform_int_distribution<int>::operator()<std::linear_congruential_engine<unsigned 
>>>>>long, 16807, 0, 2147483647>>' requested here
>>>>>void f(std::default_random_engine e) { 
>>>>>std::uniform_int_distribution<int>{0, 1}(e); }
>>>>>^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:281:17: 
>>>>>note: function parameter '__urng' with unknown value cannot be 
>>>>>used in a constant expression
>>>>>       static_assert( __urng.min() < __urng.max(),
>>>>>                      ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: 
>>>>>note: declared here
>>>>>       operator()(_UniformRandomBitGenerator& __urng,
>>>>>                                              ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:284:21: 
>>>>>error: constexpr variable '__urngmin' must be initialized by a 
>>>>>constant expression
>>>>>       constexpr __uctype __urngmin = __urng.min();
>>>>>                          ^           ~~~~~~~~~~~~
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:284:33: 
>>>>>note: function parameter '__urng' with unknown value cannot be 
>>>>>used in a constant expression
>>>>>       constexpr __uctype __urngmin = __urng.min();
>>>>>                                      ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: 
>>>>>note: declared here
>>>>>       operator()(_UniformRandomBitGenerator& __urng,
>>>>>                                              ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:21: 
>>>>>error: constexpr variable '__urngmax' must be initialized by a 
>>>>>constant expression
>>>>>       constexpr __uctype __urngmax = __urng.max();
>>>>>                          ^           ~~~~~~~~~~~~
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:33: 
>>>>>note: function parameter '__urng' with unknown value cannot be 
>>>>>used in a constant expression
>>>>>       constexpr __uctype __urngmax = __urng.max();
>>>>>                                      ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:194:41: 
>>>>>note: declared here
>>>>>       operator()(_UniformRandomBitGenerator& __urng,
>>>>>                                              ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: 
>>>>>error: constexpr variable '__urngrange' must be initialized by 
>>>>>a constant expression
>>>>>       constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>>                          ^             ~~~~~~~~~~~~~~~~~~~~~
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:35: 
>>>>>note: initializer of '__urngmax' is not a constant expression
>>>>>       constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>>                                        ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:285:21: 
>>>>>note: declared here
>>>>>       constexpr __uctype __urngmax = __urng.max();
>>>>>                          ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:299:31: 
>>>>>error: constexpr if condition is not a constant expression
>>>>>           if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT64_MAX__)
>>>>>                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:299:31: 
>>>>>note: initializer of '__urngrange' is not a constant 
>>>>>expression
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: 
>>>>>note: declared here
>>>>>       constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>>                          ^
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:308:31: 
>>>>>error: constexpr if condition is not a constant expression
>>>>>           if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT32_MAX__)
>>>>>                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:308:31: 
>>>>>note: initializer of '__urngrange' is not a constant 
>>>>>expression
>>>>>~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uniform_int_dist.h:286:21: 
>>>>>note: declared here
>>>>>       constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>>                          ^
>>>>>6 errors generated.
>>>>
>>>>which would be fixed by something like
>>>>
>>>>>diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h 
>>>>>b/libstdc++-v3/include/bits/uniform_int_dist.h
>>>>>index 524593bb984..d9c7ea96fda 100644
>>>>>--- a/libstdc++-v3/include/bits/uniform_int_dist.h
>>>>>+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
>>>>>@@ -278,11 +278,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>>       typedef typename make_unsigned<result_type>::type __utype;
>>>>>       typedef typename common_type<_Gresult_type, 
>>>>>__utype>::type __uctype;
>>>>>-       static_assert( __urng.min() < __urng.max(),
>>>>>+       static_assert( _UniformRandomBitGenerator::min() < 
>>>>>_UniformRandomBitGenerator::max(),
>>>>>           "Uniform random bit generator must define min() < max()");
>>>>>-       constexpr __uctype __urngmin = __urng.min();
>>>>>-       constexpr __uctype __urngmax = __urng.max();
>>>>>+       constexpr __uctype __urngmin = 
>>>>>_UniformRandomBitGenerator::min();
>>>>>+       constexpr __uctype __urngmax = 
>>>>>_UniformRandomBitGenerator::max();
>>>>>       constexpr __uctype __urngrange = __urngmax - __urngmin;
>>>>>       const __uctype __urange
>>>>>         = __uctype(__param.b()) - __uctype(__param.a());
>>>>
>>>>(and I think there are further similar issues in this change).
>>>
>>>I think this is a Clang bug, but I'll change the code anyway.
>>
>>To me it looks like it boils down to disagreement between g++ and 
>>clang++ over
>>
>>>struct S { static constexpr int f() { return 0; } };
>>>void f(S & s) { static_assert(s.f(), ""); }
>>
>>where I think Clang might be right in rejecting it based on 
>>[expr.const] "An expression e is a core constant expression unless 
>>[...] an id-expression that refers to a variable or data member of 
>>reference type unless the reference has a preceding initialization 
>>[...]"
>
>GCC, Intel icc and MSVC all accept it:
>
>  https://godbolt.org/z/hTsT96

But EDG rejects it without the --g++ option (which is the mode icc
uses on GNU/Linux, I believe).

I've pushed a slightly different fix (I didn't see your patch at the
bottom of the first email until after I'd already done this version).

Tested powerpc64le-linux, committed to trunk.


[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 1686 bytes --]

commit 24366207b77481bceebb425569932297c441e04e
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Nov 4 10:36:45 2020

    libstdc++: Fix constant expressions in std::uniform_int_distribution
    
    Clang and EDG say the class member access expressions __urng.min() and
    __urng.max() are not constant expressions, because the object expression
    __urng is not usable in a constant expresion. Use a qualified-id to call
    those static member functions instead.
    
    Co-authored-by: Stephan Bergmann <sbergman@redhat.com>
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/uniform_int_dist.h (uniform_int_distribution::_S_nd):
            Use qualified-id to refer to static member functions.

diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h
index 524593bb9847..8f02b85c9bb0 100644
--- a/libstdc++-v3/include/bits/uniform_int_dist.h
+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
@@ -278,12 +278,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	typedef typename make_unsigned<result_type>::type __utype;
 	typedef typename common_type<_Gresult_type, __utype>::type __uctype;
 
-	static_assert( __urng.min() < __urng.max(),
+	constexpr __uctype __urngmin = _UniformRandomBitGenerator::min();
+	constexpr __uctype __urngmax = _UniformRandomBitGenerator::max();
+	static_assert( __urngmin < __urngmax,
 	    "Uniform random bit generator must define min() < max()");
-
-	constexpr __uctype __urngmin = __urng.min();
-	constexpr __uctype __urngmax = __urng.max();
 	constexpr __uctype __urngrange = __urngmax - __urngmin;
+
 	const __uctype __urange
 	  = __uctype(__param.b()) - __uctype(__param.a());
 

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2020-11-04 10:38 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-29 14:59 [committed] libstdc++: Allow Lemire's algorithm to be used in more cases Jonathan Wakely
2020-11-03 21:28 ` Stephan Bergmann
2020-11-03 22:25   ` Jonathan Wakely
2020-11-04  8:45     ` Stephan Bergmann
2020-11-04  8:52       ` Ville Voutilainen
2020-11-04 10:15       ` Jonathan Wakely
2020-11-04 10:38         ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).