diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2025-01-19 16:30:20 +0100 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2025-01-20 10:49:48 -0500 |
commit | b342614139c0a981b369176980663941b9c27f39 (patch) | |
tree | ad8dbd76489ef7cfccb14be00a030b44fd58ed57 | |
parent | 7cc573017274acfd5a276d959a8297ba04e98002 (diff) | |
download | gcc-b342614139c0a981b369176980663941b9c27f39.zip gcc-b342614139c0a981b369176980663941b9c27f39.tar.gz gcc-b342614139c0a981b369176980663941b9c27f39.tar.bz2 |
libstdc++: perfectly forward std::ranges::clamp arguments
As reported in PR118185, std::ranges::clamp does not correctly forward
the projected value to the comparator. Add the missing forward.
libstdc++-v3/ChangeLog:
PR libstdc++/118185
PR libstdc++/100249
* include/bits/ranges_algo.h (__clamp_fn): Correctly forward the
projected value to the comparator.
* testsuite/25_algorithms/clamp/118185.cc: New test.
Signed-off-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
Reviewed-by: Patrick Palka <ppalka@redhat.com>
Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
-rw-r--r-- | libstdc++-v3/include/bits/ranges_algo.h | 8 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/25_algorithms/clamp/118185.cc | 41 |
2 files changed, 47 insertions, 2 deletions
diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h index 380f05f..df92598 100644 --- a/libstdc++-v3/include/bits/ranges_algo.h +++ b/libstdc++-v3/include/bits/ranges_algo.h @@ -2988,9 +2988,13 @@ namespace ranges std::__invoke(__proj, __hi), std::__invoke(__proj, __lo)))); auto&& __proj_val = std::__invoke(__proj, __val); - if (std::__invoke(__comp, __proj_val, std::__invoke(__proj, __lo))) + if (std::__invoke(__comp, + std::forward<decltype(__proj_val)>(__proj_val), + std::__invoke(__proj, __lo))) return __lo; - else if (std::__invoke(__comp, std::__invoke(__proj, __hi), __proj_val)) + else if (std::__invoke(__comp, + std::__invoke(__proj, __hi), + std::forward<decltype(__proj_val)>(__proj_val))) return __hi; else return __val; diff --git a/libstdc++-v3/testsuite/25_algorithms/clamp/118185.cc b/libstdc++-v3/testsuite/25_algorithms/clamp/118185.cc new file mode 100644 index 0000000..e9cf896 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/clamp/118185.cc @@ -0,0 +1,41 @@ +// { dg-do compile { target c++20 } } + +#include <algorithm> +#include <concepts> + +struct Comp +{ + constexpr bool operator()(const int&& x, const int&& y) { return x < y; } +}; + +struct Proj +{ + constexpr const int&& operator()(const int& x) const { return std::move(x); } +}; + +static_assert(std::indirect_strict_weak_order<Comp, std::projected<const int*, Proj>>); + +static_assert(std::ranges::clamp(+1, 0, 2, Comp{}, Proj{}) == 1); +static_assert(std::ranges::clamp(-1, 0, 2, Comp{}, Proj{}) == 0); +static_assert(std::ranges::clamp(10, 0, 2, Comp{}, Proj{}) == 2); + + +// Testcase from PR118185 + +struct Comp2 +{ + constexpr bool operator()(const int&& x, const int&& y) const { return x < y; } + constexpr bool operator()(const int&& x, int& y) const { return x < y; } + constexpr bool operator()(int& x, const int&& y) const { return x < y; } + constexpr bool operator()(int& x, int& y) const { return x < y; } + constexpr bool operator()(std::same_as<const int&> auto && x, std::same_as<const int&> auto && y) const + { + return x < y; + } +}; + +static_assert(std::indirect_strict_weak_order<Comp2, std::projected<const int*, Proj>>); + +static_assert(std::ranges::clamp(+1, 0, 2, Comp2{}, Proj{}) == 1); +static_assert(std::ranges::clamp(-1, 0, 2, Comp2{}, Proj{}) == 0); +static_assert(std::ranges::clamp(10, 0, 2, Comp2{}, Proj{}) == 2); |