aboutsummaryrefslogtreecommitdiff
path: root/libcxx
diff options
context:
space:
mode:
authorHui <hui.xie0621@gmail.com>2023-01-03 18:51:34 +0000
committerHui <hui.xie0621@gmail.com>2023-01-23 21:07:22 +0000
commit9af9d39a47dc634b7de17708a4daf226ca699751 (patch)
tree79a769de6e5ca172a93e664eb054e265d1165526 /libcxx
parent38a9e1d41264b551f659a5d9215109a96e74cadd (diff)
downloadllvm-9af9d39a47dc634b7de17708a4daf226ca699751.zip
llvm-9af9d39a47dc634b7de17708a4daf226ca699751.tar.gz
llvm-9af9d39a47dc634b7de17708a4daf226ca699751.tar.bz2
[libc++] implement P1020R1 P1973R1 make_unique[shared]_for_overwrite
Differential Revision: https://reviews.llvm.org/D140913
Diffstat (limited to 'libcxx')
-rw-r--r--libcxx/docs/ReleaseNotes.rst1
-rw-r--r--libcxx/docs/Status/Cxx20Papers.csv4
-rw-r--r--libcxx/docs/Status/Cxx2b.rst1
-rw-r--r--libcxx/docs/Status/Cxx2bPapers.csv2
-rw-r--r--libcxx/include/__memory/shared_ptr.h105
-rw-r--r--libcxx/include/__memory/unique_ptr.h19
-rw-r--r--libcxx/include/memory17
-rw-r--r--libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp190
-rw-r--r--libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared_for_overwrite.pass.cpp133
-rw-r--r--libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.default_init.pass.cpp59
-rw-r--r--libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.pass.cpp149
11 files changed, 666 insertions, 14 deletions
diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index c0e5542..345dd53 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -69,6 +69,7 @@ Implemented Papers
- P1035R7 - Input Range Adaptors
- P2325R3 - Views should not be required to be default constructible
- P2446R2 - ``views::as_rvalue``
+- P1020 - Smart pointer creation with default initialization
Improvements and New Features
-----------------------------
diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
index 48405b8..3999b01 100644
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -67,7 +67,7 @@
"`P0972R0 <https://wg21.link/P0972R0>`__","LWG","<chrono> ``zero()``\ , ``min()``\ , and ``max()``\ should be noexcept","San Diego","|Complete|","8.0"
"`P1006R1 <https://wg21.link/P1006R1>`__","LWG","Constexpr in std::pointer_traits","San Diego","|Complete|","8.0"
"`P1007R3 <https://wg21.link/P1007R3>`__","LWG","``std::assume_aligned``\ ","San Diego","|Complete|","15.0"
-"`P1020R1 <https://wg21.link/P1020R1>`__","LWG","Smart pointer creation with default initialization","San Diego","* *",""
+"`P1020R1 <https://wg21.link/P1020R1>`__","LWG","Smart pointer creation with default initialization","San Diego","|Complete|","16.0"
"`P1032R1 <https://wg21.link/P1032R1>`__","LWG","Misc constexpr bits","San Diego","|Complete|","13.0"
"`P1085R2 <https://wg21.link/P1085R2>`__","LWG","Should Span be Regular?","San Diego","|Complete|","8.0"
"`P1123R0 <https://wg21.link/P1123R0>`__","LWG","Editorial Guidance for merging P0019r8 and P0528r3","San Diego","* *",""
@@ -177,7 +177,7 @@
"`P1963R0 <https://wg21.link/P1963R0>`__","LWG","Fixing US 313","Prague","* *","",""
"`P1964R2 <https://wg21.link/P1964R2>`__","LWG","Wording for boolean-testable","Prague","|Complete|","13.0"
"`P1970R2 <https://wg21.link/P1970R2>`__","LWG","Consistency for size() functions: Add ranges::ssize","Prague","|Complete|","15.0","|ranges|"
-"`P1973R1 <https://wg21.link/P1973R1>`__","LWG","Rename ""_default_init"" Functions, Rev1","Prague","* *",""
+"`P1973R1 <https://wg21.link/P1973R1>`__","LWG","Rename ""_default_init"" Functions, Rev1","Prague","|Complete|","16.0"
"`P1976R2 <https://wg21.link/P1976R2>`__","LWG","Fixed-size span construction from dynamic range","Prague","|Complete|","11.0","|ranges|"
"`P1981R0 <https://wg21.link/P1981R0>`__","LWG","Rename leap to leap_second","Prague","* *",""
"`P1982R0 <https://wg21.link/P1982R0>`__","LWG","Rename link to time_zone_link","Prague","* *",""
diff --git a/libcxx/docs/Status/Cxx2b.rst b/libcxx/docs/Status/Cxx2b.rst
index 50d9a02..e79ed28 100644
--- a/libcxx/docs/Status/Cxx2b.rst
+++ b/libcxx/docs/Status/Cxx2b.rst
@@ -39,7 +39,6 @@ Paper Status
.. note::
- .. [#note-P2273] P2273: ``make_unique_for_overwrite`` isn't done yet since `P1020` hasn't been implemented yet.
.. [#note-P0533R9] P0533R9: ``isfinite``, ``isinf``, ``isnan`` and ``isnormal`` are implemented.
.. [#note-P1413R3] P1413R3: ``std::aligned_storage_t`` and ``std::aligned_union_t`` are marked deprecated, but
clang doesn't issue a diagnostic for deprecated using template declarations.
diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv
index ce5e96d..ffc9bed 100644
--- a/libcxx/docs/Status/Cxx2bPapers.csv
+++ b/libcxx/docs/Status/Cxx2bPapers.csv
@@ -44,7 +44,7 @@
"`P1206R7 <https://wg21.link/P1206R7>`__","LWG","``ranges::to``: A function to convert any range to a container","February 2022","","","|ranges|"
"`P1413R3 <https://wg21.link/P1413R3>`__","LWG","Deprecate ``std::aligned_storage`` and ``std::aligned_union``","February 2022","|Complete| [#note-P1413R3]_",""
"`P2255R2 <https://wg21.link/P2255R2>`__","LWG","A type trait to detect reference binding to temporary","February 2022","",""
-"`P2273R3 <https://wg21.link/P2273R3>`__","LWG","Making ``std::unique_ptr`` constexpr","February 2022","|Partial| [#note-P2273]_","16.0"
+"`P2273R3 <https://wg21.link/P2273R3>`__","LWG","Making ``std::unique_ptr`` constexpr","February 2022","|Complete|","16.0"
"`P2387R3 <https://wg21.link/P2387R3>`__","LWG","Pipe support for user-defined range adaptors","February 2022","","","|ranges|"
"`P2440R1 <https://wg21.link/P2440R1>`__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","","","|ranges|"
"`P2441R2 <https://wg21.link/P2441R2>`__","LWG","``views::join_with``","February 2022","","","|ranges|"
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index a76e262..b77ce92 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -260,6 +260,8 @@ __shared_ptr_pointer<_Tp, _Dp, _Alloc>::__on_zero_shared_weak() _NOEXCEPT
__a.deallocate(_PTraits::pointer_to(*this), 1);
}
+struct __default_initialize_tag {};
+
template <class _Tp, class _Alloc>
struct __shared_ptr_emplace
: __shared_weak_count
@@ -278,6 +280,16 @@ struct __shared_ptr_emplace
#endif
}
+
+#if _LIBCPP_STD_VER >= 20
+ _LIBCPP_HIDE_FROM_ABI
+ explicit __shared_ptr_emplace(__default_initialize_tag, _Alloc __a)
+ : __storage_(std::move(__a))
+ {
+ ::new ((void*)__get_elem()) _Tp;
+ }
+#endif
+
_LIBCPP_HIDE_FROM_ABI
_Alloc* __get_alloc() _NOEXCEPT { return __storage_.__get_alloc(); }
@@ -945,6 +957,29 @@ shared_ptr<_Tp> make_shared(_Args&& ...__args)
return _VSTD::allocate_shared<_Tp>(allocator<_Tp>(), _VSTD::forward<_Args>(__args)...);
}
+#if _LIBCPP_STD_VER >= 20
+
+template<class _Tp, class _Alloc, __enable_if_t<!is_array<_Tp>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI
+shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc& __a)
+{
+ using _ControlBlock = __shared_ptr_emplace<_Tp, _Alloc>;
+ using _ControlBlockAllocator = typename __allocator_traits_rebind<_Alloc, _ControlBlock>::type;
+ __allocation_guard<_ControlBlockAllocator> __guard(__a, 1);
+ ::new ((void*)_VSTD::addressof(*__guard.__get())) _ControlBlock(__default_initialize_tag{}, __a);
+ auto __control_block = __guard.__release_ptr();
+ return shared_ptr<_Tp>::__create_with_control_block((*__control_block).__get_elem(), _VSTD::addressof(*__control_block));
+}
+
+template<class _Tp, __enable_if_t<!is_array<_Tp>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI
+shared_ptr<_Tp> make_shared_for_overwrite()
+{
+ return std::allocate_shared_for_overwrite<_Tp>(allocator<_Tp>());
+}
+
+#endif // _LIBCPP_STD_VER >= 20
+
#if _LIBCPP_STD_VER > 14
template <size_t _Alignment>
@@ -975,6 +1010,17 @@ struct __unbounded_array_control_block<_Tp[], _Alloc> : __shared_weak_count
std::__uninitialized_allocator_value_construct_n(__alloc_, std::begin(__data_), __count_);
}
+#if _LIBCPP_STD_VER >= 20
+ _LIBCPP_HIDE_FROM_ABI
+ explicit __unbounded_array_control_block(_Alloc const& __alloc, size_t __count, __default_initialize_tag)
+ : __alloc_(__alloc), __count_(__count)
+ {
+ // We are purposefully not using an allocator-aware default construction because the spec says so.
+ // There's currently no way of expressing default initialization in an allocator-aware manner anyway.
+ std::uninitialized_default_construct_n(std::begin(__data_), __count_);
+ }
+#endif
+
// Returns the number of bytes required to store a control block followed by the given number
// of elements of _Tp, with the whole storage being aligned to a multiple of _Tp's alignment.
_LIBCPP_HIDE_FROM_ABI
@@ -1058,6 +1104,15 @@ struct __bounded_array_control_block<_Tp[_Count], _Alloc>
std::__uninitialized_allocator_value_construct_n(__alloc_, std::addressof(__data_[0]), _Count);
}
+#if _LIBCPP_STD_VER >= 20
+ _LIBCPP_HIDE_FROM_ABI
+ explicit __bounded_array_control_block(_Alloc const& __alloc, __default_initialize_tag) : __alloc_(__alloc) {
+ // We are purposefully not using an allocator-aware default construction because the spec says so.
+ // There's currently no way of expressing default initialization in an allocator-aware manner anyway.
+ std::uninitialized_default_construct_n(std::addressof(__data_[0]), _Count);
+ }
+#endif
+
_LIBCPP_HIDE_FROM_ABI_VIRTUAL
~__bounded_array_control_block() override { } // can't be `= default` because of the sometimes-non-trivial union member __data_
@@ -1101,6 +1156,7 @@ shared_ptr<_Array> __allocate_shared_bounded_array(const _Alloc& __a, _Arg&& ...
#if _LIBCPP_STD_VER > 17
+// bounded array variants
template<class _Tp, class _Alloc, class = __enable_if_t<is_bounded_array<_Tp>::value>>
_LIBCPP_HIDE_FROM_ABI
shared_ptr<_Tp> allocate_shared(const _Alloc& __a)
@@ -1115,18 +1171,11 @@ shared_ptr<_Tp> allocate_shared(const _Alloc& __a, const remove_extent_t<_Tp>& _
return std::__allocate_shared_bounded_array<_Tp>(__a, __u);
}
-template<class _Tp, class _Alloc, class = __enable_if_t<is_unbounded_array<_Tp>::value>>
-_LIBCPP_HIDE_FROM_ABI
-shared_ptr<_Tp> allocate_shared(const _Alloc& __a, size_t __n)
-{
- return std::__allocate_shared_unbounded_array<_Tp>(__a, __n);
-}
-
-template<class _Tp, class _Alloc, class = __enable_if_t<is_unbounded_array<_Tp>::value>>
+template<class _Tp, class _Alloc, __enable_if_t<is_bounded_array<_Tp>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI
-shared_ptr<_Tp> allocate_shared(const _Alloc& __a, size_t __n, const remove_extent_t<_Tp>& __u)
+shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc& __a)
{
- return std::__allocate_shared_unbounded_array<_Tp>(__a, __n, __u);
+ return std::__allocate_shared_bounded_array<_Tp>(__a, __default_initialize_tag{});
}
template<class _Tp, class = __enable_if_t<is_bounded_array<_Tp>::value>>
@@ -1143,6 +1192,35 @@ shared_ptr<_Tp> make_shared(const remove_extent_t<_Tp>& __u)
return std::__allocate_shared_bounded_array<_Tp>(allocator<_Tp>(), __u);
}
+template<class _Tp, __enable_if_t<is_bounded_array<_Tp>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI
+shared_ptr<_Tp> make_shared_for_overwrite()
+{
+ return std::__allocate_shared_bounded_array<_Tp>(allocator<_Tp>(), __default_initialize_tag{});
+}
+
+// unbounded array variants
+template<class _Tp, class _Alloc, class = __enable_if_t<is_unbounded_array<_Tp>::value>>
+_LIBCPP_HIDE_FROM_ABI
+shared_ptr<_Tp> allocate_shared(const _Alloc& __a, size_t __n)
+{
+ return std::__allocate_shared_unbounded_array<_Tp>(__a, __n);
+}
+
+template<class _Tp, class _Alloc, class = __enable_if_t<is_unbounded_array<_Tp>::value>>
+_LIBCPP_HIDE_FROM_ABI
+shared_ptr<_Tp> allocate_shared(const _Alloc& __a, size_t __n, const remove_extent_t<_Tp>& __u)
+{
+ return std::__allocate_shared_unbounded_array<_Tp>(__a, __n, __u);
+}
+
+template<class _Tp, class _Alloc, __enable_if_t<is_unbounded_array<_Tp>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI
+shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc& __a, size_t __n)
+{
+ return std::__allocate_shared_unbounded_array<_Tp>(__a, __n, __default_initialize_tag{});
+}
+
template<class _Tp, class = __enable_if_t<is_unbounded_array<_Tp>::value>>
_LIBCPP_HIDE_FROM_ABI
shared_ptr<_Tp> make_shared(size_t __n)
@@ -1157,6 +1235,13 @@ shared_ptr<_Tp> make_shared(size_t __n, const remove_extent_t<_Tp>& __u)
return std::__allocate_shared_unbounded_array<_Tp>(allocator<_Tp>(), __n, __u);
}
+template<class _Tp, __enable_if_t<is_unbounded_array<_Tp>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI
+shared_ptr<_Tp> make_shared_for_overwrite(size_t __n)
+{
+ return std::__allocate_shared_unbounded_array<_Tp>(allocator<_Tp>(), __n, __default_initialize_tag{});
+}
+
#endif // _LIBCPP_STD_VER > 17
template<class _Tp, class _Up>
diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h
index bb5399d..9cdbda8 100644
--- a/libcxx/include/__memory/unique_ptr.h
+++ b/libcxx/include/__memory/unique_ptr.h
@@ -699,6 +699,25 @@ template<class _Tp, class... _Args>
#endif // _LIBCPP_STD_VER > 11
+#if _LIBCPP_STD_VER >= 20
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 typename __unique_if<_Tp>::__unique_single
+make_unique_for_overwrite() {
+ return unique_ptr<_Tp>(new _Tp);
+}
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 typename __unique_if<_Tp>::__unique_array_unknown_bound
+make_unique_for_overwrite(size_t __n) {
+ return unique_ptr<_Tp>(new __remove_extent_t<_Tp>[__n]);
+}
+
+template<class _Tp, class... _Args>
+typename __unique_if<_Tp>::__unique_array_known_bound make_unique_for_overwrite(_Args&&...) = delete;
+
+#endif // _LIBCPP_STD_VER >= 20
+
template <class _Tp> struct _LIBCPP_TEMPLATE_VIS hash;
template <class _Tp, class _Dp>
diff --git a/libcxx/include/memory b/libcxx/include/memory
index 48e808e..0a7787a 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -569,6 +569,13 @@ template<class T>
constexpr unique_ptr<T> make_unique(size_t n); // C++14, constexpr since C++23
template<class T, class... Args> unspecified make_unique(Args&&...) = delete; // C++14, T == U[N]
+template<class T>
+ constexpr unique_ptr<T> make_unique_for_overwrite(); // T is not array, C++20, constexpr since C++23
+template<class T>
+ constexpr unique_ptr<T> make_unique_for_overwrite(size_t n); // T is U[], C++20, constexpr since C++23
+template<class T, class... Args>
+ unspecified make_unique_for_overwrite(Args&&...) = delete; // T is U[N], C++20
+
template<class E, class T, class Y, class D>
basic_ostream<E, T>& operator<< (basic_ostream<E, T>& os, unique_ptr<Y, D> const& p);
@@ -718,6 +725,16 @@ template<class T, class A>
shared_ptr<T> allocate_shared(const A& a, const remove_extent_t<T>& u); // T is U[N] (since C++20)
template<class T>
+ shared_ptr<T> make_shared_for_overwrite(); // T is not U[], C++20
+template<class T, class A>
+ shared_ptr<T> allocate_shared_for_overwrite(const A& a); // T is not U[], C++20
+
+template<class T>
+ shared_ptr<T> make_shared_for_overwrite(size_t N); // T is U[], C++20
+template<class T, class A>
+ shared_ptr<T> allocate_shared_for_overwrite(const A& a, size_t N); // T is U[], C++20
+
+template<class T>
class weak_ptr
{
public:
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp
new file mode 100644
index 0000000..e69adee
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp
@@ -0,0 +1,190 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17
+
+// template<class T, class A>
+// shared_ptr<T> make_shared_for_overwrite(const A& a); // T is not U[]
+//
+// template<class T, class A>
+// shared_ptr<T> make_shared_for_overwrite(const A& a, size_t N); // T is U[]
+
+#include <cassert>
+#include <concepts>
+#include <cstring>
+#include <memory>
+#include <utility>
+
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
+
+template <class T, class... Args>
+concept HasAllocateSharedForOverwrite =
+ requires(Args&&... args) { std::allocate_shared_for_overwrite<T>(std::forward<Args>(args)...); };
+
+struct Foo {
+ int i;
+};
+
+// non array
+static_assert(!HasAllocateSharedForOverwrite<int>);
+static_assert(!HasAllocateSharedForOverwrite<Foo>);
+static_assert(HasAllocateSharedForOverwrite<int, bare_allocator<void>>);
+static_assert(HasAllocateSharedForOverwrite<Foo, bare_allocator<void>>);
+static_assert(!HasAllocateSharedForOverwrite<int, bare_allocator<void>, std::size_t>);
+static_assert(!HasAllocateSharedForOverwrite<Foo, bare_allocator<void>, std::size_t>);
+
+// bounded array
+static_assert(!HasAllocateSharedForOverwrite<int[2]>);
+static_assert(!HasAllocateSharedForOverwrite<Foo[2]>);
+static_assert(HasAllocateSharedForOverwrite<int[2], bare_allocator<void>>);
+static_assert(HasAllocateSharedForOverwrite<Foo[2], bare_allocator<void>>);
+static_assert(!HasAllocateSharedForOverwrite<int[2], bare_allocator<void>, std::size_t>);
+static_assert(!HasAllocateSharedForOverwrite<Foo[2], bare_allocator<void>, std::size_t>);
+
+// unbounded array
+static_assert(!HasAllocateSharedForOverwrite<int[]>);
+static_assert(!HasAllocateSharedForOverwrite<Foo[]>);
+static_assert(!HasAllocateSharedForOverwrite<int[], bare_allocator<void>>);
+static_assert(!HasAllocateSharedForOverwrite<Foo[], bare_allocator<void>>);
+static_assert(HasAllocateSharedForOverwrite<int[], bare_allocator<void>, std::size_t>);
+static_assert(HasAllocateSharedForOverwrite<Foo[], bare_allocator<void>, std::size_t>);
+
+struct WithDefaultCtor {
+ int i;
+ WithDefaultCtor() : i(42) {}
+};
+
+template <class Alloc>
+void testDefaultConstructor() {
+ // single
+ {
+ std::same_as<std::shared_ptr<WithDefaultCtor>> auto ptr =
+ std::allocate_shared_for_overwrite<WithDefaultCtor>(Alloc{});
+ assert(ptr->i == 42);
+ }
+
+ // bounded array
+ {
+ std::same_as<std::shared_ptr<WithDefaultCtor[2]>> auto ptr =
+ std::allocate_shared_for_overwrite<WithDefaultCtor[2]>(Alloc{});
+ assert(ptr[0].i == 42);
+ assert(ptr[1].i == 42);
+ }
+
+ // unbounded array
+ {
+ std::same_as<std::shared_ptr<WithDefaultCtor[]>> auto ptr =
+ std::allocate_shared_for_overwrite<WithDefaultCtor[]>(Alloc{}, 3);
+ assert(ptr[0].i == 42);
+ assert(ptr[1].i == 42);
+ assert(ptr[2].i == 42);
+ }
+}
+
+void testTypeWithDefaultCtor() {
+ testDefaultConstructor<test_allocator<WithDefaultCtor>>();
+ testDefaultConstructor<min_allocator<WithDefaultCtor>>();
+ testDefaultConstructor<bare_allocator<WithDefaultCtor>>();
+}
+
+void testAllocatorOperationsCalled() {
+ // single
+ {
+ test_allocator_statistics alloc_stats;
+ {
+ [[maybe_unused]] std::same_as<std::shared_ptr<int>> auto ptr =
+ std::allocate_shared_for_overwrite<int>(test_allocator<void>{&alloc_stats});
+ assert(alloc_stats.alloc_count == 1);
+ }
+ assert(alloc_stats.alloc_count == 0);
+ }
+
+ // bounded array
+ {
+ test_allocator_statistics alloc_stats;
+ {
+ [[maybe_unused]] std::same_as<std::shared_ptr<int[2]>> auto ptr =
+ std::allocate_shared_for_overwrite<int[2]>(test_allocator<void>{&alloc_stats});
+ assert(alloc_stats.alloc_count == 1);
+ }
+ assert(alloc_stats.alloc_count == 0);
+ }
+
+ // unbounded array
+ {
+ test_allocator_statistics alloc_stats;
+ {
+ [[maybe_unused]] std::same_as<std::shared_ptr<int[]>> auto ptr =
+ std::allocate_shared_for_overwrite<int[]>(test_allocator<void>{&alloc_stats}, 3);
+ assert(alloc_stats.alloc_count == 1);
+ }
+ assert(alloc_stats.alloc_count == 0);
+ }
+}
+
+template <class T>
+struct AllocatorWithPattern {
+ constexpr static char pattern = 0xDE;
+
+ using value_type = T;
+
+ AllocatorWithPattern() = default;
+
+ template <class U>
+ AllocatorWithPattern(AllocatorWithPattern<U>) noexcept {}
+
+ T* allocate(std::size_t n) {
+ void* ptr = ::operator new(n * sizeof(T));
+ for (std::size_t i = 0; i < n * sizeof(T); ++i) {
+ *(reinterpret_cast<char*>(ptr) + i) = pattern;
+ }
+ return static_cast<T*>(ptr);
+ }
+
+ void deallocate(T* p, std::size_t) { return ::operator delete(static_cast<void*>(p)); }
+};
+
+void testNotValueInitialized() {
+ // single int
+ {
+ std::same_as<std::shared_ptr<int>> decltype(auto) ptr =
+ std::allocate_shared_for_overwrite<int>(AllocatorWithPattern<int>{});
+ assert(*(reinterpret_cast<char*>(ptr.get())) == AllocatorWithPattern<int>::pattern);
+ }
+
+ // bounded array int[N]
+ {
+ std::same_as<std::shared_ptr<int[2]>> decltype(auto) ptr =
+ std::allocate_shared_for_overwrite<int[2]>(AllocatorWithPattern<int>{});
+ assert(*(reinterpret_cast<char*>(&ptr[0])) == AllocatorWithPattern<int>::pattern);
+ assert(*(reinterpret_cast<char*>(&ptr[1])) == AllocatorWithPattern<int>::pattern);
+ }
+
+ // unbounded array int[]
+ {
+ std::same_as<std::shared_ptr<int[]>> decltype(auto) ptr =
+ std::allocate_shared_for_overwrite<int[]>(AllocatorWithPattern<int>{}, 3);
+ assert(*(reinterpret_cast<char*>(&ptr[0])) == AllocatorWithPattern<int>::pattern);
+ assert(*(reinterpret_cast<char*>(&ptr[1])) == AllocatorWithPattern<int>::pattern);
+ assert(*(reinterpret_cast<char*>(&ptr[2])) == AllocatorWithPattern<int>::pattern);
+ }
+}
+
+void test() {
+ testTypeWithDefaultCtor();
+ testAllocatorOperationsCalled();
+ testNotValueInitialized();
+}
+
+int main(int, char**) {
+ test();
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared_for_overwrite.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared_for_overwrite.pass.cpp
new file mode 100644
index 0000000..690a334
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared_for_overwrite.pass.cpp
@@ -0,0 +1,133 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17
+// UNSUPPORTED: sanitizer-new-delete
+
+// template<class T>
+// shared_ptr<T> make_shared_for_overwrite(); // T is not U[]
+//
+// template<class T>
+// shared_ptr<T> make_shared_for_overwrite(size_t N); // T is U[]
+
+#include <cassert>
+#include <concepts>
+#include <cstring>
+#include <memory>
+#include <stdlib.h>
+#include <utility>
+
+#include "test_macros.h"
+
+template <class T, class... Args>
+concept HasMakeSharedForOverwrite =
+ requires(Args&&... args) { std::make_shared_for_overwrite<T>(std::forward<Args>(args)...); };
+
+struct Foo {
+ int i;
+};
+
+// non array
+static_assert(HasMakeSharedForOverwrite<int>);
+static_assert(HasMakeSharedForOverwrite<Foo>);
+static_assert(!HasMakeSharedForOverwrite<int, int>);
+static_assert(!HasMakeSharedForOverwrite<Foo, Foo>);
+
+// bounded array
+static_assert(HasMakeSharedForOverwrite<int[2]>);
+static_assert(!HasMakeSharedForOverwrite<int[2], size_t>);
+static_assert(!HasMakeSharedForOverwrite<int[2], int>);
+static_assert(!HasMakeSharedForOverwrite<int[2], int, int>);
+static_assert(HasMakeSharedForOverwrite<Foo[2]>);
+static_assert(!HasMakeSharedForOverwrite<Foo[2], size_t>);
+static_assert(!HasMakeSharedForOverwrite<Foo[2], int>);
+static_assert(!HasMakeSharedForOverwrite<Foo[2], int, int>);
+
+// unbounded array
+static_assert(HasMakeSharedForOverwrite<int[], size_t>);
+static_assert(HasMakeSharedForOverwrite<Foo[], size_t>);
+static_assert(!HasMakeSharedForOverwrite<int[]>);
+static_assert(!HasMakeSharedForOverwrite<Foo[]>);
+static_assert(!HasMakeSharedForOverwrite<int[], size_t, int>);
+static_assert(!HasMakeSharedForOverwrite<Foo[], size_t, int>);
+
+constexpr char pattern = 0xDE;
+
+void* operator new(std::size_t count) {
+ void* ptr = malloc(count);
+ for (std::size_t i = 0; i < count; ++i) {
+ *(reinterpret_cast<char*>(ptr) + i) = pattern;
+ }
+ return ptr;
+}
+
+void* operator new[](std::size_t count) { return ::operator new(count); }
+
+void operator delete(void* ptr) noexcept { free(ptr); }
+
+void operator delete[](void* ptr) noexcept { ::operator delete(ptr); }
+
+struct WithDefaultConstructor {
+ int i;
+ constexpr WithDefaultConstructor() : i(5) {}
+};
+
+bool test() {
+ // single int
+ {
+ std::same_as<std::shared_ptr<int>> decltype(auto) ptr = std::make_shared_for_overwrite<int>();
+ assert(*(reinterpret_cast<char*>(ptr.get())) == pattern);
+ }
+
+ // bounded array int[N]
+ {
+ std::same_as<std::shared_ptr<int[2]>> decltype(auto) ptr = std::make_shared_for_overwrite<int[2]>();
+ assert(*(reinterpret_cast<char*>(&ptr[0])) == pattern);
+ assert(*(reinterpret_cast<char*>(&ptr[1])) == pattern);
+ }
+
+ // unbounded array int[]
+ {
+ std::same_as<std::shared_ptr<int[]>> decltype(auto) ptr = std::make_shared_for_overwrite<int[]>(3);
+ assert(*(reinterpret_cast<char*>(&ptr[0])) == pattern);
+ assert(*(reinterpret_cast<char*>(&ptr[1])) == pattern);
+ assert(*(reinterpret_cast<char*>(&ptr[2])) == pattern);
+ }
+
+ // single with default constructor
+ {
+ std::same_as<std::shared_ptr<WithDefaultConstructor>> decltype(auto) ptr =
+ std::make_shared_for_overwrite<WithDefaultConstructor>();
+ assert(ptr->i == 5);
+ }
+
+ // bounded array with default constructor
+ {
+ std::same_as<std::shared_ptr<WithDefaultConstructor[2]>> decltype(auto) ptr =
+ std::make_shared_for_overwrite<WithDefaultConstructor[2]>();
+ assert(ptr[0].i == 5);
+ assert(ptr[1].i == 5);
+ }
+
+ // unbounded array with default constructor
+ {
+ std::same_as<std::shared_ptr<WithDefaultConstructor[]>> decltype(auto) ptrs =
+ std::make_shared_for_overwrite<WithDefaultConstructor[]>(3);
+ assert(ptrs[0].i == 5);
+ assert(ptrs[1].i == 5);
+ assert(ptrs[2].i == 5);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.default_init.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.default_init.pass.cpp
new file mode 100644
index 0000000..5f4fbd4
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.default_init.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17
+// UNSUPPORTED: sanitizer-new-delete
+
+// template<class T>
+// constexpr unique_ptr<T> make_unique_for_overwrite(); // T is not array
+//
+// template<class T>
+// constexpr unique_ptr<T> make_unique_for_overwrite(size_t n); // T is U[]
+
+// Test the object is not value initialized
+
+#include <cassert>
+#include <concepts>
+#include <cstddef>
+#include <memory>
+#include <stdlib.h>
+
+constexpr char pattern = 0xDE;
+
+void* operator new(std::size_t count) {
+ void* ptr = malloc(count);
+ for (std::size_t i = 0; i < count; ++i) {
+ *(reinterpret_cast<char*>(ptr) + i) = pattern;
+ }
+ return ptr;
+}
+
+void* operator new[](std::size_t count) { return ::operator new(count); }
+
+void operator delete(void* ptr) noexcept { free(ptr); }
+
+void operator delete[](void* ptr) noexcept { ::operator delete(ptr); }
+
+void test() {
+ {
+ std::same_as<std::unique_ptr<int>> auto ptr = std::make_unique_for_overwrite<int>();
+ assert(*(reinterpret_cast<char*>(ptr.get())) == pattern);
+ }
+ {
+ std::same_as<std::unique_ptr<int[]>> auto ptr = std::make_unique_for_overwrite<int[]>(3);
+ assert(*(reinterpret_cast<char*>(&ptr[0])) == pattern);
+ assert(*(reinterpret_cast<char*>(&ptr[1])) == pattern);
+ assert(*(reinterpret_cast<char*>(&ptr[2])) == pattern);
+ }
+}
+
+int main(int, char**) {
+ test();
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.pass.cpp
new file mode 100644
index 0000000..3f86904
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.pass.cpp
@@ -0,0 +1,149 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17
+
+// template<class T>
+// constexpr unique_ptr<T> make_unique_for_overwrite(); // T is not array
+//
+// template<class T>
+// constexpr unique_ptr<T> make_unique_for_overwrite(size_t n); // T is U[]
+//
+// template<class T, class... Args>
+// unspecified make_unique_for_overwrite(Args&&...) = delete; // T is U[N]
+
+#include <cassert>
+#include <concepts>
+#include <cstring>
+#include <memory>
+#include <utility>
+
+#include "test_macros.h"
+
+template <class T, class... Args>
+concept HasMakeUniqueForOverwrite =
+ requires(Args&&... args) { std::make_unique_for_overwrite<T>(std::forward<Args>(args)...); };
+
+struct Foo {
+ int i;
+};
+
+// template<class T>
+// constexpr unique_ptr<T> make_unique_for_overwrite();
+static_assert(HasMakeUniqueForOverwrite<int>);
+static_assert(HasMakeUniqueForOverwrite<Foo>);
+static_assert(!HasMakeUniqueForOverwrite<int, int>);
+static_assert(!HasMakeUniqueForOverwrite<Foo, Foo>);
+
+// template<class T>
+// constexpr unique_ptr<T> make_unique_for_overwrite(size_t n);
+static_assert(HasMakeUniqueForOverwrite<int[], size_t>);
+static_assert(HasMakeUniqueForOverwrite<Foo[], size_t>);
+static_assert(!HasMakeUniqueForOverwrite<int[]>);
+static_assert(!HasMakeUniqueForOverwrite<Foo[]>);
+static_assert(!HasMakeUniqueForOverwrite<int[], size_t, int>);
+static_assert(!HasMakeUniqueForOverwrite<Foo[], size_t, int>);
+
+// template<class T, class... Args>
+// unspecified make_unique_for_overwrite(Args&&...) = delete;
+static_assert(!HasMakeUniqueForOverwrite<int[2]>);
+static_assert(!HasMakeUniqueForOverwrite<int[2], size_t>);
+static_assert(!HasMakeUniqueForOverwrite<int[2], int>);
+static_assert(!HasMakeUniqueForOverwrite<int[2], int, int>);
+static_assert(!HasMakeUniqueForOverwrite<Foo[2]>);
+static_assert(!HasMakeUniqueForOverwrite<Foo[2], size_t>);
+static_assert(!HasMakeUniqueForOverwrite<Foo[2], int>);
+static_assert(!HasMakeUniqueForOverwrite<Foo[2], int, int>);
+
+struct WithDefaultConstructor {
+ int i;
+ constexpr WithDefaultConstructor() : i(5) {}
+};
+
+TEST_CONSTEXPR_CXX23 bool test() {
+ // single int
+ {
+ std::same_as<std::unique_ptr<int>> decltype(auto) ptr = std::make_unique_for_overwrite<int>();
+ // memory is available for write, otherwise constexpr test would fail
+ *ptr = 5;
+ }
+
+ // unbounded array int[]
+ {
+ std::same_as<std::unique_ptr<int[]>> decltype(auto) ptrs = std::make_unique_for_overwrite<int[]>(3);
+
+ // memory is available for write, otherwise constexpr test would fail
+ ptrs[0] = 3;
+ ptrs[1] = 4;
+ ptrs[2] = 5;
+ }
+
+ // single with default constructor
+ {
+ std::same_as<std::unique_ptr<WithDefaultConstructor>> decltype(auto) ptr =
+ std::make_unique_for_overwrite<WithDefaultConstructor>();
+ assert(ptr->i == 5);
+ }
+
+ // unbounded array with default constructor
+ {
+ std::same_as<std::unique_ptr<WithDefaultConstructor[]>> decltype(auto) ptrs =
+ std::make_unique_for_overwrite<WithDefaultConstructor[]>(3);
+ assert(ptrs[0].i == 5);
+ assert(ptrs[1].i == 5);
+ assert(ptrs[2].i == 5);
+ }
+
+ return true;
+}
+
+// The standard specifically says to use `new (p) T`, which means that we should pick up any
+// custom in-class operator new if there is one.
+struct WithCustomNew {
+ inline static bool customNewCalled = false;
+ inline static bool customNewArrCalled = false;
+
+ static void* operator new(size_t n) {
+ customNewCalled = true;
+ return ::operator new(n);
+ ;
+ }
+
+ static void* operator new[](size_t n) {
+ customNewArrCalled = true;
+ return ::operator new[](n);
+ }
+};
+
+void testCustomNew() {
+ // single with custom operator new
+ {
+ [[maybe_unused]] std::same_as<std::unique_ptr<WithCustomNew>> decltype(auto) ptr =
+ std::make_unique_for_overwrite<WithCustomNew>();
+
+ assert(WithCustomNew::customNewCalled);
+ }
+
+ // unbounded array with custom operator new
+ {
+ [[maybe_unused]] std::same_as<std::unique_ptr<WithCustomNew[]>> decltype(auto) ptr =
+ std::make_unique_for_overwrite<WithCustomNew[]>(3);
+
+ assert(WithCustomNew::customNewArrCalled);
+ }
+}
+
+int main(int, char**) {
+ test();
+ testCustomNew();
+#if TEST_STD_VER >= 23
+ static_assert(test());
+#endif
+
+ return 0;
+}