[libcxx-commits] [libcxx] [libcxx][string] Test: default constructed allocators can be unequal (PR #195839)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue May 5 08:53:54 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Nikita Belenkiy (kitsnet)

<details>
<summary>Changes</summary>

In preparation to fancy_pointer_allocator, where multiple default constructed instances of the allocator may have unrelated internal states, the string tests were changed to not always assume that get_alocator() with default allocator returns value equal to Allocator().

In addition, one missing test path where substring move will cause allocation due to incompatible allocators (as already implemented in basic_string) was found and addressed.

---
Full diff: https://github.com/llvm/llvm-project/pull/195839.diff


11 Files Affected:

- (modified) libcxx/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp (+1-2) 
- (modified) libcxx/test/std/strings/basic.string/string.cons/alloc.pass.cpp (+7-3) 
- (modified) libcxx/test/std/strings/basic.string/string.cons/iter_alloc.pass.cpp (+1-1) 
- (modified) libcxx/test/std/strings/basic.string/string.cons/pointer_alloc.pass.cpp (+1-1) 
- (modified) libcxx/test/std/strings/basic.string/string.cons/pointer_size_alloc.pass.cpp (+1-1) 
- (modified) libcxx/test/std/strings/basic.string/string.cons/size_char_alloc.pass.cpp (+2-2) 
- (modified) libcxx/test/std/strings/basic.string/string.cons/string_view.pass.cpp (+2-2) 
- (modified) libcxx/test/std/strings/basic.string/string.cons/substr.pass.cpp (+2-4) 
- (modified) libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp (+8-4) 
- (modified) libcxx/test/std/strings/basic.string/string.ops/string.accessors/get_allocator.pass.cpp (+3-1) 
- (modified) libcxx/test/support/test_allocator.h (+12) 


``````````diff
diff --git a/libcxx/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp
index dcf697bed752f..8511250812d6a 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp
@@ -28,7 +28,6 @@
 template <class S, class SV>
 TEST_CONSTEXPR_CXX20 void test(SV sv, std::size_t pos, std::size_t n) {
   typedef typename S::traits_type T;
-  typedef typename S::allocator_type A;
   typedef typename S::size_type Size;
   if (pos <= sv.size()) {
     S s2(sv, static_cast<Size>(pos), static_cast<Size>(n));
@@ -37,7 +36,7 @@ TEST_CONSTEXPR_CXX20 void test(SV sv, std::size_t pos, std::size_t n) {
     std::size_t rlen = std::min(sv.size() - pos, n);
     assert(s2.size() == rlen);
     assert(T::compare(s2.data(), sv.data() + pos, rlen) == 0);
-    assert(s2.get_allocator() == A());
+    ASSERT_CONTAINER_ALLOCATOR_EQUALS_DEFAULT(S, s2);
     assert(s2.capacity() >= s2.size());
     LIBCPP_ASSERT(is_string_asan_correct(s2));
   }
diff --git a/libcxx/test/std/strings/basic.string/string.cons/alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/alloc.pass.cpp
index 91beac37764db..a2b493d5829ff 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/alloc.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/alloc.pass.cpp
@@ -67,7 +67,10 @@ TEST_CONSTEXPR_CXX20 void test2() {
     assert(s.data());
     assert(s.size() == 0);
     assert(s.capacity() >= s.size());
-    assert(s.get_allocator() == typename S::allocator_type());
+#  if TEST_STD_VER >= 11
+    static_assert(std::is_same<decltype(s.get_allocator()), typename S::allocator_type>::value, "");
+#  endif
+    ASSERT_CONTAINER_ALLOCATOR_EQUALS_DEFAULT(S, s);
     LIBCPP_ASSERT(is_string_asan_correct(s));
   }
   {
@@ -78,12 +81,13 @@ TEST_CONSTEXPR_CXX20 void test2() {
                    std::is_nothrow_copy_constructible<typename S::allocator_type>::value),
                   "");
 #  endif
-    S s(typename S::allocator_type{});
+    typename S::allocator_type a{};
+    S s(a);
     LIBCPP_ASSERT(s.__invariants());
     assert(s.data());
     assert(s.size() == 0);
     assert(s.capacity() >= s.size());
-    assert(s.get_allocator() == typename S::allocator_type());
+    assert(s.get_allocator() == a);
     LIBCPP_ASSERT(is_string_asan_correct(s));
   }
 }
diff --git a/libcxx/test/std/strings/basic.string/string.cons/iter_alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/iter_alloc.pass.cpp
index e14227d1a7717..7e924fea39490 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/iter_alloc.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/iter_alloc.pass.cpp
@@ -36,7 +36,7 @@ TEST_CONSTEXPR_CXX20 void test(It first, It last) {
     ++it;
     ++i;
   }
-  assert(s2.get_allocator() == Alloc());
+  ASSERT_CONTAINER_ALLOCATOR_EQUALS_DEFAULT(S, s2);
   assert(s2.capacity() >= s2.size());
   LIBCPP_ASSERT(is_string_asan_correct(s2));
 }
