mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
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 <nmyers@redhat.com>
This commit is contained in:
committed by
Jonathan Wakely
parent
c1ac0abefe
commit
0a2b9dc965
@@ -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<typename remove_reference_t<_Gen>::result_type, _USize>;
|
||||
using __uc_type = common_type_t<decltype(__g()), _USize>;
|
||||
|
||||
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<typename remove_reference_t<_Gen>::result_type, __ud_type>;
|
||||
using __uc_type = common_type_t<decltype(__g()), __ud_type>;
|
||||
|
||||
if constexpr (sized_sentinel_for<_Sent, _Iter>)
|
||||
{
|
||||
|
||||
@@ -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<result_type>::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<result_type>::type __utype;
|
||||
typedef typename common_type<_Gresult_type, __utype>::type __uctype;
|
||||
|
||||
|
||||
28
libstdc++-v3/testsuite/25_algorithms/sample/121919.cc
Normal file
28
libstdc++-v3/testsuite/25_algorithms/sample/121919.cc
Normal file
@@ -0,0 +1,28 @@
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
// Bug 121919 ranges::sample assumes a uniform_random_bit_generator
|
||||
// provides result_type
|
||||
|
||||
#include <algorithm>
|
||||
#include <testsuite_iterators.h>
|
||||
|
||||
struct G
|
||||
{
|
||||
constexpr static unsigned min() { return 0; }
|
||||
constexpr static unsigned max() { return 10; }
|
||||
unsigned operator()() const;
|
||||
};
|
||||
|
||||
static_assert(std::uniform_random_bit_generator<G>);
|
||||
|
||||
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{});
|
||||
}
|
||||
25
libstdc++-v3/testsuite/25_algorithms/shuffle/121919.cc
Normal file
25
libstdc++-v3/testsuite/25_algorithms/shuffle/121919.cc
Normal file
@@ -0,0 +1,25 @@
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
// Bug 121919 ranges::shuffle assumes a uniform_random_bit_generator
|
||||
// provides result_type
|
||||
|
||||
#include <algorithm>
|
||||
#include <testsuite_iterators.h>
|
||||
|
||||
struct G
|
||||
{
|
||||
constexpr static unsigned min() { return 0; }
|
||||
constexpr static unsigned max() { return 10; }
|
||||
unsigned operator()() const;
|
||||
};
|
||||
|
||||
static_assert(std::uniform_random_bit_generator<G>);
|
||||
|
||||
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{});
|
||||
}
|
||||
Reference in New Issue
Block a user