[libcxx-commits] [libcxx] [libcxx] Fix incorrect projections order for `ranges::set_` algorithms (PR #237087)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Oct 30 20:56:41 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Ruslan Arutyunyan (rarutyun)

<details>
<summary>Changes</summary>

The `ranges::set_*` algorithms combined the comparator and both projections into a single callable that always applies `proj1` to its first argument and `proj2` to its second. However, the underlying algorithms also compare elements in the reverse order (`comp(*first2, *first1)`), so in those calls `proj1` was applied to elements of the second range and `proj2` to elements of the first range. Depending on the projections, this could lead to wrong results.

This patch passes the projections separately to the internal `__set_*` helpers, which now apply each projection to the elements of its own range. The classic `std::set_*` overloads pass `__identity` for both. `__lower_bound_onesided`, used by
the forward-iterator path of `set_intersection`, now takes a projection as well. The  `ranges::__make_projected_comp` is not needed anymore, thus it is removed.

Fixes #<!-- -->237475 

---

Patch is 26.74 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/237087.diff


14 Files Affected:

- (modified) libcxx/include/__algorithm/lower_bound.h (+4-5) 
- (modified) libcxx/include/__algorithm/make_projected.h (-29) 
- (modified) libcxx/include/__algorithm/ranges_set_difference.h (+4-4) 
- (modified) libcxx/include/__algorithm/ranges_set_intersection.h (+6-3) 
- (modified) libcxx/include/__algorithm/ranges_set_symmetric_difference.h (+6-3) 
- (modified) libcxx/include/__algorithm/ranges_set_union.h (+6-3) 
- (modified) libcxx/include/__algorithm/set_difference.h (+24-6) 
- (modified) libcxx/include/__algorithm/set_intersection.h (+42-10) 
- (modified) libcxx/include/__algorithm/set_symmetric_difference.h (+23-5) 
- (modified) libcxx/include/__algorithm/set_union.h (+23-5) 
- (modified) libcxx/test/std/algorithms/alg.sorting/alg.set.operations/set.difference/ranges_set_difference.pass.cpp (+13) 
- (modified) libcxx/test/std/algorithms/alg.sorting/alg.set.operations/set.intersection/ranges_set_intersection.pass.cpp (+30) 
- (modified) libcxx/test/std/algorithms/alg.sorting/alg.set.operations/set.symmetric.difference/ranges_set_symmetric_difference.pass.cpp (+13) 
- (modified) libcxx/test/std/algorithms/alg.sorting/alg.set.operations/set.union/ranges_set_union.pass.cpp (+11) 


``````````diff
diff --git a/libcxx/include/__algorithm/lower_bound.h b/libcxx/include/__algorithm/lower_bound.h
index 941a50c6c13fa2..c19f8f74e8a26f 100644
--- a/libcxx/include/__algorithm/lower_bound.h
+++ b/libcxx/include/__algorithm/lower_bound.h
@@ -56,11 +56,11 @@ template <class _AlgPolicy, class _Iter, class _Type, class _Proj, class _Comp>
 // would yield \Omega(n*log(n)) comparisons and, for non-random-access iterators, \Omega(n^2) iterator increments,
 // whereas the one-sided version will yield O(n) operations on both counts, with a \Omega(log(n)) bound on the number of
 // comparisons.
-template <class _AlgPolicy, class _ForwardIterator, class _Sent, class _Type, class _Comp>
+template <class _AlgPolicy, class _ForwardIterator, class _Sent, class _Type, class _Comp, class _Proj>
 [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator
-__lower_bound_onesided(_ForwardIterator __first, _Sent __last, const _Type& __value, _Comp& __comp) {
+__lower_bound_onesided(_ForwardIterator __first, _Sent __last, const _Type& __value, _Comp& __comp, _Proj& __proj) {
   // step = 0, ensuring we can always short-circuit when distance is 1 later on
-  if (__first == __last || !std::__invoke(__comp, *__first, __value))
+  if (__first == __last || !std::__invoke(__comp, std::__invoke(__proj, *__first), __value))
     return __first;
 
   using _Distance = typename iterator_traits<_ForwardIterator>::difference_type;
@@ -69,12 +69,11 @@ __lower_bound_onesided(_ForwardIterator __first, _Sent __last, const _Type& __va
     auto __dist = __step - _IterOps<_AlgPolicy>::__advance_to(__it, __step, __last);
     // once we reach the last range where needle can be we must start
     // looking inwards, bisecting that range
-    if (__it == __last || !std::__invoke(__comp, *__it, __value)) {
+    if (__it == __last || !std::__invoke(__comp, std::__invoke(__proj, *__it), __value)) {
       // we've already checked the previous value and it was less, we can save
       // one comparison by skipping bisection
       if (__dist == 1)
         return __it;
-      __identity __proj;
       return std::__lower_bound_bisecting<_AlgPolicy>(__first, __value, __dist, __comp, __proj);
     }
     // range not found, move forward!
diff --git a/libcxx/include/__algorithm/make_projected.h b/libcxx/include/__algorithm/make_projected.h
index a09f47e3444b2f..b5df7dfc613a2b 100644
--- a/libcxx/include/__algorithm/make_projected.h
+++ b/libcxx/include/__algorithm/make_projected.h
@@ -71,33 +71,4 @@ _LIBCPP_CONSTEXPR _Pred& __make_projected(_Pred& __pred, _Proj&) {
 
 _LIBCPP_END_NAMESPACE_STD
 
-#if _LIBCPP_STD_VER >= 20
-
-_LIBCPP_BEGIN_NAMESPACE_STD
-
-namespace ranges {
-
-template <class _Comp, class _Proj1, class _Proj2>
-constexpr decltype(auto) __make_projected_comp(_Comp& __comp, _Proj1& __proj1, _Proj2& __proj2) {
-  if constexpr (__is_identity<decay_t<_Proj1>>::value && __is_identity<decay_t<_Proj2>>::value &&
-                !is_member_pointer_v<decay_t<_Comp>>) {
-    // Avoid creating the lambda and just use the pristine comparator -- for certain algorithms, this would enable
-    // optimizations that rely on the type of the comparator.
-    return __comp;
-
-  } else {
-    return [&](auto&& __lhs, auto&& __rhs) -> bool {
-      return std::invoke(__comp,
-                         std::invoke(__proj1, std::forward<decltype(__lhs)>(__lhs)),
-                         std::invoke(__proj2, std::forward<decltype(__rhs)>(__rhs)));
-    };
-  }
-}
-
-} // namespace ranges
-
-_LIBCPP_END_NAMESPACE_STD
-
-#endif // _LIBCPP_STD_VER >= 20
-
 #endif // _LIBCPP___ALGORITHM_MAKE_PROJECTED_H
diff --git a/libcxx/include/__algorithm/ranges_set_difference.h b/libcxx/include/__algorithm/ranges_set_difference.h
index b9e7714f6cd079..538951e04ff169 100644
--- a/libcxx/include/__algorithm/ranges_set_difference.h
+++ b/libcxx/include/__algorithm/ranges_set_difference.h
@@ -10,7 +10,6 @@
 #define _LIBCPP___ALGORITHM_RANGES_SET_DIFFERENCE_H
 
 #include <__algorithm/in_out_result.h>
-#include <__algorithm/make_projected.h>
 #include <__algorithm/set_difference.h>
 #include <__config>
 #include <__functional/identity.h>
@@ -57,8 +56,7 @@ struct __set_difference {
       _Comp __comp   = {},
       _Proj1 __proj1 = {},
       _Proj2 __proj2 = {}) const {
-    return std::__set_difference(
-        __first1, __last1, __first2, __last2, __result, ranges::__make_projected_comp(__comp, __proj1, __proj2));
+    return std::__set_difference(__first1, __last1, __first2, __last2, __result, __comp, __proj1, __proj2);
   }
 
   template <input_range _Range1,
@@ -81,7 +79,9 @@ struct __set_difference {
         ranges::begin(__range2),
         ranges::end(__range2),
         __result,
-        ranges::__make_projected_comp(__comp, __proj1, __proj2));
+        __comp,
+        __proj1,
+        __proj2);
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_set_intersection.h b/libcxx/include/__algorithm/ranges_set_intersection.h
index ab044aa32841a6..4085e9ec360c33 100644
--- a/libcxx/include/__algorithm/ranges_set_intersection.h
+++ b/libcxx/include/__algorithm/ranges_set_intersection.h
@@ -11,7 +11,6 @@
 
 #include <__algorithm/in_in_out_result.h>
 #include <__algorithm/iterator_operations.h>
-#include <__algorithm/make_projected.h>
 #include <__algorithm/set_intersection.h>
 #include <__config>
 #include <__functional/identity.h>
@@ -65,7 +64,9 @@ struct __set_intersection {
         std::move(__first2),
         std::move(__last2),
         std::move(__result),
-        ranges::__make_projected_comp(__comp, __proj1, __proj2));
+        __comp,
+        __proj1,
+        __proj2);
     return {std::move(__ret.__in1_), std::move(__ret.__in2_), std::move(__ret.__out_)};
   }
 
@@ -89,7 +90,9 @@ struct __set_intersection {
         ranges::begin(__range2),
         ranges::end(__range2),
         std::move(__result),
-        ranges::__make_projected_comp(__comp, __proj1, __proj2));
+        __comp,
+        __proj1,
+        __proj2);
     return {std::move(__ret.__in1_), std::move(__ret.__in2_), std::move(__ret.__out_)};
   }
 };
diff --git a/libcxx/include/__algorithm/ranges_set_symmetric_difference.h b/libcxx/include/__algorithm/ranges_set_symmetric_difference.h
index 50c98660fdce22..5af746148c8561 100644
--- a/libcxx/include/__algorithm/ranges_set_symmetric_difference.h
+++ b/libcxx/include/__algorithm/ranges_set_symmetric_difference.h
@@ -10,7 +10,6 @@
 #define _LIBCPP___ALGORITHM_RANGES_SET_SYMMETRIC_DIFFERENCE_H
 
 #include <__algorithm/in_in_out_result.h>
-#include <__algorithm/make_projected.h>
 #include <__algorithm/set_symmetric_difference.h>
 #include <__config>
 #include <__functional/identity.h>
@@ -64,7 +63,9 @@ struct __set_symmetric_difference {
         std::move(__first2),
         std::move(__last2),
         std::move(__result),
-        ranges::__make_projected_comp(__comp, __proj1, __proj2));
+        __comp,
+        __proj1,
+        __proj2);
     return {std::move(__ret.__in1_), std::move(__ret.__in2_), std::move(__ret.__out_)};
   }
 