diff --git a/libcxx/test/std/strings/basic.string/string.cons/pointer_alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/pointer_alloc.pass.cpp
index d5d5152e11e54..c23afad1c470b 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/pointer_alloc.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/pointer_alloc.pass.cpp
@@ -30,7 +30,7 @@ TEST_CONSTEXPR_CXX20 void test(const charT* s) {
   LIBCPP_ASSERT(s2.__invariants());
   assert(s2.size() == n);
   assert(T::compare(s2.data(), s, n) == 0);
-  assert(s2.get_allocator() == Alloc());
+  ASSERT_CONTAINER_ALLOCATOR_EQUALS_DEFAULT(S, s2);
   assert(s2.capacity() >= s2.size());
   LIBCPP_ASSERT(is_string_asan_correct(s2));
 }
diff --git a/libcxx/test/std/strings/basic.string/string.cons/pointer_size_alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/pointer_size_alloc.pass.cpp
index b6ba2be46d18b..cf8280e940eed 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/pointer_size_alloc.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/pointer_size_alloc.pass.cpp
@@ -28,7 +28,7 @@ TEST_CONSTEXPR_CXX20 void test(const CharT* s, unsigned n) {
   LIBCPP_ASSERT(s2.__invariants());
   assert(s2.size() == n);
   assert(T::compare(s2.data(), s, n) == 0);
-  assert(s2.get_allocator() == Alloc());
+  ASSERT_CONTAINER_ALLOCATOR_EQUALS_DEFAULT(S, s2);
   assert(s2.capacity() >= s2.size());
   LIBCPP_ASSERT(is_string_asan_correct(s2));
 }
diff --git a/libcxx/test/std/strings/basic.string/string.cons/size_char_alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/size_char_alloc.pass.cpp
index a87e01f0fc088..e92232935db3e 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/size_char_alloc.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/size_char_alloc.pass.cpp
@@ -29,7 +29,7 @@ TEST_CONSTEXPR_CXX20 void test(unsigned n, charT c) {
   assert(s2.size() == n);
   for (unsigned i = 0; i < n; ++i)
     assert(s2[i] == c);
-  assert(s2.get_allocator() == Alloc());
+  ASSERT_CONTAINER_ALLOCATOR_EQUALS_DEFAULT(S, s2);
   assert(s2.capacity() >= s2.size());
   LIBCPP_ASSERT(is_string_asan_correct(s2));
 }
@@ -56,7 +56,7 @@ TEST_CONSTEXPR_CXX20 void test(Tp n, Tp c) {
   assert(s2.size() == static_cast<std::size_t>(n));
   for (int i = 0; i < n; ++i)
     assert(s2[i] == c);
-  assert(s2.get_allocator() == Alloc());
+  ASSERT_CONTAINER_ALLOCATOR_EQUALS_DEFAULT(S, s2);
   assert(s2.capacity() >= s2.size());
 }
 
