https://github.com/llvmbot created 
https://github.com/llvm/llvm-project/pull/180732

Backport 9d2303103288f6110622644f78dbd26c8bcf28d5

Requested by: @philnik777

>From 2830c2267f5c994070f6ba7fb9f23fa02d80d00f Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <[email protected]>
Date: Tue, 10 Feb 2026 13:26:55 +0100
Subject: [PATCH] [libc++] Only make comparators transparent in __tree if they
 don't cause a conversion (#179453)

We're currently unwrapping `less<T>` even if the `key_type` isn't `T`.
This causes the removal of an implicit conversion to `const T&` if the
types mismatch. Making `less<T>` transparent in that case changes
overload resolution and makes it fail potentially.

Fixes #179319

(cherry picked from commit 9d2303103288f6110622644f78dbd26c8bcf28d5)
---
 libcxx/include/__functional/operations.h       |  4 ++--
 libcxx/include/__tree                          |  5 +++--
 .../include/__type_traits/make_transparent.h   | 18 +++++++++++-------
 libcxx/include/map                             |  4 ++--
 .../associative/map/map.ops/find.pass.cpp      | 12 ++++++++++++
 5 files changed, 30 insertions(+), 13 deletions(-)

diff --git a/libcxx/include/__functional/operations.h 
b/libcxx/include/__functional/operations.h
index 7f315ca851c08..c0e719bb581b6 100644
--- a/libcxx/include/__functional/operations.h
+++ b/libcxx/include/__functional/operations.h
@@ -380,7 +380,7 @@ struct less<void> {
 };
 
 template <class _Tp>
-struct __make_transparent<less<_Tp> > {
+struct __make_transparent<_Tp, less<_Tp> > {
   using type _LIBCPP_NODEBUG = less<>;
 };
 
@@ -478,7 +478,7 @@ template <class _Tp, class _Up>
 inline const bool __desugars_to_v<__greater_tag, greater<>, _Tp, _Up> = true;
 
 template <class _Tp>
-struct __make_transparent<greater<_Tp>> {
+struct __make_transparent<_Tp, greater<_Tp>> {
   using type _LIBCPP_NODEBUG = greater<>;
 };
 
diff --git a/libcxx/include/__tree b/libcxx/include/__tree
index fbb48f8196964..84711057be409 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -1808,8 +1808,9 @@ __tree<_Tp, _Compare, _Allocator>::__find_equal(const 
_Key& __v) {
   }
 
   __node_base_pointer* __node_ptr = __root_ptr();
-  auto&& __transparent            = std::__as_transparent(value_comp());
-  auto __comp = 
__lazy_synth_three_way_comparator<__make_transparent_t<_Compare>, _Key, 
value_type>(__transparent);
+  auto&& __transparent            = std::__as_transparent<_Key>(value_comp());
+  auto __comp =
+      __lazy_synth_three_way_comparator<__make_transparent_t<_Key, _Compare>, 
_Key, value_type>(__transparent);
 
   while (true) {
     auto __comp_res = __comp(__v, __nd->__get_value());
diff --git a/libcxx/include/__type_traits/make_transparent.h 
b/libcxx/include/__type_traits/make_transparent.h
index 4d3207a807fa7..c2edf126d4990 100644
--- a/libcxx/include/__type_traits/make_transparent.h
+++ b/libcxx/include/__type_traits/make_transparent.h
@@ -24,23 +24,27 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 // `less<>` from `less<T>`. This is useful in cases where conversions can be 
avoided (e.g. a string literal to a
 // std::string).
 
-template <class _Comparator>
+template <class _Tp, class _Comparator>
 struct __make_transparent {
   using type _LIBCPP_NODEBUG = _Comparator;
 };
 
-template <class _Comparator>
-using __make_transparent_t _LIBCPP_NODEBUG = typename 
__make_transparent<_Comparator>::type;
+template <class _Tp, class _Comparator>
+using __make_transparent_t _LIBCPP_NODEBUG = typename __make_transparent<_Tp, 
_Comparator>::type;
 
-template <class _Comparator, __enable_if_t<is_same<_Comparator, 
__make_transparent_t<_Comparator> >::value, int> = 0>
+template <class _Tp,
+          class _Comparator,
+          __enable_if_t<is_same<_Comparator, __make_transparent_t<_Tp, 
_Comparator> >::value, int> = 0>
 _LIBCPP_HIDE_FROM_ABI _Comparator& __as_transparent(_Comparator& __comp) {
   return __comp;
 }
 
-template <class _Comparator, __enable_if_t<!is_same<_Comparator, 
__make_transparent_t<_Comparator> >::value, int> = 0>
-_LIBCPP_HIDE_FROM_ABI __make_transparent_t<_Comparator> 
__as_transparent(_Comparator&) {
+template <class _Tp,
+          class _Comparator,
+          __enable_if_t<!is_same<_Comparator, __make_transparent_t<_Tp, 
_Comparator> >::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI __make_transparent_t<_Tp, _Comparator> 
__as_transparent(_Comparator&) {
   static_assert(is_empty<_Comparator>::value);
-  return __make_transparent_t<_Comparator>();
+  return __make_transparent_t<_Tp, _Comparator>();
 }
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/map b/libcxx/include/map
index 03c92e152e04f..27678b710f19e 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -669,8 +669,8 @@ public:
 };
 
 template <class _Key, class _MapValueT, class _Compare>
-struct __make_transparent<__map_value_compare<_Key, _MapValueT, _Compare> > {
-  using type _LIBCPP_NODEBUG = __map_value_compare<_Key, _MapValueT, 
__make_transparent_t<_Compare> >;
+struct __make_transparent<_Key, __map_value_compare<_Key, _MapValueT, 
_Compare> > {
+  using type _LIBCPP_NODEBUG = __map_value_compare<_Key, _MapValueT, 
__make_transparent_t<_Key, _Compare> >;
 };
 
 #  if _LIBCPP_STD_VER >= 14
diff --git a/libcxx/test/std/containers/associative/map/map.ops/find.pass.cpp 
b/libcxx/test/std/containers/associative/map/map.ops/find.pass.cpp
index 63dbcda512803..85811046c0048 100644
--- a/libcxx/test/std/containers/associative/map/map.ops/find.pass.cpp
+++ b/libcxx/test/std/containers/associative/map/map.ops/find.pass.cpp
@@ -222,6 +222,18 @@ int main(int, char**) {
     assert(r == std::next(m.begin(), 8));
   }
 #endif
+  { // Make sure we only make the comparator transparent if it's not 
converting the arguments
+    struct S {
+      int i_;
+
+      S(int i) : i_(i) {}
+      bool operator<(S lhs) const { return lhs.i_ < i_; }
+    };
+    // less<S> causes an implicit conversion from reference_wrapper<S> to 
const S&, making the `<` lookup succeed
+    std::map<std::reference_wrapper<S>, void*, std::less<S> > m;
+    S v(1);
+    assert(m.find(v) == m.end());
+  }
 
   return 0;
 }

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to