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 @@ -266,6 +266,8 @@ ------------------------------------------------- ----------------- ``__cpp_lib_semaphore`` ``201907L`` ------------------------------------------------- ----------------- + ``__cpp_lib_shared_ptr_arrays`` ``201707L`` + ------------------------------------------------- ----------------- ``__cpp_lib_shift`` *unimplemented* ------------------------------------------------- ----------------- ``__cpp_lib_smart_ptr_for_overwrite`` *unimplemented* diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -514,9 +514,29 @@ template D* get_deleter(shared_ptr const& p) noexcept; template - shared_ptr make_shared(Args&&... args); + shared_ptr make_shared(Args&&... args); // T is not array template - shared_ptr allocate_shared(const A& a, Args&&... args); + shared_ptr allocate_shared(const A& a, Args&&... args); // T is not array + +template + shared_ptr make_shared(size_t N); // T is U[] (since C++20) +template + shared_ptr allocate_shared(const A& a, size_t N); // T is U[] (since C++20) + +template + shared_ptr make_shared(); // T is U[N] (since C++20) +template + shared_ptr allocate_shared(const A& a); // T is U[N] (since C++20) + +template + shared_ptr make_shared(size_t N, const remove_extent_t& u); // T is U[] (since C++20) +template + shared_ptr allocate_shared(const A& a, size_t N, const remove_extent_t& u); // T is U[] (since C++20) + +template shared_ptr + make_shared(const remove_extent_t& u); // T is U[N] (since C++20) +template + shared_ptr allocate_shared(const A& a, const remove_extent_t& u); // T is U[N] (since C++20) template class weak_ptr @@ -2660,6 +2680,179 @@ _Storage __storage_; }; + +#if _LIBCPP_STD_VER > 17 +template +struct __shared_ptr_array_base + : __shared_weak_count +{ + _LIBCPP_HIDE_FROM_ABI + virtual _Tp* __get_elem_begin() noexcept = 0; + + // This is the size (in bytes) that needs to be allocated/deallocated. + _LIBCPP_HIDE_FROM_ABI + virtual size_t __get_size() noexcept = 0; + + // This is the number of elements in the array. + _LIBCPP_HIDE_FROM_ABI + virtual size_t __get_count() noexcept = 0; + +private: + template + _LIBCPP_HIDE_FROM_ABI + explicit __shared_ptr_array_base(_Alloc const&__alloc) + : __alloc_(__alloc) { } + + template + friend struct __shared_ptr_array_unbound; + + template + friend struct __shared_ptr_array_bound; + + // Destroys every element in the range [first, first + n) FROM RIGHT TO LEFT + // using allocator destruction by rebinding this::alloc to the correct allocator + // type. If elements are themselves C-style arrays, they are recursively + // destroyed in the same manner. + // + // This function assumes that destructors do not throw. + template + _LIBCPP_HIDE_FROM_ABI + void __destroy_elements(_ValueType *__first, long __n) noexcept { + using _ValueAlloc = typename __allocator_traits_rebind<_Alloc, _ValueType>::type; + _ValueAlloc __value_alloc(__alloc_); + for (--__n; __n >= 0; --__n) { + if constexpr (is_array_v<_ValueType>) { + __destroy_elements(__first[__n], extent_v<_ValueType>); + } else { + allocator_traits<_ValueAlloc>::destroy(__value_alloc, __first + __n); + } + } + } + + // Given a range delimited by [first, first + n), initializes + // the range [first, first + n) from left to right using the construct method + // of this::alloc rebound to the correct allocator type. + // + // Each element is initialized using allocator_traits construction, and the given + // arguments are passed to construction. The arguments are not perfect-forwarded + // because that could set us up for double-moves. If the elements of the range + // are themselves C-style arrays, they are recursively constructed in the same + // manner. + // + // If an exception is thrown, the initialized elements are destroyed in reverse + // order of initialization using allocator_traits destruction. + template + _LIBCPP_HIDE_FROM_ABI + void __construct_elements(_ValueType *__first, size_t __n, _Args&& ...__args) { + using _ValueAlloc = typename __allocator_traits_rebind<_Alloc, _ValueType>::type; + _ValueAlloc __value_alloc(__alloc_); + size_t __i = 0; + + #ifndef _LIBCPP_NO_EXCEPTIONS + try { + #endif + for (; __i < __n; ++__i) { + if constexpr (is_array_v<_ValueType>) { + __construct_elements(_VSTD::begin(*(__first + __i)), extent_v<_ValueType>, __args...); + } else { + allocator_traits<_ValueAlloc>::construct(__value_alloc, __first + __i, __args...); + } + } + #ifndef _LIBCPP_NO_EXCEPTIONS + } catch (...) { + // When _ValueType is NOT an array: destroy the half-open range + // [__first, __first + __i + 1) which includes the last object that was fully + // construct, but not the object that was partially constructed. + // + // When _ValueType is an array: only destroy [__first, __first + __i), because the + // one-deeper level of recursion (the function that propagated the exception), has + // already destroyed all constructed elements in the array at __first + __i, as + // described above. + // + // NOTE: because elements are destroyed right to left, the second argument to + // __destroy_elements should always be one greater than the number of elements to be + // destroyed. + if constexpr (is_array_v<_ValueType>) + __destroy_elements(__first, __i); + else + __destroy_elements(__first, __i + 1); + throw; + } + #endif + } + + virtual void __on_zero_shared() _NOEXCEPT { + __destroy_elements(__get_elem_begin(), __get_count()); + } + + virtual void __on_zero_shared_weak() _NOEXCEPT { + using _CharAlloc = typename __allocator_traits_rebind<_Alloc, char>::type; + _CharAlloc __tmp(__alloc_); + allocator_traits<_CharAlloc>::deallocate(__tmp, reinterpret_cast(this), __get_size()); + } + + [[no_unique_address]] _Alloc __alloc_; +}; + +template +struct __shared_ptr_array_unbound + : __shared_ptr_array_base<_Tp, _Alloc> +{ + using _Base = __shared_ptr_array_base<_Tp, _Alloc>; + + _LIBCPP_HIDE_FROM_ABI + _Tp* __get_elem_begin() noexcept { return reinterpret_cast<_Tp*>(&__data_); } + + _LIBCPP_HIDE_FROM_ABI + size_t __get_size() noexcept { + return __count_ * sizeof(_Tp) + sizeof(__shared_ptr_array_unbound); + } + + _LIBCPP_HIDE_FROM_ABI + size_t __get_count() noexcept { return __count_; } + + template + _LIBCPP_HIDE_FROM_ABI + explicit __shared_ptr_array_unbound(_Alloc const&__alloc, size_t __count, _Args&&... __args) + : _Base(__alloc), __count_(__count) { + _Base::__construct_elements(__get_elem_begin(), __count, _VSTD::forward<_Args>(__args)...); + } + +private: + size_t __count_; + using _DataBlock = typename std::aligned_storage::type; + _DataBlock __data_[0]; +}; + +template +struct __shared_ptr_array_bound + : __shared_ptr_array_base<_Tp, _Alloc> +{ + using _Base = __shared_ptr_array_base<_Tp, _Alloc>; + + _LIBCPP_HIDE_FROM_ABI + _Tp* __get_elem_begin() noexcept { return reinterpret_cast<_Tp*>(&__data_); } + + _LIBCPP_HIDE_FROM_ABI + size_t __get_size() noexcept { return sizeof(__shared_ptr_array_bound); } + + _LIBCPP_HIDE_FROM_ABI + size_t __get_count() noexcept { return _Count; } + + template + _LIBCPP_HIDE_FROM_ABI + explicit __shared_ptr_array_bound(_Alloc const&__alloc, _Args&&... __args) + : _Base(__alloc) { + _Base::__construct_elements(__get_elem_begin(), _Count, _VSTD::forward<_Args>(__args)...); + } + +private: + using _DataBlock = typename std::aligned_storage::type; + _DataBlock __data_[_Count]; +}; + +#endif // _LIBCPP_STD_VER > 17 + struct __shared_ptr_dummy_rebind_allocator_type; template <> class _LIBCPP_TEMPLATE_VIS allocator<__shared_ptr_dummy_rebind_allocator_type> @@ -3369,6 +3562,95 @@ return _VSTD::allocate_shared<_Tp>(allocator<_Tp>(), _VSTD::forward<_Args>(__args)...); } +#if _LIBCPP_STD_VER > 17 + +template +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> __allocate_shared_array_unbound(const _Alloc& __a, size_t __n, _Args&& ...__args) +{ + using _ElemT = remove_extent_t<_Tp>; + using _ControlBlock = __shared_ptr_array_unbound<_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, _VSTD::forward<_Args>(__args)...); + 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 +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> __allocate_shared_array_bound(const _Alloc& __a, _Args&& ...__args) +{ + using _ElemT = remove_extent_t<_Tp>; + using _ControlBlock = __shared_ptr_array_bound<_ElemT, _Alloc, extent_v<_Tp>>; + using _ControlBlockAllocator = typename __allocator_traits_rebind<_Alloc, _ControlBlock>::type; + + __allocation_guard<_ControlBlockAllocator> __guard(__a, sizeof(_ControlBlock)); + ::new ((void*)_VSTD::addressof(*__guard.__get())) _ControlBlock(__a, _VSTD::forward<_Args>(__args)...); + return shared_ptr<_Tp>::__create_with_control_block(__guard.__get()->__get_elem_begin(), __guard.__release_ptr()); +} + +template::value> > +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> allocate_shared(const _Alloc& __a) +{ + return __allocate_shared_array_bound<_Tp>(__a); +} + +template::value> > +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> allocate_shared(const _Alloc& __a, const remove_extent_t<_Tp>& __u) +{ + return __allocate_shared_array_bound<_Tp>(__a, __u); +} + +template::value> > +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> allocate_shared(const _Alloc& __a, size_t __n) +{ + return __allocate_shared_array_unbound<_Tp>(__a, __n); +} + +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_unbound<_Tp>(__a, __n, __u); +} + +template::value> > +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> make_shared() +{ + return __allocate_shared_array_bound<_Tp>(allocator<_Tp>()); +} + +template::value> > +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> make_shared(const remove_extent_t<_Tp>& __u) +{ + return __allocate_shared_array_bound<_Tp>(allocator<_Tp>(), __u); +} + +template::value> > +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> make_shared(size_t __n) +{ + return __allocate_shared_array_unbound<_Tp>(allocator<_Tp>(), __n); +} + +template::value> > +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> make_shared(size_t __n, const remove_extent_t<_Tp>& __u) +{ + return __allocate_shared_array_unbound<_Tp>(allocator<_Tp>(), __n, __u); +} + +#endif // _LIBCPP_STD_VER > 17 + + template inline _LIBCPP_INLINE_VISIBILITY bool diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -129,7 +129,8 @@ __cpp_lib_scoped_lock 201703L __cpp_lib_semaphore 201907L __cpp_lib_shared_mutex 201505L -__cpp_lib_shared_ptr_arrays 201611L +__cpp_lib_shared_ptr_arrays 201707L + 201611L // C++17 __cpp_lib_shared_ptr_weak_type 201606L __cpp_lib_shared_timed_mutex 201402L __cpp_lib_shift 201806L @@ -339,6 +340,8 @@ # if !defined(_LIBCPP_HAS_NO_THREADS) # define __cpp_lib_semaphore 201907L # endif +# undef __cpp_lib_shared_ptr_arrays +# define __cpp_lib_shared_ptr_arrays 201707L // # define __cpp_lib_shift 201806L // # define __cpp_lib_smart_ptr_for_overwrite 202002L // # define __cpp_lib_source_location 201907L 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 @@ -26,6 +26,7 @@ __cpp_lib_ranges 201811L [C++20] __cpp_lib_raw_memory_algorithms 201606L [C++17] __cpp_lib_shared_ptr_arrays 201611L [C++17] + 201707L [C++20] __cpp_lib_shared_ptr_weak_type 201606L [C++17] __cpp_lib_smart_ptr_for_overwrite 202002L [C++20] __cpp_lib_to_address 201711L [C++20] @@ -388,8 +389,8 @@ # ifndef __cpp_lib_shared_ptr_arrays # error "__cpp_lib_shared_ptr_arrays should be defined in c++20" # endif -# if __cpp_lib_shared_ptr_arrays != 201611L -# error "__cpp_lib_shared_ptr_arrays should have the value 201611L in c++20" +#if __cpp_lib_shared_ptr_arrays != 201707L +#error "__cpp_lib_shared_ptr_arrays should have the value 201707L in c++20" # endif # ifndef __cpp_lib_shared_ptr_weak_type @@ -544,8 +545,8 @@ # ifndef __cpp_lib_shared_ptr_arrays # error "__cpp_lib_shared_ptr_arrays should be defined in c++2b" # endif -# if __cpp_lib_shared_ptr_arrays != 201611L -# error "__cpp_lib_shared_ptr_arrays should have the value 201611L in c++2b" +#if __cpp_lib_shared_ptr_arrays != 201707L +#error "__cpp_lib_shared_ptr_arrays should have the value 201707L in c++2b" # 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 @@ -118,6 +118,7 @@ __cpp_lib_semaphore 201907L [C++20] __cpp_lib_shared_mutex 201505L [C++17] __cpp_lib_shared_ptr_arrays 201611L [C++17] + 201707L [C++20] __cpp_lib_shared_ptr_weak_type 201606L [C++17] __cpp_lib_shared_timed_mutex 201402L [C++14] __cpp_lib_shift 201806L [C++20] @@ -3046,8 +3047,8 @@ # ifndef __cpp_lib_shared_ptr_arrays # error "__cpp_lib_shared_ptr_arrays should be defined in c++20" # endif -# if __cpp_lib_shared_ptr_arrays != 201611L -# error "__cpp_lib_shared_ptr_arrays should have the value 201611L in c++20" +#if __cpp_lib_shared_ptr_arrays != 201707L +#error "__cpp_lib_shared_ptr_arrays should have the value 201707L in c++20" # endif # ifndef __cpp_lib_shared_ptr_weak_type @@ -4267,8 +4268,8 @@ # ifndef __cpp_lib_shared_ptr_arrays # error "__cpp_lib_shared_ptr_arrays should be defined in c++2b" # endif -# if __cpp_lib_shared_ptr_arrays != 201611L -# error "__cpp_lib_shared_ptr_arrays should have the value 201611L in c++2b" +#if __cpp_lib_shared_ptr_arrays != 201707L +#error "__cpp_lib_shared_ptr_arrays should have the value 201707L in c++2b" # 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,355 @@ +//===----------------------------------------------------------------------===// +// +// 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; + + int value; + A() : value(++count) {} + A(const A&) : value(++count) {} + ~A() { assert(count-- == value); } +}; + +int A::count = 0; + +struct B { + std::max_align_t val; +}; + +struct C { + static int count; + + int value; + C() : value(++count) {} + ~C() { assert(count-- == value); } +}; + +int C::count = 0; + +struct D { + static int count; + static int total; + static int throwAt; + + int value; + D() : value(++count) { + ++total; + printf("ctor value = %d\n", value); + if (value == throwAt) + throw 0; + } + ~D() { + printf("dtor value = %d; count = %d\n", value, count); + assert(count-- == value); + } +}; + +int D::count = 0; +int D::total = 0; +int D::throwAt = 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; +}; + +struct CopyCounter { + static int count; + CopyCounter() = default; + CopyCounter(const CopyCounter&) { ++count; } +}; + +int CopyCounter::count = 0; + +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(3); + std::shared_ptr ptr1 = std::allocate_shared(std::allocator(), 3); + assert(ptr0[0][0].value == 1); + assert(ptr0[0][1].value == 2); + assert(ptr0[1][0].value == 3); + assert(ptr0[1][1].value == 4); + assert(ptr0[2][0].value == 5); + assert(ptr0[2][1].value == 6); + assert(ptr1[0][0].value == 7); + assert(ptr1[0][1].value == 8); + assert(ptr1[1][0].value == 9); + assert(ptr1[1][1].value == 10); + assert(ptr1[2][0].value == 11); + assert(ptr1[2][1].value == 12); + } + + { + 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[3][2]; + std::shared_ptr ptr0 = std::make_shared(); + std::shared_ptr ptr1 = std::allocate_shared(std::allocator()); + assert(ptr0[0][0].value == 1); + assert(ptr0[0][1].value == 2); + assert(ptr0[1][0].value == 3); + assert(ptr0[1][1].value == 4); + assert(ptr0[2][0].value == 5); + assert(ptr0[2][1].value == 6); + assert(ptr1[0][0].value == 7); + assert(ptr1[0][1].value == 8); + assert(ptr1[1][0].value == 9); + assert(ptr1[1][1].value == 10); + assert(ptr1[2][0].value == 11); + assert(ptr1[2][1].value == 12); + } + + { + 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)); + } + + { + using T = D[][2][2][2][4][4]; + D::count = 0; + D::throwAt = 512; + + try { + std::shared_ptr ptr = std::allocate_shared(std::allocator(), 8); + assert(false && "We should have thrown and recovered."); + } catch (...) { + } + assert(D::total == 512); + assert(D::count == 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()); + } + + { + using T = CopyCounter[]; + CopyCounter::count = 0; + std::shared_ptr ptr = std::make_shared(4, CopyCounter()); + assert(CopyCounter::count == 4); + } + + { + using T = CopyCounter[4]; + CopyCounter::count = 0; + std::shared_ptr ptr = std::make_shared(CopyCounter()); + assert(CopyCounter::count == 4); + } + + // make sure alignment works + { + using T = B[8]; + std::shared_ptr ptr = std::make_shared(); + assert(reinterpret_cast(ptr.get()) % alignof(B) == 0); + } + { + using T = B[]; + std::shared_ptr ptr = std::make_shared(8); + 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 @@ -507,7 +507,7 @@ "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)", }, { "name": "__cpp_lib_shared_ptr_arrays", - "values": { "c++17": 201611 }, + "values": { "c++17": 201611, "c++20": 201707 }, "headers": ["memory"], }, { "name": "__cpp_lib_shared_ptr_weak_type",