@@ -88,7 +89,9 @@ struct __set_symmetric_difference {
         ranges::begin(__range2),
         ranges::end(__range2),
         std::move(__result),
-        ranges::__make_projected_comp(__comp, __proj1, __proj2));
+        __comp,
+        __proj1,
+        __proj2);
     return {std::move(__ret.__in1_), std::move(__ret.__in2_), std::move(__ret.__out_)};
   }
 };
diff --git a/libcxx/include/__algorithm/ranges_set_union.h b/libcxx/include/__algorithm/ranges_set_union.h
index 6307570b35ab56..f40e7ff5873ebd 100644
--- a/libcxx/include/__algorithm/ranges_set_union.h
+++ b/libcxx/include/__algorithm/ranges_set_union.h
@@ -10,7 +10,6 @@
 #define _LIBCPP___ALGORITHM_RANGES_SET_UNION_H
 
 #include <__algorithm/in_in_out_result.h>
-#include <__algorithm/make_projected.h>
 #include <__algorithm/set_union.h>
 #include <__config>
 #include <__functional/identity.h>
@@ -67,7 +66,9 @@ struct __set_union {
         std::move(__first2),
         std::move(__last2),
         std::move(__result),
-        ranges::__make_projected_comp(__comp, __proj1, __proj2));
+        __comp,
+        __proj1,
+        __proj2);
     return {std::move(__ret.__in1_), std::move(__ret.__in2_), std::move(__ret.__out_)};
   }
 
