[libcxx-commits] [libcxx] [libc++] Don't use std::allocator inside <any> (PR #161061)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Oct 7 01:38:38 PDT 2025
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/161061
>From 61fd754bdc33e97e8a6a441ac1f1b5e2a47a816c Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sun, 28 Sep 2025 10:42:13 +0200
Subject: [PATCH] [libc++] Don't use std::allocator inside <any>
---
libcxx/include/any | 46 +++----
.../test/libcxx/transitive_includes/cxx26.csv | 2 -
.../libcxx/utilities/any/allocator.pass.cpp | 127 ------------------
.../any/any.class/allocator.pass.cpp | 83 ++++++++++++
4 files changed, 101 insertions(+), 157 deletions(-)
delete mode 100644 libcxx/test/libcxx/utilities/any/allocator.pass.cpp
create mode 100644 libcxx/test/std/utilities/any/any.class/allocator.pass.cpp
diff --git a/libcxx/include/any b/libcxx/include/any
index 89bf3cf1f7df0..148fb16c802a5 100644
--- a/libcxx/include/any
+++ b/libcxx/include/any
@@ -84,10 +84,8 @@ namespace std {
# include <__cxx03/__config>
#else
# include <__config>
-# include <__memory/allocator.h>
-# include <__memory/allocator_destructor.h>
-# include <__memory/allocator_traits.h>
-# include <__memory/unique_ptr.h>
+# include <__memory/construct_at.h>
+# include <__new/allocate.h>
# include <__type_traits/add_cv_quals.h>
# include <__type_traits/add_pointer.h>
# include <__type_traits/aligned_storage.h>
@@ -103,6 +101,7 @@ namespace std {
# include <__type_traits/remove_cv.h>
# include <__type_traits/remove_cvref.h>
# include <__type_traits/remove_reference.h>
+# include <__utility/exception_guard.h>
# include <__utility/forward.h>
# include <__utility/in_place.h>
# include <__utility/move.h>
@@ -339,22 +338,14 @@ struct _SmallHandler {
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI static _Tp& __create(any& __dest, _Args&&... __args) {
- typedef allocator<_Tp> _Alloc;
- typedef allocator_traits<_Alloc> _ATraits;
- _Alloc __a;
- _Tp* __ret = static_cast<_Tp*>(static_cast<void*>(&__dest.__s_.__buf));
- _ATraits::construct(__a, __ret, std::forward<_Args>(__args)...);
+ auto __ret = std::__construct_at(reinterpret_cast<_Tp*>(&__dest.__s_.__buf), std::forward<_Args>(__args)...);
__dest.__h_ = &_SmallHandler::__handle;
return *__ret;
}
private:
_LIBCPP_HIDE_FROM_ABI static void __destroy(any& __this) {
- typedef allocator<_Tp> _Alloc;
- typedef allocator_traits<_Alloc> _ATraits;
- _Alloc __a;
- _Tp* __p = static_cast<_Tp*>(static_cast<void*>(&__this.__s_.__buf));
- _ATraits::destroy(__a, __p);
+ std::__destroy_at(reinterpret_cast<_Tp*>(&__this.__s_.__buf));
__this.__h_ = nullptr;
}
@@ -406,26 +397,20 @@ struct _LargeHandler {
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI static _Tp& __create(any& __dest, _Args&&... __args) {
- typedef allocator<_Tp> _Alloc;
- typedef allocator_traits<_Alloc> _ATraits;
- typedef __allocator_destructor<_Alloc> _Dp;
- _Alloc __a;
- unique_ptr<_Tp, _Dp> __hold(_ATraits::allocate(__a, 1), _Dp(__a, 1));
- _Tp* __ret = __hold.get();
- _ATraits::construct(__a, __ret, std::forward<_Args>(__args)...);
- __dest.__s_.__ptr = __hold.release();
+ _Tp* __ptr = static_cast<_Tp*>(std::__libcpp_allocate<_Tp>(__element_count(1)));
+ std::__exception_guard __guard([&] { std::__libcpp_deallocate<_Tp>(__ptr, __element_count(1)); });
+ std::__construct_at(__ptr, std::forward<_Args>(__args)...);
+ __guard.__complete();
+ __dest.__s_.__ptr = __ptr;
__dest.__h_ = &_LargeHandler::__handle;
- return *__ret;
+ return *__ptr;
}
private:
_LIBCPP_HIDE_FROM_ABI static void __destroy(any& __this) {
- typedef allocator<_Tp> _Alloc;
- typedef allocator_traits<_Alloc> _ATraits;
- _Alloc __a;
_Tp* __p = static_cast<_Tp*>(__this.__s_.__ptr);
- _ATraits::destroy(__a, __p);
- _ATraits::deallocate(__a, __p, 1);
+ std::__destroy_at(__p);
+ std::__libcpp_deallocate<_Tp>(__p, __element_count(1));
__this.__h_ = nullptr;
}
@@ -613,6 +598,11 @@ _LIBCPP_POP_MACROS
# include <type_traits>
# include <variant>
# endif
+
+# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 23
+# include <cstring>
+# include <limits>
+# endif
#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
#endif // _LIBCPP_ANY
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 81c8c41d88756..d047b29b63cc6 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -14,9 +14,7 @@ algorithm ratio
algorithm tuple
algorithm version
any cstdint
-any cstring
any initializer_list
-any limits
any typeinfo
any version
array cctype
diff --git a/libcxx/test/libcxx/utilities/any/allocator.pass.cpp b/libcxx/test/libcxx/utilities/any/allocator.pass.cpp
deleted file mode 100644
index eab3ca8826493..0000000000000
--- a/libcxx/test/libcxx/utilities/any/allocator.pass.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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, c++11, c++14
-
-// <any>
-
-// Check that we're consistently using std::allocator_traits to
-// allocate/deallocate/construct/destroy objects in std::any.
-// See https://llvm.org/PR45099 for details.
-
-#include <any>
-#include <cassert>
-#include <cstddef>
-#include <memory>
-#include <new>
-#include <type_traits>
-#include <utility>
-
-#include "test_macros.h"
-
-
-// Make sure we don't fit in std::any's SBO
-struct Large { char big[sizeof(std::any) + 1]; };
-
-// Make sure we fit in std::any's SBO
-struct Small { };
-
-bool Large_was_allocated = false;
-bool Large_was_constructed = false;
-bool Large_was_destroyed = false;
-bool Large_was_deallocated = false;
-
-bool Small_was_constructed = false;
-bool Small_was_destroyed = false;
-
-template <>
-struct std::allocator<Large> {
- using value_type = Large;
- using size_type = std::size_t;
- using difference_type = std::ptrdiff_t;
- using propagate_on_container_move_assignment = std::true_type;
- using is_always_equal = std::true_type;
-
- Large* allocate(std::size_t n) {
- Large_was_allocated = true;
- return static_cast<Large*>(::operator new(n * sizeof(Large)));
- }
-
- template <typename... Args>
- void construct(Large* p, Args&&... args) {
- new (p) Large(std::forward<Args>(args)...);
- Large_was_constructed = true;
- }
-
- void destroy(Large* p) {
- p->~Large();
- Large_was_destroyed = true;
- }
-
- void deallocate(Large* p, std::size_t) {
- Large_was_deallocated = true;
- return ::operator delete(p);
- }
-};
-
-template <>
-struct std::allocator<Small> {
- using value_type = Small;
- using size_type = std::size_t;
- using difference_type = std::ptrdiff_t;
- using propagate_on_container_move_assignment = std::true_type;
- using is_always_equal = std::true_type;
-
- Small* allocate(std::size_t) {
- assert(false);
- return nullptr;
- }
-
- template <typename... Args>
- void construct(Small* p, Args&&... args) {
- new (p) Small(std::forward<Args>(args)...);
- Small_was_constructed = true;
- }
-
- void destroy(Small* p) {
- p->~Small();
- Small_was_destroyed = true;
- }
-
- void deallocate(Small*, std::size_t) { assert(false); }
-};
-
-int main(int, char**) {
- // Test large types
- {
- {
- std::any a = Large();
- (void)a;
-
- assert(Large_was_allocated);
- assert(Large_was_constructed);
- }
-
- assert(Large_was_destroyed);
- assert(Large_was_deallocated);
- }
-
- // Test small types
- {
- {
- std::any a = Small();
- (void)a;
-
- assert(Small_was_constructed);
- }
-
- assert(Small_was_destroyed);
- }
-
- return 0;
-}
diff --git a/libcxx/test/std/utilities/any/any.class/allocator.pass.cpp b/libcxx/test/std/utilities/any/any.class/allocator.pass.cpp
new file mode 100644
index 0000000000000..a11bcfca1d06d
--- /dev/null
+++ b/libcxx/test/std/utilities/any/any.class/allocator.pass.cpp
@@ -0,0 +1,83 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++11, c++14
+
+// <any>
+
+// Check that we're consistently using the same allocation functions to
+// allocate/deallocate/construct/destroy objects in std::any.
+// See https://llvm.org/PR45099 for details.
+
+#include <any>
+#include <cassert>
+#include <cstddef>
+#include <new>
+
+// Make sure we don't fit in std::any's SBO
+int allocated_count = 0;
+int constructed_count = 0;
+
+struct Large {
+ Large() { ++constructed_count; }
+
+ Large(const Large&) { ++constructed_count; }
+
+ ~Large() { --constructed_count; }
+
+ char big[sizeof(std::any) + 1];
+
+ static void* operator new(size_t n) {
+ ++allocated_count;
+ return ::operator new(n);
+ }
+
+ static void operator delete(void* ptr) {
+ --allocated_count;
+ ::operator delete(ptr);
+ }
+};
+
+// Make sure we fit in std::any's SBO
+struct Small {
+ Small() { ++constructed_count; }
+
+ Small(const Small&) { ++constructed_count; }
+
+ ~Small() { --constructed_count; }
+
+ static void* operator new(size_t n) {
+ ++allocated_count;
+ return ::operator new(n);
+ }
+
+ static void operator delete(void* ptr) {
+ --allocated_count;
+ ::operator delete(ptr);
+ }
+};
+
+int main(int, char**) {
+ // Test large types
+ {
+ [[maybe_unused]] std::any a = Large();
+ assert(constructed_count == 1);
+ }
+ assert(allocated_count == 0);
+ assert(constructed_count == 0);
+
+ // Test small types
+ {
+ [[maybe_unused]] std::any a = Small();
+ assert(constructed_count == 1);
+ }
+ assert(allocated_count == 0);
+ assert(constructed_count == 0);
+
+ return 0;
+}
More information about the libcxx-commits
mailing list