[gcc r16-8867] libstdc++: Do not assume URBG::result_type exists [PR121919]

Jonathan Wakely redi@gcc.gnu.org
Tue May 5 10:39:50 GMT 2026


https://gcc.gnu.org/g:0a19c6cbabd60737967df931f9455c800630faff

commit r16-8867-g0a19c6cbabd60737967df931f9455c800630faff
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Apr 30 13:27:48 2026 +0100

    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>
    (cherry picked from commit 0a2b9dc9655f12e43a0e67f26ea21ff4f4e038fe)

Diff:
---
 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(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index 0d1928d52a2f..4330d3e70b84 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<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>)
 	  {
diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h
index dcf763ae7649..9c5514c7c138 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<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;
 
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 000000000000..9fdfbf560c71
--- /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 <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{});
+}
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 000000000000..9425394c50ee
--- /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 <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{});
+}


More information about the Libstdc++-cvs mailing list