[libc++] Expand test coverage for converting comparators in associative containers (#187133)

This is in preparation for fixing #187105.
This commit is contained in:
Louis Dionne 2026-03-18 14:22:22 -04:00 committed by GitHub
parent a33e9e5047
commit 3e09538a42
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 87 additions and 13 deletions

View File

@ -0,0 +1,87 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03
// Make sure that lookup methods on ordered associative containers work properly
// with comparators that require an implicit conversion on lookup. Using a
// comparator like less<S> with reference_wrapper<S> as the key type causes an
// implicit conversion from reference_wrapper<S> to const S& during comparison.
//
// Potential heterogeneous lookup optimizations must not break this by making the
// comparator "transparent" when doing so would remove that conversion.
//
// This is a regression test for https://llvm.org/PR179319.
#include <cassert>
#include <functional>
#include <map>
#include <set>
#include "test_macros.h"
struct S {
int i_;
S(int i) : i_(i) {}
bool operator<(S lhs) const { return lhs.i_ < i_; }
};
template <class Container>
void test(Container& container) {
// non-const
{
Container& c = container;
S v(1);
assert(c.find(v) == c.end());
assert(c.count(v) == 0);
assert(c.lower_bound(v) == c.end());
assert(c.upper_bound(v) == c.end());
assert(c.equal_range(v).first == c.end());
assert(c.equal_range(v).second == c.end());
#if TEST_STD_VER >= 20
assert(!c.contains(v));
#endif
}
// const
{
Container const& c = container;
S v(1);
assert(c.find(v) == c.end());
assert(c.count(v) == 0);
assert(c.lower_bound(v) == c.end());
assert(c.upper_bound(v) == c.end());
assert(c.equal_range(v).first == c.end());
assert(c.equal_range(v).second == c.end());
#if TEST_STD_VER >= 20
assert(!c.contains(v));
#endif
}
}
int main(int, char**) {
{
std::map<std::reference_wrapper<S>, void*, std::less<S>> m;
test(m);
}
{
std::multimap<std::reference_wrapper<S>, void*, std::less<S>> m;
test(m);
}
{
std::set<std::reference_wrapper<S>, std::less<S>> s;
test(s);
}
{
std::multiset<std::reference_wrapper<S>, std::less<S>> s;
test(s);
}
return 0;
}

View File

@ -222,18 +222,5 @@ 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;
}