aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/include
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/include
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/include')
-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
3 files changed, 562 insertions, 14 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