From b2dc09e7063604984f56390edeb549861d3095c6 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Thu, 24 Sep 2020 16:24:29 +0200 Subject: [PATCH 01/24] Implement P1020R1 and P1973R1 --- stl/inc/memory | 170 +++++++++ stl/inc/xutility | 6 + stl/inc/yvals_core.h | 3 + tests/std/test.lst | 1 + .../env.lst | 4 + .../test.cpp | 336 ++++++++++++++++++ .../VSO_0157762_feature_test_macros/test.cpp | 14 + 7 files changed, 534 insertions(+) create mode 100644 tests/std/tests/P1020R1_smart_pointer_for_overwrite/env.lst create mode 100644 tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp diff --git a/stl/inc/memory b/stl/inc/memory index dcfded85434..05730b1db23 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -1935,6 +1935,20 @@ private: template friend enable_if_t, shared_ptr<_Ty0>> allocate_shared( const _Alloc& _Al_arg, const remove_extent_t<_Ty0>& _Val); + + template + friend enable_if_t, shared_ptr<_Ty0>> make_shared_for_overwrite(); + + template + friend enable_if_t, shared_ptr<_Ty0>> allocate_shared_for_overwrite( + const _Alloc& _Al_arg); + + template + friend enable_if_t, shared_ptr<_Ty0>> make_shared_for_overwrite(size_t _Count); + + template + friend enable_if_t, shared_ptr<_Ty0>> allocate_shared_for_overwrite( + const _Alloc& _Al_arg, size_t _Count); #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template friend shared_ptr<_Ty0> make_shared(_Types&&... _Args); @@ -2163,6 +2177,10 @@ template _Dx* get_deleter(const shared_ptr<_Ty>&) noexcept = delete; // requires static RTTI #endif // _HAS_STATIC_RTTI +struct _For_overwrite_tag { + explicit _For_overwrite_tag() = default; +}; + // CLASS TEMPLATE _Ref_count_obj2 template class _Ref_count_obj2 : public _Ref_count_base { // handle reference counting for object in control block, no allocator @@ -2172,6 +2190,10 @@ public: _Construct_in_place(_Storage._Value, _STD forward<_Types>(_Args)...); } + explicit _Ref_count_obj2(_For_overwrite_tag) : _Ref_count_base() { + _Construct_in_place_for_overwrite(_Storage._Value); + } + ~_Ref_count_obj2() { // nothing to do, _Storage._Value was already destroyed in _Destroy @@ -2282,6 +2304,11 @@ struct _Uninitialized_rev_destroying_backout { ++_Last; } + void _Emplace_back_for_overwrite() { + _Construct_in_place_for_overwrite(*_Last); + ++_Last; + } + _NoThrowIt _Release() noexcept { // suppress any exception handling backout and return _Last _First = _Last; return _Last; @@ -2351,6 +2378,26 @@ void _Uninitialized_value_construct_multidimensional_n(_Ty* const _Out, const si } } +template +void _Uninitialized_default_construct_multidimensional_n(_Ty* const _Out, const size_t _Size) { + using _Item = remove_all_extents_t<_Ty>; + if constexpr (!is_trivially_default_constructible_v<_Ty>) { + if constexpr (is_array_v<_Ty>) { + _Reverse_destroy_multidimensional_n_guard<_Ty> _Guard{_Out, 0}; + for (size_t& _Idx = _Guard._Index; _Idx < _Size; ++_Idx) { + _Uninitialized_default_construct_multidimensional_n(_Out[_Idx], extent_v<_Ty>); + } + _Guard._Target = nullptr; + } else { + _Uninitialized_rev_destroying_backout _Backout{_Out}; + for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { + _Backout._Emplace_back_for_overwrite(); + } + _Backout._Release(); + } + } +} + template void _Uninitialized_fill_multidimensional_n(_Ty* const _Out, const size_t _Size, const _Ty& _Val) { if constexpr (is_array_v<_Ty>) { @@ -2387,6 +2434,10 @@ public: _Uninitialized_fill_multidimensional_n(_Get_ptr(), _Count, _Val); } + explicit _Ref_count_unbounded_array(const size_t _Count, _For_overwrite_tag) : _Ref_count_base() { + _Uninitialized_default_construct_multidimensional_n(_Get_ptr(), _Count); + } + _NODISCARD auto _Get_ptr() noexcept { return _STD addressof(_Storage._Value); } @@ -2429,6 +2480,10 @@ public: _Uninitialized_fill_multidimensional_n(_Get_ptr(), _Size, _Val); } + explicit _Ref_count_unbounded_array(const size_t _Count, _For_overwrite_tag) : _Ref_count_base(), _Size(_Count) { + _Uninitialized_default_construct_multidimensional_n(_Get_ptr(), _Size); + } + _NODISCARD auto _Get_ptr() noexcept { return _STD addressof(_Storage._Value); } @@ -2470,6 +2525,10 @@ public: _Uninitialized_fill_multidimensional_n(_Storage._Value, extent_v<_Ty>, _Val); } + explicit _Ref_count_bounded_array(_For_overwrite_tag) : _Ref_count_base() { + _Uninitialized_default_construct_multidimensional_n(_Storage._Value, extent_v<_Ty>); + } + union { _Wrap<_Ty> _Storage; }; @@ -2548,6 +2607,11 @@ public: this->_Get_val(), _STD addressof(_Storage._Value), _STD forward<_Types>(_Args)...); } + explicit _Ref_count_obj_alloc3(const _Alloc& _Al_arg, _For_overwrite_tag) + : _Ebco_base<_Rebound>(_Al_arg), _Ref_count_base() { + _Construct_in_place_for_overwrite(_Storage._Value); + } + union { _Wrap<_Ty> _Storage; }; @@ -2718,6 +2782,11 @@ public: _Uninitialized_fill_multidimensional_n_al(_Get_ptr(), _Size, _Val, this->_Get_val()); } + explicit _Ref_count_unbounded_array_alloc(const _Alloc& _Al_arg, const size_t _Count, _For_overwrite_tag) + : _Ebco_base<_Rebound>(_Al_arg), _Ref_count_base(), _Size(_Count) { + _Uninitialized_default_construct_multidimensional_n(_Get_ptr(), _Size); // the allocator isn't needed + } + _NODISCARD auto _Get_ptr() noexcept { return _STD addressof(_Storage._Value); } @@ -2779,6 +2848,12 @@ public: _Uninitialized_fill_multidimensional_n_al(_Storage._Value, extent_v<_Ty>, _Val, this->_Get_val()); } + explicit _Ref_count_bounded_array_alloc(const _Alloc& _Al_arg, _For_overwrite_tag) + : _Ebco_base<_Rebound>(_Al_arg), _Ref_count_base() { // don't value-initialize _Storage + _Uninitialized_default_construct_multidimensional_n( + _Storage._Value, extent_v<_Ty>); // the allocator isn't needed + } + union { _Wrap<_Ty> _Storage; }; @@ -2878,6 +2953,36 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> make_shared(con _Ret._Set_ptr_rep_and_enable_shared(_Rx->_Storage._Value, _Rx); return _Ret; } + +// FUNCTION TEMPLATE make_shared_for_overwrite +template +_NODISCARD enable_if_t, shared_ptr<_Ty>> make_shared_for_overwrite() { + shared_ptr<_Ty> _Ret; + if constexpr (!is_array_v<_Ty>) { + // make a shared_ptr to non-array object + const auto _Rx = new _Ref_count_obj2<_Ty>(_For_overwrite_tag{}); + _Ret._Set_ptr_rep_and_enable_shared(_STD addressof(_Rx->_Storage._Value), _Rx); + } else { + // make a shared_ptr to a bounded array + const auto _Rx = new _Ref_count_bounded_array<_Ty>(_For_overwrite_tag{}); + _Ret._Set_ptr_rep_and_enable_shared(_Rx->_Storage._Value, _Rx); + } + return _Ret; +} + + +template +_NODISCARD enable_if_t, shared_ptr<_Ty>> make_shared_for_overwrite(size_t _Count) { + // make a shared_ptr to an unbounded array + using _Refc = _Ref_count_unbounded_array<_Ty>; + const auto _Rx = _Allocate_flexible_array<_Refc>(_Count); + _Global_delete_guard<_Refc> _Guard{_Rx}; + ::new (static_cast(_Rx)) _Refc(_Count, _For_overwrite_tag{}); + _Guard._Target = nullptr; + shared_ptr<_Ty> _Ret; + _Ret._Set_ptr_rep_and_enable_shared(_Rx->_Get_ptr(), _Rx); + return _Ret; +} #endif // _HAS_CXX20 // FUNCTION TEMPLATE allocate_shared @@ -2990,6 +3095,54 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shared _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); return _Ret; } + +// FUNCTION TEMPLATE allocate_shared_for_overwrite +template +_NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shared_for_overwrite(const _Alloc& _Al) { + shared_ptr<_Ty> _Ret; + if constexpr (!is_array_v<_Ty>) { + // make a shared_ptr to non-array object + using _Refoa = _Ref_count_obj_alloc3, _Alloc>; + using _Alblock = _Rebind_alloc_t<_Alloc, _Refoa>; + _Alblock _Rebound(_Al); + _Alloc_construct_ptr<_Alblock> _Constructor{_Rebound}; + _Constructor._Allocate(); + _Construct_in_place(*_Constructor._Ptr, _Al, _For_overwrite_tag{}); + const auto _Ptr = reinterpret_cast<_Ty*>(_STD addressof(_Constructor._Ptr->_Storage._Value)); + _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); + } else { + // make a shared_ptr to a bounded array + using _Refc = _Ref_count_bounded_array_alloc, _Alloc>; + using _Alblock = _Rebind_alloc_t<_Alloc, _Refc>; + _Alblock _Rebound(_Al); + _Alloc_construct_ptr _Constructor{_Rebound}; + _Constructor._Allocate(); + ::new (static_cast(_Unfancy(_Constructor._Ptr))) _Refc(_Al, _For_overwrite_tag{}); + const auto _Ptr = static_cast*>(_Constructor._Ptr->_Storage._Value); + _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); + } + + return _Ret; +} + +template +_NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shared_for_overwrite( + const _Alloc& _Al, const size_t _Count) { + // make a shared_ptr to an unbounded array + using _Refc = _Ref_count_unbounded_array_alloc, _Alloc>; + constexpr size_t _Align = alignof(_Refc); + using _Storage = _Alignas_storage_unit<_Align>; + _Rebind_alloc_t<_Alloc, _Storage> _Rebound(_Al); + const size_t _Bytes = _Calculate_bytes_for_flexible_array<_Refc, _Check_overflow::_Yes>(_Count); + const size_t _Storage_units = _Bytes / sizeof(_Storage); + _Allocate_n_ptr _Guard{_Rebound, _Storage_units}; + const auto _Rx = reinterpret_cast<_Refc*>(_Unfancy(_Guard._Ptr)); + ::new (static_cast(_Rx)) _Refc(_Al, _Count, _For_overwrite_tag{}); + _Guard._Ptr = nullptr; + shared_ptr<_Ty> _Ret; + _Ret._Set_ptr_rep_and_enable_shared(_Rx->_Get_ptr(), _Rx); + return _Ret; +} #endif // _HAS_CXX20 // CLASS TEMPLATE weak_ptr @@ -3450,6 +3603,23 @@ _NODISCARD unique_ptr<_Ty> make_unique(size_t _Size) { // make a unique_ptr template != 0, int> = 0> void make_unique(_Types&&...) = delete; +#if _HAS_CXX20 +// FUNCTION TEMPLATE make_unique_for_overwrite +template , int> = 0> +_NODISCARD unique_ptr<_Ty> make_unique_for_overwrite() { // make a unique_ptr with default initialization + return unique_ptr<_Ty>(new _Ty); +} + +template && extent_v<_Ty> == 0, int> = 0> +_NODISCARD unique_ptr<_Ty> make_unique_for_overwrite(size_t _Size) { // make a unique_ptr with default initialization + using _Elem = remove_extent_t<_Ty>; + return unique_ptr<_Ty>(new _Elem[_Size]); +} + +template != 0, int> = 0> +void make_unique_for_overwrite(_Types&&...) = delete; +#endif + template ::value, int> = 0> void swap(unique_ptr<_Ty, _Dx>& _Left, unique_ptr<_Ty, _Dx>& _Right) noexcept { _Left.swap(_Right); diff --git a/stl/inc/xutility b/stl/inc/xutility index 0a402f4d210..d2d0589fdcd 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -126,6 +126,12 @@ void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept(is_nothrow_const _Ty(_STD forward<_Types>(_Args)...); } +// FUNCTION TEMPLATE _Construct_in_place_for_overwrite +template +void _Construct_in_place_for_overwrite(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { + ::new (const_cast(static_cast(_STD addressof(_Obj)))) _Ty; +} + // STRUCT TEMPLATE pointer_traits template struct pointer_traits { diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 123e4a46dc2..3b67c9da81e 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -178,6 +178,7 @@ // P1001R2 execution::unseq // P1006R1 constexpr For pointer_traits::pointer_to() // P1007R3 assume_aligned() +// P1020R1 Smart Pointer Creation With Default Initialization // P1023R0 constexpr For std::array Comparisons // P1024R3 Enhancing span Usability // P1032R1 Miscellaneous constexpr @@ -218,6 +219,7 @@ // P1959R0 Removing weak_equality And strong_equality // P1960R0 atomic_ref Cleanup // P1964R2 Replacing boolean With boolean-testable +// P1973R1 Renaming default_init To for_overwrite // P1976R2 Explicit Constructors For Fixed-Extent span From Dynamic-Extent Ranges // P2091R0 Fixing Issues With Range Access CPOs // P2102R0 Making "Implicit Expression Variations" More Explicit @@ -1206,6 +1208,7 @@ #define __cpp_lib_remove_cvref 201711L #define __cpp_lib_semaphore 201907L #define __cpp_lib_shift 201806L +#define __cpp_lib_smart_ptr_for_overwrite 201811L #define __cpp_lib_span 202002L #define __cpp_lib_ssize 201902L #define __cpp_lib_starts_ends_with 201711L diff --git a/tests/std/test.lst b/tests/std/test.lst index 3f2fc7c9ef9..0a343fea00e 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -349,6 +349,7 @@ tests\P0912R5_coroutine tests\P0919R3_heterogeneous_unordered_lookup tests\P0966R1_string_reserve_should_not_shrink tests\P1007R3_assume_aligned +tests\P1020R1_smart_pointer_for_overwrite tests\P1023R0_constexpr_for_array_comparisons tests\P1032R1_miscellaneous_constexpr tests\P1135R6_atomic_flag_test diff --git a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/env.lst b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp new file mode 100644 index 00000000000..8e5fd6eae24 --- /dev/null +++ b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp @@ -0,0 +1,336 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +int allocationCount = 0; +int canCreate = 10; // Counter to force an exception when constructing a + // sufficiently large ReportAddress array + +struct ReportAddress; +vector ascendingAddressBuffer; +vector descendingAddressBuffer; + +// According to N4849, the default behavior of operator new[](size) is to return +// operator new(size), so only the latter needs to be replaced. +void* operator new(size_t size) { + void* const p = ::operator new(size, nothrow); + + if (p) { + return p; + } else { + throw bad_alloc(); + } +} + +void* operator new(size_t size, const nothrow_t&) noexcept { + void* const result = malloc(size == 0 ? 1 : size); + ++allocationCount; + if (result) { + memset(result, 0xEE, size); + } + + return result; +} + +void* operator new(size_t size, align_val_t align) { + void* const p = ::operator new(size, align, nothrow); + + if (p) { + return p; + } else { + throw bad_alloc(); + } +} + +void* operator new(size_t size, align_val_t align, const nothrow_t&) noexcept { + void* const result = ::_aligned_malloc(size, static_cast(align)); + ++allocationCount; + if (result) { + memset(result, 0xEE, size); + } + + return result; +} + +// Helper struct to check if type T is default initable without arguments. +template +struct unique_is_for_overwritable : false_type {}; + +template +struct unique_is_for_overwritable())>> : true_type {}; + +template +constexpr bool unique_is_for_overwritable_v = unique_is_for_overwritable::value; + +struct DefaultInitializableInt { + int value; + DefaultInitializableInt() : value(106) {} +}; + +struct alignas(32) HighlyAligned { + uint64_t a; + uint64_t b; + uint64_t c; + uint64_t d; +}; + +struct ReportAddress { + ReportAddress() { + if (canCreate > 0) { + ascendingAddressBuffer.push_back(this); + --canCreate; + } else { + throw runtime_error("Can't create more ReportAddress objects."); + } + } + + ~ReportAddress() { + ++canCreate; + descendingAddressBuffer.push_back(this); + } +}; + +void assert_ascending_init() { + for (size_t i = 1; i < ascendingAddressBuffer.size(); ++i) { + assert(ascendingAddressBuffer[i - 1] < ascendingAddressBuffer[i]); + } + + ascendingAddressBuffer.clear(); +} + +void assert_descending_destruct() { + for (size_t i = 1; i < descendingAddressBuffer.size(); ++i) { + assert(descendingAddressBuffer[i - 1] > descendingAddressBuffer[i]); + } + + descendingAddressBuffer.clear(); +} + +void assert_uninitialized(void* p, size_t size) { + unsigned char* chPtr = reinterpret_cast(p); + for (unsigned int offset = 0; offset < size; ++offset) { + assert(*(chPtr + offset) == 0xEE); + } +} + +template +void assert_shared_use_get(const shared_ptr& sp) { + assert(sp.use_count() == 1); + assert(sp.get() != nullptr); +} + +template +shared_ptr make_shared_for_overwrite_assert(Args&&... vals) { + int count = allocationCount; + shared_ptr sp = make_shared_for_overwrite(forward(vals)...); + assert_shared_use_get(sp); + assert(count + 1 == allocationCount); + return sp; +} + +template +void test_make_init_destruct_order(Args&&... vals) { + try { + shared_ptr sp = make_shared_for_overwrite(forward(vals)...); + assert_shared_use_get(sp); + } catch (const runtime_error& exc) { + assert(exc.what() == "Can't create more ReportAddress objects."sv); + } + + assert_ascending_init(); + assert_descending_destruct(); +} + +void test_make_unique_for_overwrite() { + static_assert(unique_is_for_overwritable_v); + static_assert(!unique_is_for_overwritable_v); + + auto p0 = make_unique_for_overwrite(); + assert_uninitialized(addressof(*p0), sizeof(int)); + + auto p1 = make_unique_for_overwrite(100u); + assert_uninitialized(addressof(p1[0]), sizeof(int) * 100u); + + auto p2 = make_unique_for_overwrite(); + assert(p2->value == 106); + + auto p3 = make_unique_for_overwrite(2u); + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 89; ++j) { + assert(p3[i][j].value == 106); + } + } + + auto p4 = make_unique_for_overwrite(0u); // p4 cannot be dereferenced +} + +void test_make_shared_for_overwrite() { + auto p0 = make_shared_for_overwrite_assert(); + assert_uninitialized(addressof(*p0), sizeof(int)); + + auto p1 = make_shared_for_overwrite_assert(); + assert(p1->value == 106); + + auto p2 = make_shared_for_overwrite_assert(); + assert(reinterpret_cast(p2.get()) % alignof(HighlyAligned) == 0); + assert_uninitialized(addressof(*p2), sizeof(HighlyAligned)); + + auto p3 = make_shared_for_overwrite_assert(); + assert_uninitialized(addressof(p3[0]), sizeof(int) * 100u); + + auto p4 = make_shared_for_overwrite_assert(); + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 8; ++j) { + assert(p4[i][j].value == 106); + } + } + + auto p5 = make_shared_for_overwrite_assert(); + assert(reinterpret_cast(p5.get()) % alignof(HighlyAligned) == 0); + assert_uninitialized(addressof(p5[0]), sizeof(HighlyAligned) * 10u); + + auto p6 = make_shared_for_overwrite_assert(100u); + for (int i = 0; i < 100; ++i) { + assert(p6[i].value == 106); + } + + auto p7 = make_shared_for_overwrite_assert(2u); + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 8; ++j) { + for (int k = 0; k < 9; ++k) { + assert(p7[i][j][k].value == 106); + } + } + } + + auto p8 = make_shared_for_overwrite_assert(100u); + assert_uninitialized(addressof(p8[0]), sizeof(int) * 100u); + + auto p9 = make_shared_for_overwrite_assert(0u); // p9 cannot be dereferenced + + auto p10 = make_shared_for_overwrite_assert(10u); + assert(reinterpret_cast(p10.get()) % alignof(HighlyAligned) == 0); + assert_uninitialized(addressof(p10[0]), sizeof(HighlyAligned) * 10u); + + test_make_init_destruct_order(); // success one dimensional + + test_make_init_destruct_order(); // failure one dimensional + + test_make_init_destruct_order(); // success multidimensional + + test_make_init_destruct_order(); // failure multidimensional + + test_make_init_destruct_order(5u); // success one dimensional + + test_make_init_destruct_order(20u); // failure one dimensional + + test_make_init_destruct_order(2u); // success multidimensional + + test_make_init_destruct_order(3u); // failure multidimensional +} + +template +shared_ptr allocate_shared_for_overwrite_assert(Args&&... vals) { + int aCount = allocationCount; + shared_ptr sp = allocate_shared_for_overwrite(forward(vals)...); + assert_shared_use_get(sp); + assert(aCount + 1 == allocationCount); + return sp; +} + +template +void test_allocate_init_destruct_order(Args&&... vals) { + allocator> a{}; + + try { + shared_ptr sp = allocate_shared_for_overwrite(a, forward(vals)...); + assert_shared_use_get(sp); + } catch (const runtime_error& exc) { + assert(exc.what() == "Can't create more ReportAddress objects."sv); + } + + assert_ascending_init(); + assert_descending_destruct(); +} + +void test_allocate_shared_for_overwrite() { + allocator a0{}; + auto p0 = allocate_shared_for_overwrite_assert(a0); + assert_uninitialized(addressof(*p0), sizeof(int)); + + allocator a1{}; + auto p1 = allocate_shared_for_overwrite_assert(a1); + assert(p1->value == 106); + + allocator a2{}; + auto p2 = allocate_shared_for_overwrite_assert(a2); + assert_uninitialized(addressof(*p2), sizeof(HighlyAligned)); + + auto p3 = allocate_shared_for_overwrite_assert(a0); + assert_uninitialized(addressof(p3[0]), sizeof(int) * 100u); + + auto p4 = allocate_shared_for_overwrite_assert(a1); + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 8; ++j) { + assert(p4[i][j].value == 106); + } + } + + auto p5 = allocate_shared_for_overwrite_assert(a2); + assert(reinterpret_cast(p5.get()) % alignof(HighlyAligned) == 0); + assert_uninitialized(addressof(p5[0]), sizeof(HighlyAligned) * 10u); + + auto p6 = allocate_shared_for_overwrite_assert(a1, 100u); + for (int i = 0; i < 100; ++i) { + assert(p6[i].value == 106); + } + + auto p7 = allocate_shared_for_overwrite_assert(a1, 2u); + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 8; ++j) { + for (int k = 0; k < 9; ++k) { + assert(p7[i][j][k].value == 106); + } + } + } + + auto p8 = allocate_shared_for_overwrite_assert(a0, 100u); + assert_uninitialized(addressof(p8[0]), sizeof(int) * 100u); + + auto p9 = allocate_shared_for_overwrite_assert(a0, 0u); // p9 cannot be dereferenced + + auto p10 = allocate_shared_for_overwrite_assert(a2, 10u); + assert(reinterpret_cast(p10.get()) % alignof(HighlyAligned) == 0); + assert_uninitialized(addressof(p10[0]), sizeof(HighlyAligned) * 10u); + + test_allocate_init_destruct_order(); // success one dimensional + + test_allocate_init_destruct_order(); // failure one dimensional + + test_allocate_init_destruct_order(); // success multidimensional + + test_allocate_init_destruct_order(); // failure multidimensional + + test_allocate_init_destruct_order(5u); // success one dimensional + + test_allocate_init_destruct_order(20u); // failure one dimensional + + test_allocate_init_destruct_order(2u); // success multidimensional + + test_allocate_init_destruct_order(3u); // failure multidimensional +} + +int main() { + test_make_unique_for_overwrite(); + test_make_shared_for_overwrite(); + test_allocate_shared_for_overwrite(); +} diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp index e81dd2968a6..a3ef7f02d79 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp @@ -1252,6 +1252,20 @@ STATIC_ASSERT(__cpp_lib_shift == 201806L); #endif #endif +#if _HAS_CXX20 +#ifndef __cpp_lib_smart_ptr_for_overwrite +#error __cpp_lib_smart_ptr_for_overwrite is not defined +#elif __cpp_lib_smart_ptr_for_overwrite != 201811L +#error __cpp_lib_smart_ptr_for_overwrite is not 201811L +#else +STATIC_ASSERT(__cpp_lib_smart_ptr_for_overwrite == 201811L); +#endif +#else +#ifdef __cpp_lib_smart_ptr_for_overwrite +#error __cpp_lib_smart_ptr_for_overwrite is defined +#endif +#endif + #if _HAS_CXX20 #ifndef __cpp_lib_span #error __cpp_lib_span is not defined From bbb74d7ee0f6a6d29d315faf57a7b02eec7c79fe Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Thu, 24 Sep 2020 16:44:57 +0200 Subject: [PATCH 02/24] Unused template parameter pack --- stl/inc/xutility | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index d2d0589fdcd..0ed559e84eb 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -127,7 +127,7 @@ void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept(is_nothrow_const } // FUNCTION TEMPLATE _Construct_in_place_for_overwrite -template +template void _Construct_in_place_for_overwrite(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { ::new (const_cast(static_cast(_STD addressof(_Obj)))) _Ty; } From 8e417f779a00c2e779c8a27c9a3d7c6e1924b538 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Thu, 24 Sep 2020 16:54:26 +0200 Subject: [PATCH 03/24] Remove unused alias --- stl/inc/memory | 1 - 1 file changed, 1 deletion(-) diff --git a/stl/inc/memory b/stl/inc/memory index 05730b1db23..429569da78d 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -2380,7 +2380,6 @@ void _Uninitialized_value_construct_multidimensional_n(_Ty* const _Out, const si template void _Uninitialized_default_construct_multidimensional_n(_Ty* const _Out, const size_t _Size) { - using _Item = remove_all_extents_t<_Ty>; if constexpr (!is_trivially_default_constructible_v<_Ty>) { if constexpr (is_array_v<_Ty>) { _Reverse_destroy_multidimensional_n_guard<_Ty> _Guard{_Out, 0}; From 7733d8525980f243c62cf6ef78465913892ada40 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Thu, 24 Sep 2020 18:01:34 +0200 Subject: [PATCH 04/24] Fix test --- .../test.cpp | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp index 8e5fd6eae24..64cd6b72297 100644 --- a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp +++ b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp @@ -11,9 +11,7 @@ using namespace std; -int allocationCount = 0; -int canCreate = 10; // Counter to force an exception when constructing a - // sufficiently large ReportAddress array +size_t allocationCount = 0; struct ReportAddress; vector ascendingAddressBuffer; @@ -61,7 +59,6 @@ void* operator new(size_t size, align_val_t align, const nothrow_t&) noexcept { return result; } -// Helper struct to check if type T is default initable without arguments. template struct unique_is_for_overwritable : false_type {}; @@ -83,6 +80,8 @@ struct alignas(32) HighlyAligned { uint64_t d; }; +size_t canCreate = 10; // Counter to force an exception when constructing a sufficiently large ReportAddress array + struct ReportAddress { ReportAddress() { if (canCreate > 0) { @@ -117,7 +116,7 @@ void assert_descending_destruct() { void assert_uninitialized(void* p, size_t size) { unsigned char* chPtr = reinterpret_cast(p); - for (unsigned int offset = 0; offset < size; ++offset) { + for (size_t offset = 0; offset < size; ++offset) { assert(*(chPtr + offset) == 0xEE); } } @@ -130,7 +129,7 @@ void assert_shared_use_get(const shared_ptr& sp) { template shared_ptr make_shared_for_overwrite_assert(Args&&... vals) { - int count = allocationCount; + size_t count = allocationCount; shared_ptr sp = make_shared_for_overwrite(forward(vals)...); assert_shared_use_get(sp); assert(count + 1 == allocationCount); @@ -164,8 +163,8 @@ void test_make_unique_for_overwrite() { assert(p2->value == 106); auto p3 = make_unique_for_overwrite(2u); - for (int i = 0; i < 2; ++i) { - for (int j = 0; j < 89; ++j) { + for (size_t i = 0; i < 2; ++i) { + for (size_t j = 0; j < 89; ++j) { assert(p3[i][j].value == 106); } } @@ -188,8 +187,8 @@ void test_make_shared_for_overwrite() { assert_uninitialized(addressof(p3[0]), sizeof(int) * 100u); auto p4 = make_shared_for_overwrite_assert(); - for (int i = 0; i < 2; ++i) { - for (int j = 0; j < 8; ++j) { + for (size_t i = 0; i < 2; ++i) { + for (size_t j = 0; j < 8; ++j) { assert(p4[i][j].value == 106); } } @@ -199,14 +198,14 @@ void test_make_shared_for_overwrite() { assert_uninitialized(addressof(p5[0]), sizeof(HighlyAligned) * 10u); auto p6 = make_shared_for_overwrite_assert(100u); - for (int i = 0; i < 100; ++i) { + for (size_t i = 0; i < 100; ++i) { assert(p6[i].value == 106); } auto p7 = make_shared_for_overwrite_assert(2u); - for (int i = 0; i < 2; ++i) { - for (int j = 0; j < 8; ++j) { - for (int k = 0; k < 9; ++k) { + for (size_t i = 0; i < 2; ++i) { + for (size_t j = 0; j < 8; ++j) { + for (size_t k = 0; k < 9; ++k) { assert(p7[i][j][k].value == 106); } } @@ -240,7 +239,7 @@ void test_make_shared_for_overwrite() { template shared_ptr allocate_shared_for_overwrite_assert(Args&&... vals) { - int aCount = allocationCount; + size_t aCount = allocationCount; shared_ptr sp = allocate_shared_for_overwrite(forward(vals)...); assert_shared_use_get(sp); assert(aCount + 1 == allocationCount); @@ -279,8 +278,8 @@ void test_allocate_shared_for_overwrite() { assert_uninitialized(addressof(p3[0]), sizeof(int) * 100u); auto p4 = allocate_shared_for_overwrite_assert(a1); - for (int i = 0; i < 2; ++i) { - for (int j = 0; j < 8; ++j) { + for (size_t i = 0; i < 2; ++i) { + for (size_t j = 0; j < 8; ++j) { assert(p4[i][j].value == 106); } } @@ -290,14 +289,14 @@ void test_allocate_shared_for_overwrite() { assert_uninitialized(addressof(p5[0]), sizeof(HighlyAligned) * 10u); auto p6 = allocate_shared_for_overwrite_assert(a1, 100u); - for (int i = 0; i < 100; ++i) { + for (size_t i = 0; i < 100; ++i) { assert(p6[i].value == 106); } auto p7 = allocate_shared_for_overwrite_assert(a1, 2u); - for (int i = 0; i < 2; ++i) { - for (int j = 0; j < 8; ++j) { - for (int k = 0; k < 9; ++k) { + for (size_t i = 0; i < 2; ++i) { + for (size_t j = 0; j < 8; ++j) { + for (size_t k = 0; k < 9; ++k) { assert(p7[i][j][k].value == 106); } } From bcfba089abe0d21410a2e6838a4e43d4b3a1c671 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Thu, 24 Sep 2020 18:50:27 +0200 Subject: [PATCH 05/24] signed/unsigned mismatch --- .../test.cpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp index 64cd6b72297..7dd9b1c7226 100644 --- a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp +++ b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp @@ -163,8 +163,8 @@ void test_make_unique_for_overwrite() { assert(p2->value == 106); auto p3 = make_unique_for_overwrite(2u); - for (size_t i = 0; i < 2; ++i) { - for (size_t j = 0; j < 89; ++j) { + for (ptrdiff_t i = 0; i < 2; ++i) { + for (ptrdiff_t j = 0; j < 89; ++j) { assert(p3[i][j].value == 106); } } @@ -187,8 +187,8 @@ void test_make_shared_for_overwrite() { assert_uninitialized(addressof(p3[0]), sizeof(int) * 100u); auto p4 = make_shared_for_overwrite_assert(); - for (size_t i = 0; i < 2; ++i) { - for (size_t j = 0; j < 8; ++j) { + for (ptrdiff_t i = 0; i < 2; ++i) { + for (ptrdiff_t j = 0; j < 8; ++j) { assert(p4[i][j].value == 106); } } @@ -198,14 +198,14 @@ void test_make_shared_for_overwrite() { assert_uninitialized(addressof(p5[0]), sizeof(HighlyAligned) * 10u); auto p6 = make_shared_for_overwrite_assert(100u); - for (size_t i = 0; i < 100; ++i) { + for (ptrdiff_t i = 0; i < 100; ++i) { assert(p6[i].value == 106); } auto p7 = make_shared_for_overwrite_assert(2u); - for (size_t i = 0; i < 2; ++i) { - for (size_t j = 0; j < 8; ++j) { - for (size_t k = 0; k < 9; ++k) { + for (ptrdiff_t i = 0; i < 2; ++i) { + for (ptrdiff_t j = 0; j < 8; ++j) { + for (ptrdiff_t k = 0; k < 9; ++k) { assert(p7[i][j][k].value == 106); } } @@ -278,8 +278,8 @@ void test_allocate_shared_for_overwrite() { assert_uninitialized(addressof(p3[0]), sizeof(int) * 100u); auto p4 = allocate_shared_for_overwrite_assert(a1); - for (size_t i = 0; i < 2; ++i) { - for (size_t j = 0; j < 8; ++j) { + for (ptrdiff_t i = 0; i < 2; ++i) { + for (ptrdiff_t j = 0; j < 8; ++j) { assert(p4[i][j].value == 106); } } @@ -289,14 +289,14 @@ void test_allocate_shared_for_overwrite() { assert_uninitialized(addressof(p5[0]), sizeof(HighlyAligned) * 10u); auto p6 = allocate_shared_for_overwrite_assert(a1, 100u); - for (size_t i = 0; i < 100; ++i) { + for (ptrdiff_t i = 0; i < 100; ++i) { assert(p6[i].value == 106); } auto p7 = allocate_shared_for_overwrite_assert(a1, 2u); - for (size_t i = 0; i < 2; ++i) { - for (size_t j = 0; j < 8; ++j) { - for (size_t k = 0; k < 9; ++k) { + for (ptrdiff_t i = 0; i < 2; ++i) { + for (ptrdiff_t j = 0; j < 8; ++j) { + for (ptrdiff_t k = 0; k < 9; ++k) { assert(p7[i][j][k].value == 106); } } From 562ae57b55abe7145a8235c3a4c34fa4dc3c58fa Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Thu, 24 Sep 2020 19:07:08 +0200 Subject: [PATCH 06/24] unique_ptr's subscript operator wants size_t --- tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp index 7dd9b1c7226..79d78085e55 100644 --- a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp +++ b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp @@ -163,8 +163,8 @@ void test_make_unique_for_overwrite() { assert(p2->value == 106); auto p3 = make_unique_for_overwrite(2u); - for (ptrdiff_t i = 0; i < 2; ++i) { - for (ptrdiff_t j = 0; j < 89; ++j) { + for (size_t i = 0; i < 2; ++i) { + for (size_t j = 0; j < 89; ++j) { assert(p3[i][j].value == 106); } } From e8122e527febf1a2dbfc25ba1c2255bc254efd70 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Thu, 24 Sep 2020 20:38:01 +0200 Subject: [PATCH 07/24] Code review and warning --- stl/inc/memory | 32 +++++++++---------- .../test.cpp | 2 ++ 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 429569da78d..d68eb9932a0 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -2957,14 +2957,14 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> make_shared(con template _NODISCARD enable_if_t, shared_ptr<_Ty>> make_shared_for_overwrite() { shared_ptr<_Ty> _Ret; - if constexpr (!is_array_v<_Ty>) { - // make a shared_ptr to non-array object - const auto _Rx = new _Ref_count_obj2<_Ty>(_For_overwrite_tag{}); - _Ret._Set_ptr_rep_and_enable_shared(_STD addressof(_Rx->_Storage._Value), _Rx); - } else { + if constexpr (is_array_v<_Ty>) { // make a shared_ptr to a bounded array const auto _Rx = new _Ref_count_bounded_array<_Ty>(_For_overwrite_tag{}); _Ret._Set_ptr_rep_and_enable_shared(_Rx->_Storage._Value, _Rx); + } else { + // make a shared_ptr to non-array object + const auto _Rx = new _Ref_count_obj2<_Ty>(_For_overwrite_tag{}); + _Ret._Set_ptr_rep_and_enable_shared(_STD addressof(_Rx->_Storage._Value), _Rx); } return _Ret; } @@ -3099,17 +3099,7 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shared template _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shared_for_overwrite(const _Alloc& _Al) { shared_ptr<_Ty> _Ret; - if constexpr (!is_array_v<_Ty>) { - // make a shared_ptr to non-array object - using _Refoa = _Ref_count_obj_alloc3, _Alloc>; - using _Alblock = _Rebind_alloc_t<_Alloc, _Refoa>; - _Alblock _Rebound(_Al); - _Alloc_construct_ptr<_Alblock> _Constructor{_Rebound}; - _Constructor._Allocate(); - _Construct_in_place(*_Constructor._Ptr, _Al, _For_overwrite_tag{}); - const auto _Ptr = reinterpret_cast<_Ty*>(_STD addressof(_Constructor._Ptr->_Storage._Value)); - _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); - } else { + if constexpr (is_array_v<_Ty>) { // make a shared_ptr to a bounded array using _Refc = _Ref_count_bounded_array_alloc, _Alloc>; using _Alblock = _Rebind_alloc_t<_Alloc, _Refc>; @@ -3119,6 +3109,16 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_sha ::new (static_cast(_Unfancy(_Constructor._Ptr))) _Refc(_Al, _For_overwrite_tag{}); const auto _Ptr = static_cast*>(_Constructor._Ptr->_Storage._Value); _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); + } else { + // make a shared_ptr to non-array object + using _Refoa = _Ref_count_obj_alloc3, _Alloc>; + using _Alblock = _Rebind_alloc_t<_Alloc, _Refoa>; + _Alblock _Rebound(_Al); + _Alloc_construct_ptr<_Alblock> _Constructor{_Rebound}; + _Constructor._Allocate(); + _Construct_in_place(*_Constructor._Ptr, _Al, _For_overwrite_tag{}); + const auto _Ptr = reinterpret_cast<_Ty*>(_STD addressof(_Constructor._Ptr->_Storage._Value)); + _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); } return _Ret; diff --git a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp index 79d78085e55..a77804eda0d 100644 --- a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp +++ b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp @@ -17,6 +17,8 @@ struct ReportAddress; vector ascendingAddressBuffer; vector descendingAddressBuffer; +#pragma warning(disable : 28251) // Inconsistent annotation for 'new' + // According to N4849, the default behavior of operator new[](size) is to return // operator new(size), so only the latter needs to be replaced. void* operator new(size_t size) { From d57e8a62b3c1f01679aa7ee74f46653f90b1d284 Mon Sep 17 00:00:00 2001 From: Weheineman Date: Thu, 24 Sep 2020 15:05:55 -0700 Subject: [PATCH 08/24] GH-1315 is based on GH-778 by @Weheineman. --- stl/inc/memory | 1 - 1 file changed, 1 deletion(-) diff --git a/stl/inc/memory b/stl/inc/memory index d68eb9932a0..6369c75a225 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -2969,7 +2969,6 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> make_shared_ return _Ret; } - template _NODISCARD enable_if_t, shared_ptr<_Ty>> make_shared_for_overwrite(size_t _Count) { // make a shared_ptr to an unbounded array From 520ccf7a0b81a85b8a87841c7c850f79b74e22f9 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 9 Oct 2020 08:53:00 +0200 Subject: [PATCH 09/24] Apply suggestions from code review Co-authored-by: Stephan T. Lavavej --- stl/inc/memory | 2 +- tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 6369c75a225..f318ce4ff21 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -3616,7 +3616,7 @@ _NODISCARD unique_ptr<_Ty> make_unique_for_overwrite(size_t _Size) { // make a u template != 0, int> = 0> void make_unique_for_overwrite(_Types&&...) = delete; -#endif +#endif // _HAS_CXX20 template ::value, int> = 0> void swap(unique_ptr<_Ty, _Dx>& _Left, unique_ptr<_Ty, _Dx>& _Right) noexcept { diff --git a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp index a77804eda0d..22a43683b86 100644 --- a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp +++ b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp @@ -156,10 +156,10 @@ void test_make_unique_for_overwrite() { static_assert(!unique_is_for_overwritable_v); auto p0 = make_unique_for_overwrite(); - assert_uninitialized(addressof(*p0), sizeof(int)); + assert_uninitialized(p0.get(), sizeof(int)); auto p1 = make_unique_for_overwrite(100u); - assert_uninitialized(addressof(p1[0]), sizeof(int) * 100u); + assert_uninitialized(p1.get(), sizeof(int) * 100u); auto p2 = make_unique_for_overwrite(); assert(p2->value == 106); From 6a3b07fd5cb664d7e5028c5b70dfe3c605080abc Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 9 Oct 2020 16:42:09 +0200 Subject: [PATCH 10/24] Code review --- stl/inc/memory | 199 +++++++++--------- .../test.cpp | 75 ++++--- 2 files changed, 135 insertions(+), 139 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index f318ce4ff21..f03e59c46ff 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -1949,6 +1949,13 @@ private: template friend enable_if_t, shared_ptr<_Ty0>> allocate_shared_for_overwrite( const _Alloc& _Al_arg, size_t _Count); + + template + friend shared_ptr<_Ty> _Make_shared_unbounded_array(const size_t _Count, const _ArgTypes&... _Args); + + template + friend shared_ptr<_Ty> _Allocate_shared_unbounded_array( + const _Alloc& _Al, const size_t _Count, const _ArgTypes&... _Args); #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template friend shared_ptr<_Ty0> make_shared(_Types&&... _Args); @@ -2177,9 +2184,11 @@ template _Dx* get_deleter(const shared_ptr<_Ty>&) noexcept = delete; // requires static RTTI #endif // _HAS_STATIC_RTTI +#if _HAS_CXX20 struct _For_overwrite_tag { explicit _For_overwrite_tag() = default; }; +#endif // _HAS_CXX20 // CLASS TEMPLATE _Ref_count_obj2 template @@ -2187,11 +2196,15 @@ class _Ref_count_obj2 : public _Ref_count_base { // handle reference counting fo public: template explicit _Ref_count_obj2(_Types&&... _Args) : _Ref_count_base() { - _Construct_in_place(_Storage._Value, _STD forward<_Types>(_Args)...); - } - - explicit _Ref_count_obj2(_For_overwrite_tag) : _Ref_count_base() { - _Construct_in_place_for_overwrite(_Storage._Value); +#if _HAS_CXX20 + if constexpr (sizeof...(_Types) == 1 && (is_same_v<_For_overwrite_tag, remove_cvref_t<_Types>> && ...)) { + _Construct_in_place_for_overwrite(_Storage._Value); + (void) (_Args, ...); + } else +#endif // _HAS_CXX20 + { + _Construct_in_place(_Storage._Value, _STD forward<_Types>(_Args)...); + } } ~_Ref_count_obj2() { @@ -2429,12 +2442,13 @@ public: _Uninitialized_value_construct_multidimensional_n(_Get_ptr(), _Count); } - explicit _Ref_count_unbounded_array(const size_t _Count, const _Element_type& _Val) : _Ref_count_base() { - _Uninitialized_fill_multidimensional_n(_Get_ptr(), _Count, _Val); - } - - explicit _Ref_count_unbounded_array(const size_t _Count, _For_overwrite_tag) : _Ref_count_base() { - _Uninitialized_default_construct_multidimensional_n(_Get_ptr(), _Count); + template + explicit _Ref_count_unbounded_array(const size_t _Count, const _Arg& _Val) : _Ref_count_base() { + if constexpr (is_same_v<_For_overwrite_tag, remove_cvref_t<_Arg>>) { + _Uninitialized_default_construct_multidimensional_n(_Get_ptr(), _Count); + } else { + _Uninitialized_fill_multidimensional_n(_Get_ptr(), _Count, _Val); + } } _NODISCARD auto _Get_ptr() noexcept { @@ -2474,13 +2488,13 @@ public: _Uninitialized_value_construct_multidimensional_n(_Get_ptr(), _Size); } - explicit _Ref_count_unbounded_array(const size_t _Count, const _Element_type& _Val) - : _Ref_count_base(), _Size(_Count) { - _Uninitialized_fill_multidimensional_n(_Get_ptr(), _Size, _Val); - } - - explicit _Ref_count_unbounded_array(const size_t _Count, _For_overwrite_tag) : _Ref_count_base(), _Size(_Count) { - _Uninitialized_default_construct_multidimensional_n(_Get_ptr(), _Size); + template + explicit _Ref_count_unbounded_array(const size_t _Count, const _Arg& _Val) : _Ref_count_base(), _Size(_Count) { + if constexpr (is_same_v<_For_overwrite_tag, remove_cvref_t<_Arg>>) { + _Uninitialized_default_construct_multidimensional_n(_Get_ptr(), _Size); + } else { + _Uninitialized_fill_multidimensional_n(_Get_ptr(), _Size, _Val); + } } _NODISCARD auto _Get_ptr() noexcept { @@ -2519,13 +2533,13 @@ public: _Ref_count_bounded_array() : _Ref_count_base(), _Storage() {} // value-initializing _Storage is necessary here - explicit _Ref_count_bounded_array(const remove_extent_t<_Ty>& _Val) - : _Ref_count_base() { // don't value-initialize _Storage - _Uninitialized_fill_multidimensional_n(_Storage._Value, extent_v<_Ty>, _Val); - } - - explicit _Ref_count_bounded_array(_For_overwrite_tag) : _Ref_count_base() { - _Uninitialized_default_construct_multidimensional_n(_Storage._Value, extent_v<_Ty>); + template + explicit _Ref_count_bounded_array(const _Arg& _Val) : _Ref_count_base() { // don't value-initialize _Storage + if constexpr (is_same_v<_For_overwrite_tag, remove_cvref_t<_Arg>>) { + _Uninitialized_default_construct_multidimensional_n(_Storage._Value, extent_v<_Ty>); + } else { + _Uninitialized_fill_multidimensional_n(_Storage._Value, extent_v<_Ty>, _Val); + } } union { @@ -2602,13 +2616,16 @@ public: template explicit _Ref_count_obj_alloc3(const _Alloc& _Al_arg, _Types&&... _Args) : _Ebco_base<_Rebound>(_Al_arg), _Ref_count_base() { - allocator_traits<_Rebound>::construct( - this->_Get_val(), _STD addressof(_Storage._Value), _STD forward<_Types>(_Args)...); - } - - explicit _Ref_count_obj_alloc3(const _Alloc& _Al_arg, _For_overwrite_tag) - : _Ebco_base<_Rebound>(_Al_arg), _Ref_count_base() { - _Construct_in_place_for_overwrite(_Storage._Value); +#if _HAS_CXX20 + if constexpr (sizeof...(_Types) == 1 && (is_same_v<_For_overwrite_tag, remove_cvref_t<_Types>> && ...)) { + _Construct_in_place_for_overwrite(_Storage._Value); + (void) (_Args, ...); + } else +#endif // _HAS_CXX20 + { + allocator_traits<_Rebound>::construct( + this->_Get_val(), _STD addressof(_Storage._Value), _STD forward<_Types>(_Args)...); + } } union { @@ -2776,14 +2793,14 @@ public: _Uninitialized_value_construct_multidimensional_n_al(_Get_ptr(), _Size, this->_Get_val()); } - explicit _Ref_count_unbounded_array_alloc(const _Alloc& _Al_arg, const size_t _Count, const _Element_type& _Val) - : _Ebco_base<_Rebound>(_Al_arg), _Ref_count_base(), _Size(_Count) { - _Uninitialized_fill_multidimensional_n_al(_Get_ptr(), _Size, _Val, this->_Get_val()); - } - - explicit _Ref_count_unbounded_array_alloc(const _Alloc& _Al_arg, const size_t _Count, _For_overwrite_tag) + template + explicit _Ref_count_unbounded_array_alloc(const _Alloc& _Al_arg, const size_t _Count, const _Arg& _Val) : _Ebco_base<_Rebound>(_Al_arg), _Ref_count_base(), _Size(_Count) { - _Uninitialized_default_construct_multidimensional_n(_Get_ptr(), _Size); // the allocator isn't needed + if constexpr (is_same_v<_For_overwrite_tag, remove_cvref_t<_Arg>>) { + _Uninitialized_default_construct_multidimensional_n(_Get_ptr(), _Size); // the allocator isn't needed + } else { + _Uninitialized_fill_multidimensional_n_al(_Get_ptr(), _Size, _Val, this->_Get_val()); + } } _NODISCARD auto _Get_ptr() noexcept { @@ -2842,15 +2859,15 @@ public: _Uninitialized_value_construct_multidimensional_n_al(_Storage._Value, extent_v<_Ty>, this->_Get_val()); } - explicit _Ref_count_bounded_array_alloc(const _Alloc& _Al_arg, const remove_extent_t<_Ty>& _Val) - : _Ebco_base<_Rebound>(_Al_arg), _Ref_count_base() { // don't value-initialize _Storage - _Uninitialized_fill_multidimensional_n_al(_Storage._Value, extent_v<_Ty>, _Val, this->_Get_val()); - } - - explicit _Ref_count_bounded_array_alloc(const _Alloc& _Al_arg, _For_overwrite_tag) + template + explicit _Ref_count_bounded_array_alloc(const _Alloc& _Al_arg, const _Arg& _Val) : _Ebco_base<_Rebound>(_Al_arg), _Ref_count_base() { // don't value-initialize _Storage - _Uninitialized_default_construct_multidimensional_n( - _Storage._Value, extent_v<_Ty>); // the allocator isn't needed + if constexpr (is_same_v<_For_overwrite_tag, remove_cvref_t<_Arg>>) { + _Uninitialized_default_construct_multidimensional_n( + _Storage._Value, extent_v<_Ty>); // the allocator isn't needed + } else { + _Uninitialized_fill_multidimensional_n_al(_Storage._Value, extent_v<_Ty>, _Val, this->_Get_val()); + } } union { @@ -2908,31 +2925,29 @@ struct _Global_delete_guard { } }; -template -_NODISCARD enable_if_t, shared_ptr<_Ty>> make_shared(const size_t _Count) { +template +_NODISCARD shared_ptr<_Ty> _Make_shared_unbounded_array(const size_t _Count, const _ArgTypes&... _Args) { // make a shared_ptr to an unbounded array + static_assert(is_unbounded_array_v<_Ty>); using _Refc = _Ref_count_unbounded_array<_Ty>; const auto _Rx = _Allocate_flexible_array<_Refc>(_Count); _Global_delete_guard<_Refc> _Guard{_Rx}; - ::new (static_cast(_Rx)) _Refc(_Count); + ::new (static_cast(_Rx)) _Refc(_Count, _Args...); _Guard._Target = nullptr; shared_ptr<_Ty> _Ret; _Ret._Set_ptr_rep_and_enable_shared(_Rx->_Get_ptr(), _Rx); return _Ret; } +template +_NODISCARD enable_if_t, shared_ptr<_Ty>> make_shared(const size_t _Count) { + return _Make_shared_unbounded_array<_Ty>(_Count); +} + template _NODISCARD enable_if_t, shared_ptr<_Ty>> make_shared( const size_t _Count, const remove_extent_t<_Ty>& _Val) { - // make a shared_ptr to an unbounded array - using _Refc = _Ref_count_unbounded_array<_Ty>; - const auto _Rx = _Allocate_flexible_array<_Refc>(_Count); - _Global_delete_guard<_Refc> _Guard{_Rx}; - ::new (static_cast(_Rx)) _Refc(_Count, _Val); - _Guard._Target = nullptr; - shared_ptr<_Ty> _Ret; - _Ret._Set_ptr_rep_and_enable_shared(_Rx->_Get_ptr(), _Rx); - return _Ret; + return _Make_shared_unbounded_array<_Ty>(_Count, _Val); } template @@ -2970,16 +2985,8 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> make_shared_ } template -_NODISCARD enable_if_t, shared_ptr<_Ty>> make_shared_for_overwrite(size_t _Count) { - // make a shared_ptr to an unbounded array - using _Refc = _Ref_count_unbounded_array<_Ty>; - const auto _Rx = _Allocate_flexible_array<_Refc>(_Count); - _Global_delete_guard<_Refc> _Guard{_Rx}; - ::new (static_cast(_Rx)) _Refc(_Count, _For_overwrite_tag{}); - _Guard._Target = nullptr; - shared_ptr<_Ty> _Ret; - _Ret._Set_ptr_rep_and_enable_shared(_Rx->_Get_ptr(), _Rx); - return _Ret; +_NODISCARD enable_if_t, shared_ptr<_Ty>> make_shared_for_overwrite(const size_t _Count) { + return _Make_shared_unbounded_array<_Ty>(_Count, _For_overwrite_tag{}); } #endif // _HAS_CXX20 @@ -3025,10 +3032,10 @@ struct _Allocate_n_ptr { _Allocate_n_ptr& operator=(const _Allocate_n_ptr&) = delete; }; -template -_NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shared( - const _Alloc& _Al, const size_t _Count) { +template +_NODISCARD shared_ptr<_Ty> _Allocate_shared_unbounded_array(const _Alloc& _Al, const size_t _Count, const _ArgTypes&... _Args) { // make a shared_ptr to an unbounded array + static_assert(is_unbounded_array_v<_Ty>); using _Refc = _Ref_count_unbounded_array_alloc, _Alloc>; constexpr size_t _Align = alignof(_Refc); using _Storage = _Alignas_storage_unit<_Align>; @@ -3037,7 +3044,7 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shar const size_t _Storage_units = _Bytes / sizeof(_Storage); _Allocate_n_ptr _Guard{_Rebound, _Storage_units}; const auto _Rx = reinterpret_cast<_Refc*>(_Unfancy(_Guard._Ptr)); - ::new (static_cast(_Rx)) _Refc(_Al, _Count); + ::new (static_cast(_Rx)) _Refc(_Al, _Count, _Args...); _Guard._Ptr = nullptr; shared_ptr<_Ty> _Ret; _Ret._Set_ptr_rep_and_enable_shared(_Rx->_Get_ptr(), _Rx); @@ -3046,21 +3053,15 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shar template _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shared( - const _Alloc& _Al, const size_t _Count, const remove_extent_t<_Ty>& _Val) { + const _Alloc& _Al, const size_t _Count) { // make a shared_ptr to an unbounded array - using _Refc = _Ref_count_unbounded_array_alloc, _Alloc>; - constexpr size_t _Align = alignof(_Refc); - using _Storage = _Alignas_storage_unit<_Align>; - _Rebind_alloc_t<_Alloc, _Storage> _Rebound(_Al); - const size_t _Bytes = _Calculate_bytes_for_flexible_array<_Refc, _Check_overflow::_Yes>(_Count); - const size_t _Storage_units = _Bytes / sizeof(_Storage); - _Allocate_n_ptr _Guard{_Rebound, _Storage_units}; - const auto _Rx = reinterpret_cast<_Refc*>(_Unfancy(_Guard._Ptr)); - ::new (static_cast(_Rx)) _Refc(_Al, _Count, _Val); - _Guard._Ptr = nullptr; - shared_ptr<_Ty> _Ret; - _Ret._Set_ptr_rep_and_enable_shared(_Rx->_Get_ptr(), _Rx); - return _Ret; + return _Allocate_shared_unbounded_array<_Ty>(_Al, _Count); +} + +template +_NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shared( + const _Alloc& _Al, const size_t _Count, const remove_extent_t<_Ty>& _Val) { + return _Allocate_shared_unbounded_array<_Ty>(_Al, _Count, _Val); } template @@ -3126,20 +3127,7 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_sha template _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shared_for_overwrite( const _Alloc& _Al, const size_t _Count) { - // make a shared_ptr to an unbounded array - using _Refc = _Ref_count_unbounded_array_alloc, _Alloc>; - constexpr size_t _Align = alignof(_Refc); - using _Storage = _Alignas_storage_unit<_Align>; - _Rebind_alloc_t<_Alloc, _Storage> _Rebound(_Al); - const size_t _Bytes = _Calculate_bytes_for_flexible_array<_Refc, _Check_overflow::_Yes>(_Count); - const size_t _Storage_units = _Bytes / sizeof(_Storage); - _Allocate_n_ptr _Guard{_Rebound, _Storage_units}; - const auto _Rx = reinterpret_cast<_Refc*>(_Unfancy(_Guard._Ptr)); - ::new (static_cast(_Rx)) _Refc(_Al, _Count, _For_overwrite_tag{}); - _Guard._Ptr = nullptr; - shared_ptr<_Ty> _Ret; - _Ret._Set_ptr_rep_and_enable_shared(_Rx->_Get_ptr(), _Rx); - return _Ret; + return _Allocate_shared_unbounded_array<_Ty>(_Al, _Count, _For_overwrite_tag{}); } #endif // _HAS_CXX20 @@ -3592,8 +3580,8 @@ _NODISCARD unique_ptr<_Ty> make_unique(_Types&&... _Args) { // make a unique_ptr return unique_ptr<_Ty>(new _Ty(_STD forward<_Types>(_Args)...)); } -template && extent_v<_Ty> == 0, int> = 0> -_NODISCARD unique_ptr<_Ty> make_unique(size_t _Size) { // make a unique_ptr +template , int> = 0> +_NODISCARD unique_ptr<_Ty> make_unique(const size_t _Size) { // make a unique_ptr using _Elem = remove_extent_t<_Ty>; return unique_ptr<_Ty>(new _Elem[_Size]()); } @@ -3608,8 +3596,9 @@ _NODISCARD unique_ptr<_Ty> make_unique_for_overwrite() { // make a unique_ptr wi return unique_ptr<_Ty>(new _Ty); } -template && extent_v<_Ty> == 0, int> = 0> -_NODISCARD unique_ptr<_Ty> make_unique_for_overwrite(size_t _Size) { // make a unique_ptr with default initialization +template , int> = 0> +_NODISCARD unique_ptr<_Ty> make_unique_for_overwrite( + const size_t _Size) { // make a unique_ptr with default initialization using _Elem = remove_extent_t<_Ty>; return unique_ptr<_Ty>(new _Elem[_Size]); } diff --git a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp index 22a43683b86..818c11e7056 100644 --- a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp +++ b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp @@ -2,15 +2,21 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include #include +#include #include #include #include +#include #include +#include #include using namespace std; +constexpr int uninitializedValue = 0xEE; +constexpr int defaultValue = 106; size_t allocationCount = 0; struct ReportAddress; @@ -35,7 +41,7 @@ void* operator new(size_t size, const nothrow_t&) noexcept { void* const result = malloc(size == 0 ? 1 : size); ++allocationCount; if (result) { - memset(result, 0xEE, size); + memset(result, uninitializedValue, size); } return result; @@ -55,7 +61,7 @@ void* operator new(size_t size, align_val_t align, const nothrow_t&) noexcept { void* const result = ::_aligned_malloc(size, static_cast(align)); ++allocationCount; if (result) { - memset(result, 0xEE, size); + memset(result, uninitializedValue, size); } return result; @@ -72,7 +78,7 @@ constexpr bool unique_is_for_overwritable_v = unique_is_for_overwritable::val struct DefaultInitializableInt { int value; - DefaultInitializableInt() : value(106) {} + DefaultInitializableInt() : value(defaultValue) {} }; struct alignas(32) HighlyAligned { @@ -119,7 +125,7 @@ void assert_descending_destruct() { void assert_uninitialized(void* p, size_t size) { unsigned char* chPtr = reinterpret_cast(p); for (size_t offset = 0; offset < size; ++offset) { - assert(*(chPtr + offset) == 0xEE); + assert(chPtr[offset] == uninitializedValue); } } @@ -131,15 +137,15 @@ void assert_shared_use_get(const shared_ptr& sp) { template shared_ptr make_shared_for_overwrite_assert(Args&&... vals) { - size_t count = allocationCount; + size_t aCount = allocationCount; shared_ptr sp = make_shared_for_overwrite(forward(vals)...); assert_shared_use_get(sp); - assert(count + 1 == allocationCount); + assert(aCount + 1 == allocationCount); return sp; } template -void test_make_init_destruct_order(Args&&... vals) { +void test_make_shared_init_destruct_order(Args&&... vals) { try { shared_ptr sp = make_shared_for_overwrite(forward(vals)...); assert_shared_use_get(sp); @@ -162,12 +168,12 @@ void test_make_unique_for_overwrite() { assert_uninitialized(p1.get(), sizeof(int) * 100u); auto p2 = make_unique_for_overwrite(); - assert(p2->value == 106); + assert(p2->value == defaultValue); auto p3 = make_unique_for_overwrite(2u); for (size_t i = 0; i < 2; ++i) { for (size_t j = 0; j < 89; ++j) { - assert(p3[i][j].value == 106); + assert(p3[i][j].value == defaultValue); } } @@ -179,7 +185,7 @@ void test_make_shared_for_overwrite() { assert_uninitialized(addressof(*p0), sizeof(int)); auto p1 = make_shared_for_overwrite_assert(); - assert(p1->value == 106); + assert(p1->value == defaultValue); auto p2 = make_shared_for_overwrite_assert(); assert(reinterpret_cast(p2.get()) % alignof(HighlyAligned) == 0); @@ -191,7 +197,7 @@ void test_make_shared_for_overwrite() { auto p4 = make_shared_for_overwrite_assert(); for (ptrdiff_t i = 0; i < 2; ++i) { for (ptrdiff_t j = 0; j < 8; ++j) { - assert(p4[i][j].value == 106); + assert(p4[i][j].value == defaultValue); } } @@ -201,14 +207,14 @@ void test_make_shared_for_overwrite() { auto p6 = make_shared_for_overwrite_assert(100u); for (ptrdiff_t i = 0; i < 100; ++i) { - assert(p6[i].value == 106); + assert(p6[i].value == defaultValue); } auto p7 = make_shared_for_overwrite_assert(2u); for (ptrdiff_t i = 0; i < 2; ++i) { for (ptrdiff_t j = 0; j < 8; ++j) { for (ptrdiff_t k = 0; k < 9; ++k) { - assert(p7[i][j][k].value == 106); + assert(p7[i][j][k].value == defaultValue); } } } @@ -222,21 +228,21 @@ void test_make_shared_for_overwrite() { assert(reinterpret_cast(p10.get()) % alignof(HighlyAligned) == 0); assert_uninitialized(addressof(p10[0]), sizeof(HighlyAligned) * 10u); - test_make_init_destruct_order(); // success one dimensional + test_make_shared_init_destruct_order(); // success one dimensional - test_make_init_destruct_order(); // failure one dimensional + test_make_shared_init_destruct_order(); // failure one dimensional - test_make_init_destruct_order(); // success multidimensional + test_make_shared_init_destruct_order(); // success multidimensional - test_make_init_destruct_order(); // failure multidimensional + test_make_shared_init_destruct_order(); // failure multidimensional - test_make_init_destruct_order(5u); // success one dimensional + test_make_shared_init_destruct_order(5u); // success one dimensional - test_make_init_destruct_order(20u); // failure one dimensional + test_make_shared_init_destruct_order(20u); // failure one dimensional - test_make_init_destruct_order(2u); // success multidimensional + test_make_shared_init_destruct_order(2u); // success multidimensional - test_make_init_destruct_order(3u); // failure multidimensional + test_make_shared_init_destruct_order(3u); // failure multidimensional } template @@ -249,7 +255,7 @@ shared_ptr allocate_shared_for_overwrite_assert(Args&&... vals) { } template -void test_allocate_init_destruct_order(Args&&... vals) { +void test_allocate_shared_init_destruct_order(Args&&... vals) { allocator> a{}; try { @@ -270,10 +276,11 @@ void test_allocate_shared_for_overwrite() { allocator a1{}; auto p1 = allocate_shared_for_overwrite_assert(a1); - assert(p1->value == 106); + assert(p1->value == defaultValue); allocator a2{}; auto p2 = allocate_shared_for_overwrite_assert(a2); + assert(reinterpret_cast(p2.get()) % alignof(HighlyAligned) == 0); assert_uninitialized(addressof(*p2), sizeof(HighlyAligned)); auto p3 = allocate_shared_for_overwrite_assert(a0); @@ -282,7 +289,7 @@ void test_allocate_shared_for_overwrite() { auto p4 = allocate_shared_for_overwrite_assert(a1); for (ptrdiff_t i = 0; i < 2; ++i) { for (ptrdiff_t j = 0; j < 8; ++j) { - assert(p4[i][j].value == 106); + assert(p4[i][j].value == defaultValue); } } @@ -292,14 +299,14 @@ void test_allocate_shared_for_overwrite() { auto p6 = allocate_shared_for_overwrite_assert(a1, 100u); for (ptrdiff_t i = 0; i < 100; ++i) { - assert(p6[i].value == 106); + assert(p6[i].value == defaultValue); } auto p7 = allocate_shared_for_overwrite_assert(a1, 2u); for (ptrdiff_t i = 0; i < 2; ++i) { for (ptrdiff_t j = 0; j < 8; ++j) { for (ptrdiff_t k = 0; k < 9; ++k) { - assert(p7[i][j][k].value == 106); + assert(p7[i][j][k].value == defaultValue); } } } @@ -313,21 +320,21 @@ void test_allocate_shared_for_overwrite() { assert(reinterpret_cast(p10.get()) % alignof(HighlyAligned) == 0); assert_uninitialized(addressof(p10[0]), sizeof(HighlyAligned) * 10u); - test_allocate_init_destruct_order(); // success one dimensional + test_allocate_shared_init_destruct_order(); // success one dimensional - test_allocate_init_destruct_order(); // failure one dimensional + test_allocate_shared_init_destruct_order(); // failure one dimensional - test_allocate_init_destruct_order(); // success multidimensional + test_allocate_shared_init_destruct_order(); // success multidimensional - test_allocate_init_destruct_order(); // failure multidimensional + test_allocate_shared_init_destruct_order(); // failure multidimensional - test_allocate_init_destruct_order(5u); // success one dimensional + test_allocate_shared_init_destruct_order(5u); // success one dimensional - test_allocate_init_destruct_order(20u); // failure one dimensional + test_allocate_shared_init_destruct_order(20u); // failure one dimensional - test_allocate_init_destruct_order(2u); // success multidimensional + test_allocate_shared_init_destruct_order(2u); // success multidimensional - test_allocate_init_destruct_order(3u); // failure multidimensional + test_allocate_shared_init_destruct_order(3u); // failure multidimensional } int main() { From 5a8ceb80be4ae8ab5cb068303c21798760dedbe5 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 9 Oct 2020 16:46:28 +0200 Subject: [PATCH 11/24] clang-format (as always) --- stl/inc/memory | 3 ++- tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index f03e59c46ff..8aeaefea3b8 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -3033,7 +3033,8 @@ struct _Allocate_n_ptr { }; template -_NODISCARD shared_ptr<_Ty> _Allocate_shared_unbounded_array(const _Alloc& _Al, const size_t _Count, const _ArgTypes&... _Args) { +_NODISCARD shared_ptr<_Ty> _Allocate_shared_unbounded_array( + const _Alloc& _Al, const size_t _Count, const _ArgTypes&... _Args) { // make a shared_ptr to an unbounded array static_assert(is_unbounded_array_v<_Ty>); using _Refc = _Ref_count_unbounded_array_alloc, _Alloc>; diff --git a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp index 818c11e7056..63e99b759f9 100644 --- a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp +++ b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp @@ -17,7 +17,7 @@ using namespace std; constexpr int uninitializedValue = 0xEE; constexpr int defaultValue = 106; -size_t allocationCount = 0; +size_t allocationCount = 0; struct ReportAddress; vector ascendingAddressBuffer; @@ -137,7 +137,7 @@ void assert_shared_use_get(const shared_ptr& sp) { template shared_ptr make_shared_for_overwrite_assert(Args&&... vals) { - size_t aCount = allocationCount; + size_t aCount = allocationCount; shared_ptr sp = make_shared_for_overwrite(forward(vals)...); assert_shared_use_get(sp); assert(aCount + 1 == allocationCount); From 615e0445b4972e8110dfeeb433ad8bfc36cce694 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 9 Oct 2020 16:56:06 +0200 Subject: [PATCH 12/24] Use _Voidify_iter --- stl/inc/memory | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/memory b/stl/inc/memory index 8aeaefea3b8..80bf5a886dc 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -3107,7 +3107,7 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_sha _Alblock _Rebound(_Al); _Alloc_construct_ptr _Constructor{_Rebound}; _Constructor._Allocate(); - ::new (static_cast(_Unfancy(_Constructor._Ptr))) _Refc(_Al, _For_overwrite_tag{}); + ::new (_Voidify_iter(_Constructor._Ptr)) _Refc(_Al, _For_overwrite_tag{}); const auto _Ptr = static_cast*>(_Constructor._Ptr->_Storage._Value); _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); } else { From 1a19fe0dc8b9009752931b4916689ac8e2f43881 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 9 Oct 2020 17:43:18 +0200 Subject: [PATCH 13/24] Fix tests --- stl/inc/memory | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 80bf5a886dc..978863c7e7c 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -1950,11 +1950,11 @@ private: friend enable_if_t, shared_ptr<_Ty0>> allocate_shared_for_overwrite( const _Alloc& _Al_arg, size_t _Count); - template - friend shared_ptr<_Ty> _Make_shared_unbounded_array(const size_t _Count, const _ArgTypes&... _Args); + template + friend shared_ptr<_Ty0> _Make_shared_unbounded_array(const size_t _Count, const _ArgTypes&... _Args); - template - friend shared_ptr<_Ty> _Allocate_shared_unbounded_array( + template + friend shared_ptr<_Ty0> _Allocate_shared_unbounded_array( const _Alloc& _Al, const size_t _Count, const _ArgTypes&... _Args); #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template @@ -2199,7 +2199,7 @@ public: #if _HAS_CXX20 if constexpr (sizeof...(_Types) == 1 && (is_same_v<_For_overwrite_tag, remove_cvref_t<_Types>> && ...)) { _Construct_in_place_for_overwrite(_Storage._Value); - (void) (_Args, ...); + ((void)_Args, ...); } else #endif // _HAS_CXX20 { @@ -2619,7 +2619,7 @@ public: #if _HAS_CXX20 if constexpr (sizeof...(_Types) == 1 && (is_same_v<_For_overwrite_tag, remove_cvref_t<_Types>> && ...)) { _Construct_in_place_for_overwrite(_Storage._Value); - (void) (_Args, ...); + ((void)_Args, ...); } else #endif // _HAS_CXX20 { From 3ab3eeb48d61c97ba82601ba8734f49543c7087f Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 9 Oct 2020 17:45:16 +0200 Subject: [PATCH 14/24] clang-format (obviously) --- stl/inc/memory | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 978863c7e7c..c4e22973de7 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -2199,7 +2199,7 @@ public: #if _HAS_CXX20 if constexpr (sizeof...(_Types) == 1 && (is_same_v<_For_overwrite_tag, remove_cvref_t<_Types>> && ...)) { _Construct_in_place_for_overwrite(_Storage._Value); - ((void)_Args, ...); + ((void) _Args, ...); } else #endif // _HAS_CXX20 { @@ -2619,7 +2619,7 @@ public: #if _HAS_CXX20 if constexpr (sizeof...(_Types) == 1 && (is_same_v<_For_overwrite_tag, remove_cvref_t<_Types>> && ...)) { _Construct_in_place_for_overwrite(_Storage._Value); - ((void)_Args, ...); + ((void) _Args, ...); } else #endif // _HAS_CXX20 { From f19690ee31e2094273c070f08996969f1dad7703 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 9 Oct 2020 17:51:06 +0200 Subject: [PATCH 15/24] Fix tests --- stl/inc/memory | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/memory b/stl/inc/memory index c4e22973de7..0ae24ed2e5e 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -3581,7 +3581,7 @@ _NODISCARD unique_ptr<_Ty> make_unique(_Types&&... _Args) { // make a unique_ptr return unique_ptr<_Ty>(new _Ty(_STD forward<_Types>(_Args)...)); } -template , int> = 0> +template && extent_v<_Ty> == 0, int> = 0> _NODISCARD unique_ptr<_Ty> make_unique(const size_t _Size) { // make a unique_ptr using _Elem = remove_extent_t<_Ty>; return unique_ptr<_Ty>(new _Elem[_Size]()); From 2b357f024ac3579004c5439ba5cab31ddcbd4213 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Sat, 10 Oct 2020 08:50:32 +0200 Subject: [PATCH 16/24] Rename defaultValue to initializedValue --- .../test.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp index 63e99b759f9..c6ee3f4c3c9 100644 --- a/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp +++ b/tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp @@ -16,7 +16,7 @@ using namespace std; constexpr int uninitializedValue = 0xEE; -constexpr int defaultValue = 106; +constexpr int initializedValue = 106; size_t allocationCount = 0; struct ReportAddress; @@ -78,7 +78,7 @@ constexpr bool unique_is_for_overwritable_v = unique_is_for_overwritable::val struct DefaultInitializableInt { int value; - DefaultInitializableInt() : value(defaultValue) {} + DefaultInitializableInt() : value(initializedValue) {} }; struct alignas(32) HighlyAligned { @@ -168,12 +168,12 @@ void test_make_unique_for_overwrite() { assert_uninitialized(p1.get(), sizeof(int) * 100u); auto p2 = make_unique_for_overwrite(); - assert(p2->value == defaultValue); + assert(p2->value == initializedValue); auto p3 = make_unique_for_overwrite(2u); for (size_t i = 0; i < 2; ++i) { for (size_t j = 0; j < 89; ++j) { - assert(p3[i][j].value == defaultValue); + assert(p3[i][j].value == initializedValue); } } @@ -185,7 +185,7 @@ void test_make_shared_for_overwrite() { assert_uninitialized(addressof(*p0), sizeof(int)); auto p1 = make_shared_for_overwrite_assert(); - assert(p1->value == defaultValue); + assert(p1->value == initializedValue); auto p2 = make_shared_for_overwrite_assert(); assert(reinterpret_cast(p2.get()) % alignof(HighlyAligned) == 0); @@ -197,7 +197,7 @@ void test_make_shared_for_overwrite() { auto p4 = make_shared_for_overwrite_assert(); for (ptrdiff_t i = 0; i < 2; ++i) { for (ptrdiff_t j = 0; j < 8; ++j) { - assert(p4[i][j].value == defaultValue); + assert(p4[i][j].value == initializedValue); } } @@ -207,14 +207,14 @@ void test_make_shared_for_overwrite() { auto p6 = make_shared_for_overwrite_assert(100u); for (ptrdiff_t i = 0; i < 100; ++i) { - assert(p6[i].value == defaultValue); + assert(p6[i].value == initializedValue); } auto p7 = make_shared_for_overwrite_assert(2u); for (ptrdiff_t i = 0; i < 2; ++i) { for (ptrdiff_t j = 0; j < 8; ++j) { for (ptrdiff_t k = 0; k < 9; ++k) { - assert(p7[i][j][k].value == defaultValue); + assert(p7[i][j][k].value == initializedValue); } } } @@ -276,7 +276,7 @@ void test_allocate_shared_for_overwrite() { allocator a1{}; auto p1 = allocate_shared_for_overwrite_assert(a1); - assert(p1->value == defaultValue); + assert(p1->value == initializedValue); allocator a2{}; auto p2 = allocate_shared_for_overwrite_assert(a2); @@ -289,7 +289,7 @@ void test_allocate_shared_for_overwrite() { auto p4 = allocate_shared_for_overwrite_assert(a1); for (ptrdiff_t i = 0; i < 2; ++i) { for (ptrdiff_t j = 0; j < 8; ++j) { - assert(p4[i][j].value == defaultValue); + assert(p4[i][j].value == initializedValue); } } @@ -299,14 +299,14 @@ void test_allocate_shared_for_overwrite() { auto p6 = allocate_shared_for_overwrite_assert(a1, 100u); for (ptrdiff_t i = 0; i < 100; ++i) { - assert(p6[i].value == defaultValue); + assert(p6[i].value == initializedValue); } auto p7 = allocate_shared_for_overwrite_assert(a1, 2u); for (ptrdiff_t i = 0; i < 2; ++i) { for (ptrdiff_t j = 0; j < 8; ++j) { for (ptrdiff_t k = 0; k < 9; ++k) { - assert(p7[i][j][k].value == defaultValue); + assert(p7[i][j][k].value == initializedValue); } } } From 2480d7be0e9e5101b3df8a17a9c07852b823a8f2 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 15 Oct 2020 23:58:03 -0700 Subject: [PATCH 17/24] Drop const for value parameters in friend declarations. --- stl/inc/memory | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 502c12924ef..737879e0a8c 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -1951,11 +1951,11 @@ private: const _Alloc& _Al_arg, size_t _Count); template - friend shared_ptr<_Ty0> _Make_shared_unbounded_array(const size_t _Count, const _ArgTypes&... _Args); + friend shared_ptr<_Ty0> _Make_shared_unbounded_array(size_t _Count, const _ArgTypes&... _Args); template friend shared_ptr<_Ty0> _Allocate_shared_unbounded_array( - const _Alloc& _Al, const size_t _Count, const _ArgTypes&... _Args); + const _Alloc& _Al, size_t _Count, const _ArgTypes&... _Args); #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template friend shared_ptr<_Ty0> make_shared(_Types&&... _Args); From c7adba8f147f548629e1ae62112d1c3bbf804ec6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 16 Oct 2020 00:05:01 -0700 Subject: [PATCH 18/24] Drop unnecessary friendship after refactoring. --- stl/inc/memory | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 737879e0a8c..2fb17a2bbb1 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -1908,27 +1908,12 @@ private: template friend enable_if_t, shared_ptr<_Ty0>> allocate_shared(const _Alloc& _Al_arg, _Types&&... _Args); - template - friend enable_if_t, shared_ptr<_Ty0>> make_shared(size_t _Count); - - template - friend enable_if_t, shared_ptr<_Ty0>> allocate_shared( - const _Alloc& _Al_arg, size_t _Count); - template friend enable_if_t, shared_ptr<_Ty0>> make_shared(); template friend enable_if_t, shared_ptr<_Ty0>> allocate_shared(const _Alloc& _Al_arg); - template - friend enable_if_t, shared_ptr<_Ty0>> make_shared( - size_t _Count, const remove_extent_t<_Ty0>& _Val); - - template - friend enable_if_t, shared_ptr<_Ty0>> allocate_shared( - const _Alloc& _Al_arg, size_t _Count, const remove_extent_t<_Ty0>& _Val); - template friend enable_if_t, shared_ptr<_Ty0>> make_shared(const remove_extent_t<_Ty0>& _Val); @@ -1943,13 +1928,6 @@ private: friend enable_if_t, shared_ptr<_Ty0>> allocate_shared_for_overwrite( const _Alloc& _Al_arg); - template - friend enable_if_t, shared_ptr<_Ty0>> make_shared_for_overwrite(size_t _Count); - - template - friend enable_if_t, shared_ptr<_Ty0>> allocate_shared_for_overwrite( - const _Alloc& _Al_arg, size_t _Count); - template friend shared_ptr<_Ty0> _Make_shared_unbounded_array(size_t _Count, const _ArgTypes&... _Args); From 90e2ebc531c354d6b9d8efca8bd608d48b1146a0 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 16 Oct 2020 00:19:00 -0700 Subject: [PATCH 19/24] Given `const _Arg&` we don't need `remove_cvref_t`. --- stl/inc/memory | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 2fb17a2bbb1..ca2a339bac0 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -2422,7 +2422,7 @@ public: template explicit _Ref_count_unbounded_array(const size_t _Count, const _Arg& _Val) : _Ref_count_base() { - if constexpr (is_same_v<_For_overwrite_tag, remove_cvref_t<_Arg>>) { + if constexpr (is_same_v<_For_overwrite_tag, _Arg>) { _Uninitialized_default_construct_multidimensional_n(_Get_ptr(), _Count); } else { _Uninitialized_fill_multidimensional_n(_Get_ptr(), _Count, _Val); @@ -2468,7 +2468,7 @@ public: template explicit _Ref_count_unbounded_array(const size_t _Count, const _Arg& _Val) : _Ref_count_base(), _Size(_Count) { - if constexpr (is_same_v<_For_overwrite_tag, remove_cvref_t<_Arg>>) { + if constexpr (is_same_v<_For_overwrite_tag, _Arg>) { _Uninitialized_default_construct_multidimensional_n(_Get_ptr(), _Size); } else { _Uninitialized_fill_multidimensional_n(_Get_ptr(), _Size, _Val); @@ -2513,7 +2513,7 @@ public: template explicit _Ref_count_bounded_array(const _Arg& _Val) : _Ref_count_base() { // don't value-initialize _Storage - if constexpr (is_same_v<_For_overwrite_tag, remove_cvref_t<_Arg>>) { + if constexpr (is_same_v<_For_overwrite_tag, _Arg>) { _Uninitialized_default_construct_multidimensional_n(_Storage._Value, extent_v<_Ty>); } else { _Uninitialized_fill_multidimensional_n(_Storage._Value, extent_v<_Ty>, _Val); @@ -2774,7 +2774,7 @@ public: template explicit _Ref_count_unbounded_array_alloc(const _Alloc& _Al_arg, const size_t _Count, const _Arg& _Val) : _Ebco_base<_Rebound>(_Al_arg), _Ref_count_base(), _Size(_Count) { - if constexpr (is_same_v<_For_overwrite_tag, remove_cvref_t<_Arg>>) { + if constexpr (is_same_v<_For_overwrite_tag, _Arg>) { _Uninitialized_default_construct_multidimensional_n(_Get_ptr(), _Size); // the allocator isn't needed } else { _Uninitialized_fill_multidimensional_n_al(_Get_ptr(), _Size, _Val, this->_Get_val()); @@ -2840,7 +2840,7 @@ public: template explicit _Ref_count_bounded_array_alloc(const _Alloc& _Al_arg, const _Arg& _Val) : _Ebco_base<_Rebound>(_Al_arg), _Ref_count_base() { // don't value-initialize _Storage - if constexpr (is_same_v<_For_overwrite_tag, remove_cvref_t<_Arg>>) { + if constexpr (is_same_v<_For_overwrite_tag, _Arg>) { _Uninitialized_default_construct_multidimensional_n( _Storage._Value, extent_v<_Ty>); // the allocator isn't needed } else { From cb088ffe8a41bcbbd187d11c9f7d497a2ed68022 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 16 Oct 2020 00:33:30 -0700 Subject: [PATCH 20/24] Remove leftover comment. --- stl/inc/memory | 1 - 1 file changed, 1 deletion(-) diff --git a/stl/inc/memory b/stl/inc/memory index ca2a339bac0..529bbeae749 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -3033,7 +3033,6 @@ _NODISCARD shared_ptr<_Ty> _Allocate_shared_unbounded_array( template _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shared( const _Alloc& _Al, const size_t _Count) { - // make a shared_ptr to an unbounded array return _Allocate_shared_unbounded_array<_Ty>(_Al, _Count); } From 1280bad6702a47a29ca522e0d770ad9b13d7f696 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 16 Oct 2020 00:40:52 -0700 Subject: [PATCH 21/24] Use is_bounded_array_v in make_unique_for_overwrite. --- stl/inc/memory | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/memory b/stl/inc/memory index 529bbeae749..22efeb8248f 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -3581,7 +3581,7 @@ _NODISCARD unique_ptr<_Ty> make_unique_for_overwrite( return unique_ptr<_Ty>(new _Elem[_Size]); } -template != 0, int> = 0> +template , int> = 0> void make_unique_for_overwrite(_Types&&...) = delete; #endif // _HAS_CXX20 From b96db2c17d95905f64d0e538d735650ebd1b49c6 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 16 Oct 2020 14:32:37 +0200 Subject: [PATCH 22/24] Code review --- stl/inc/memory | 21 ++++++++------------- stl/inc/xutility | 14 +++++++++----- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 22efeb8248f..915acf7c89b 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -736,11 +736,6 @@ namespace ranges { #endif // __cpp_lib_concepts // FUNCTION TEMPLATE uninitialized_default_construct -template -_NODISCARD void* _Voidify_iter(_Iter _It) noexcept { - return const_cast(static_cast(_STD addressof(*_It))); -} - template void uninitialized_default_construct(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { // default-initialize all elements in [_First, _Last) @@ -750,7 +745,7 @@ void uninitialized_default_construct(const _NoThrowFwdIt _First, const _NoThrowF _Uninitialized_backout _Backout{_Get_unwrapped(_First)}; for (const auto _ULast = _Get_unwrapped(_Last); _Backout._Last != _ULast; ++_Backout._Last) { - ::new (_Voidify_iter(_Backout._Last)) _Ty; + _Default_construct_in_place(*_Backout._Last); } _Backout._Release(); @@ -802,7 +797,7 @@ namespace ranges { _Uninitialized_backout _Backout{_STD move(_OFirst)}; for (; _Backout._Last != _OLast; ++_Backout._Last) { - ::new (_Voidify_iter(_Backout._Last)) _Ty; + _Default_construct_in_place(*_Backout._Last); } return _Backout._Release(); @@ -831,7 +826,7 @@ _NoThrowFwdIt uninitialized_default_construct_n(_NoThrowFwdIt _First, const _Dif _Uninitialized_backout _Backout{_Get_unwrapped_n(_First, _Count)}; for (; _Count > 0; ++_Backout._Last, (void) --_Count) { - ::new (_Voidify_iter(_Backout._Last)) _Ty; + _Default_construct_in_place(*_Backout._Last); } _Seek_wrapped(_First, _Backout._Release()); @@ -862,7 +857,7 @@ namespace ranges { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); for (; _Count > 0; --_Count, (void) ++_UFirst) { - ::new (_Voidify_iter(_UFirst)) _Ty; + _Default_construct_in_place(*_UFirst); } _Seek_wrapped(_First, _STD move(_UFirst)); @@ -870,7 +865,7 @@ namespace ranges { _Uninitialized_backout _Backout{_Get_unwrapped_n(_STD move(_First), _Count)}; for (; _Count > 0; --_Count, (void) ++_Backout._Last) { - ::new (_Voidify_iter(_Backout._Last)) _Ty; + _Default_construct_in_place(*_Backout._Last); } _Seek_wrapped(_First, _Backout._Release()); @@ -2176,7 +2171,7 @@ public: explicit _Ref_count_obj2(_Types&&... _Args) : _Ref_count_base() { #if _HAS_CXX20 if constexpr (sizeof...(_Types) == 1 && (is_same_v<_For_overwrite_tag, remove_cvref_t<_Types>> && ...)) { - _Construct_in_place_for_overwrite(_Storage._Value); + _Default_construct_in_place(_Storage._Value); ((void) _Args, ...); } else #endif // _HAS_CXX20 @@ -2296,7 +2291,7 @@ struct _Uninitialized_rev_destroying_backout { } void _Emplace_back_for_overwrite() { - _Construct_in_place_for_overwrite(*_Last); + _Default_construct_in_place(*_Last); ++_Last; } @@ -2596,7 +2591,7 @@ public: : _Ebco_base<_Rebound>(_Al_arg), _Ref_count_base() { #if _HAS_CXX20 if constexpr (sizeof...(_Types) == 1 && (is_same_v<_For_overwrite_tag, remove_cvref_t<_Types>> && ...)) { - _Construct_in_place_for_overwrite(_Storage._Value); + _Default_construct_in_place(_Storage._Value); ((void) _Args, ...); } else #endif // _HAS_CXX20 diff --git a/stl/inc/xutility b/stl/inc/xutility index 6a6b29e5a84..0f809138dd1 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -120,16 +120,20 @@ struct _Get_rebind_alias<_Ty, _Other, void_t +_NODISCARD void* _Voidify_iter(_Iter _It) noexcept { + return const_cast(static_cast(_STD addressof(*_It))); +} + template void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) { - ::new (const_cast(static_cast(_STD addressof(_Obj)))) - _Ty(_STD forward<_Types>(_Args)...); + ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...); } -// FUNCTION TEMPLATE _Construct_in_place_for_overwrite +// FUNCTION TEMPLATE _Default_construct_in_place template -void _Construct_in_place_for_overwrite(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { - ::new (const_cast(static_cast(_STD addressof(_Obj)))) _Ty; +void _Default_construct_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { + ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty; } // STRUCT TEMPLATE pointer_traits From 0334b4316d82f914ecb723b89a595356ddae6ced Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 16 Oct 2020 11:02:51 -0700 Subject: [PATCH 23/24] Correct feature-test macro value is 202002L --- stl/inc/yvals_core.h | 2 +- tests/std/tests/VSO_0157762_feature_test_macros/test.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 840ec038707..afb1523b28f 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1210,7 +1210,7 @@ #define __cpp_lib_remove_cvref 201711L #define __cpp_lib_semaphore 201907L #define __cpp_lib_shift 201806L -#define __cpp_lib_smart_ptr_for_overwrite 201811L +#define __cpp_lib_smart_ptr_for_overwrite 202002L #define __cpp_lib_span 202002L #define __cpp_lib_ssize 201902L #define __cpp_lib_starts_ends_with 201711L diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp index ab6666e2d2a..216ac473b68 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp @@ -1269,10 +1269,10 @@ STATIC_ASSERT(__cpp_lib_shift == 201806L); #if _HAS_CXX20 #ifndef __cpp_lib_smart_ptr_for_overwrite #error __cpp_lib_smart_ptr_for_overwrite is not defined -#elif __cpp_lib_smart_ptr_for_overwrite != 201811L -#error __cpp_lib_smart_ptr_for_overwrite is not 201811L +#elif __cpp_lib_smart_ptr_for_overwrite != 202002L +#error __cpp_lib_smart_ptr_for_overwrite is not 202002L #else -STATIC_ASSERT(__cpp_lib_smart_ptr_for_overwrite == 201811L); +STATIC_ASSERT(__cpp_lib_smart_ptr_for_overwrite == 202002L); #endif #else #ifdef __cpp_lib_smart_ptr_for_overwrite From a7a069340c7538cabda6662373e5728d4b56097f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 16 Oct 2020 14:50:14 -0700 Subject: [PATCH 24/24] Improve _Voidify_iter debug codegen. --- stl/inc/xutility | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 0f809138dd1..fa244555d08 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -119,12 +119,20 @@ struct _Get_rebind_alias<_Ty, _Other, void_t; }; -// FUNCTION TEMPLATE _Construct_in_place +// FUNCTION TEMPLATE _Voidify_iter template _NODISCARD void* _Voidify_iter(_Iter _It) noexcept { - return const_cast(static_cast(_STD addressof(*_It))); +#if _HAS_IF_CONSTEXPR + if constexpr (is_pointer_v<_Iter>) { + return const_cast(static_cast(_It)); + } else +#endif // _HAS_IF_CONSTEXPR + { + return const_cast(static_cast(_STD addressof(*_It))); + } } +// FUNCTION TEMPLATE _Construct_in_place template void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) { ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...);