+2019-01-18 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/87514
+ PR libstdc++/87520
+ PR libstdc++/88782
+ * config/abi/pre/gnu.ver (GLIBCXX_3.4.26): Export new symbol.
+ * include/bits/shared_ptr.h
+ (shared_ptr(_Sp_make_shared_tag, const Alloc&, Args&&...))
+ (allocate_shared): Change to use new tag type.
+ * include/bits/shared_ptr_base.h (_Sp_make_shared_tag::_S_eq):
+ Declare new member function.
+ (_Sp_alloc_shared_tag): Define new type.
+ (_Sp_counted_ptr_inplace): Declare __shared_count<_Lp> as a friend.
+ (_Sp_counted_ptr_inplace::_M_get_deleter) [!__cpp_rtti]: Use
+ _Sp_make_shared_tag::_S_eq to check type_info.
+ (__shared_count(Ptr, Deleter),__shared_count(Ptr, Deleter, Alloc)):
+ Constrain to prevent being called with _Sp_alloc_shared_tag.
+ (__shared_count(_Sp_make_shared_tag, const _Alloc&, Args&&...)):
+ Replace constructor with ...
+ (__shared_count(Tp*&, _Sp_alloc_shared_tag<_Alloc>, Args&&...)): Use
+ reference parameter so address of the new object can be returned to
+ the caller. Obtain the allocator from the tag type.
+ (__shared_ptr(_Sp_make_shared_tag, const Alloc&, Args&&...)): Replace
+ constructor with ...
+ (__shared_ptr(_Sp_alloc_shared_tag<Alloc>, Args&&...)): Pass _M_ptr
+ to the __shared_count constructor.
+ (__allocate_shared): Change to use new tag type.
+ * src/c++11/shared_ptr.cc (_Sp_make_shared_tag::_S_eq): Define.
+
2019-01-17 Jonathan Wakely <jwakely@redhat.com>
* src/c++17/fs_ops.cc
struct _Sp_make_shared_tag
{
private:
- template<typename _Tp, _Lock_policy _Lp>
- friend class __shared_ptr;
template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
friend class _Sp_counted_ptr_inplace;
alignas(type_info) static constexpr char __tag[sizeof(type_info)] = { };
return reinterpret_cast<const type_info&>(__tag);
}
+
+ static bool _S_eq(const type_info&) noexcept;
};
+ template<typename _Alloc>
+ struct _Sp_alloc_shared_tag
+ {
+ const _Alloc& _M_a;
+ };
+
template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>
{
this->~_Sp_counted_ptr_inplace();
}
- // Sneaky trick so __shared_ptr can get the managed pointer.
+ private:
+ friend class __shared_count<_Lp>; // To be able to call _M_ptr().
+
+ // No longer used, but code compiled against old libstdc++ headers
+ // might still call it from __shared_ptr ctor to get the pointer out.
virtual void*
_M_get_deleter(const std::type_info& __ti) noexcept override
{
+ auto __ptr = const_cast<typename remove_cv<_Tp>::type*>(_M_ptr());
// Check for the fake type_info first, so we don't try to access it
- // as a real type_info object.
- if (&__ti == &_Sp_make_shared_tag::_S_ti())
- return const_cast<typename remove_cv<_Tp>::type*>(_M_ptr());
+ // as a real type_info object. Otherwise, check if it's the real
+ // type_info for this class. With RTTI enabled we can check directly,
+ // or call a library function to do it.
+ if (&__ti == &_Sp_make_shared_tag::_S_ti()
+ ||
#if __cpp_rtti
- // Callers compiled with old libstdc++ headers and RTTI enabled
- // might pass this instead:
- else if (__ti == typeid(_Sp_make_shared_tag))
- return const_cast<typename remove_cv<_Tp>::type*>(_M_ptr());
+ __ti == typeid(_Sp_make_shared_tag)
+#else
+ _Sp_make_shared_tag::_S_eq(__ti)
#endif
+ )
+ return __ptr;
return nullptr;
}
- private:
_Tp* _M_ptr() noexcept { return _M_impl._M_storage._M_ptr(); }
_Impl _M_impl;
template<_Lock_policy _Lp>
class __shared_count
{
+ template<typename _Tp>
+ struct __not_alloc_shared_tag { using type = void; };
+
+ template<typename _Tp>
+ struct __not_alloc_shared_tag<_Sp_alloc_shared_tag<_Tp>> { };
+
public:
constexpr __shared_count() noexcept : _M_pi(0)
{ }
: __shared_count(__p, __sp_array_delete{}, allocator<void>())
{ }
- template<typename _Ptr, typename _Deleter>
+ template<typename _Ptr, typename _Deleter,
+ typename = typename __not_alloc_shared_tag<_Deleter>::type>
__shared_count(_Ptr __p, _Deleter __d)
: __shared_count(__p, std::move(__d), allocator<void>())
{ }
- template<typename _Ptr, typename _Deleter, typename _Alloc>
+ template<typename _Ptr, typename _Deleter, typename _Alloc,
+ typename = typename __not_alloc_shared_tag<_Deleter>::type>
__shared_count(_Ptr __p, _Deleter __d, _Alloc __a) : _M_pi(0)
{
typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type;
}
template<typename _Tp, typename _Alloc, typename... _Args>
- __shared_count(_Sp_make_shared_tag, _Tp*, const _Alloc& __a,
+ __shared_count(_Tp*& __p, _Sp_alloc_shared_tag<_Alloc> __a,
_Args&&... __args)
- : _M_pi(0)
{
typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type;
- typename _Sp_cp_type::__allocator_type __a2(__a);
+ typename _Sp_cp_type::__allocator_type __a2(__a._M_a);
auto __guard = std::__allocate_guarded(__a2);
_Sp_cp_type* __mem = __guard.get();
- ::new (__mem) _Sp_cp_type(__a, std::forward<_Args>(__args)...);
- _M_pi = __mem;
+ auto __pi = ::new (__mem)
+ _Sp_cp_type(__a._M_a, std::forward<_Args>(__args)...);
__guard = nullptr;
+ _M_pi = __pi;
+ __p = __pi->_M_ptr();
}
#if _GLIBCXX_USE_DEPRECATED
protected:
// This constructor is non-standard, it is used by allocate_shared.
template<typename _Alloc, typename... _Args>
- __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
- _Args&&... __args)
- : _M_ptr(), _M_refcount(__tag, (_Tp*)0, __a,
- std::forward<_Args>(__args)...)
- {
- // _M_ptr needs to point to the newly constructed object.
- // This relies on _Sp_counted_ptr_inplace::_M_get_deleter.
- void* __p = _M_refcount._M_get_deleter(_Sp_make_shared_tag::_S_ti());
- _M_ptr = static_cast<_Tp*>(__p);
- _M_enable_shared_from_this_with(_M_ptr);
- }
+ __shared_ptr(_Sp_alloc_shared_tag<_Alloc> __tag, _Args&&... __args)
+ : _M_ptr(), _M_refcount(_M_ptr, __tag, std::forward<_Args>(__args)...)
+ { _M_enable_shared_from_this_with(_M_ptr); }
template<typename _Tp1, _Lock_policy _Lp1, typename _Alloc,
typename... _Args>
inline __shared_ptr<_Tp, _Lp>
__allocate_shared(const _Alloc& __a, _Args&&... __args)
{
- return __shared_ptr<_Tp, _Lp>(_Sp_make_shared_tag(), __a,
+ return __shared_ptr<_Tp, _Lp>(_Sp_alloc_shared_tag<_Alloc>{__a},
std::forward<_Args>(__args)...);
}