aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2022-01-13 22:08:43 +0000
committerJonathan Wakely <jwakely@redhat.com>2022-01-14 10:14:25 +0000
commit9a0b518a82db68c5cbd9ea8ccc47c2ff45182519 (patch)
tree6fce64cd7aacd03b1f14e5cb0282f4d917d49d23 /libstdc++-v3
parentfc6f1128ae603164aea6303ce2b3ed0b57e6a378 (diff)
downloadgcc-9a0b518a82db68c5cbd9ea8ccc47c2ff45182519.zip
gcc-9a0b518a82db68c5cbd9ea8ccc47c2ff45182519.tar.gz
gcc-9a0b518a82db68c5cbd9ea8ccc47c2ff45182519.tar.bz2
libstdc++: Add C++20 std::make_shared enhancements (P0674R1)
This adds the overloads of std::make_shared and std::allocate_shared for creating arrays, added to C++20 by P0674R1. It also adds std::make_shared_for_overwrite, added to C++20 by P1020R1 (and renamed by P1973R1). The std::make_unique_for_overwite overloads are already supported. The original std::make_shared overload is changed to construct a shared_ptr directly instead of calling std::allocate_shared. This removes a function call at runtime, and avoids having to do overload resolution for std::allocate_shared, now that there are five overloads of it. Allocating a shared array is done by a new __shared_count constructor. An array is allocated with space for additional elements at the end and an instance of new _Sp_counted_array class template is constructed in that unused capacity. The non-array form of std::make_shared_for_overwrite uses the same __shared_count constructor as the original std::make_shared overload, but a new partial specialization of _Sp_counted_ptr_inplace is selected when the allocator's value_type is the new _Sp_overwrite_tag type. That new partial specialization default-initializes its contained object and destroys it with a destructor call rather than using the allocator. Despite being C++20 features, this implementation only uses concepts conditionally, with workarounds when they are not supported. This allows it to work with older non-GCC compilers (Clang 9 and icc 2021). At some point we can simplify the code by removing the workarounds. libstdc++-v3/ChangeLog: * include/bits/shared_ptr.h (__cpp_lib_shared_ptr_weak_type): Correct type of macro value. (shared_ptr): Add additional friend declarations. (make_shared, allocate_shared): Constrain existing overloads and remove static_assert. * include/bits/shared_ptr_base.h (__cpp_lib_smart_ptr_for_overwrite): New macro. (_Sp_counted_ptr_inplace<T, Alloc, Lp>): New partial specialization for use with make_shared_for_overwrite. (__cpp_lib_shared_ptr_arrays): Update value for C++20. (_Sp_counted_array_base): New class template. (_Sp_counted_array): New class template. (__shared_count(_Tp*&, const _Sp_counted_array_base&, _Init)): New constructor for allocating shared arrays. (__shared_ptr(const _Sp_counted_array_base&, _Init)): Likewise. * include/std/version (__cpp_lib_shared_ptr_weak_type): Correct type. (__cpp_lib_shared_ptr_arrays): Update value for C++20. (__cpp_lib_smart_ptr_for_overwrite): New macro. * testsuite/20_util/shared_ptr/creation/99006.cc: Adjust expected errors. * testsuite/20_util/shared_ptr/creation/array.cc: New test. * testsuite/20_util/shared_ptr/creation/overwrite.cc: New test. * testsuite/20_util/shared_ptr/creation/version.cc: New test. * testsuite/20_util/unique_ptr/creation/for_overwrite.cc: Check feature test macro. Test non-trivial default-initialization.
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/include/bits/shared_ptr.h271
-rw-r--r--libstdc++-v3/include/bits/shared_ptr_base.h299
-rw-r--r--libstdc++-v3/include/std/version6
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/creation/99006.cc7
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/creation/array.cc224
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/creation/overwrite.cc143
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/creation/version.cc18
-rw-r--r--libstdc++-v3/testsuite/20_util/unique_ptr/creation/for_overwrite.cc25
8 files changed, 975 insertions, 18 deletions
diff --git a/libstdc++-v3/include/bits/shared_ptr.h b/libstdc++-v3/include/bits/shared_ptr.h
index 5fdfcb2..f44008e 100644
--- a/libstdc++-v3/include/bits/shared_ptr.h
+++ b/libstdc++-v3/include/bits/shared_ptr.h
@@ -100,6 +100,57 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
}
+ /// @cond undocumented
+
+ // Constraint for overloads taking non-array types.
+#if __cpp_concepts && __cpp_lib_type_trait_variable_templates
+ template<typename _Tp>
+ requires (!is_array_v<_Tp>)
+ using _NonArray = _Tp;
+#else
+ template<typename _Tp>
+ using _NonArray = __enable_if_t<!is_array<_Tp>::value, _Tp>;
+#endif
+
+#if __cpp_lib_shared_ptr_arrays >= 201707L
+ // Constraint for overloads taking array types with unknown bound, U[].
+#if __cpp_concepts
+ template<typename _Tp>
+ requires is_array_v<_Tp> && (extent_v<_Tp> == 0)
+ using _UnboundedArray = _Tp;
+#else
+ template<typename _Tp>
+ using _UnboundedArray
+ = __enable_if_t<__is_array_unknown_bounds<_Tp>::value, _Tp>;
+#endif
+
+ // Constraint for overloads taking array types with known bound, U[N].
+#if __cpp_concepts
+ template<typename _Tp>
+ requires (extent_v<_Tp> != 0)
+ using _BoundedArray = _Tp;
+#else
+ template<typename _Tp>
+ using _BoundedArray
+ = __enable_if_t<__is_array_known_bounds<_Tp>::value, _Tp>;
+#endif
+
+#if __cpp_lib_smart_ptr_for_overwrite
+ // Constraint for overloads taking either non-array or bounded array, U[N].
+#if __cpp_concepts
+ template<typename _Tp>
+ requires (!is_array_v<_Tp>) || (extent_v<_Tp> != 0)
+ using _NotUnboundedArray = _Tp;
+#else
+ template<typename _Tp>
+ using _NotUnboundedArray
+ = __enable_if_t<!__is_array_unknown_bounds<_Tp>::value, _Tp>;
+#endif
+#endif // smart_ptr_for_overwrite
+#endif // shared_ptr_arrays
+
+ /// @endcond
+
/**
* @brief A smart pointer with reference-counted copy semantics.
* @headerfile memory
@@ -139,7 +190,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using element_type = typename __shared_ptr<_Tp>::element_type;
#if __cplusplus >= 201703L
-# define __cpp_lib_shared_ptr_weak_type 201606
+# define __cpp_lib_shared_ptr_weak_type 201606L
/// The corresponding weak_ptr type for this shared_ptr
/// @since C++17
using weak_type = weak_ptr<_Tp>;
@@ -414,8 +465,71 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ }
template<typename _Yp, typename _Alloc, typename... _Args>
- friend shared_ptr<_Yp>
- allocate_shared(const _Alloc& __a, _Args&&... __args);
+ friend shared_ptr<_NonArray<_Yp>>
+ allocate_shared(const _Alloc&, _Args&&...);
+
+ template<typename _Yp, typename... _Args>
+ friend shared_ptr<_NonArray<_Yp>>
+ make_shared(_Args&&...);
+
+#if __cpp_lib_shared_ptr_arrays >= 201707L
+ // This constructor is non-standard, it is used by allocate_shared<T[]>.
+ template<typename _Alloc, typename _Init = const remove_extent_t<_Tp>*>
+ shared_ptr(const _Sp_counted_array_base<_Alloc>& __a,
+ _Init __init = nullptr)
+ : __shared_ptr<_Tp>(__a, __init)
+ { }
+
+ template<typename _Yp, typename _Alloc>
+ friend shared_ptr<_UnboundedArray<_Yp>>
+ allocate_shared(const _Alloc&, size_t);
+
+ template<typename _Yp>
+ friend shared_ptr<_UnboundedArray<_Yp>>
+ make_shared(size_t);
+
+ template<typename _Yp, typename _Alloc>
+ friend shared_ptr<_UnboundedArray<_Yp>>
+ allocate_shared(const _Alloc&, size_t, const remove_extent_t<_Yp>&);
+
+ template<typename _Yp>
+ friend shared_ptr<_UnboundedArray<_Yp>>
+ make_shared(size_t, const remove_extent_t<_Yp>&);
+
+ template<typename _Yp, typename _Alloc>
+ friend shared_ptr<_BoundedArray<_Yp>>
+ allocate_shared(const _Alloc&);
+
+ template<typename _Yp>
+ friend shared_ptr<_BoundedArray<_Yp>>
+ make_shared();
+
+ template<typename _Yp, typename _Alloc>
+ friend shared_ptr<_BoundedArray<_Yp>>
+ allocate_shared(const _Alloc&, const remove_extent_t<_Yp>&);
+
+ template<typename _Yp>
+ friend shared_ptr<_BoundedArray<_Yp>>
+ make_shared(const remove_extent_t<_Yp>&);
+
+#if __cpp_lib_smart_ptr_for_overwrite
+ template<typename _Yp, typename _Alloc>
+ friend shared_ptr<_NotUnboundedArray<_Yp>>
+ allocate_shared_for_overwrite(const _Alloc&);
+
+ template<typename _Yp>
+ friend shared_ptr<_NotUnboundedArray<_Yp>>
+ make_shared_for_overwrite();
+
+ template<typename _Yp, typename _Alloc>
+ friend shared_ptr<_UnboundedArray<_Yp>>
+ allocate_shared_for_overwrite(const _Alloc&, size_t);
+
+ template<typename _Yp>
+ friend shared_ptr<_UnboundedArray<_Yp>>
+ make_shared_for_overwrite(size_t);
+#endif
+#endif
// This constructor is non-standard, it is used by weak_ptr::lock().
shared_ptr(const weak_ptr<_Tp>& __r, std::nothrow_t) noexcept
@@ -872,11 +986,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* and the new object.
*/
template<typename _Tp, typename _Alloc, typename... _Args>
- inline shared_ptr<_Tp>
+ inline shared_ptr<_NonArray<_Tp>>
allocate_shared(const _Alloc& __a, _Args&&... __args)
{
- static_assert(!is_array<_Tp>::value, "make_shared<T[]> not supported");
-
return shared_ptr<_Tp>(_Sp_alloc_shared_tag<_Alloc>{__a},
std::forward<_Args>(__args)...);
}
@@ -889,13 +1001,152 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* constructor of @a _Tp.
*/
template<typename _Tp, typename... _Args>
- inline shared_ptr<_Tp>
+ inline shared_ptr<_NonArray<_Tp>>
make_shared(_Args&&... __args)
{
- typedef typename std::remove_cv<_Tp>::type _Tp_nc;
- return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(),
- std::forward<_Args>(__args)...);
+ using _Alloc = allocator<void>;
+ _Alloc __a;
+ return shared_ptr<_Tp>(_Sp_alloc_shared_tag<_Alloc>{__a},
+ std::forward<_Args>(__args)...);
+ }
+
+#if __cpp_lib_shared_ptr_arrays >= 201707L
+ /// @cond undocumented
+ template<typename _Tp, typename _Alloc = allocator<void>>
+ auto
+ __make_shared_arr_tag(size_t __n, const _Alloc& __a = _Alloc()) noexcept
+ {
+ using _Up = remove_all_extents_t<_Tp>;
+ using _UpAlloc = __alloc_rebind<_Alloc, _Up>;
+ size_t __s = sizeof(remove_extent_t<_Tp>) / sizeof(_Up);
+ if (__builtin_mul_overflow(__s, __n, &__n))
+ std::__throw_bad_array_new_length();
+ return _Sp_counted_array_base<_UpAlloc>{_UpAlloc(__a), __n};
+ }
+ /// @endcond
+
+ template<typename _Tp, typename _Alloc>
+ inline shared_ptr<_UnboundedArray<_Tp>>
+ allocate_shared(const _Alloc& __a, size_t __n)
+ {
+ return shared_ptr<_Tp>(std::__make_shared_arr_tag<_Tp>(__n, __a));
+ }
+
+ template<typename _Tp>
+ inline shared_ptr<_UnboundedArray<_Tp>>
+ make_shared(size_t __n)
+ {
+ return shared_ptr<_Tp>(std::__make_shared_arr_tag<_Tp>(__n));
+ }
+
+ template<typename _Tp, typename _Alloc>
+ inline shared_ptr<_UnboundedArray<_Tp>>
+ allocate_shared(const _Alloc& __a, size_t __n,
+ const remove_extent_t<_Tp>& __u)
+ {
+ return shared_ptr<_Tp>(std::__make_shared_arr_tag<_Tp>(__n, __a),
+ std::__addressof(__u));
+ }
+
+ template<typename _Tp>
+ inline shared_ptr<_UnboundedArray<_Tp>>
+ make_shared(size_t __n, const remove_extent_t<_Tp>& __u)
+ {
+ return shared_ptr<_Tp>(std::__make_shared_arr_tag<_Tp>(__n),
+ std::__addressof(__u));
+ }
+
+ /// @cond undocumented
+ template<typename _Tp, typename _Alloc = allocator<void>>
+ auto
+ __make_shared_arrN_tag(const _Alloc& __a = _Alloc()) noexcept
+ {
+ using _Up = remove_all_extents_t<_Tp>;
+ using _UpAlloc = __alloc_rebind<_Alloc, _Up>;
+ size_t __n = sizeof(_Tp) / sizeof(_Up);
+ return _Sp_counted_array_base<_UpAlloc>{_UpAlloc(__a), __n};
+ }
+ /// @endcond
+
+ template<typename _Tp, typename _Alloc>
+ inline shared_ptr<_BoundedArray<_Tp>>
+ allocate_shared(const _Alloc& __a)
+ {
+ return shared_ptr<_Tp>(std::__make_shared_arrN_tag<_Tp>(__a));
+ }
+
+ template<typename _Tp>
+ inline shared_ptr<_BoundedArray<_Tp>>
+ make_shared()
+ {
+ return shared_ptr<_Tp>(std::__make_shared_arrN_tag<_Tp>());
+ }
+
+ template<typename _Tp, typename _Alloc>
+ inline shared_ptr<_BoundedArray<_Tp>>
+ allocate_shared(const _Alloc& __a, const remove_extent_t<_Tp>& __u)
+ {
+ return shared_ptr<_Tp>(std::__make_shared_arrN_tag<_Tp>(__a),
+ std::__addressof(__u));
+ }
+
+ template<typename _Tp>
+ inline shared_ptr<_BoundedArray<_Tp>>
+ make_shared(const remove_extent_t<_Tp>& __u)
+ {
+ return shared_ptr<_Tp>(std::__make_shared_arrN_tag<_Tp>(),
+ std::__addressof(__u));
+ }
+
+#if __cpp_lib_smart_ptr_for_overwrite
+ template<typename _Tp, typename _Alloc>
+ inline shared_ptr<_NotUnboundedArray<_Tp>>
+ allocate_shared_for_overwrite(const _Alloc& __a)
+ {
+ if constexpr (is_array_v<_Tp>)
+ return shared_ptr<_Tp>(std::__make_shared_arrN_tag<_Tp>(__a),
+ _Sp_overwrite_tag{});
+ else
+ {
+ // Rebind the allocator to _Sp_overwrite_tag, so that the
+ // relevant _Sp_counted_ptr_inplace specialization is used.
+ using _Alloc2 = __alloc_rebind<_Alloc, _Sp_overwrite_tag>;
+ _Alloc2 __a2 = __a;
+ return shared_ptr<_Tp>(_Sp_alloc_shared_tag<_Alloc2>{__a2});
+ }
+ }
+
+ template<typename _Tp>
+ inline shared_ptr<_NotUnboundedArray<_Tp>>
+ make_shared_for_overwrite()
+ {
+ if constexpr (is_array_v<_Tp>)
+ return shared_ptr<_Tp>(std::__make_shared_arrN_tag<_Tp>(),
+ _Sp_overwrite_tag{});
+ else
+ {
+ using _Alloc = allocator<_Sp_overwrite_tag>;
+ return shared_ptr<_Tp>(_Sp_alloc_shared_tag<_Alloc>{{}});
+ }
+ }
+
+ template<typename _Tp, typename _Alloc>
+ inline shared_ptr<_UnboundedArray<_Tp>>
+ allocate_shared_for_overwrite(const _Alloc& __a, size_t __n)
+ {
+ return shared_ptr<_Tp>(std::__make_shared_arr_tag<_Tp>(__n, __a),
+ _Sp_overwrite_tag{});
+ }
+
+ template<typename _Tp>
+ inline shared_ptr<_UnboundedArray<_Tp>>
+ make_shared_for_overwrite(size_t __n)
+ {
+ return shared_ptr<_Tp>(std::__make_shared_arr_tag<_Tp>(__n),
+ _Sp_overwrite_tag{});
}
+#endif // smart_ptr_for_overwrite
+#endif // shared_ptr_arrays
/// std::hash specialization for shared_ptr.
template<typename _Tp>
diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h
index e9f4743..e16a925 100644
--- a/libstdc++-v3/include/bits/shared_ptr_base.h
+++ b/libstdc++-v3/include/bits/shared_ptr_base.h
@@ -60,8 +60,11 @@
#include <ext/aligned_buffer.h>
#include <ext/atomicity.h>
#include <ext/concurrence.h>
-#if __cplusplus > 201703L
+#if __cplusplus >= 202002L
+# include <bit> // __bit_floor
# include <compare>
+# include <bits/align.h> // std::align
+# include <bits/stl_uninitialized.h>
#endif
namespace std _GLIBCXX_VISIBILITY(default)
@@ -447,6 +450,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline void
_Sp_counted_ptr<nullptr_t, _S_atomic>::_M_dispose() noexcept { }
+ // FIXME: once __has_cpp_attribute(__no_unique_address__)) is true for
+ // all supported compilers we can greatly simplify _Sp_ebo_helper.
+ // N.B. unconditionally applying the attribute could change layout for
+ // final types, which currently cannot use EBO so have a unique address.
+
template<int _Nm, typename _Tp,
bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>
struct _Sp_ebo_helper;
@@ -640,6 +648,233 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Impl _M_impl;
};
+#if __cplusplus >= 202002L
+# define __cpp_lib_smart_ptr_for_overwrite 202002L
+ struct _Sp_overwrite_tag { };
+
+ // Partial specialization used for make_shared_for_overwrite<non-array>().
+ // This partial specialization is used when the allocator's value type
+ // is the special _Sp_overwrite_tag type.
+#if __cpp_concepts
+ template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
+ requires is_same_v<typename _Alloc::value_type, _Sp_overwrite_tag>
+ class _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> final
+#else
+ template<typename _Tp, template<typename> class _Alloc, _Lock_policy _Lp>
+ class _Sp_counted_ptr_inplace<_Tp, _Alloc<_Sp_overwrite_tag>, _Lp> final
+#endif
+ : public _Sp_counted_base<_Lp>
+ {
+ [[no_unique_address]] _Alloc _M_alloc;
+
+ union {
+ _Tp _M_obj;
+ char _M_unused;
+ };
+
+ friend class __shared_count<_Lp>; // To be able to call _M_ptr().
+
+ _Tp* _M_ptr() noexcept { return std::__addressof(_M_obj); }
+
+ public:
+ using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_ptr_inplace>;
+
+ _Sp_counted_ptr_inplace(const _Alloc& __a)
+ : _M_alloc(__a)
+ {
+ ::new((void*)_M_ptr()) _Tp; // default-initialized, for overwrite.
+ }
+
+ ~_Sp_counted_ptr_inplace() noexcept { }
+
+ virtual void
+ _M_dispose() noexcept
+ {
+ _M_obj.~_Tp();
+ }
+
+ // Override because the allocator needs to know the dynamic type
+ virtual void
+ _M_destroy() noexcept
+ {
+ using pointer = typename allocator_traits<__allocator_type>::pointer;
+ __allocator_type __a(_M_alloc);
+ auto __p = pointer_traits<pointer>::pointer_to(*this);
+ __allocated_ptr<__allocator_type> __guard_ptr{ __a, __p };
+ this->~_Sp_counted_ptr_inplace();
+ }
+
+ void*
+ _M_get_deleter(const std::type_info&) noexcept override
+ { return nullptr; }
+ };
+#endif // C++20
+
+#if __cplusplus <= 201703L
+# define __cpp_lib_shared_ptr_arrays 201611L
+#else
+# define __cpp_lib_shared_ptr_arrays 201707L
+
+ struct _Sp_overwrite_tag;
+
+ // For make_shared<T[]>, make_shared<T[N]>, allocate_shared<T[]> etc.
+ template<typename _Alloc>
+ struct _Sp_counted_array_base
+ {
+ [[no_unique_address]] _Alloc _M_alloc{};
+ size_t _M_n = 0;
+ bool _M_overwrite = false;
+
+ typename allocator_traits<_Alloc>::pointer
+ _M_alloc_array(size_t __tail)
+ {
+ return allocator_traits<_Alloc>::allocate(_M_alloc, _M_n + __tail);
+ }
+
+ void
+ _M_dealloc_array(typename allocator_traits<_Alloc>::pointer __p,
+ size_t __tail)
+ {
+ allocator_traits<_Alloc>::deallocate(_M_alloc, __p, _M_n + __tail);
+ }
+
+ // Init the array elements
+ template<typename _Init>
+ void
+ _M_init(typename allocator_traits<_Alloc>::value_type* __p,
+ _Init __init)
+ {
+ using _Tp = remove_pointer_t<_Init>;
+ using _Up = typename allocator_traits<_Alloc>::value_type;
+
+ if constexpr (is_same_v<_Init, _Sp_overwrite_tag>)
+ {
+ std::uninitialized_default_construct_n(__p, _M_n);
+ _M_overwrite = true;
+ }
+ else if (__init == nullptr)
+ std::__uninitialized_default_n_a(__p, _M_n, _M_alloc);
+ else if constexpr (!is_array_v<_Tp>)
+ std::__uninitialized_fill_n_a(__p, _M_n, *__init, _M_alloc);
+ else
+ {
+ struct _Iter
+ {
+ using value_type = _Up;
+ using difference_type = ptrdiff_t;
+ using pointer = const _Up*;
+ using reference = const _Up&;
+ using iterator_category = forward_iterator_tag;
+
+ const _Up* _M_p;
+ size_t _M_len;
+ size_t _M_pos;
+
+ _Iter& operator++() { ++_M_pos; return *this; }
+ _Iter operator++(int) { auto __i(*this); ++_M_pos; return __i; }
+
+ reference operator*() const { return _M_p[_M_pos % _M_len]; }
+ pointer operator->() const { return _M_p + (_M_pos % _M_len); }
+
+ bool operator==(const _Iter& __i) const
+ { return _M_pos == __i._M_pos; }
+ };
+
+ _Iter __first{_S_first_elem(__init), sizeof(_Tp) / sizeof(_Up)};
+ _Iter __last = __first;
+ __last._M_pos = _M_n;
+ std::__uninitialized_copy_a(__first, __last, __p, _M_alloc);
+ }
+ }
+
+ protected:
+ // Destroy the array elements
+ void
+ _M_dispose_array(typename allocator_traits<_Alloc>::value_type* __p)
+ {
+ if (_M_overwrite)
+ std::destroy_n(__p, _M_n);
+ else
+ {
+ size_t __n = _M_n;
+ while (__n--)
+ allocator_traits<_Alloc>::destroy(_M_alloc, __p + __n);
+ }
+ }
+
+ private:
+ template<typename _Tp>
+ static _Tp*
+ _S_first_elem(_Tp* __p) { return __p; }
+
+ template<typename _Tp, size_t _Nm>
+ static auto
+ _S_first_elem(_Tp (*__p)[_Nm]) { return _S_first_elem(*__p); }
+ };
+
+ // Control block for make_shared<T[]>, make_shared<T[N]> etc. that will be
+ // placed into unused memory at the end of the array.
+ template<typename _Alloc, _Lock_policy _Lp>
+ class _Sp_counted_array final
+ : public _Sp_counted_base<_Lp>, _Sp_counted_array_base<_Alloc>
+ {
+ using pointer = typename allocator_traits<_Alloc>::pointer;
+
+ pointer _M_alloc_ptr;
+
+ auto _M_ptr() const noexcept { return std::to_address(_M_alloc_ptr); }
+
+ friend class __shared_count<_Lp>; // To be able to call _M_ptr().
+
+ public:
+ _Sp_counted_array(const _Sp_counted_array_base<_Alloc>& __a,
+ pointer __p) noexcept
+ : _Sp_counted_array_base<_Alloc>(__a), _M_alloc_ptr(__p)
+ { }
+
+ ~_Sp_counted_array() = default;
+
+ virtual void
+ _M_dispose() noexcept
+ {
+ if (this->_M_n)
+ this->_M_dispose_array(_M_ptr());
+ }
+
+ // Override because the allocator needs to know the dynamic type
+ virtual void
+ _M_destroy() noexcept
+ {
+ _Sp_counted_array_base<_Alloc> __a = *this;
+ pointer __p = _M_alloc_ptr;
+ this->~_Sp_counted_array();
+ __a._M_dealloc_array(__p, _S_tail());
+ }
+
+ // Returns the number of additional array elements that must be
+ // allocated in order to store a _Sp_counted_array at the end.
+ static constexpr size_t
+ _S_tail()
+ {
+ // The array elemenent type.
+ using _Tp = typename allocator_traits<_Alloc>::value_type;
+
+ // The space needed to store a _Sp_counted_array object.
+ size_t __bytes = sizeof(_Sp_counted_array);
+
+ // Add any padding needed for manual alignment within the buffer.
+ if constexpr (alignof(_Tp) < alignof(_Sp_counted_array))
+ __bytes += alignof(_Sp_counted_array) - alignof(_Tp);
+
+ return (__bytes + sizeof(_Tp) - 1) / sizeof(_Tp);
+ }
+
+ void*
+ _M_get_deleter(const std::type_info&) noexcept override
+ { return nullptr; }
+ };
+#endif // C++20
+
// The default deleter for shared_ptr<T[]> and shared_ptr<T[N]>.
struct __sp_array_delete
{
@@ -650,12 +885,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<_Lock_policy _Lp>
class __shared_count
{
+ // Prevent _Sp_alloc_shared_tag from matching the shared_ptr(P, D) ctor.
template<typename _Tp>
struct __not_alloc_shared_tag { using type = void; };
template<typename _Tp>
struct __not_alloc_shared_tag<_Sp_alloc_shared_tag<_Tp>> { };
+#if __cpp_lib_shared_ptr_arrays >= 201707L
+ template<typename _Alloc>
+ struct __not_alloc_shared_tag<_Sp_counted_array_base<_Alloc>> { };
+#endif
+
public:
constexpr __shared_count() noexcept : _M_pi(0)
{ }
@@ -727,6 +968,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__p = __pi->_M_ptr();
}
+#if __cpp_lib_shared_ptr_arrays >= 201707L
+ template<typename _Tp, typename _Alloc, typename _Init>
+ __shared_count(_Tp*& __p, const _Sp_counted_array_base<_Alloc>& __a,
+ _Init __init)
+ {
+ using _Up = remove_all_extents_t<_Tp>;
+ static_assert(is_same_v<_Up, typename _Alloc::value_type>);
+
+ using _Sp_ca_type = _Sp_counted_array<_Alloc, _Lp>;
+ const size_t __tail = _Sp_ca_type::_S_tail();
+
+ struct _Guarded_ptr : _Sp_counted_array_base<_Alloc>
+ {
+ typename allocator_traits<_Alloc>::pointer _M_ptr;
+
+ _Guarded_ptr(_Sp_counted_array_base<_Alloc> __a)
+ : _Sp_counted_array_base<_Alloc>(__a),
+ _M_ptr(this->_M_alloc_array(_Sp_ca_type::_S_tail()))
+ { }
+
+ ~_Guarded_ptr()
+ {
+ if (_M_ptr)
+ this->_M_dealloc_array(_M_ptr, _Sp_ca_type::_S_tail());
+ }
+ };
+
+ _Guarded_ptr __guard{__a};
+ _Up* const __raw = std::to_address(__guard._M_ptr);
+ __guard._M_init(__raw, __init); // might throw
+
+ void* __c = __raw + __a._M_n;
+ if constexpr (alignof(_Up) < alignof(_Sp_ca_type))
+ {
+ size_t __space = sizeof(_Up) * __tail;
+ __c = std::align(alignof(_Sp_ca_type), sizeof(_Sp_ca_type),
+ __c, __space);
+ }
+ auto __pi = ::new(__c) _Sp_ca_type(__guard, __guard._M_ptr);
+ __guard._M_ptr = nullptr;
+ _M_pi = __pi;
+ __p = reinterpret_cast<_Tp*>(__raw);
+ }
+#endif
+
#if _GLIBCXX_USE_DEPRECATED
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
@@ -957,8 +1243,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_pi = nullptr;
}
-#define __cpp_lib_shared_ptr_arrays 201611L
-
// Helper traits for shared_ptr of array:
// A pointer type Y* is said to be compatible with a pointer type T* when
@@ -1420,6 +1704,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
friend __shared_ptr<_Tp1, _Lp1>
__allocate_shared(const _Alloc& __a, _Args&&... __args);
+#if __cpp_lib_shared_ptr_arrays >= 201707L
+ // This constructor is non-standard, it is used by allocate_shared<T[]>.
+ template<typename _Alloc, typename _Init = const remove_extent_t<_Tp>*>
+ __shared_ptr(const _Sp_counted_array_base<_Alloc>& __a,
+ _Init __init = nullptr)
+ : _M_ptr(), _M_refcount(_M_ptr, __a, __init)
+ { }
+#endif
+
// This constructor is used by __weak_ptr::lock() and
// shared_ptr::shared_ptr(const weak_ptr&, std::nothrow_t).
__shared_ptr(const __weak_ptr<_Tp, _Lp>& __r, std::nothrow_t) noexcept
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index c5d5efb..a8b792e 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -51,8 +51,10 @@
#if _GLIBCXX_HOSTED
# define __cpp_lib_allocator_traits_is_always_equal 201411
+#if __cplusplus < 201703L // N.B. updated value in C++20
# define __cpp_lib_shared_ptr_arrays 201611L
#endif
+#endif
#if !defined(__STRICT_ANSI__)
// gnu++11
@@ -167,7 +169,7 @@
# define __cpp_lib_scoped_lock 201703
# define __cpp_lib_shared_mutex 201505L
#endif
-#define __cpp_lib_shared_ptr_weak_type 201606
+#define __cpp_lib_shared_ptr_weak_type 201606L
#define __cpp_lib_string_view 201803L
#if _GLIBCXX_HAVE_USELOCALE
# define __cpp_lib_to_chars 201611L
@@ -275,7 +277,9 @@
#if __cpp_lib_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE
# define __cpp_lib_semaphore 201907L
#endif
+#define __cpp_lib_shared_ptr_arrays 201707L
#define __cpp_lib_shift 201806L
+#define __cpp_lib_smart_ptr_for_overwrite 202002L
#if __cpp_lib_concepts
# define __cpp_lib_span 202002L
#endif
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/99006.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/99006.cc
index e070fb9..67069a1 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/99006.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/99006.cc
@@ -1,9 +1,10 @@
-// FIXME: This should use { target { c++11 && { ! c++20 } } }
// { dg-do compile { target { c++11 } } }
#include <memory>
-auto p = std::make_shared<int[]>(2); // { dg-error "here" }
+auto p = std::make_shared<int[]>(2); // { dg-error "here" "" { target c++17_down } }
auto q = std::make_shared<int[2]>(1, 2); // { dg-error "here" }
-// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "enable_if<false" }
+// { dg-prune-output "template constraint failure" }
+// { dg-prune-output "no matching function" }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/array.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/array.cc
new file mode 100644
index 0000000..cd614c0
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/array.cc
@@ -0,0 +1,224 @@
+// { dg-options "-std=gnu++20" }
+// { dg-do run { target c++20 } }
+
+// C++20 20.11.3.7 shared_ptr Creation [util.smartptr.shared.create]
+
+#include <memory>
+
+#ifndef __cpp_lib_shared_ptr_arrays
+# error "Feature-test macro for make_shared arrays missing in <memory>"
+#elif __cpp_lib_shared_ptr_arrays < 201707L
+# error "Feature-test macro for make_shared arrays has wrong value in <memory>"
+#endif
+
+#include <testsuite_hooks.h>
+
+int counter = 0;
+
+template<typename T>
+struct Alloc : std::allocator<T>
+{
+ Alloc() = default;
+
+ template<typename U>
+ Alloc(const Alloc<U>&) { }
+
+ T* allocate(std::size_t n)
+ {
+ ++counter;
+ return std::allocator<T>::allocate(n);
+ }
+};
+
+void
+test01()
+{
+ Alloc<int> a;
+
+ std::shared_ptr<int[]> p1 = std::allocate_shared<int[]>(a, 24);
+ VERIFY( counter == 1 );
+ VERIFY( p1[23] == 0 );
+ std::shared_ptr<int[48]> p2 = std::allocate_shared<int[48]>(a);
+ VERIFY( counter == 2 );
+ VERIFY( p2[47] == 0 );
+
+ std::shared_ptr<int[][12]> p3 = std::allocate_shared<int[][12]>(a, 3);
+ VERIFY( counter == 3 );
+ VERIFY( p3[2][11] == 0 );
+ std::shared_ptr<int[4][5]> p4 = std::allocate_shared<int[4][5]>(a);
+ VERIFY( counter == 4 );
+ VERIFY( p4[3][4] == 0 );
+}
+
+void
+test02()
+{
+ std::shared_ptr<int[]> p1 = std::make_shared<int[]>(24);
+ VERIFY( p1[23] == 0 );
+ std::shared_ptr<int[48]> p2 = std::make_shared<int[48]>();
+ VERIFY( p2[47] == 0 );
+
+ std::shared_ptr<int[][12]> p3 = std::make_shared<int[][12]>(3);
+ VERIFY( p3[2][11] == 0 );
+ std::shared_ptr<int[4][5]> p4 = std::make_shared<int[4][5]>();
+ VERIFY( p4[3][4] == 0 );
+}
+
+#include <vector>
+
+std::vector<std::uintptr_t> addresses;
+
+void
+test03()
+{
+ // Verify construction and destruction order
+ struct Addressed
+ {
+ Addressed() { addresses.push_back(me()); }
+ ~Addressed() { VERIFY( addresses.back() == me() ); addresses.pop_back(); }
+
+ std::uintptr_t me() const { return reinterpret_cast<std::uintptr_t>(this); }
+ };
+
+ auto check = [](auto shptr) {
+ std::uintptr_t last = 0;
+ for (auto a : addresses)
+ {
+ VERIFY( a > last );
+ last = a;
+ }
+ shptr.reset();
+ return addresses.empty();
+ };
+
+ VERIFY( check(std::make_shared<Addressed[][2]>(3)) );
+ VERIFY( check(std::make_shared<Addressed[4][2]>()) );
+}
+
+void
+test04()
+{
+ // Verify initial value
+ auto p1 = std::make_shared<int[]>(3, 9);
+ VERIFY( p1[0] == 9 && p1[1] == 9 && p1[2] == 9 );
+
+ auto p2 = std::make_shared<int[2]>(4);
+ VERIFY( p2[0] == 4 && p2[1] == 4 );
+
+ auto p3 = std::make_shared<int[][3]>(10, {1,2,3});
+ const auto& p3_0 = p3[0];
+ VERIFY( p3_0[0] == 1 && p3_0[1] == 2 && p3_0[2] == 3 );
+ for (int i = 1; i < 10; ++i)
+ for (int j = 0; j < 3; ++j)
+ VERIFY( p3[i][j] == p3_0[j] );
+
+ auto p4 = std::make_shared<int[10][3]>({4,5,6});
+ const auto& p4_0 = p4[0];
+ VERIFY( p4_0[0] == 4 && p4_0[1] == 5 && p4_0[2] == 6 );
+ for (int i = 1; i < 10; ++i)
+ for (int j = 0; j < 3; ++j)
+ VERIFY( p4[i][j] == p4_0[j] );
+
+ auto p5 = std::make_shared<int[][3][2]>(10, {{1,2},{3,4},{5,6}});
+ const auto& p5_0 = p5[0];
+ VERIFY( p5_0[0][0] == 1 && p5_0[0][1] == 2 );
+ VERIFY( p5_0[1][0] == 3 && p5_0[1][1] == 4 );
+ VERIFY( p5_0[2][0] == 5 && p5_0[2][1] == 6 );
+ for (int i = 1; i < 10; ++i)
+ for (int j = 0; j < 3; ++j)
+ for (int k = 0; k < 2; ++k)
+ VERIFY( p5[i][j][k] == p5_0[j][k] );
+
+ auto p6 = std::make_shared<int[4][3][2]>({{7,8},{9,10},{11,12}});
+ const auto& p6_0 = p6[0];
+ VERIFY( p6_0[0][0] == 7 && p6_0[0][1] == 8 );
+ VERIFY( p6_0[1][0] == 9 && p6_0[1][1] == 10 );
+ VERIFY( p6_0[2][0] == 11 && p6_0[2][1] == 12 );
+ for (int i = 1; i < 4; ++i)
+ for (int j = 0; j < 3; ++j)
+ for (int k = 0; k < 2; ++k)
+ VERIFY( p6[i][j][k] == p6_0[j][k] );
+}
+
+void
+test05()
+{
+ // Examples from the standard
+ using namespace std;
+
+ // Example 2
+ {
+ shared_ptr<double[]> p = make_shared<double[]>(1024);
+ // shared_ptr to a value-initialized double[1024]
+ for (int i = 0; i < 1024; ++i)
+ VERIFY( p[i] == 0.0 );
+
+ shared_ptr<double[][2][2]> q = make_shared<double[][2][2]>(6);
+ // shared_ptr to a value-initialized double[6][2][2]
+ for (int i = 0; i < 6; ++i)
+ for (auto& j : q[i])
+ for (auto& k : j)
+ VERIFY( k == 0.0 );
+ }
+
+ // Example 3
+ {
+ shared_ptr<double[1024]> p = make_shared<double[1024]>();
+ // shared_ptr to a value-initialized double[1024]
+ for (int i = 0; i < 1024; ++i)
+ VERIFY( p[i] == 0.0 );
+
+ shared_ptr<double[6][2][2]> q = make_shared<double[6][2][2]>();
+ // shared_ptr to a value-initialized double[6][2][2]
+ for (int i = 0; i < 6; ++i)
+ for (auto& j : q[i])
+ for (auto& k : j)
+ VERIFY( k == 0.0 );
+ }
+
+ // Example 4
+ {
+ shared_ptr<double[]> p = make_shared<double[]>(1024, 1.0);
+ // shared_ptr to a double[1024], where each element is 1.0
+ for (int i = 0; i < 1024; ++i)
+ VERIFY( p[i] == 1.0 );
+
+ shared_ptr<double[][2]> q = make_shared<double[][2]>(6, {1.0, 0.0});
+ // shared_ptr to a double[6][2], where each double[2] element is {1.0, 0.0}
+ for (int i = 0; i < 6; ++i)
+ VERIFY( q[i][0] == 1.0 && q[i][1] == 0.0 );
+
+ shared_ptr<vector<int>[]> r = make_shared<vector<int>[]>(4, {1, 2});
+ // shared_ptr to a vector<int>[4], where each vector has contents {1, 2}
+ for (int i = 0; i < 4; ++i)
+ VERIFY( r[i] == vector<int>({1, 2}) );
+ }
+
+ // Example 5
+ {
+ shared_ptr<double[1024]> p = make_shared<double[1024]>(1.0);
+ // shared_ptr to a double[1024], where each element is 1.0
+ for (int i = 0; i < 1024; ++i)
+ VERIFY( p[i] == 1.0 );
+
+ shared_ptr<double[6][2]> q = make_shared<double[6][2]>({1.0, 0.0});
+ // shared_ptr to a double[6][2], where each double[2] element is {1.0, 0.0}
+ for (int i = 0; i < 6; ++i)
+ VERIFY( q[i][0] == 1.0 && q[i][1] == 0.0 );
+
+ shared_ptr<vector<int>[4]> r = make_shared<vector<int>[4]>({1, 2});
+ // shared_ptr to a vector<int>[4], where each vector has contents {1, 2}
+ for (int i = 0; i < 4; ++i)
+ VERIFY( r[i] == vector<int>({1, 2}) );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+}
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/overwrite.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/overwrite.cc
new file mode 100644
index 0000000..f207fde
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/overwrite.cc
@@ -0,0 +1,143 @@
+// { dg-options "-std=gnu++20 -fno-lifetime-dse -O0" }
+// { dg-do run { target c++20 } }
+
+// C++20 20.11.3.7 shared_ptr Creation [util.smartptr.shared.create]
+
+#include <memory>
+
+#ifndef __cpp_lib_smart_ptr_for_overwrite
+# error "Feature-test macro for make_shared_for_overwrite missing in <memory>"
+#elif __cpp_lib_smart_ptr_for_overwrite < 202002L
+# error "Feature-test macro for make_shared_for_overwrite has wrong value in <memory>"
+#endif
+
+#include <cstring>
+#include <testsuite_hooks.h>
+
+int counter = 0;
+
+template<typename T>
+struct Alloc : std::allocator<T>
+{
+ Alloc() = default;
+
+ template<typename U>
+ Alloc(const Alloc<U>&) { }
+
+ T* allocate(std::size_t n)
+ {
+ ++counter;
+ void* p = std::allocator<T>::allocate(n);
+ // need -fno-lifetime-dse to check for these values later.
+ std::memset(p, 0xff, n * sizeof(T));
+ return (T*)p;
+ }
+
+ void construct(auto*, auto&&...)
+ {
+ // The objects must be default-initialized, not using this function.
+ VERIFY( ! "allocator_traits::construct" );
+ }
+
+ void destroy(auto*)
+ {
+ // The objects must be destroyed by ~T(), not using this function.
+ VERIFY( ! "allocator_traits::destroy" );
+ }
+};
+
+void
+test01()
+{
+ Alloc<int> a;
+ const int expected = 0xffffffff;
+
+ std::shared_ptr<int> p1 = std::allocate_shared_for_overwrite<int>(a);
+ VERIFY( counter == 1 );
+ VERIFY( *p1 == expected );
+ std::shared_ptr<int[44]> p2 = std::allocate_shared_for_overwrite<int[44]>(a);
+ VERIFY( counter == 2 );
+ VERIFY( p2[0] == expected );
+ p2.reset();
+ std::shared_ptr<int[]> p3 = std::allocate_shared_for_overwrite<int[]>(a, 88);
+ VERIFY( counter == 3 );
+ VERIFY( p3[0] == expected );
+ VERIFY( p3[87] == expected );
+ std::shared_ptr<int[3][4]> p4 = std::allocate_shared_for_overwrite<int[3][4]>(a);
+ VERIFY( counter == 4 );
+ VERIFY( p4[0][0] == expected );
+ VERIFY( p4[2][3] == expected );
+ std::shared_ptr<int[][5]> p5 = std::allocate_shared_for_overwrite<int[][5]>(a, 6);
+ VERIFY( counter == 5 );
+ VERIFY( p5[0][0] == expected );
+ VERIFY( p5[5][4] == expected );
+
+ struct BigBoi { int x[100]; };
+ std::shared_ptr<BigBoi> p6 = std::allocate_shared_for_overwrite<BigBoi>(a);
+ VERIFY( counter == 6 );
+ VERIFY( p6->x[0] == expected );
+ std::shared_ptr<BigBoi[22]> p7 = std::allocate_shared_for_overwrite<BigBoi[22]>(a);
+ VERIFY( counter == 7 );
+ VERIFY( p7[0].x[0] == expected );
+ VERIFY( p7[21].x[99] == expected );
+ std::shared_ptr<BigBoi[]> p8 = std::allocate_shared_for_overwrite<BigBoi[]>(a, 11);
+ VERIFY( counter == 8 );
+ VERIFY( p8[0].x[0] == expected );
+ VERIFY( p8[10].x[10] == expected );
+}
+
+void
+test02()
+{
+ // These aren't created by the custom allocator, so we can't check that the
+ // memory was left uninitialized. Just dereference them.
+
+ std::shared_ptr<int> p1 = std::make_shared_for_overwrite<int>();
+ (void) *p1;
+ std::shared_ptr<int[44]> p2 = std::make_shared_for_overwrite<int[44]>();
+ (void) p2[0];
+ std::shared_ptr<int[]> p3 = std::make_shared_for_overwrite<int[]>(88);
+ (void) p3[0];
+ (void) p3[87];
+ std::shared_ptr<int[3][4]> p4 = std::make_shared_for_overwrite<int[3][4]>();
+ (void) p4[0][0];
+ (void) p4[2][3];
+ std::shared_ptr<int[][5]> p5 = std::make_shared_for_overwrite<int[][5]>(6);
+ (void) p5[0][0];
+ (void) p5[5][4];
+
+ struct BigBoi { int x[100]; };
+ std::shared_ptr<BigBoi> p6 = std::make_shared_for_overwrite<BigBoi>();
+ (void) p6->x[0];
+ std::shared_ptr<BigBoi[22]> p7 = std::make_shared_for_overwrite<BigBoi[22]>();
+ (void) p7[0].x[0];
+ (void) p7[21].x[99];
+ std::shared_ptr<BigBoi[]> p8 = std::make_shared_for_overwrite<BigBoi[]>(11);
+ (void) p8[0].x[0];
+ (void) p8[10].x[10];
+}
+
+void
+test03()
+{
+ // Type with non-trivial initialization should still be default-initialized.
+ struct NonTriv
+ {
+ int init = 0xbb;
+ int uninit;
+ };
+ std::shared_ptr<NonTriv> a = std::make_shared_for_overwrite<NonTriv>();
+ VERIFY( a->init == 0xbb );
+ std::shared_ptr<NonTriv[]> b = std::make_shared_for_overwrite<NonTriv[2]>();
+ VERIFY( b[1].init == 0xbb );
+ std::shared_ptr<NonTriv[]> c = std::make_shared_for_overwrite<NonTriv[]>(2);
+ VERIFY( c[1].init == 0xbb );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+}
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/version.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/version.cc
new file mode 100644
index 0000000..0e47f19
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/version.cc
@@ -0,0 +1,18 @@
+// { dg-options "-std=gnu++20" }
+// { dg-do preprocess { target c++20 } }
+
+// C++20 20.11.3.7 shared_ptr Creation [util.smartptr.shared.create]
+
+#include <version>
+
+#ifndef __cpp_lib_shared_ptr_arrays
+# error "Feature-test macro for make_shared arrays missing in <version>"
+#elif __cpp_lib_shared_ptr_arrays < 201707L
+# error "Feature-test macro for make_shared arrays has wrong value in <version>"
+#endif
+
+#ifndef __cpp_lib_smart_ptr_for_overwrite
+# error "Feature-test macro for make_shared_for_overwrite missing in <version>"
+#elif __cpp_lib_smart_ptr_for_overwrite < 202002L
+# error "Feature-test macro for make_shared_for_overwrite has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/creation/for_overwrite.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/creation/for_overwrite.cc
index c6bcbf0..f736c76 100644
--- a/libstdc++-v3/testsuite/20_util/unique_ptr/creation/for_overwrite.cc
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/creation/for_overwrite.cc
@@ -1,4 +1,4 @@
-// { dg-options "-std=gnu++20" }
+// { dg-options "-std=gnu++20 -fno-lifetime-dse -O0" }
// { dg-do run { target c++2a } }
// { dg-xfail-run-if "AIX operator new" { powerpc-ibm-aix* } }
@@ -22,6 +22,13 @@
// C++20 20.11.1.5 unique_ptr creation [unique.ptr.create]
#include <memory>
+
+#ifndef __cpp_lib_smart_ptr_for_overwrite
+# error "Feature-test macro for make_unique_for_overwrite missing in <memory>"
+#elif __cpp_lib_smart_ptr_for_overwrite < 202002L
+# error "Feature-test macro for make_unique_for_overwrite has wrong value in <memory>"
+#endif
+
#include <cstdlib>
#include <cstring>
#include <testsuite_hooks.h>
@@ -58,9 +65,25 @@ test02()
VERIFY( c == 0xaa );
}
+void
+test03()
+{
+ // Type with non-trivial initialization should still be default-initialized.
+ struct NonTriv
+ {
+ int init = 0xbb;
+ int uninit;
+ };
+ std::unique_ptr<NonTriv> a = std::make_unique_for_overwrite<NonTriv>();
+ VERIFY( a->init == 0xbb );
+ std::unique_ptr<NonTriv[]> b = std::make_unique_for_overwrite<NonTriv[]>(2);
+ VERIFY( b[1].init == 0xbb );
+}
+
int
main()
{
test01();
test02();
+ test03();
}