https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121917
Jonathan Wakely <redi at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Summary|ranges::shuffle incorrectly |[16 Regression]
|requires its arguments to |ranges::shuffle incorrectly
|model sized_sentinel_for |requires its arguments to
| |model sized_sentinel_for
Ever confirmed|0 |1
Version|15.2.0 |16.0
Known to work| |15.2.1
Status|UNCONFIRMED |NEW
Known to fail| |16.0
Last reconfirmed| |2025-09-11
--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Oops, fixed testcase:
#include <algorithm>
#include <iterator>
#include <random>
struct non_default_sentinel_t { };
template<std::input_or_output_iterator I>
bool operator==(const I& i, non_default_sentinel_t)
{ return i == std::default_sentinel; }
int main()
{
int a[2]{};
std::counted_iterator iter(a, 2);
std::default_random_engine e;
std::ranges::shuffle(iter, non_default_sentinel_t{}, e);
}
The problem is that we assume that last - first is valid, because we have a
random access iterator and its sentinel. But an arbitrary sentinel doesn't have
to model sized_sentinel_for.
This code was copied from std::shuffle where we always have two iterators of
the same type, so last - first is always valid. This is a regression because in
GCC 15 ranges::shuffle just forwarded its arguments to std::shuffle, so didn't
have this problem (but was non-conforming in other ways).
Patrick suggested that we just disable the optimization to use the URBG more
efficiently for the non-sized sentinel case:
-- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -1968,6 +1968,8 @@ namespace ranges
using __uc_type
= common_type_t<typename remove_reference_t<_Gen>::result_type,
__ud_type>;
+ if constexpr (sized_sentinel_for<_Sent, _Iter>)
+ {
const __uc_type __urngrange = __g.max() - __g.min();
const __uc_type __urange = __uc_type(__last - __first);
@@ -2003,6 +2005,7 @@ namespace ranges
return __i;
}
+ }
__distr_type __d;