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.
$ 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.
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());