Skip to content

Commit 9af9d39

Browse files
committed
[libc++] implement P1020R1 P1973R1 make_unique[shared]_for_overwrite
Differential Revision: https://reviews.llvm.org/D140913
1 parent 38a9e1d commit 9af9d39

File tree

11 files changed

+666
-14
lines changed

11 files changed

+666
-14
lines changed

libcxx/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ Implemented Papers
6969
- P1035R7 - Input Range Adaptors
7070
- P2325R3 - Views should not be required to be default constructible
7171
- P2446R2 - ``views::as_rvalue``
72+
- P1020 - Smart pointer creation with default initialization
7273

7374
Improvements and New Features
7475
-----------------------------

libcxx/docs/Status/Cxx20Papers.csv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
"`P0972R0 <https://wg21.link/P0972R0>`__","LWG","<chrono> ``zero()``\ , ``min()``\ , and ``max()``\ should be noexcept","San Diego","|Complete|","8.0"
6868
"`P1006R1 <https://wg21.link/P1006R1>`__","LWG","Constexpr in std::pointer_traits","San Diego","|Complete|","8.0"
6969
"`P1007R3 <https://wg21.link/P1007R3>`__","LWG","``std::assume_aligned``\ ","San Diego","|Complete|","15.0"
70-
"`P1020R1 <https://wg21.link/P1020R1>`__","LWG","Smart pointer creation with default initialization","San Diego","* *",""
70+
"`P1020R1 <https://wg21.link/P1020R1>`__","LWG","Smart pointer creation with default initialization","San Diego","|Complete|","16.0"
7171
"`P1032R1 <https://wg21.link/P1032R1>`__","LWG","Misc constexpr bits","San Diego","|Complete|","13.0"
7272
"`P1085R2 <https://wg21.link/P1085R2>`__","LWG","Should Span be Regular?","San Diego","|Complete|","8.0"
7373
"`P1123R0 <https://wg21.link/P1123R0>`__","LWG","Editorial Guidance for merging P0019r8 and P0528r3","San Diego","* *",""
@@ -177,7 +177,7 @@
177177
"`P1963R0 <https://wg21.link/P1963R0>`__","LWG","Fixing US 313","Prague","* *","",""
178178
"`P1964R2 <https://wg21.link/P1964R2>`__","LWG","Wording for boolean-testable","Prague","|Complete|","13.0"
179179
"`P1970R2 <https://wg21.link/P1970R2>`__","LWG","Consistency for size() functions: Add ranges::ssize","Prague","|Complete|","15.0","|ranges|"
180-
"`P1973R1 <https://wg21.link/P1973R1>`__","LWG","Rename ""_default_init"" Functions, Rev1","Prague","* *",""
180+
"`P1973R1 <https://wg21.link/P1973R1>`__","LWG","Rename ""_default_init"" Functions, Rev1","Prague","|Complete|","16.0"
181181
"`P1976R2 <https://wg21.link/P1976R2>`__","LWG","Fixed-size span construction from dynamic range","Prague","|Complete|","11.0","|ranges|"
182182
"`P1981R0 <https://wg21.link/P1981R0>`__","LWG","Rename leap to leap_second","Prague","* *",""
183183
"`P1982R0 <https://wg21.link/P1982R0>`__","LWG","Rename link to time_zone_link","Prague","* *",""

libcxx/docs/Status/Cxx2b.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ Paper Status
3939

4040
.. note::
4141

