From 61fd754bdc33e97e8a6a441ac1f1b5e2a47a816c Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Sun, 28 Sep 2025 10:42:13 +0200 Subject: [PATCH] [libc++] Don't use std::allocator inside --- 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 _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(&__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(&__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 _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 # include # endif + +# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 23 +# include +# include +# 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 - -// - -// 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 -#include -#include -#include -#include -#include -#include - -#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 { - 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(::operator new(n * sizeof(Large))); - } - - template - void construct(Large* p, Args&&... args) { - new (p) Large(std::forward(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 { - 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 - void construct(Small* p, Args&&... args) { - new (p) Small(std::forward(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 + +// + +// 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 +#include +#include +#include + +// 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; +}