Commit e182393e by Jonathan Wakely Committed by Jonathan Wakely

PR77990 refactor unique_ptr to encapsulate tuple

	PR libstdc++/77990
	* include/bits/unique_ptr.h (__uniq_ptr_impl): New type to
	encapsulate implementation details.
	(unique_ptr::unique_ptr(_Up)): Don't copy deleter object.
	(unique_ptr::get, unique_ptr::get_deleter, unique_ptr::release):
	Call member functions of implementation object.
	(unique_ptr<T[], D>): Likewise.
	* python/libstdcxx/v6/printers.py (UniquePointerPrinter): Adjust for
	new implementation.
	* python/libstdcxx/v6/xmethods.py (UniquePtrGetWorker): Likewise.
	* testsuite/20_util/unique_ptr/assign/48635_neg.cc: Adjust dg-error
	lines.
	* testsuite/20_util/unique_ptr/assign/cv_qual.cc: Likewise.
	* testsuite/20_util/unique_ptr/cons/cv_qual.cc: Likewise.
	* testsuite/20_util/unique_ptr/cons/77990.cc: New test.

From-SVN: r241330
parent e7a3e0c6
2016-10-19 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/77990
* include/bits/unique_ptr.h (__uniq_ptr_impl): New type to
encapsulate implementation details.
(unique_ptr::unique_ptr(_Up)): Don't copy deleter object.
(unique_ptr::get, unique_ptr::get_deleter, unique_ptr::release):
Call member functions of implementation object.
(unique_ptr<T[], D>): Likewise.
* python/libstdcxx/v6/printers.py (UniquePointerPrinter): Adjust for
new implementation.
* python/libstdcxx/v6/xmethods.py (UniquePtrGetWorker): Likewise.
* testsuite/20_util/unique_ptr/assign/48635_neg.cc: Adjust dg-error
lines.
* testsuite/20_util/unique_ptr/assign/cv_qual.cc: Likewise.
* testsuite/20_util/unique_ptr/cons/cv_qual.cc: Likewise.
* testsuite/20_util/unique_ptr/cons/77990.cc: New test.
2016-10-18 Jonathan Wakely <jwakely@redhat.com> 2016-10-18 Jonathan Wakely <jwakely@redhat.com>
* include/experimental/bits/shared_ptr.h: Fix indentation. * include/experimental/bits/shared_ptr.h: Fix indentation.
......
...@@ -111,33 +111,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -111,33 +111,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
}; };
/// 20.7.1.2 unique_ptr for single objects. template <typename _Tp, typename _Dp>
template <typename _Tp, typename _Dp = default_delete<_Tp> > class __uniq_ptr_impl
class unique_ptr
{ {
// use SFINAE to determine whether _Del::pointer exists template <typename _Up, typename _Ep, typename = void>
class _Pointer struct _Ptr
{ {
template<typename _Up> using type = _Up*;
static typename _Up::pointer __test(typename _Up::pointer*); };
template <typename _Up, typename _Ep>
struct
_Ptr<_Up, _Ep, __void_t<typename remove_reference<_Ep>::type::pointer>>
{
using type = typename remove_reference<_Ep>::type::pointer;
};
template<typename _Up> public:
static _Tp* __test(...); using pointer = typename _Ptr<_Tp, _Dp>::type;
typedef typename remove_reference<_Dp>::type _Del; __uniq_ptr_impl() = default;
__uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; }
public: template<typename _Del>
typedef decltype(__test<_Del>(0)) type; __uniq_ptr_impl(pointer __p, _Del&& __d)
}; : _M_t(__p, std::forward<_Del>(__d)) { }
typedef std::tuple<typename _Pointer::type, _Dp> __tuple_type; pointer& _M_ptr() { return std::get<0>(_M_t); }
__tuple_type _M_t; pointer _M_ptr() const { return std::get<0>(_M_t); }
_Dp& _M_deleter() { return std::get<1>(_M_t); }
const _Dp& _M_deleter() const { return std::get<1>(_M_t); }
public: private:
typedef typename _Pointer::type pointer; tuple<pointer, _Dp> _M_t;
typedef _Tp element_type; };
typedef _Dp deleter_type;
/// 20.7.1.2 unique_ptr for single objects.
template <typename _Tp, typename _Dp = default_delete<_Tp>>
class unique_ptr
{
__uniq_ptr_impl<_Tp, _Dp> _M_t;
public:
using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
using element_type = _Tp;
using deleter_type = _Dp;
// helper template for detecting a safe conversion from another // helper template for detecting a safe conversion from another
// unique_ptr // unique_ptr
...@@ -168,7 +186,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -168,7 +186,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*/ */
explicit explicit
unique_ptr(pointer __p) noexcept unique_ptr(pointer __p) noexcept
: _M_t(__p, deleter_type()) : _M_t(__p)
{ static_assert(!is_pointer<deleter_type>::value, { static_assert(!is_pointer<deleter_type>::value,
"constructed with null function pointer deleter"); } "constructed with null function pointer deleter"); }
...@@ -231,7 +249,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -231,7 +249,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Destructor, invokes the deleter if the stored pointer is not null. /// Destructor, invokes the deleter if the stored pointer is not null.
~unique_ptr() noexcept ~unique_ptr() noexcept
{ {
auto& __ptr = std::get<0>(_M_t); auto& __ptr = _M_t._M_ptr();
if (__ptr != nullptr) if (__ptr != nullptr)
get_deleter()(__ptr); get_deleter()(__ptr);
__ptr = pointer(); __ptr = pointer();
...@@ -302,17 +320,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -302,17 +320,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Return the stored pointer. /// Return the stored pointer.
pointer pointer
get() const noexcept get() const noexcept
{ return std::get<0>(_M_t); } { return _M_t._M_ptr(); }
/// Return a reference to the stored deleter. /// Return a reference to the stored deleter.
deleter_type& deleter_type&
get_deleter() noexcept get_deleter() noexcept
{ return std::get<1>(_M_t); } { return _M_t._M_deleter(); }
/// Return a reference to the stored deleter. /// Return a reference to the stored deleter.
const deleter_type& const deleter_type&
get_deleter() const noexcept get_deleter() const noexcept
{ return std::get<1>(_M_t); } { return _M_t._M_deleter(); }
/// Return @c true if the stored pointer is not null. /// Return @c true if the stored pointer is not null.
explicit operator bool() const noexcept explicit operator bool() const noexcept
...@@ -325,7 +343,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -325,7 +343,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
release() noexcept release() noexcept
{ {
pointer __p = get(); pointer __p = get();
std::get<0>(_M_t) = pointer(); _M_t._M_ptr() = pointer();
return __p; return __p;
} }
...@@ -339,7 +357,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -339,7 +357,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
reset(pointer __p = pointer()) noexcept reset(pointer __p = pointer()) noexcept
{ {
using std::swap; using std::swap;
swap(std::get<0>(_M_t), __p); swap(_M_t._M_ptr(), __p);
if (__p != pointer()) if (__p != pointer())
get_deleter()(__p); get_deleter()(__p);
} }
...@@ -364,23 +382,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -364,23 +382,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Dp> template<typename _Tp, typename _Dp>
class unique_ptr<_Tp[], _Dp> class unique_ptr<_Tp[], _Dp>
{ {
// use SFINAE to determine whether _Del::pointer exists __uniq_ptr_impl<_Tp, _Dp> _M_t;
class _Pointer
{
template<typename _Up>
static typename _Up::pointer __test(typename _Up::pointer*);
template<typename _Up>
static _Tp* __test(...);
typedef typename remove_reference<_Dp>::type _Del;
public:
typedef decltype(__test<_Del>(0)) type;
};
typedef std::tuple<typename _Pointer::type, _Dp> __tuple_type;
__tuple_type _M_t;
template<typename _Up> template<typename _Up>
using __remove_cv = typename remove_cv<_Up>::type; using __remove_cv = typename remove_cv<_Up>::type;
...@@ -391,11 +393,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -391,11 +393,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
= __and_< is_base_of<_Tp, _Up>, = __and_< is_base_of<_Tp, _Up>,
__not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >; __not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >;
public: public:
typedef typename _Pointer::type pointer; using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
typedef _Tp element_type; using element_type = _Tp;
typedef _Dp deleter_type; using deleter_type = _Dp;
// helper template for detecting a safe conversion from another // helper template for detecting a safe conversion from another
// unique_ptr // unique_ptr
...@@ -446,7 +447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -446,7 +447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__safe_conversion_raw<_Up>::value, bool>::type> __safe_conversion_raw<_Up>::value, bool>::type>
explicit explicit
unique_ptr(_Up __p) noexcept unique_ptr(_Up __p) noexcept
: _M_t(__p, deleter_type()) : _M_t(__p)
{ static_assert(!is_pointer<deleter_type>::value, { static_assert(!is_pointer<deleter_type>::value,
"constructed with null function pointer deleter"); } "constructed with null function pointer deleter"); }
...@@ -499,7 +500,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -499,7 +500,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Destructor, invokes the deleter if the stored pointer is not null. /// Destructor, invokes the deleter if the stored pointer is not null.
~unique_ptr() ~unique_ptr()
{ {
auto& __ptr = std::get<0>(_M_t); auto& __ptr = _M_t._M_ptr();
if (__ptr != nullptr) if (__ptr != nullptr)
get_deleter()(__ptr); get_deleter()(__ptr);
__ptr = pointer(); __ptr = pointer();
...@@ -562,17 +563,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -562,17 +563,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Return the stored pointer. /// Return the stored pointer.
pointer pointer
get() const noexcept get() const noexcept
{ return std::get<0>(_M_t); } { return _M_t._M_ptr(); }
/// Return a reference to the stored deleter. /// Return a reference to the stored deleter.
deleter_type& deleter_type&
get_deleter() noexcept get_deleter() noexcept
{ return std::get<1>(_M_t); } { return _M_t._M_deleter(); }
/// Return a reference to the stored deleter. /// Return a reference to the stored deleter.
const deleter_type& const deleter_type&
get_deleter() const noexcept get_deleter() const noexcept
{ return std::get<1>(_M_t); } { return _M_t._M_deleter(); }
/// Return @c true if the stored pointer is not null. /// Return @c true if the stored pointer is not null.
explicit operator bool() const noexcept explicit operator bool() const noexcept
...@@ -585,7 +586,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -585,7 +586,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
release() noexcept release() noexcept
{ {
pointer __p = get(); pointer __p = get();
std::get<0>(_M_t) = pointer(); _M_t._M_ptr() = pointer();
return __p; return __p;
} }
...@@ -612,7 +613,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -612,7 +613,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ {
pointer __ptr = __p; pointer __ptr = __p;
using std::swap; using std::swap;
swap(std::get<0>(_M_t), __ptr); swap(_M_t._M_ptr(), __ptr);
if (__ptr != nullptr) if (__ptr != nullptr)
get_deleter()(__ptr); get_deleter()(__ptr);
} }
......
...@@ -126,7 +126,13 @@ class UniquePointerPrinter: ...@@ -126,7 +126,13 @@ class UniquePointerPrinter:
self.val = val self.val = val
def to_string (self): def to_string (self):
v = self.val['_M_t']['_M_head_impl'] impl_type = self.val.type.fields()[0].type.tag
if impl_type.startswith('std::__uniq_ptr_impl<'): # New implementation
v = self.val['_M_t']['_M_t']['_M_head_impl']
elif impl_type.startswith('std::tuple<'):
v = self.val['_M_t']['_M_head_impl']
else:
raise ValueError("Unsupported implementation for unique_ptr: %s" % self.val.type.fields()[0].type.tag)
return ('std::unique_ptr<%s> containing %s' % (str(v.type.target()), return ('std::unique_ptr<%s> containing %s' % (str(v.type.target()),
str(v))) str(v)))
......
...@@ -575,7 +575,12 @@ class UniquePtrGetWorker(gdb.xmethod.XMethodWorker): ...@@ -575,7 +575,12 @@ class UniquePtrGetWorker(gdb.xmethod.XMethodWorker):
return self._elem_type.pointer() return self._elem_type.pointer()
def __call__(self, obj): def __call__(self, obj):
return obj['_M_t']['_M_head_impl'] impl_type = obj.dereference().type.fields()[0].type.tag
if impl_type.startswith('std::__uniq_ptr_impl<'): # New implementation
return obj['_M_t']['_M_t']['_M_head_impl']
elif impl_type.startswith('std::tuple<'):
return obj['_M_t']['_M_head_impl']
return None
class UniquePtrDerefWorker(UniquePtrGetWorker): class UniquePtrDerefWorker(UniquePtrGetWorker):
def __init__(self, elem_type): def __init__(self, elem_type):
......
...@@ -42,10 +42,10 @@ void f() ...@@ -42,10 +42,10 @@ void f()
std::unique_ptr<int, D&> ud(nullptr, d); std::unique_ptr<int, D&> ud(nullptr, d);
ub = std::move(ud); // { dg-error "no match" } ub = std::move(ud); // { dg-error "no match" }
ub2 = ud; // { dg-error "no match" } ub2 = ud; // { dg-error "no match" }
// { dg-error "no type" "" { target *-*-* } 269 } // { dg-error "no type" "" { target *-*-* } 287 }
std::unique_ptr<int[], B&> uba(nullptr, b); std::unique_ptr<int[], B&> uba(nullptr, b);
std::unique_ptr<int[], D&> uda(nullptr, d); std::unique_ptr<int[], D&> uda(nullptr, d);
uba = std::move(uda); // { dg-error "no match" } uba = std::move(uda); // { dg-error "no match" }
// { dg-error "no type" "" { target *-*-* } 537 } // { dg-error "no type" "" { target *-*-* } 538 }
} }
// Copyright (C) 2016 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 compile { target c++11 } }
#include <memory>
struct D {
D() = default;
D(const D&) = delete;
void operator()(int*);
};
std::unique_ptr<int, D> p((int*)nullptr); // PR libstdc++/77990
...@@ -105,7 +105,7 @@ test07() ...@@ -105,7 +105,7 @@ test07()
std::unique_ptr<const A[]> cA3(p); // { dg-error "no matching function" } std::unique_ptr<const A[]> cA3(p); // { dg-error "no matching function" }
std::unique_ptr<volatile A[]> vA3(p); // { dg-error "no matching function" } std::unique_ptr<volatile A[]> vA3(p); // { dg-error "no matching function" }
std::unique_ptr<const volatile A[]> cvA3(p); // { dg-error "no matching function" } std::unique_ptr<const volatile A[]> cvA3(p); // { dg-error "no matching function" }
// { dg-error "no type" "" { target *-*-* } 445 } // { dg-error "no type" "" { target *-*-* } 446 }
} }
template<typename T> template<typename T>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment