Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 75fb34a

Browse files
philnik777c-rhodes
authored andcommitted
[libc++] Only make comparators transparent in __tree if they don't cause a conversion (llvm#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 llvm#179319 (cherry picked from commit 9d23031)
1 parent 4688b97 commit 75fb34a

5 files changed

Lines changed: 30 additions & 13 deletions

File tree

libcxx/include/__functional/operations.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ struct less<void> {
380380
};
381381

382382
template <class _Tp>
383-
struct __make_transparent<less<_Tp> > {
383+
struct __make_transparent<_Tp, less<_Tp> > {
384384
using type _LIBCPP_NODEBUG = less<>;
385385
};
386386

@@ -478,7 +478,7 @@ template <class _Tp, class _Up>
478478
inline const bool __desugars_to_v<__greater_tag, greater<>, _Tp, _Up> = true;
479479

480480
template <class _Tp>
481-
struct __make_transparent<greater<_Tp>> {
481+
struct __make_transparent<_Tp, greater<_Tp>> {
482482
using type _LIBCPP_NODEBUG = greater<>;
483483
};
484484

libcxx/include/__tree

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,8 +1808,9 @@ __tree<_Tp, _Compare, _Allocator>::__find_equal(const _Key& __v) {
18081808
}
18091809

18101810
__node_base_pointer* __node_ptr = __root_ptr();
1811-
auto&& __transparent = std::__as_transparent(value_comp());
1812-
auto __comp = __lazy_synth_three_way_comparator<__make_transparent_t<_Compare>, _Key, value_type>(__transparent);
1811+
auto&& __transparent = std::__as_transparent<_Key>(value_comp());
1812+
auto __comp =
1813+
__lazy_synth_three_way_comparator<__make_transparent_t<_Key, _Compare>, _Key, value_type>(__transparent);
18131814

18141815
while (true) {
18151816
auto __comp_res = __comp(__v, __nd->__get_value());

libcxx/include/__type_traits/make_transparent.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,27 @@ _LIBCPP_BEGIN_NAMESPACE_STD
2424
// `less<>` from `less<T>`. This is useful in cases where conversions can be avoided (e.g. a string literal to a
2525
// std::string).
2626

27-
template <class _Comparator>
27+
template <class _Tp, class _Comparator>
2828
struct __make_transparent {
2929
using type _LIBCPP_NODEBUG = _Comparator;
3030
};
3131

32-
template <class _Comparator>
33-
using __make_transparent_t _LIBCPP_NODEBUG = typename __make_transparent<_Comparator>::type;
32+
template <class _Tp, class _Comparator>
33+
using __make_transparent_t _LIBCPP_NODEBUG = typename __make_transparent<_Tp, _Comparator>::type;
3434

35-
template <class _Comparator, __enable_if_t<is_same<_Comparator, __make_transparent_t<_Comparator> >::value, int> = 0>
35+
template <class _Tp,
36+
class _Comparator,
37+
__enable_if_t<is_same<_Comparator, __make_transparent_t<_Tp, _Comparator> >::value, int> = 0>
3638
_LIBCPP_HIDE_FROM_ABI _Comparator& __as_transparent(_Comparator& __comp) {
3739
return __comp;
3840
}
3941

40-
template <class _Comparator, __enable_if_t<!is_same<_Comparator, __make_transparent_t<_Comparator> >::value, int> = 0>
41-
_LIBCPP_HIDE_FROM_ABI __make_transparent_t<_Comparator> __as_transparent(_Comparator&) {
42+
template <class _Tp,
43+
class _Comparator,
44+
__enable_if_t<!is_same<_Comparator, __make_transparent_t<_Tp, _Comparator> >::value, int> = 0>
45+
_LIBCPP_HIDE_FROM_ABI __make_transparent_t<_Tp, _Comparator> __as_transparent(_Comparator&) {
4246
static_assert(is_empty<_Comparator>::value);
43-
return __make_transparent_t<_Comparator>();
47+
return __make_transparent_t<_Tp, _Comparator>();
4448
}
4549

4650
_LIBCPP_END_NAMESPACE_STD

libcxx/include/map

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -669,8 +669,8 @@ public:
669669
};
670670

671671
template <class _Key, class _MapValueT, class _Compare>
672-
struct __make_transparent<__map_value_compare<_Key, _MapValueT, _Compare> > {
673-
using type _LIBCPP_NODEBUG = __map_value_compare<_Key, _MapValueT, __make_transparent_t<_Compare> >;
672+
struct __make_transparent<_Key, __map_value_compare<_Key, _MapValueT, _Compare> > {
673+
using type _LIBCPP_NODEBUG = __map_value_compare<_Key, _MapValueT, __make_transparent_t<_Key, _Compare> >;
674674
};
675675

676676
# if _LIBCPP_STD_VER >= 14

libcxx/test/std/containers/associative/map/map.ops/find.pass.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,18 @@ int main(int, char**) {
222222
assert(r == std::next(m.begin(), 8));
223223
}
224224
#endif
225+
{ // Make sure we only make the comparator transparent if it's not converting the arguments
226+
struct S {
227+
int i_;
228+
229+
S(int i) : i_(i) {}
230+
bool operator<(S lhs) const { return lhs.i_ < i_; }
231+
};
232+
// less<S> causes an implicit conversion from reference_wrapper<S> to const S&, making the `<` lookup succeed
233+
std::map<std::reference_wrapper<S>, void*, std::less<S> > m;
234+
S v(1);
235+
assert(m.find(v) == m.end());
236+
}
225237

226238
return 0;
227239
}

0 commit comments

Comments
 (0)