https://gcc.gnu.org/g:b342614139c0a981b369176980663941b9c27f39

commit r15-7066-gb342614139c0a981b369176980663941b9c27f39
Author: Giuseppe D'Angelo <giuseppe.dang...@kdab.com>
Date:   Sun Jan 19 16:30:20 2025 +0100

    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.dang...@kdab.com>
    Reviewed-by: Patrick Palka <ppa...@redhat.com>
    Reviewed-by: Jonathan Wakely <jwak...@redhat.com>

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h            |  8 +++--
 .../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 380f05f1e296..df92598f51a1 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 000000000000..e9cf896d3556
--- /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);

Reply via email to