From 0a2b9dc9655f12e43a0e67f26ea21ff4f4e038fe Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Thu, 30 Apr 2026 13:27:48 +0100 Subject: [PATCH] libstdc++: Do not assume URBG::result_type exists [PR121919] The ranges::sample and ranges::shuffle algorithms are supposed to work with types which model std::uniform_random_bit_generator, which means they should not assume that G::result_type is present. That isn't needed to satisfy the concept. Change the algorithms to use decltype(__g()) instead of using result_type. This isn't sufficient to fix the bug though, because those algorithms use std::uniform_int_distribution and that class template's operator() overloads depend on the more restrictive uniform random bit generator requirements, which do include the presence of a nested result_type member. We need to change std::uniform_int_distribution to also use decltype instead of the nested result_type, even though the standard says that std::uniform_int_distribution is allowed to assume that result_type exists. There's yet another problem, which is that a type that returns random bool values can model the concept, but doesn't meet the named requirements and can't be used with std::uniform_int_distribution. That isn't addressed by this change. libstdc++-v3/ChangeLog: PR libstdc++/121919 * include/bits/ranges_algo.h (__sample_fn, __shuffle_fn): Use decltype(__g()) instead of remove_reference_t<_G>::result_type. * include/bits/uniform_int_dist.h (uniform_int_distribution::operator()): Use decltype(__urng()) instead of _UniformRandomBitGenerator::result_type (uniform_int_distribution::__generate_impl): Likewise. * testsuite/25_algorithms/sample/121919.cc: New test. * testsuite/25_algorithms/shuffle/121919.cc: New test. Reviewed-by: Nathan Myers --- libstdc++-v3/include/bits/ranges_algo.h | 7 ++--- libstdc++-v3/include/bits/uniform_int_dist.h | 4 +-- .../testsuite/25_algorithms/sample/121919.cc | 28 +++++++++++++++++++ .../testsuite/25_algorithms/shuffle/121919.cc | 25 +++++++++++++++++ 4 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 libstdc++-v3/testsuite/25_algorithms/sample/121919.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/shuffle/121919.cc diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h index 0d1928d52a2..4330d3e70b8 100644 --- a/libstdc++-v3/include/bits/ranges_algo.h +++ b/libstdc++-v3/include/bits/ranges_algo.h @@ -1850,8 +1850,7 @@ namespace ranges using __distrib_type = uniform_int_distribution<_Size>; using __param_type = typename __distrib_type::param_type; using _USize = __detail::__make_unsigned_like_t<_Size>; - using __uc_type - = common_type_t::result_type, _USize>; + using __uc_type = common_type_t; if (__first == __last) return __out; @@ -1964,9 +1963,7 @@ namespace ranges using __ud_type = __detail::__make_unsigned_like_t<_DistanceType>; using __distr_type = std::uniform_int_distribution<__ud_type>; using __p_type = typename __distr_type::param_type; - - using __uc_type - = common_type_t::result_type, __ud_type>; + using __uc_type = common_type_t; if constexpr (sized_sentinel_for<_Sent, _Iter>) { diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h index dcf763ae764..9c5514c7c13 100644 --- a/libstdc++-v3/include/bits/uniform_int_dist.h +++ b/libstdc++-v3/include/bits/uniform_int_dist.h @@ -288,7 +288,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator()(_UniformRandomBitGenerator& __urng, const param_type& __param) { - typedef typename _UniformRandomBitGenerator::result_type _Gresult_type; + typedef decltype(__urng()) _Gresult_type; typedef typename make_unsigned::type __utype; typedef typename common_type<_Gresult_type, __utype>::type __uctype; @@ -386,7 +386,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION const param_type& __param) { __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) - typedef typename _UniformRandomBitGenerator::result_type _Gresult_type; + typedef decltype(__urng()) _Gresult_type; typedef typename make_unsigned::type __utype; typedef typename common_type<_Gresult_type, __utype>::type __uctype; diff --git a/libstdc++-v3/testsuite/25_algorithms/sample/121919.cc b/libstdc++-v3/testsuite/25_algorithms/sample/121919.cc new file mode 100644 index 00000000000..9fdfbf560c7 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/sample/121919.cc @@ -0,0 +1,28 @@ +// { dg-do compile { target c++20 } } + +// Bug 121919 ranges::sample assumes a uniform_random_bit_generator +// provides result_type + +#include +#include + +struct G +{ + constexpr static unsigned min() { return 0; } + constexpr static unsigned max() { return 10; } + unsigned operator()() const; +}; + +static_assert(std::uniform_random_bit_generator); + +void +test_pr121919() +{ + int i2[2]{ 1, 2 }; + __gnu_test::test_random_access_range from(i2); + int i1[1]; + __gnu_test::test_random_access_range to(i1); + std::ranges::sample(from, std::ranges::begin(to), 1, G{}); + std::ranges::sample(std::ranges::begin(from), std::ranges::end(to), + std::ranges::begin(to), 1, G{}); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/shuffle/121919.cc b/libstdc++-v3/testsuite/25_algorithms/shuffle/121919.cc new file mode 100644 index 00000000000..9425394c50e --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/shuffle/121919.cc @@ -0,0 +1,25 @@ +// { dg-do compile { target c++20 } } + +// Bug 121919 ranges::shuffle assumes a uniform_random_bit_generator +// provides result_type + +#include +#include + +struct G +{ + constexpr static unsigned min() { return 0; } + constexpr static unsigned max() { return 10; } + unsigned operator()() const; +}; + +static_assert(std::uniform_random_bit_generator); + +void +test_pr121919() +{ + int arr[2]{ 1, 2 }; + __gnu_test::test_random_access_range r(arr); + std::ranges::shuffle(r, G{}); + std::ranges::shuffle(std::ranges::begin(r), std::ranges::end(r), G{}); +}