aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2025-01-19 16:30:20 +0100
committerPatrick Palka <ppalka@redhat.com>2025-01-20 10:49:48 -0500
commitb342614139c0a981b369176980663941b9c27f39 (patch)
treead8dbd76489ef7cfccb14be00a030b44fd58ed57
parent7cc573017274acfd5a276d959a8297ba04e98002 (diff)
downloadgcc-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.h8
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/clamp/118185.cc41
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);