diff --git a/libcxx/test/std/strings/basic.string/string.cons/string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/string_view.pass.cpp
index ad37b50b83ba7..3ef7fb01f9c2c 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/string_view.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/string_view.pass.cpp
@@ -34,7 +34,7 @@ TEST_CONSTEXPR_CXX20 void test(std::basic_string_view<CharT> sv) {
     LIBCPP_ASSERT(s2.__invariants());
     assert(s2.size() == sv.size());
     assert(T::compare(s2.data(), sv.data(), sv.size()) == 0);
-    assert(s2.get_allocator() == Alloc());
+    ASSERT_CONTAINER_ALLOCATOR_EQUALS_DEFAULT(S, s2);
     assert(s2.capacity() >= s2.size());
     LIBCPP_ASSERT(is_string_asan_correct(s2));
   }
@@ -44,7 +44,7 @@ TEST_CONSTEXPR_CXX20 void test(std::basic_string_view<CharT> sv) {
     LIBCPP_ASSERT(s2.__invariants());
     assert(s2.size() == sv.size());
     assert(T::compare(s2.data(), sv.data(), sv.size()) == 0);
-    assert(s2.get_allocator() == Alloc());
+    ASSERT_CONTAINER_ALLOCATOR_EQUALS_DEFAULT(S, s2);
     assert(s2.capacity() >= s2.size());
     LIBCPP_ASSERT(is_string_asan_correct(s2));
   }
