+2017-05-11 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/80285
+ * include/bits/shared_ptr_base.h (_Sp_make_shared_tag::_S_ti): Define
+ function to get unique fake std::type_info reference.
+ (_Sp_counted_ptr_inplace::_M_get_deleter) [!__cpp_rtti]: Compare to
+ _S_ti() fake reference.
+ (__shared_ptr(_Sp_make_shared_tag, const Alloc&, Args&&...)): Share
+ single implementation with or without RTTI enable.
+ [!__cpp_rtti]: Pass fake reference to _M_get_deleter.
+ * testsuite/20_util/shared_ptr/creation/alloc.cc: Change expected
+ allocation and deallocation counts.
+ * testsuite/20_util/shared_ptr/creation/single_allocation.cc: New.
+ * testsuite/20_util/shared_ptr/creation/single_allocation_no_rtti.cc:
+ New.
+
2017-05-10 François Dumont <fdumont@gcc.gnu.org>
Bump version namespace.
#pragma GCC diagnostic pop
#endif
+#if !__cpp_rtti
+ class type_info;
+#endif
+
/**
* @brief Exception possibly thrown by @c shared_ptr.
* @ingroup exceptions
// helpers for make_shared / allocate_shared
- struct _Sp_make_shared_tag { };
+ struct _Sp_make_shared_tag
+ {
+#if !__cpp_rtti
+ 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;
+
+ static const type_info&
+ _S_ti() noexcept
+ {
+ static constexpr _Sp_make_shared_tag __tag;
+ return reinterpret_cast<const type_info&>(__tag);
+ }
+#endif
+ };
template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>
{
#if __cpp_rtti
if (__ti == typeid(_Sp_make_shared_tag))
- return const_cast<typename remove_cv<_Tp>::type*>(_M_ptr());
+#else
+ if (&__ti == &_Sp_make_shared_tag::_S_ti())
#endif
+ return const_cast<typename remove_cv<_Tp>::type*>(_M_ptr());
return nullptr;
}
owner_before(__weak_ptr<_Tp1, _Lp> const& __rhs) const
{ return _M_refcount._M_less(__rhs._M_refcount); }
-#if __cpp_rtti
protected:
// This constructor is non-standard, it is used by allocate_shared.
template<typename _Alloc, typename... _Args>
{
// _M_ptr needs to point to the newly constructed object.
// This relies on _Sp_counted_ptr_inplace::_M_get_deleter.
+#if __cpp_rtti
void* __p = _M_refcount._M_get_deleter(typeid(__tag));
- _M_ptr = static_cast<_Tp*>(__p);
- _M_enable_shared_from_this_with(_M_ptr);
- }
#else
- template<typename _Alloc>
- struct _Deleter
- {
- void operator()(typename _Alloc::value_type* __ptr)
- {
- __allocated_ptr<_Alloc> __guard{ _M_alloc, __ptr };
- allocator_traits<_Alloc>::destroy(_M_alloc, __guard.get());
- }
- _Alloc _M_alloc;
- };
-
- template<typename _Alloc, typename... _Args>
- __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
- _Args&&... __args)
- : _M_ptr(), _M_refcount()
- {
- typedef typename allocator_traits<_Alloc>::template
- rebind_traits<typename std::remove_cv<_Tp>::type> __traits;
- _Deleter<typename __traits::allocator_type> __del = { __a };
- auto __guard = std::__allocate_guarded(__del._M_alloc);
- auto __ptr = __guard.get();
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 2070. allocate_shared should use allocator_traits<A>::construct
- __traits::construct(__del._M_alloc, __ptr,
- std::forward<_Args>(__args)...);
- __guard = nullptr;
- __shared_count<_Lp> __count(__ptr, __del, __del._M_alloc);
- _M_refcount._M_swap(__count);
- _M_ptr = __ptr;
+ void* __p = _M_refcount._M_get_deleter(_Sp_make_shared_tag::_S_ti());
+#endif
+ _M_ptr = static_cast<_Tp*>(__p);
_M_enable_shared_from_this_with(_M_ptr);
}
-#endif
template<typename _Tp1, _Lock_policy _Lp1, typename _Alloc,
typename... _Args>
VERIFY( p1.get() != 0 );
VERIFY( p1.use_count() == 1 );
VERIFY( A::ctor_count == 1 );
- VERIFY( tracker_allocator_counter::get_allocation_count() > 0 );
+ VERIFY( tracker_allocator_counter::get_allocation_count() > sizeof(A) );
}
VERIFY( A::ctor_count == A::dtor_count );
VERIFY( tracker_allocator_counter::get_allocation_count()
p1 = std::allocate_shared<A>(tracker_allocator<A>(), 1);
VERIFY( A::ctor_count == 1 );
- VERIFY( tracker_allocator_counter::get_allocation_count() > 0 );
+ VERIFY( tracker_allocator_counter::get_allocation_count() > sizeof(A) );
p1 = std::allocate_shared<A>(tracker_allocator<A>(), 1, 2.0);
VERIFY( A::ctor_count == 2 );
VERIFY( A::dtor_count == 1 );
- VERIFY( tracker_allocator_counter::get_deallocation_count() > 0 );
+ VERIFY( tracker_allocator_counter::get_deallocation_count() > sizeof(A) );
p1 = std::allocate_shared<A>(tracker_allocator<A>(), 1, 2.0, '3');
VERIFY( A::ctor_count == 3 );
--- /dev/null
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+int counter = 0;
+
+template<typename T>
+struct Alloc : std::allocator<T>
+{
+ template<typename U>
+ struct rebind { using other = Alloc<U>; };
+
+ Alloc() = default;
+
+ template<typename U>
+ Alloc(const Alloc<U>&) { }
+
+ T* allocate(std::size_t n)
+ {
+ ++counter;
+ return std::allocator<T>::allocate(n);
+ }
+};
+
+
+void
+test01()
+{
+ std::allocate_shared<int>(Alloc<int>());
+ VERIFY( counter == 1 );
+}
+
+int
+main()
+{
+ test01();
+}
--- /dev/null
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-fno-rtti" }
+// { dg-do run { target c++11 } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+int counter = 0;
+
+template<typename T>
+struct Alloc : std::allocator<T>
+{
+ template<typename U>
+ struct rebind { using other = Alloc<U>; };
+
+ Alloc() = default;
+
+ template<typename U>
+ Alloc(const Alloc<U>&) { }
+
+ T* allocate(std::size_t n)
+ {
+ ++counter;
+ return std::allocator<T>::allocate(n);
+ }
+};
+
+
+void
+test01()
+{
+ std::allocate_shared<int>(Alloc<int>());
+ VERIFY( counter == 1 );
+}
+
+int
+main()
+{
+ test01();
+}