[libcxx-commits] [libcxx] [libcxx][test-support] Improve thread_unsafe_shared_ptr (PR #195932)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed May 6 00:54:04 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Nikita Belenkiy (kitsnet)

<details>
<summary>Changes</summary>

Adapting test support class thread_unsafe_shared_ptr for future use with fancy_pointer_allocator, in particular, in constexpr contexts:

* Implementing the rule of 5 / the rule of 3;
* Annotating noexcept methods (and removing the workaround in the respective test);
* Making deallocation of its control block ignored by DisableAllocationGuard;
* Adding workaround for (expected later) module export problem (https://llvm.org/PR120108)

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


3 Files Affected:

- (modified) libcxx/test/std/strings/basic.string/string.cons/move_noexcept.pass.cpp (-4) 
- (modified) libcxx/test/support/module.modulemap (+4-1) 
- (modified) libcxx/test/support/test_allocator.h (+47-9) 


``````````diff
diff --git a/libcxx/test/std/strings/basic.string/string.cons/move_noexcept.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/move_noexcept.pass.cpp
index d807cac2c72c8..89502f6652655 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/move_noexcept.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/move_noexcept.pass.cpp
@@ -32,11 +32,7 @@ int main(int, char**) {
   }
   {
     typedef std::basic_string<char, std::char_traits<char>, limited_allocator<char, 10>> C;
-#if TEST_STD_VER <= 14
-    static_assert(!std::is_nothrow_move_constructible<C>::value, "");
-#else
     static_assert(std::is_nothrow_move_constructible<C>::value, "");
-#endif
   }
 
   return 0;
diff --git a/libcxx/test/support/module.modulemap b/libcxx/test/support/module.modulemap
index 0af147d75ee5d..07acbb6b2e2fd 100644
--- a/libcxx/test/support/module.modulemap
+++ b/libcxx/test/support/module.modulemap
@@ -5,7 +5,10 @@ module test_config {
 
 module test {
   module double_move_tracker    { header "double_move_tracker.h" }
-  module test_allocator         { header "test_allocator.h" }
+  module test_allocator {
+    header "test_allocator.h"
+    export * // TODO: Workaround for https://llvm.org/PR120108
+  }
   module test_iterators         { header "test_iterators.h" }
   module type_algorithms        { header "type_algorithms.h" }
 }
diff --git a/libcxx/test/support/test_allocator.h b/libcxx/test/support/test_allocator.h
index f8b622d7f9520..d6046518d6cf5 100644
--- a/libcxx/test/support/test_allocator.h
+++ b/libcxx/test/support/test_allocator.h
@@ -395,19 +395,32 @@ class thread_unsafe_shared_ptr {
 public:
   thread_unsafe_shared_ptr() = default;
 
-  TEST_CONSTEXPR_CXX14 thread_unsafe_shared_ptr(const thread_unsafe_shared_ptr& other) : block(other.block) {
+  TEST_CONSTEXPR_CXX14 thread_unsafe_shared_ptr(const thread_unsafe_shared_ptr& other) TEST_NOEXCEPT
+      : block(other.block) {
     ++block->ref_count;
   }
+  TEST_CONSTEXPR_CXX14 thread_unsafe_shared_ptr& operator=(const thread_unsafe_shared_ptr& other) TEST_NOEXCEPT {
+    // self-assignment safe order
+    ++other.block->ref_count;
+    detach_control_block();
+    block = other.block;
+    return *this;
+  }
 
-  TEST_CONSTEXPR_CXX20 ~thread_unsafe_shared_ptr() {
-    --block->ref_count;
-    if (block->ref_count != 0)
-      return;
-    typedef std::allocator_traits<std::allocator<control_block> > allocator_traits;
-    std::allocator<control_block> alloc;
-    allocator_traits::destroy(alloc, block);
-    allocator_traits::deallocate(alloc, block, 1);
+#if TEST_STD_VER >= 11
+  TEST_CONSTEXPR_CXX14 thread_unsafe_shared_ptr(thread_unsafe_shared_ptr&& other) TEST_NOEXCEPT : block(other.block) {
+    ++block->ref_count;
   }
+  TEST_CONSTEXPR_CXX20 thread_unsafe_shared_ptr& operator=(thread_unsafe_shared_ptr&& other) TEST_NOEXCEPT {
+    // self-assignment safe order
+    ++other.block->ref_count;
+    detach_control_block();
+    block = other.block;
+    return *this;
+  }
+#endif
+
+  TEST_CONSTEXPR_CXX20 ~thread_unsafe_shared_ptr() TEST_NOEXCEPT { detach_control_block(); }
 
   TEST_CONSTEXPR const T& operator*() const { return block->content; }
   TEST_CONSTEXPR const T* operator->() const { return &block->content; }
@@ -424,6 +437,31 @@ class thread_unsafe_shared_ptr {
     T content;
   };
 
+  TEST_CONSTEXPR_CXX20 void detach_control_block() {
+    --block->ref_count;
+    if (block->ref_count != 0)
+      return;
+    typedef std::allocator_traits<std::allocator<control_block> > allocator_traits;
+    std::allocator<control_block> alloc;
+    allocator_traits::destroy(alloc, block);
+#ifdef COUNT_NEW_H
+    // We are called from test code instrumented by counting operator new/operator delete,
+    // which might be surprised by unexpected deallocations we introduce.
+    // Instead of changing all the potentially affected tests, we will just temporarily
+    // disable that counting here.
+    bool disable_allocations = false;
+    if (!TEST_IS_CONSTANT_EVALUATED) {
+      disable_allocations                  = globalMemCounter.disable_allocations;
+      globalMemCounter.disable_allocations = false;
+    }
+#endif
+    allocator_traits::deallocate(alloc, block, 1);
+#ifdef COUNT_NEW_H
+    if (!TEST_IS_CONSTANT_EVALUATED)
+      globalMemCounter.disable_allocations = disable_allocations;
+#endif
+  }
+
   control_block* block = nullptr;
 
   template <class U, class... Args>

``````````

</details>


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


More information about the libcxx-commits mailing list