[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