42-
.. [#note-P2273] P2273: ``make_unique_for_overwrite`` isn't done yet since `P1020` hasn't been implemented yet.
4342
.. [#note-P0533R9] P0533R9: ``isfinite``, ``isinf``, ``isnan`` and ``isnormal`` are implemented.
4443
.. [#note-P1413R3] P1413R3: ``std::aligned_storage_t`` and ``std::aligned_union_t`` are marked deprecated, but
4544
clang doesn't issue a diagnostic for deprecated using template declarations.

libcxx/docs/Status/Cxx2bPapers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"`P1206R7 <https://wg21.link/P1206R7>`__","LWG","``ranges::to``: A function to convert any range to a container","February 2022","","","|ranges|"
4545
"`P1413R3 <https://wg21.link/P1413R3>`__","LWG","Deprecate ``std::aligned_storage`` and ``std::aligned_union``","February 2022","|Complete| [#note-P1413R3]_",""
4646
"`P2255R2 <https://wg21.link/P2255R2>`__","LWG","A type trait to detect reference binding to temporary","February 2022","",""
47-
"`P2273R3 <https://wg21.link/P2273R3>`__","LWG","Making ``std::unique_ptr`` constexpr","February 2022","|Partial| [#note-P2273]_","16.0"
47+
"`P2273R3 <https://wg21.link/P2273R3>`__","LWG","Making ``std::unique_ptr`` constexpr","February 2022","|Complete|","16.0"
4848
"`P2387R3 <https://wg21.link/P2387R3>`__","LWG","Pipe support for user-defined range adaptors","February 2022","","","|ranges|"
4949
"`P2440R1 <https://wg21.link/P2440R1>`__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","","","|ranges|"
5050
"`P2441R2 <https://wg21.link/P2441R2>`__","LWG","``views::join_with``","February 2022","","","|ranges|"

libcxx/include/__memory/shared_ptr.h

Lines changed: 95 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ __shared_ptr_pointer<_Tp, _Dp, _Alloc>::__on_zero_shared_weak() _NOEXCEPT
260260
__a.deallocate(_PTraits::pointer_to(*this), 1);
261261
}
262262

263+
struct __default_initialize_tag {};
264+
263265
template <class _Tp, class _Alloc>
264266
struct __shared_ptr_emplace
265267
: __shared_weak_count
@@ -278,6 +280,16 @@ struct __shared_ptr_emplace
278280
#endif
279281
}
280282

283+
284+
#if _LIBCPP_STD_VER >= 20
285+
_LIBCPP_HIDE_FROM_ABI
286+
explicit __shared_ptr_emplace(__default_initialize_tag, _Alloc __a)
287+
: __storage_(std::move(__a))
288+
{
289+
::new ((void*)__get_elem()) _Tp;
290+
}
291+
#endif
292+
281293
_LIBCPP_HIDE_FROM_ABI
282294
_Alloc* __get_alloc() _NOEXCEPT { return __storage_.__get_alloc(); }
283295

@@ -945,6 +957,29 @@ shared_ptr<_Tp> make_shared(_Args&& ...__args)
945957
return _VSTD::allocate_shared<_Tp>(allocator<_Tp>(), _VSTD::forward<_Args>(__args)...);
946958
}
947959

960+
#if _LIBCPP_STD_VER >= 20
961+
962+
template<class _Tp, class _Alloc, __enable_if_t<!is_array<_Tp>::value, int> = 0>
963+
_LIBCPP_HIDE_FROM_ABI
964+
shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc& __a)
965+
{
966+
using _ControlBlock = __shared_ptr_emplace<_Tp, _Alloc>;
967+
using _ControlBlockAllocator = typename __allocator_traits_rebind<_Alloc, _ControlBlock>::type;
968+
__allocation_guard<_ControlBlockAllocator> __guard(__a, 1);
969+
::new ((void*)_VSTD::addressof(*__guard.__get())) _ControlBlock(__default_initialize_tag{}, __a);
970+
auto __control_block = __guard.__release_ptr();
971+
return shared_ptr<_Tp>::__create_with_control_block((*__control_block).__get_elem(), _VSTD::addressof(*__control_block));
972+
}
973+
974+
template<class _Tp, __enable_if_t<!is_array<_Tp>::value, int> = 0>
975+
_LIBCPP_HIDE_FROM_ABI
976+
shared_ptr<_Tp> make_shared_for_overwrite()
977+
{
978+
return std::allocate_shared_for_overwrite<_Tp>(allocator<_Tp>());
979+
}
980+
981+
#endif // _LIBCPP_STD_VER >= 20
982+
948983
#if _LIBCPP_STD_VER > 14
949984

950985
template <size_t _Alignment>
@@ -975,6 +1010,17 @@ struct __unbounded_array_control_block<_Tp[], _Alloc> : __shared_weak_count
9751010
std::__uninitialized_allocator_value_construct_n(__alloc_, std::begin(__data_), __count_);
9761011
}
9771012

