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
