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

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Wed Mar 18 07:34:25 PDT 2026


https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/187133

>From c80b76f5c0d357dba97d3a32550cb322fa43f9a2 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Tue, 17 Mar 2026 17:34:39 -0400
Subject: [PATCH 1/2] [libc++] Expand test coverage for converting comparators
 in associative containers

This is in preparation for fixing #187105.
---
 ...lookup_with_converting_comparator.pass.cpp | 68 +++++++++++++++++++
 .../associative/map/map.ops/find.pass.cpp     | 13 ----
 2 files changed, 68 insertions(+), 13 deletions(-)
 create mode 100644 libcxx/test/std/containers/associative/lookup_with_converting_comparator.pass.cpp

diff --git a/libcxx/test/std/containers/associative/lookup_with_converting_comparator.pass.cpp b/libcxx/test/std/containers/associative/lookup_with_converting_comparator.pass.cpp
new file mode 100644
index 0000000000000..f7e3285194d2d
--- /dev/null
+++ b/libcxx/test/std/containers/associative/lookup_with_converting_comparator.pass.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// 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& c) {
+  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;
+}
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 85811046c0048..b0e8b5ee8ba9e 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,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;
 }

>From 52f9a67685132bb0b2c5a6d69fc09f04ff0c0399 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Wed, 18 Mar 2026 10:33:24 -0400
Subject: [PATCH 2/2] Also add coverage for const

---
 ...lookup_with_converting_comparator.pass.cpp | 37 ++++++++++++++-----
 1 file changed, 28 insertions(+), 9 deletions(-)

diff --git a/libcxx/test/std/containers/associative/lookup_with_converting_comparator.pass.cpp b/libcxx/test/std/containers/associative/lookup_with_converting_comparator.pass.cpp
index f7e3285194d2d..6310ac333945b 100644
--- a/libcxx/test/std/containers/associative/lookup_with_converting_comparator.pass.cpp
+++ b/libcxx/test/std/containers/associative/lookup_with_converting_comparator.pass.cpp
@@ -33,17 +33,36 @@ struct S {
 };
 
 template <class Container>
-void test(Container& c) {
-  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());
+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));
+    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**) {



More information about the libcxx-commits mailing list