1013+
#if _LIBCPP_STD_VER >= 20
1014+
_LIBCPP_HIDE_FROM_ABI
1015+
explicit __unbounded_array_control_block(_Alloc const& __alloc, size_t __count, __default_initialize_tag)
1016+
: __alloc_(__alloc), __count_(__count)
1017+
{
1018+
// We are purposefully not using an allocator-aware default construction because the spec says so.
1019+
// There's currently no way of expressing default initialization in an allocator-aware manner anyway.
1020+
std::uninitialized_default_construct_n(std::begin(__data_), __count_);
1021+
}
1022+
#endif
1023+
9781024
// Returns the number of bytes required to store a control block followed by the given number
9791025
// of elements of _Tp, with the whole storage being aligned to a multiple of _Tp's alignment.
9801026
_LIBCPP_HIDE_FROM_ABI
@@ -1058,6 +1104,15 @@ struct __bounded_array_control_block<_Tp[_Count], _Alloc>
10581104
std::__uninitialized_allocator_value_construct_n(__alloc_, std::addressof(__data_[0]), _Count);
10591105
}
10601106

1107+
#if _LIBCPP_STD_VER >= 20
1108+
_LIBCPP_HIDE_FROM_ABI
1109+
explicit __bounded_array_control_block(_Alloc const& __alloc, __default_initialize_tag) : __alloc_(__alloc) {
1110+
// We are purposefully not using an allocator-aware default construction because the spec says so.
1111+
// There's currently no way of expressing default initialization in an allocator-aware manner anyway.
1112+
std::uninitialized_default_construct_n(std::addressof(__data_[0]), _Count);
1113+
}
1114+
#endif
1115+
10611116
_LIBCPP_HIDE_FROM_ABI_VIRTUAL
10621117
~__bounded_array_control_block() override { } // can't be `= default` because of the sometimes-non-trivial union member __data_
10631118

@@ -1101,6 +1156,7 @@ shared_ptr<_Array> __allocate_shared_bounded_array(const _Alloc& __a, _Arg&& ...
11011156

11021157
#if _LIBCPP_STD_VER > 17
11031158

1159+
// bounded array variants
11041160
template<class _Tp, class _Alloc, class = __enable_if_t<is_bounded_array<_Tp>::value>>
11051161
_LIBCPP_HIDE_FROM_ABI
11061162
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>& _
11151171
return std::__allocate_shared_bounded_array<_Tp>(__a, __u);
11161172
}
11171173

1118-
template<class _Tp, class _Alloc, class = __enable_if_t<is_unbounded_array<_Tp>::value>>
1119-
_LIBCPP_HIDE_FROM_ABI
1120-
shared_ptr<_Tp> allocate_shared(const _Alloc& __a, size_t __n)
1121-
{
1122-
return std::__allocate_shared_unbounded_array<_Tp>(__a, __n);
1123-
}
1124-
1125-
template<class _Tp, class _Alloc, class = __enable_if_t<is_unbounded_array<_Tp>::value>>
1174+
template<class _Tp, class _Alloc, __enable_if_t<is_bounded_array<_Tp>::value, int> = 0>
11261175
_LIBCPP_HIDE_FROM_ABI
1127-
shared_ptr<_Tp> allocate_shared(const _Alloc& __a, size_t __n, const remove_extent_t<_Tp>& __u)
1176+
shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc& __a)
11281177
{
1129-
return std::__allocate_shared_unbounded_array<_Tp>(__a, __n, __u);
1178+
return std::__allocate_shared_bounded_array<_Tp>(__a, __default_initialize_tag{});
11301179
}
11311180

11321181
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)
11431192
return std::__allocate_shared_bounded_array<_Tp>(allocator<_Tp>(), __u);
11441193
}
11451194

1195+
template<class _Tp, __enable_if_t<is_bounded_array<_Tp>::value, int> = 0>
1196+
_LIBCPP_HIDE_FROM_ABI
1197+
shared_ptr<_Tp> make_shared_for_overwrite()
1198+
{
1199+
return std::__allocate_shared_bounded_array<_Tp>(allocator<_Tp>(), __default_initialize_tag{});
1200+
}
1201+
1202+
// unbounded array variants
1203+
template<class _Tp, class _Alloc, class = __enable_if_t<is_unbounded_array<_Tp>::value>>
1204+
_LIBCPP_HIDE_FROM_ABI
1205+
shared_ptr<_Tp> allocate_shared(const _Alloc& __a, size_t __n)
1206+
{
1207+
return std::__allocate_shared_unbounded_array<_Tp>(__a, __n);
1208+
}
1209+
1210+
template<class _Tp, class _Alloc, class = __enable_if_t<is_unbounded_array<_Tp>::value>>
1211+
_LIBCPP_HIDE_FROM_ABI
1212+
shared_ptr<_Tp> allocate_shared(const _Alloc& __a, size_t __n, const remove_extent_t<_Tp>& __u)
1213+
{
1214+
return std::__allocate_shared_unbounded_array<_Tp>(__a, __n, __u);
1215+
}
1216+
1217+
template<class _Tp, class _Alloc, __enable_if_t<is_unbounded_array<_Tp>::value, int> = 0>
1218+
_LIBCPP_HIDE_FROM_ABI
1219+
shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc& __a, size_t __n)
1220+
{
1221+
return std::__allocate_shared_unbounded_array<_Tp>(__a, __n, __default_initialize_tag{});
1222+
}
1223+
11461224
template<class _Tp, class = __enable_if_t<is_unbounded_array<_Tp>::value>>
11471225
_LIBCPP_HIDE_FROM_ABI
11481226
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)
11571235
return std::__allocate_shared_unbounded_array<_Tp>(allocator<_Tp>(), __n, __u);
11581236
}
11591237

