[libcxx-commits] [libcxx] 9af9d39 - [libc++] implement P1020R1 P1973R1 make_unique[shared]_for_overwrite

via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jan 23 13:08:21 PST 2023


Author: Hui
Date: 2023-01-23T21:07:22Z
New Revision: 9af9d39a47dc634b7de17708a4daf226ca699751

URL: https://github.com/llvm/llvm-project/commit/9af9d39a47dc634b7de17708a4daf226ca699751
DIFF: https://github.com/llvm/llvm-project/commit/9af9d39a47dc634b7de17708a4daf226ca699751.diff

LOG: [libc++] implement P1020R1 P1973R1 make_unique[shared]_for_overwrite

Differential Revision: https://reviews.llvm.org/D140913

Added: 
    libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp
    libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared_for_overwrite.pass.cpp
    libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.default_init.pass.cpp
    libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.pass.cpp

Modified: 
    libcxx/docs/ReleaseNotes.rst
    libcxx/docs/Status/Cxx20Papers.csv
    libcxx/docs/Status/Cxx2b.rst
    libcxx/docs/Status/Cxx2bPapers.csv
    libcxx/include/__memory/shared_ptr.h
    libcxx/include/__memory/unique_ptr.h
    libcxx/include/memory

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index c0e55424294ff..345dd53d21884 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 48405b8b6f4b3..3999b013cb425 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 50d9a029a3e6b..e79ed285c644d 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 ce5e96d2f91ff..ffc9bed969fcc 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 a76e262ea0516..b77ce9230bff4 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 bb5399d78fc40..9cdbda8eba409 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 48e808ef54cb1..0a7787acf1a8e 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);
 
@@ -717,6 +724,16 @@ template<class T> shared_ptr<T>
 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
 {

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 0000000000000..e69adeeb3ea69
--- /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 0000000000000..690a334557161
--- /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 0000000000000..5f4fbd4232fa8
--- /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 0000000000000..3f86904798fb8
--- /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;
+}


        


More information about the libcxx-commits mailing list