From e182393e31609b0d1474cea18c69bbb6c287ae6b Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 19 Oct 2016 10:34:57 +0100 Subject: [PATCH] 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): 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 --- libstdc++-v3/ChangeLog | 18 +++ libstdc++-v3/include/bits/unique_ptr.h | 111 +++++++++--------- libstdc++-v3/python/libstdcxx/v6/printers.py | 8 +- libstdc++-v3/python/libstdcxx/v6/xmethods.py | 7 +- .../20_util/unique_ptr/assign/48635_neg.cc | 4 +- .../20_util/unique_ptr/cons/77990.cc | 27 +++++ .../20_util/unique_ptr/cons/cv_qual.cc | 2 +- 7 files changed, 117 insertions(+), 60 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/cons/77990.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 7bf2b346b5d..378d8177bac 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,21 @@ +2016-10-19 Jonathan Wakely + + 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): 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 * include/experimental/bits/shared_ptr.h: Fix indentation. diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h index a36794d632e..e32b6c959b3 100644 --- a/libstdc++-v3/include/bits/unique_ptr.h +++ b/libstdc++-v3/include/bits/unique_ptr.h @@ -111,33 +111,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; - /// 20.7.1.2 unique_ptr for single objects. - template > - class unique_ptr + template + class __uniq_ptr_impl { - // use SFINAE to determine whether _Del::pointer exists - class _Pointer - { - template - static typename _Up::pointer __test(typename _Up::pointer*); + template + struct _Ptr + { + using type = _Up*; + }; + + template + struct + _Ptr<_Up, _Ep, __void_t::type::pointer>> + { + using type = typename remove_reference<_Ep>::type::pointer; + }; - template - static _Tp* __test(...); + public: + 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: - typedef decltype(__test<_Del>(0)) type; - }; + template + __uniq_ptr_impl(pointer __p, _Del&& __d) + : _M_t(__p, std::forward<_Del>(__d)) { } - typedef std::tuple __tuple_type; - __tuple_type _M_t; + pointer& _M_ptr() { return std::get<0>(_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: - typedef typename _Pointer::type pointer; - typedef _Tp element_type; - typedef _Dp deleter_type; + private: + tuple _M_t; + }; + + /// 20.7.1.2 unique_ptr for single objects. + template > + 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 // unique_ptr @@ -168,7 +186,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ explicit unique_ptr(pointer __p) noexcept - : _M_t(__p, deleter_type()) + : _M_t(__p) { static_assert(!is_pointer::value, "constructed with null function pointer deleter"); } @@ -231,7 +249,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Destructor, invokes the deleter if the stored pointer is not null. ~unique_ptr() noexcept { - auto& __ptr = std::get<0>(_M_t); + auto& __ptr = _M_t._M_ptr(); if (__ptr != nullptr) get_deleter()(__ptr); __ptr = pointer(); @@ -302,17 +320,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Return the stored pointer. pointer get() const noexcept - { return std::get<0>(_M_t); } + { return _M_t._M_ptr(); } /// Return a reference to the stored deleter. deleter_type& get_deleter() noexcept - { return std::get<1>(_M_t); } + { return _M_t._M_deleter(); } /// Return a reference to the stored deleter. const deleter_type& 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. explicit operator bool() const noexcept @@ -325,7 +343,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION release() noexcept { pointer __p = get(); - std::get<0>(_M_t) = pointer(); + _M_t._M_ptr() = pointer(); return __p; } @@ -339,7 +357,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION reset(pointer __p = pointer()) noexcept { using std::swap; - swap(std::get<0>(_M_t), __p); + swap(_M_t._M_ptr(), __p); if (__p != pointer()) get_deleter()(__p); } @@ -364,23 +382,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template class unique_ptr<_Tp[], _Dp> { - // use SFINAE to determine whether _Del::pointer exists - class _Pointer - { - template - static typename _Up::pointer __test(typename _Up::pointer*); - - template - static _Tp* __test(...); - - typedef typename remove_reference<_Dp>::type _Del; - - public: - typedef decltype(__test<_Del>(0)) type; - }; - - typedef std::tuple __tuple_type; - __tuple_type _M_t; + __uniq_ptr_impl<_Tp, _Dp> _M_t; template using __remove_cv = typename remove_cv<_Up>::type; @@ -391,11 +393,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION = __and_< is_base_of<_Tp, _Up>, __not_, __remove_cv<_Up>>> >; - public: - typedef typename _Pointer::type pointer; - typedef _Tp element_type; - typedef _Dp deleter_type; + 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 // unique_ptr @@ -446,7 +447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __safe_conversion_raw<_Up>::value, bool>::type> explicit unique_ptr(_Up __p) noexcept - : _M_t(__p, deleter_type()) + : _M_t(__p) { static_assert(!is_pointer::value, "constructed with null function pointer deleter"); } @@ -499,7 +500,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Destructor, invokes the deleter if the stored pointer is not null. ~unique_ptr() { - auto& __ptr = std::get<0>(_M_t); + auto& __ptr = _M_t._M_ptr(); if (__ptr != nullptr) get_deleter()(__ptr); __ptr = pointer(); @@ -562,17 +563,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Return the stored pointer. pointer get() const noexcept - { return std::get<0>(_M_t); } + { return _M_t._M_ptr(); } /// Return a reference to the stored deleter. deleter_type& get_deleter() noexcept - { return std::get<1>(_M_t); } + { return _M_t._M_deleter(); } /// Return a reference to the stored deleter. const deleter_type& 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. explicit operator bool() const noexcept @@ -585,7 +586,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION release() noexcept { pointer __p = get(); - std::get<0>(_M_t) = pointer(); + _M_t._M_ptr() = pointer(); return __p; } @@ -612,7 +613,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { pointer __ptr = __p; using std::swap; - swap(std::get<0>(_M_t), __ptr); + swap(_M_t._M_ptr(), __ptr); if (__ptr != nullptr) get_deleter()(__ptr); } diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py index 714e1b86af5..bad42b472a9 100644 --- a/libstdc++-v3/python/libstdcxx/v6/printers.py +++ b/libstdc++-v3/python/libstdcxx/v6/printers.py @@ -126,7 +126,13 @@ class UniquePointerPrinter: self.val = val 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()), str(v))) diff --git a/libstdc++-v3/python/libstdcxx/v6/xmethods.py b/libstdc++-v3/python/libstdcxx/v6/xmethods.py index 605cda11761..045b6617637 100644 --- a/libstdc++-v3/python/libstdcxx/v6/xmethods.py +++ b/libstdc++-v3/python/libstdcxx/v6/xmethods.py @@ -575,7 +575,12 @@ class UniquePtrGetWorker(gdb.xmethod.XMethodWorker): return self._elem_type.pointer() 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): def __init__(self, elem_type): diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635_neg.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635_neg.cc index 7f6d27c0ae8..311e8d55f5c 100644 --- a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635_neg.cc +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635_neg.cc @@ -42,10 +42,10 @@ void f() std::unique_ptr ud(nullptr, d); ub = std::move(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 uba(nullptr, b); std::unique_ptr uda(nullptr, d); uba = std::move(uda); // { dg-error "no match" } -// { dg-error "no type" "" { target *-*-* } 537 } +// { dg-error "no type" "" { target *-*-* } 538 } } diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/77990.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/77990.cc new file mode 100644 index 00000000000..e3e9a208de8 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/77990.cc @@ -0,0 +1,27 @@ +// 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 +// . + +// { dg-do compile { target c++11 } } + +#include + +struct D { + D() = default; + D(const D&) = delete; + void operator()(int*); +}; +std::unique_ptr p((int*)nullptr); // PR libstdc++/77990 diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual.cc index fcd5c5e7335..829d11283cf 100644 --- a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual.cc +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual.cc @@ -105,7 +105,7 @@ test07() std::unique_ptr cA3(p); // { dg-error "no matching function" } std::unique_ptr vA3(p); // { dg-error "no matching function" } std::unique_ptr cvA3(p); // { dg-error "no matching function" } - // { dg-error "no type" "" { target *-*-* } 445 } + // { dg-error "no type" "" { target *-*-* } 446 } } template -- 2.30.2