1238+
template<class _Tp, __enable_if_t<is_unbounded_array<_Tp>::value, int> = 0>
1239+
_LIBCPP_HIDE_FROM_ABI
1240+
shared_ptr<_Tp> make_shared_for_overwrite(size_t __n)
1241+
{
1242+
return std::__allocate_shared_unbounded_array<_Tp>(allocator<_Tp>(), __n, __default_initialize_tag{});
1243+
}
1244+
11601245
#endif // _LIBCPP_STD_VER > 17
11611246

11621247
template<class _Tp, class _Up>

libcxx/include/__memory/unique_ptr.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,25 @@ template<class _Tp, class... _Args>
699699

700700
#endif // _LIBCPP_STD_VER > 11
701701

702+
#if _LIBCPP_STD_VER >= 20
703+
704+
template <class _Tp>
705+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 typename __unique_if<_Tp>::__unique_single
706+
make_unique_for_overwrite() {
707+
return unique_ptr<_Tp>(new _Tp);
708+
}
709+
710+
template <class _Tp>
711+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 typename __unique_if<_Tp>::__unique_array_unknown_bound
712+
make_unique_for_overwrite(size_t __n) {
713+
return unique_ptr<_Tp>(new __remove_extent_t<_Tp>[__n]);
714+
}
715+
716+
template<class _Tp, class... _Args>
717+
typename __unique_if<_Tp>::__unique_array_known_bound make_unique_for_overwrite(_Args&&...) = delete;
718+
719+
#endif // _LIBCPP_STD_VER >= 20
720+
702721
template <class _Tp> struct _LIBCPP_TEMPLATE_VIS hash;
703722

704723
template <class _Tp, class _Dp>

libcxx/include/memory

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,13 @@ template<class T>
569569
constexpr unique_ptr<T> make_unique(size_t n); // C++14, constexpr since C++23
570570
template<class T, class... Args> unspecified make_unique(Args&&...) = delete; // C++14, T == U[N]
571571
572+
template<class T>
573+
constexpr unique_ptr<T> make_unique_for_overwrite(); // T is not array, C++20, constexpr since C++23
574+
template<class T>
575+
constexpr unique_ptr<T> make_unique_for_overwrite(size_t n); // T is U[], C++20, constexpr since C++23
576+
template<class T, class... Args>
577+
unspecified make_unique_for_overwrite(Args&&...) = delete; // T is U[N], C++20
578+
572579
template<class E, class T, class Y, class D>
573580
basic_ostream<E, T>& operator<< (basic_ostream<E, T>& os, unique_ptr<Y, D> const& p);
574581
@@ -717,6 +724,16 @@ template<class T> shared_ptr<T>
717724
template<class T, class A>
718725
shared_ptr<T> allocate_shared(const A& a, const remove_extent_t<T>& u); // T is U[N] (since C++20)
719726
727+
template<class T>
728+
shared_ptr<T> make_shared_for_overwrite(); // T is not U[], C++20
729+
template<class T, class A>
730+
shared_ptr<T> allocate_shared_for_overwrite(const A& a); // T is not U[], C++20
731+
732+
template<class T>
733+
shared_ptr<T> make_shared_for_overwrite(size_t N); // T is U[], C++20
734+
template<class T, class A>
735+
shared_ptr<T> allocate_shared_for_overwrite(const A& a, size_t N); // T is U[], C++20
736+
720737
template<class T>
721738
class weak_ptr
722739
{

0 commit comments

Comments
 (0)