diff --git a/libcxx/docs/Cxx2aStatusPaperStatus.csv b/libcxx/docs/Cxx2aStatusPaperStatus.csv --- a/libcxx/docs/Cxx2aStatusPaperStatus.csv +++ b/libcxx/docs/Cxx2aStatusPaperStatus.csv @@ -1,6 +1,6 @@ "Paper #","Group","Paper Name","Meeting","Status","First released version" "`P0463R1 `__","LWG","Endian just Endian","Toronto","|Complete|","7.0" -"`P0674R1 `__","LWG","Extending make_shared to Support Arrays","Toronto","","" +"`P0674R1 `__","LWG","Extending make_shared to Support Arrays","Toronto","|Complete|","12.0" "","","","","","" "`P0020R6 `__","LWG","Floating Point Atomic","Albuquerque","","" "`P0053R7 `__","LWG","C++ Synchronized Buffered Ostream","Albuquerque","","" diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -146,7 +146,7 @@ ------------------------------------------------- ----------------- ``__cpp_lib_shared_mutex`` ``201505L`` ------------------------------------------------- ----------------- - ``__cpp_lib_shared_ptr_arrays`` ``201611L`` + ``__cpp_lib_shared_ptr_arrays`` ``201707L`` ------------------------------------------------- ----------------- ``__cpp_lib_shared_ptr_weak_type`` ``201606L`` ------------------------------------------------- ----------------- diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -2710,6 +2710,89 @@ }; #endif // >= C++20 && supports [[no_unique_address]] + +#if _LIBCPP_STD_VER > 17 +template>> +void __shared_ptr_destroy_elem(_Tp* __ptr) { __ptr->~_Tp(); } + +template +void __shared_ptr_destroy_elem(_Tp(*__ptr)[_Sz]) +{ + for (size_t __i = 0; __i < _Sz; ++__i) + __shared_ptr_destroy_elem(__ptr[__i]); +} + +template +struct __shared_ptr_array_info +{ + [[no_unique_address]] _Alloc __alloc; + size_t __size; +}; + +template +struct __shared_ptr_array + : __shared_weak_count +{ + using _Info = __shared_ptr_array_info<_Alloc>; + using _InfoBlock = typename std::aligned_storage::type; + using _DataBlock = typename std::aligned_storage::type; + + _LIBCPP_HIDE_FROM_ABI + _Tp* __get_elem_begin() _NOEXCEPT { return reinterpret_cast<_Tp*>(&__data); } + + _LIBCPP_HIDE_FROM_ABI + size_t __get_size() _NOEXCEPT { return reinterpret_cast<_Info*>(&__info)->__size; } + + _LIBCPP_HIDE_FROM_ABI + _Alloc* __get_alloc() _NOEXCEPT { + return _VSTD::addressof(reinterpret_cast<_Info*>(&__info)->__alloc); + } + + template + __shared_ptr_array(_Alloc const&__a, size_t __size, _Et const&__element) { + *reinterpret_cast<_Info*>(&__info) = {__a, __size}; + __fill_data(__element); + } + +private: + template + void __fill_data(_Et __element) { + _Tp *__ptr = __get_elem_begin(); + size_t __size = __get_size(); + for (size_t __i = 0; __i < __size; ++__i, ++__ptr) + ::new(static_cast(__ptr)) _Tp(__element); + } + + void __fill_data(false_type) { + _Tp *__ptr = __get_elem_begin(); + size_t __size = __get_size(); + for (size_t __i = 0; __i < __size; ++__i, ++__ptr) + ::new(static_cast(__ptr)) _Tp(); + } + + virtual void __on_zero_shared() _NOEXCEPT { + size_t __i = 0; + size_t __size = __get_size(); + _Tp *__ptr = __get_elem_begin(); + for (; __i < __size; ++__i, ++__ptr) { + __shared_ptr_destroy_elem(__ptr); + } + } + + virtual void __on_zero_shared_weak() _NOEXCEPT { + using _CharAlloc = typename __allocator_traits_rebind<_Alloc, char>::type; + _CharAlloc __tmp(*__get_alloc()); + __get_alloc()->~_Alloc(); + size_t __size = __get_size() * sizeof(_Tp) + sizeof(__shared_ptr_array); + allocator_traits<_CharAlloc>::deallocate(__tmp, reinterpret_cast(this), __size); + } + + _InfoBlock __info; + _DataBlock __data[0]; +}; + +#endif // _LIBCPP_STD_VER > 17 + struct __shared_ptr_dummy_rebind_allocator_type; template <> class _LIBCPP_TEMPLATE_VIS allocator<__shared_ptr_dummy_rebind_allocator_type> @@ -3412,13 +3495,61 @@ return shared_ptr<_Tp>::__create_with_control_block((*__control_block).__get_elem(), _VSTD::addressof(*__control_block)); } -template::value> > +#if _LIBCPP_STD_VER > 17 + +template +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> __allocate_shared_array(const _Alloc& __a, size_t __n, const _Et& __u) +{ + using _ElemT = remove_extent_t<_Tp>; + using _ControlBlock = __shared_ptr_array<_ElemT, _Alloc>; + using _CharAllocator = typename __allocator_traits_rebind<_Alloc, char>::type; + + size_t __size = __n * sizeof(_ElemT) + sizeof(_ControlBlock); + __allocation_guard<_CharAllocator> __guard(__a, __size); + ::new ((void*)_VSTD::addressof(*__guard.__get())) _ControlBlock(__a, __n, __u); + auto __control_block = reinterpret_cast<_ControlBlock*>(__guard.__release_ptr()); + return shared_ptr<_Tp>::__create_with_control_block((*__control_block).__get_elem_begin(), _VSTD::addressof(*__control_block)); +} + +template::value> > +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> allocate_shared(const _Alloc& __a) +{ + return __allocate_shared_array<_Tp>(__a, extent_v<_Tp>, false_type()); +} + +template::value> > +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> allocate_shared(const _Alloc& __a, const remove_extent_t<_Tp>& __u) +{ + return __allocate_shared_array<_Tp>(__a, extent_v<_Tp>, __u); +} + +template::value> > +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> allocate_shared(const _Alloc& __a, size_t __n) +{ + return __allocate_shared_array<_Tp>(__a, __n, false_type()); +} + +template::value> > +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> allocate_shared(const _Alloc& __a, size_t __n, const remove_extent_t<_Tp>& __u) +{ + return __allocate_shared_array<_Tp>(__a, __n, __u); +} + +#endif // _LIBCPP_STD_VER > 17 + +template _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared(_Args&& ...__args) { return _VSTD::allocate_shared<_Tp>(allocator<_Tp>(), _VSTD::forward<_Args>(__args)...); } + template inline _LIBCPP_INLINE_VISIBILITY bool diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -107,7 +107,7 @@ __cpp_lib_sample 201603L __cpp_lib_scoped_lock 201703L __cpp_lib_shared_mutex 201505L -__cpp_lib_shared_ptr_arrays 201611L +__cpp_lib_shared_ptr_arrays 201707L __cpp_lib_shared_ptr_weak_type 201606L __cpp_lib_shared_timed_mutex 201402L __cpp_lib_span 202002L @@ -210,7 +210,7 @@ # if !defined(_LIBCPP_HAS_NO_THREADS) # define __cpp_lib_shared_mutex 201505L # endif -# define __cpp_lib_shared_ptr_arrays 201611L +# define __cpp_lib_shared_ptr_arrays 201707L # define __cpp_lib_shared_ptr_weak_type 201606L # define __cpp_lib_string_view 201606L // # define __cpp_lib_to_chars 201611L diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp @@ -22,7 +22,7 @@ __cpp_lib_make_unique 201304L [C++14] __cpp_lib_ranges 201811L [C++2a] __cpp_lib_raw_memory_algorithms 201606L [C++17] - __cpp_lib_shared_ptr_arrays 201611L [C++17] + __cpp_lib_shared_ptr_arrays 201707L [C++17] __cpp_lib_shared_ptr_weak_type 201606L [C++17] */ @@ -174,8 +174,8 @@ # ifndef __cpp_lib_shared_ptr_arrays # error "__cpp_lib_shared_ptr_arrays should be defined in c++17" # endif -# if __cpp_lib_shared_ptr_arrays != 201611L -# error "__cpp_lib_shared_ptr_arrays should have the value 201611L in c++17" +# if __cpp_lib_shared_ptr_arrays != 201707L +# error "__cpp_lib_shared_ptr_arrays should have the value 201707L in c++17" # endif # ifndef __cpp_lib_shared_ptr_weak_type @@ -264,8 +264,8 @@ # ifndef __cpp_lib_shared_ptr_arrays # error "__cpp_lib_shared_ptr_arrays should be defined in c++2a" # endif -# if __cpp_lib_shared_ptr_arrays != 201611L -# error "__cpp_lib_shared_ptr_arrays should have the value 201611L in c++2a" +# if __cpp_lib_shared_ptr_arrays != 201707L +# error "__cpp_lib_shared_ptr_arrays should have the value 201707L in c++2a" # endif # ifndef __cpp_lib_shared_ptr_weak_type diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -94,7 +94,7 @@ __cpp_lib_sample 201603L [C++17] __cpp_lib_scoped_lock 201703L [C++17] __cpp_lib_shared_mutex 201505L [C++17] - __cpp_lib_shared_ptr_arrays 201611L [C++17] + __cpp_lib_shared_ptr_arrays 201707L [C++17] __cpp_lib_shared_ptr_weak_type 201606L [C++17] __cpp_lib_shared_timed_mutex 201402L [C++14] __cpp_lib_span 202002L [C++2a] @@ -1510,8 +1510,8 @@ # ifndef __cpp_lib_shared_ptr_arrays # error "__cpp_lib_shared_ptr_arrays should be defined in c++17" # endif -# if __cpp_lib_shared_ptr_arrays != 201611L -# error "__cpp_lib_shared_ptr_arrays should have the value 201611L in c++17" +# if __cpp_lib_shared_ptr_arrays != 201707L +# error "__cpp_lib_shared_ptr_arrays should have the value 201707L in c++17" # endif # ifndef __cpp_lib_shared_ptr_weak_type @@ -2362,8 +2362,8 @@ # ifndef __cpp_lib_shared_ptr_arrays # error "__cpp_lib_shared_ptr_arrays should be defined in c++2a" # endif -# if __cpp_lib_shared_ptr_arrays != 201611L -# error "__cpp_lib_shared_ptr_arrays should have the value 201611L in c++2a" +# if __cpp_lib_shared_ptr_arrays != 201707L +# error "__cpp_lib_shared_ptr_arrays should have the value 201707L in c++2a" # endif # ifndef __cpp_lib_shared_ptr_weak_type diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/create_array.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/create_array.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/create_array.pass.cpp @@ -0,0 +1,281 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// + +// shared_ptr + +// template shared_ptr make_shared(size_t N); // T is U[] +// template +// shared_ptr allocate_shared(const A& a, size_t N); // T is U[] + +// template shared_ptr make_shared(); // T is U[N] +// template +// shared_ptr allocate_shared(const A& a); // T is U[N] + +// template +// shared_ptr make_shared(size_t N, const remove_extent_t& u); // T is U[] +// template +// shared_ptr allocate_shared(const A& a, size_t N, +// const remove_extent_t& u); // T is U[] + +// template shared_ptr +// make_shared(const remove_extent_t& u); // T is U[N] +// template +// shared_ptr allocate_shared(const A& a, +// const remove_extent_t& u); // T is U[N] + +#include +#include + +#include "count_new.h" +#include "test_macros.h" + +struct A { + static int count; + + A() { ++count; } + A(const A&) { ++count; } + ~A() { --count; } +}; + +int A::count = 0; + +struct B { + std::max_align_t val; +}; + +struct C { + static int count; + + int value; + C() : value(count++) {} +}; + +int C::count = 0; + +struct BigType { + char buff[128]; + + BigType(char value = 1) { + for (auto &e : buff) + e = value; + } + + long sum() { + long out = 0; + for (auto e : buff) + out += e; + return out; + } +}; + +struct NoCopyMove { + NoCopyMove() = default; + NoCopyMove(NoCopyMove const &) = delete; + NoCopyMove(NoCopyMove &&) = delete; +}; + +struct MoveOnly { + MoveOnly() = default; + MoveOnly(MoveOnly const &) = delete; + MoveOnly(MoveOnly &&) = default; +}; + +int main() { + { + using Unbound = A[]; + { + std::shared_ptr ptr0 = std::make_shared(8); + assert(A::count == 8); + } + assert(A::count == 0); + { + std::shared_ptr ptr1 = + std::allocate_shared(std::allocator(), 8); + assert(A::count == 8); + } + assert(A::count == 0); + + using Unbound1 = A[][2]; + { + std::shared_ptr ptr0 = std::make_shared(8); + assert(A::count == 16); + } + assert(A::count == 0); + { + std::shared_ptr ptr1 = + std::allocate_shared(std::allocator(), 8); + assert(A::count == 16); + } + assert(A::count == 0); + + using Unbound2 = A[][2][2]; + { + std::shared_ptr ptr0 = std::make_shared(8); + assert(A::count == 32); + } + assert(A::count == 0); + { + std::shared_ptr ptr1 = + std::allocate_shared(std::allocator(), 8); + assert(A::count == 32); + } + assert(A::count == 0); + } + + { + using Bound = A[8]; + { + std::shared_ptr ptr0 = std::make_shared(); + assert(A::count == 8); + } + assert(A::count == 0); + { + std::shared_ptr ptr1 = + std::allocate_shared(std::allocator()); + assert(A::count == 8); + } + assert(A::count == 0); + + using Bound1 = A[8][2]; + { + std::shared_ptr ptr0 = std::make_shared(); + assert(A::count == 16); + } + assert(A::count == 0); + { + std::shared_ptr ptr1 = + std::allocate_shared(std::allocator()); + assert(A::count == 16); + } + assert(A::count == 0); + + using Bound2 = A[8][2][2]; + { + std::shared_ptr ptr0 = std::make_shared(); + assert(A::count == 32); + } + assert(A::count == 0); + { + std::shared_ptr ptr1 = + std::allocate_shared(std::allocator()); + assert(A::count == 32); + } + assert(A::count == 0); + } + + { + using T = int[]; + std::shared_ptr ptr0 = std::make_shared(8, 42); + std::shared_ptr ptr1 = + std::allocate_shared(std::allocator(), 8, 42); + + for (unsigned i = 0; i < 8; ++i) { + assert(ptr0[i] == 42); + assert(ptr1[i] == 42); + } + } + + { + using T = C[][2]; + std::shared_ptr ptr0 = std::make_shared(8); + C::count = 0; + std::shared_ptr ptr1 = std::allocate_shared(std::allocator(), 8); + C::count = 0; + + for (int i = 0; i < 8; ++i) { + assert(ptr0[i][0].value == i * 2); + assert(ptr1[i][0].value == i * 2); + assert(ptr0[i][1].value == (i * 2) + 1); + assert(ptr1[i][1].value == (i * 2) + 1); + } + } + + { + using T = int[8]; + std::shared_ptr ptr0 = std::make_shared(42); + std::shared_ptr ptr1 = std::allocate_shared(std::allocator(), 42); + + for (unsigned i = 0; i < 8; ++i) { + assert(ptr0[i] == 42); + assert(ptr1[i] == 42); + } + } + + { + using T = C[8][2]; + std::shared_ptr ptr0 = std::make_shared(); + C::count = 0; + std::shared_ptr ptr1 = std::allocate_shared(std::allocator()); + C::count = 0; + + for (int i = 0; i < 8; ++i) { + assert(ptr0[i][0].value == i * 2); + assert(ptr1[i][0].value == i * 2); + assert(ptr0[i][1].value == (i * 2) + 1); + assert(ptr1[i][1].value == (i * 2) + 1); + } + } + + { + using T = BigType[8]; + std::shared_ptr ptr = std::make_shared(); + for (unsigned i = 0; i < 8; ++i) + assert(ptr[i].sum() == 128); + } + + { + using T = A[8]; + A::count = 0; + globalMemCounter.reset(); + globalMemCounter.throw_after = 0; + try { + std::shared_ptr ptr = std::make_shared(); + assert(false && "We should have thrown and recovered."); + } catch (...) { + assert(A::count == 0); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); + } + + { + using T = A[8]; + A::count = 0; + globalMemCounter.reset(); + globalMemCounter.throw_after = 0; + try { + std::shared_ptr ptr = std::allocate_shared(std::allocator()); + assert(false && "We should have thrown and recovered."); + } catch (...) { + assert(A::count == 0); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); + } + + { + std::shared_ptr ptr1 = std::allocate_shared(std::allocator()); + std::shared_ptr ptr2 = std::allocate_shared(std::allocator(), 8); + std::shared_ptr ptr3 = std::allocate_shared(std::allocator()); + std::shared_ptr ptr4 = std::allocate_shared(std::allocator(), 8); + assert(ptr1.get()); + assert(ptr2.get()); + assert(ptr3.get()); + assert(ptr4.get()); + } + + // make sure alignment works + { + using T = B[8]; + + std::shared_ptr ptr = std::make_shared(); + assert(reinterpret_cast(ptr.get()) % alignof(B) == 0); + } +} diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -200,7 +200,7 @@ "headers": ["memory"], }, { "name": "__cpp_lib_shared_ptr_arrays", - "values": { "c++17": int(201611) }, # "c++20": int(201707) # Enable this when we support arrays in std::make_shared + "values": { "c++17": int(201707) }, "headers": ["memory"], }, { "name": "__cpp_lib_memory_resource",