diff --git a/libcxx/test/std/strings/basic.string/string.cons/substr.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/substr.pass.cpp
index cafd9674f4898..a47995699ae34 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/substr.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/substr.pass.cpp
@@ -31,7 +31,6 @@
 template <class S>
 TEST_CONSTEXPR_CXX20 void test(S str, unsigned pos) {
   typedef typename S::traits_type T;
-  typedef typename S::allocator_type A;
 
   if (pos <= str.size()) {
     S s2(str, pos);
@@ -39,7 +38,7 @@ TEST_CONSTEXPR_CXX20 void test(S str, unsigned pos) {
     typename S::size_type rlen = str.size() - pos;
     assert(s2.size() == rlen);
     assert(T::compare(s2.data(), str.data() + pos, rlen) == 0);
-    assert(s2.get_allocator() == A());
+    ASSERT_CONTAINER_ALLOCATOR_EQUALS_DEFAULT(S, s2);
     assert(s2.capacity() >= s2.size());
     LIBCPP_ASSERT(is_string_asan_correct(s2));
   }
@@ -58,14 +57,13 @@ TEST_CONSTEXPR_CXX20 void test(S str, unsigned pos) {
 template <class S>
 TEST_CONSTEXPR_CXX20 void test(S str, unsigned pos, unsigned n) {
   typedef typename S::traits_type T;
-  typedef typename S::allocator_type A;
   if (pos <= str.size()) {
     S s2(str, pos, n);
     LIBCPP_ASSERT(s2.__invariants());
     typename S::size_type rlen = std::min<typename S::size_type>(str.size() - pos, n);
     assert(s2.size() == rlen);
     assert(T::compare(s2.data(), str.data() + pos, rlen) == 0);
-    assert(s2.get_allocator() == A());
+    ASSERT_CONTAINER_ALLOCATOR_EQUALS_DEFAULT(S, s2);
     assert(s2.capacity() >= s2.size());
     LIBCPP_ASSERT(is_string_asan_correct(s2));
   }
diff --git a/libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp
index 9c7c341302df9..ae16130d7b5b1 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp
@@ -33,12 +33,14 @@ constexpr struct should_throw_exception_t {
 
 template <class S>
 constexpr void test_string_pos(S orig, typename S::size_type pos, S expected) {
+  const bool expect_no_allocation = orig.get_allocator() == typename S::allocator_type();
 #ifdef _LIBCPP_VERSION
-  ConstexprDisableAllocationGuard g;
+  ConstexprDisableAllocationGuard g(expect_no_allocation);
 #endif
   S substr(std::move(orig), pos);
   LIBCPP_ASSERT(orig.__invariants());
-  LIBCPP_ASSERT(orig.empty());
+  if (expect_no_allocation)
+    LIBCPP_ASSERT(orig.empty());
   LIBCPP_ASSERT(substr.__invariants());
   assert(substr == expected);
   LIBCPP_ASSERT(is_string_asan_correct(orig));
@@ -93,12 +95,14 @@ constexpr void test_string_pos_alloc(
 
 template <class S>
 constexpr void test_string_pos_n(S orig, typename S::size_type pos, typename S::size_type n, S expected) {
+  const bool expect_no_allocation = orig.get_allocator() == typename S::allocator_type();
 #ifdef _LIBCPP_VERSION
-  ConstexprDisableAllocationGuard g;
+  ConstexprDisableAllocationGuard g(expect_no_allocation);
 #endif
   S substr(std::move(orig), pos, n);
   LIBCPP_ASSERT(orig.__invariants());
-  LIBCPP_ASSERT(orig.empty());
+  if (expect_no_allocation)
+    LIBCPP_ASSERT(orig.empty());
   LIBCPP_ASSERT(substr.__invariants());
   assert(substr == expected);
   LIBCPP_ASSERT(is_string_asan_correct(orig));
diff --git a/libcxx/test/std/strings/basic.string/string.ops/string.accessors/get_allocator.pass.cpp b/libcxx/test/std/strings/basic.string/string.ops/string.accessors/get_allocator.pass.cpp
index a6158aeb38dc2..a54df7a1f144c 100644
--- a/libcxx/test/std/strings/basic.string/string.ops/string.accessors/get_allocator.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.ops/string.accessors/get_allocator.pass.cpp
@@ -25,7 +25,9 @@ TEST_CONSTEXPR_CXX20 void test(const S& s, const typename S::allocator_type& a)
 template <class Alloc>
 TEST_CONSTEXPR_CXX20 void test_string(const Alloc& a) {
   using S = std::basic_string<char, std::char_traits<char>, Alloc>;
-  test(S(""), Alloc());
+  if (are_default_allocators_always_equal<Alloc>::value)
+    test(S(""), Alloc());
+  test(S("", Alloc(a)), Alloc(a));
   test(S("abcde", Alloc(a)), Alloc(a));
   test(S("abcdefghij", Alloc(a)), Alloc(a));
   test(S("abcdefghijklmnopqrst", Alloc(a)), Alloc(a));
diff --git a/libcxx/test/support/test_allocator.h b/libcxx/test/support/test_allocator.h
index f8b622d7f9520..064aca94a37c2 100644
--- a/libcxx/test/support/test_allocator.h
+++ b/libcxx/test/support/test_allocator.h
@@ -20,6 +20,18 @@
 
 #include "test_macros.h"
 
+// unless explicitly specified as false
+template <class T>
+struct are_default_allocators_always_equal {
+  enum { value = 1 };
+};
+
+#define ASSERT_CONTAINER_ALLOCATOR_EQUALS_DEFAULT(C, c)                                                                \
+  do {                                                                                                                 \
+    if (are_default_allocators_always_equal<typename C::allocator_type>::value)                                        \
+      assert(c.get_allocator() == typename C::allocator_type());                                                       \
+  } while (0)
+
 template <class Alloc>
 TEST_CONSTEXPR_CXX20 inline typename std::allocator_traits<Alloc>::size_type alloc_max_size(Alloc const& a) {
   typedef std::allocator_traits<Alloc> AT;

``````````

</details>


https://github.com/llvm/llvm-project/pull/195839


More information about the libcxx-commits mailing list