@@ -91,7 +92,9 @@ struct __set_union {
         ranges::begin(__range2),
         ranges::end(__range2),
         std::move(__result),
-        ranges::__make_projected_comp(__comp, __proj1, __proj2));
+        __comp,
+        __proj1,
+        __proj2);
     return {std::move(__ret.__in1_), std::move(__ret.__in2_), std::move(__ret.__out_)};
   }
 };
diff --git a/libcxx/include/__algorithm/set_difference.h b/libcxx/include/__algorithm/set_difference.h
index 957642a54bdcb9..1fc34012ef1c68 100644
--- a/libcxx/include/__algorithm/set_difference.h
+++ b/libcxx/include/__algorithm/set_difference.h
@@ -14,6 +14,8 @@
 #include <__algorithm/copy.h>
 #include <__algorithm/in_out_result.h>
 #include <__config>
+#include <__functional/identity.h>
+#include <__type_traits/invoke.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/move.h>
 
@@ -26,15 +28,29 @@ _LIBCPP_PUSH_MACROS
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Comp, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter>
+template <class _Comp,
+          class _InIter1,
+          class _Sent1,
+          class _InIter2,
+          class _Sent2,
+          class _OutIter,
+          class _Proj1,
+          class _Proj2>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 __in_out_result<__remove_cvref_t<_InIter1>, __remove_cvref_t<_OutIter> > __set_difference(
-    _InIter1&& __first1, _Sent1&& __last1, _InIter2&& __first2, _Sent2&& __last2, _OutIter&& __result, _Comp&& __comp) {
+    _InIter1&& __first1,
+    _Sent1&& __last1,
+    _InIter2&& __first2,
+    _Sent2&& __last2,
+    _OutIter&& __result,
+    _Comp&& __comp,
+    _Proj1&& __proj1,
+    _Proj2&& __proj2) {
   while (__first1 != __last1 && __first2 != __last2) {
-    if (__comp(*__first1, *__first2)) {
+    if (std::__invoke(__comp, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) {
       *__result = *__first1;
       ++__first1;
       ++__result;
-    } else if (__comp(*__first2, *__first1)) {
+    } else if (std::__invoke(__comp, std::__invoke(__proj2, *__first2), std::__invoke(__proj1, *__first1))) {
       ++__first2;
     } else {
       ++__first1;
@@ -52,7 +68,8 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_difference(
     _InputIterator2 __last2,
     _OutputIterator __result,
     _Compare __comp) {
-  return std::__set_difference<__comp_ref_type<_Compare> >(__first1, __last1, __first2, __last2, __result, __comp)
+  return std::__set_difference<__comp_ref_type<_Compare> >(
+             __first1, __last1, __first2, __last2, __result, __comp, __identity(), __identity())
       .__out_;
 }
 
@@ -63,7 +80,8 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_difference(
     _InputIterator2 __first2,
     _InputIterator2 __last2,
     _OutputIterator __result) {
-  return std::__set_difference(__first1, __last1, __first2, __last2, __result, __less<>()).__out_;
+  return std::__set_difference(__first1, __last1, __first2, __last2, __result, __less<>(), __identity(), __identity())
+      .__out_;
 }
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__algorithm/set_intersection.h b/libcxx/include/__algorithm/set_intersection.h
index c99bbb1817633d..0284e58f616ef4 100644
--- a/libcxx/include/__algorithm/set_intersection.h
+++ b/libcxx/include/__algorithm/set_intersection.h
@@ -17,6 +17,7 @@
 #include <__functional/identity.h>
 #include <__iterator/iterator_traits.h>
 #include <__iterator/next.h>
+#include <__type_traits/invoke.h>
 #include <__type_traits/is_same.h>
 #include <__utility/exchange.h>
 #include <__utility/forward.h>
@@ -84,7 +85,9 @@ template <class _AlgPolicy,
           class _Sent1,
           class _InForwardIter2,
           class _Sent2,
-          class _OutIter>
+          class _OutIter,
+          class _Proj1,
+          class _Proj2>
 [[__nodiscard__]]
 _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InForwardIter1, _InForwardIter2, _OutIter> __set_intersection(
     _InForwardIter1 __first1,
@@ -93,12 +96,15 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InForwardIter1, _InForw
     _Sent2 __last2,
     _OutIter __result,
     _Compare&& __comp,
+    _Proj1&& __proj1,
+    _Proj2&& __proj2,
     std::forward_iterator_tag,
     std::forward_iterator_tag) {
   bool __prev_may_be_equal = false;
 
   while (__first2 != __last2) {
-    _InForwardIter1 __first1_next = std::__lower_bound_onesided<_AlgPolicy>(__first1, __last1, *__first2, __comp);
+    _InForwardIter1 __first1_next =
+        std::__lower_bound_onesided<_AlgPolicy>(__first1, __last1, std::__invoke(__proj2, *__first2), __comp, __proj1);
     std::swap(__first1_next, __first1);
     // keeping in mind that a==b iff !(a<b) && !(b<a):
     // if we can't advance __first1, that means !(*__first1 < *_first2), therefore __may_be_equal==true
@@ -107,7 +113,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InForwardIter1, _InForw
     if (__first1 == __last1)
       break;
 
-    _InForwardIter2 __first2_next = std::__lower_bound_onesided<_AlgPolicy>(__first2, __last2, *__first1, __comp);
+    _InForwardIter2 __first2_next =
+        std::__lower_bound_onesided<_AlgPolicy>(__first2, __last2, std::__invoke(__proj1, *__first1), __comp, __proj2);
     std::swap(__first2_next, __first2);
     std::__set_intersection_add_output_if_equal(
         __first2 == __first2_next, __first1, __first2, __result, __prev_may_be_equal);
@@ -125,7 +132,9 @@ template <class _AlgPolicy,
           class _Sent1,
           class _InInputIter2,
           class _Sent2,
-          class _OutIter>
+          class _OutIter,
+          class _Proj1,
+          class _Proj2>
 [[__nodiscard__]]
 _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InInputIter1, _InInputIter2, _OutIter> __set_intersection(
     _InInputIter1 __first1,
@@ -134,13 +143,15 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InInputIter1, _InInputI
     _Sent2 __last2,
     _OutIter __result,
     _Compare&& __comp,
+    _Proj1&& __proj1,
+    _Proj2&& __proj2,
     std::input_iterator_tag,
     std::input_iterator_tag) {
   while (__first1 != __last1 && __first2 != __last2) {
-    if (__comp(*__first1, *__first2))
+    if (std::__invoke(__comp, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2)))
       ++__first1;
     else {
-      if (!__comp(*__first2, *__first1)) {
+      if (!std::__invoke(__comp, std::__invoke(__proj2, *__first2), std::__invoke(__proj1, *__first1))) {
         *__result = *__first1;
         ++__result;
         ++__first1;
@@ -155,10 +166,25 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InInputIter1, _InInputI
       std::move(__result));
 }
 
-template <class _AlgPolicy, class _Compare, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter>
+template <class _AlgPolicy,
+          class _Compare,
+          class _InIter1,
+          class _Sent1,
+          class _InIter2,
+          class _Sent2,
+          class _OutIter,
+          class _Proj1,
+          class _Proj2>
 [[__nodiscard__]]
 _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InIter1, _InIter2, _OutIter> __set_intersection(
-    _InIter1 __first1, _Sent1 __last1, _InIter2 __first2, _Sent2 __last2, _OutIter __result, _Compare&& __comp) {
+    _InIter1 __first1,
+    _Sent1 __last1,
+    _InIter2 __first2,
+    _Sent2 __last2,
+    _OutIter __result,
+    _Compare&& __comp,
+    _Proj1&& __proj1,
+    _Proj2&& __proj2) {
   return std::__set_intersection<_AlgPolicy>(
       std::move(__first1),
       std::move(__last1),
@@ -166,6 +192,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InIter1, _InIter2, _Out
       std::move(__last2),
       std::move(__result),
       std::forward<_Compare>(__comp),
+      std::forward<_Proj1>(__proj1),
+      std::forward<_Proj2>(__proj2),
       typename std::_IterOps<_AlgPolicy>::template __iterator_category<_InIter1>(),
       typename std::_IterOps<_AlgPolicy>::template __iterator_category<_InIter2>());
 }
@@ -184,7 +212,9 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_intersection(
              std::move(__first2),
              std::move(__last2),
              std::move(__result),
-             __comp)
+             __comp,
+             __identity(),
+             __identity())
       .__out_;
 }
 
@@ -201,7 +231,9 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_intersection(
              std::move(__first2),
              std::move(__last2),
              std::move(__result),
-             __less<>())
+             __less<>(),
+             __identity(),
+             __identity())
       .__out_;
 }
 
diff --git a/libcxx/include/__algorithm/set_symmetric_difference.h b/libcxx/include/__algorithm/set_symmetric_difference.h
index 2bf0b6a2d6a4e0..27e01f73a26f5d 100644
--- a/libcxx/include/__algorithm/set_symmetric_difference.h
+++ b/libcxx/include/__algorithm/set_symmetric_difference.h
@@ -13,7 +13,9 @@
 #include <__algorithm/comp_ref_type.h>
 #include <__algorithm/copy.h>
 #include <__config>
+#include <__functional/identity.h>
 #include <__iterator/iterator_traits.h>
+#include <__type_traits/invoke.h>
 #include <__utility/move.h>
 #include <__utility/pair.h>
 
@@ -38,22 +40,36 @@ struct __set_symmetric_difference_result {
       : __in1_(std::move(__in_iter1)), __in2_(std::move(__in_iter2)), __out_(std::move(__out_iter)) {}
 };
 
-template <class _Compare, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter>
+template <class _Compare,
+          class _InIter1,
+          class _Sent1,
+          class _InIter2,
+          class _Sent2,
+          class _OutIter,
+          class _Proj1,
+          class _Proj2>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_symmetric_difference_result<_InIter1, _InIter2, _OutIter>
 __set_symmetric_difference(
-    _InIter1 __first1, _Sent1 __last1, _InIter2 __first2, _Sent2 __last2, _OutIter __result, _Compare&& __comp) {
+    _InIter1 __first1,
+    _Sent1 __last1,
+    _InIter2 __first2,
+    _Sent2 __last2,
+    _OutIter __result,
+    _Compare&& __comp,
+    _Proj1&& __proj1,
+    _Proj2&& __proj2) {
   while (__first1 != __last1) {
     if (__first2 == __last2) {
       auto __ret1 = std::__copy(std::move(__first1), std::move(__last1), std::move(__result));
       return __set_symmetric_difference_result<_InIter1, _InIter2, _OutIter>(
           std::move(__ret1.__in_), std::move(__first2), std::move((__ret1.__out_)));
     }
-    if (__comp(*__first1, *__first2)) {
+    if (std::__invoke(__comp, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) {
       *__result = *__first1;
       ++__result;
       ++__first1;
     } else {
-      if (__comp(*__first2, *__first1)) {
+      if (std::__invoke(__comp, std::__invoke(__proj2, *__first2), std::__invoke(__proj1, *__first1))) {
         *__result = *__first2;
         ++__result;
       } else {
@@ -81,7 +97,9 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_symmetric_difference(
              std::move(__first2),
              std::move(__last2),
              std::move(__result),
-             __comp)
+             __comp,
+             __identity(),
+             __identity())
       .__out_;
 }
 
diff --git a/libcxx/include/__algorithm/set_union.h b/libcxx/include/__algorithm/set_union.h
index e0a0490c018355..d29dcf97a90392 100644
--- a/libcxx/include/__algorithm/set_union.h
+++ b/libcxx/include/__algorithm/set_union.h
@@ -13,7 +13,9 @@
 #include <__algorithm/comp_ref_type.h>
 #include <__algorithm/copy.h>
 #include <__config>
+#include <__functional/identity.h>
 #include <__iterator/iterator_traits.h>
+#include <__type_traits/invoke.h>
 #include <__utility/move.h>
 #include <__utility/pair.h>
 
@@ -37,20 +39,34 @@ struct __set_union_result {
       : __in1_(std::move(__in_iter1)), __in2_(std::move(__in_iter2)), __out_(std::move(__out_iter)) {}
 };
 
-template <class _Compare, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter>
+template <class _Compare,
+          class _InIter1,
+          class _Sent1,
+          class _InIter2,
+          class _Sent2,
+          class _OutIter,
+          class _Proj1,
+          class _Proj2>
 _LIBCPP_CONSTEXPR_SINCE...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/237087


More information about the libcxx-commits mailing list