* doc/xml/manual/intro.xml: Document LWG DR 2996 change. * doc/html/*: Regenerate. * include/bits/shared_ptr.h (shared_ptr(shared_ptr&&, T*)): Add rvalue aliasing constructor. (static_pointer_cast, const_pointer, dynamic_pointer_cast) (reinterpret_pointer_cast): Add overloads taking rvalues. * include/bits/shared_ptr_base.h (__shared_ptr(__shared_ptr&&, T*)): Add rvalue aliasing constructor. * testsuite/20_util/shared_ptr/casts/1.cc: Change "compile" test to "run" and check return values as well as types. * testsuite/20_util/shared_ptr/casts/reinterpret.cc: Likewise. * testsuite/20_util/shared_ptr/casts/rval.cc: New test. * testsuite/20_util/shared_ptr/cons/alias-rval.cc: New test. * testsuite/20_util/shared_ptr/cons/alias.cc: Remove unused return values.
Tested powerpc64le-linux, committed to trunk.
commit 7398b0aacbcd98032a893b40941c6a88d074eb31 Author: Jonathan Wakely <jwak...@redhat.com> Date: Thu May 23 17:28:16 2019 +0100 LWG 2996 add rvalue overloads for shared_ptr aliasing and casting * doc/xml/manual/intro.xml: Document LWG DR 2996 change. * doc/html/*: Regenerate. * include/bits/shared_ptr.h (shared_ptr(shared_ptr&&, T*)): Add rvalue aliasing constructor. (static_pointer_cast, const_pointer, dynamic_pointer_cast) (reinterpret_pointer_cast): Add overloads taking rvalues. * include/bits/shared_ptr_base.h (__shared_ptr(__shared_ptr&&, T*)): Add rvalue aliasing constructor. * testsuite/20_util/shared_ptr/casts/1.cc: Change "compile" test to "run" and check return values as well as types. * testsuite/20_util/shared_ptr/casts/reinterpret.cc: Likewise. * testsuite/20_util/shared_ptr/casts/rval.cc: New test. * testsuite/20_util/shared_ptr/cons/alias-rval.cc: New test. * testsuite/20_util/shared_ptr/cons/alias.cc: Remove unused return values. diff --git a/libstdc++-v3/doc/xml/manual/intro.xml b/libstdc++-v3/doc/xml/manual/intro.xml index a2162562b54..4a5d25fa0d7 100644 --- a/libstdc++-v3/doc/xml/manual/intro.xml +++ b/libstdc++-v3/doc/xml/manual/intro.xml @@ -1237,6 +1237,14 @@ requirements of the license of GCC. <listitem><para>Add noexcept. </para></listitem></varlistentry> + <varlistentry xml:id="manual.bugs.dr2996"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#2996">2996</link>: + <emphasis>Missing rvalue overloads for + <code>shared_ptr</code> operations + </emphasis> + </term> + <listitem><para>Add additional constructor and cast overloads. + </para></listitem></varlistentry> + <varlistentry xml:id="manual.bugs.dr2993"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#2993">2993</link>: <emphasis><code>reference_wrapper<T></code> conversion from <code>T&&</code> </emphasis> diff --git a/libstdc++-v3/include/bits/shared_ptr.h b/libstdc++-v3/include/bits/shared_ptr.h index 8f219e73d60..41f6b126b3d 100644 --- a/libstdc++-v3/include/bits/shared_ptr.h +++ b/libstdc++-v3/include/bits/shared_ptr.h @@ -235,17 +235,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Aliasing constructor /** - * @brief Constructs a %shared_ptr instance that stores @a __p - * and shares ownership with @a __r. - * @param __r A %shared_ptr. - * @param __p A pointer that will remain valid while @a *__r is valid. - * @post get() == __p && use_count() == __r.use_count() + * @brief Constructs a `shared_ptr` instance that stores `__p` + * and shares ownership with `__r`. + * @param __r A `shared_ptr`. + * @param __p A pointer that will remain valid while `*__r` is valid. + * @post `get() == __p && use_count() == __r.use_count()` * - * This can be used to construct a @c shared_ptr to a sub-object - * of an object managed by an existing @c shared_ptr. + * This can be used to construct a `shared_ptr` to a sub-object + * of an object managed by an existing `shared_ptr`. The complete + * object will remain valid while any `shared_ptr` owns it, even + * if they don't store a pointer to the complete object. * * @code - * shared_ptr< pair<int,int> > pii(new pair<int,int>()); + * shared_ptr<pair<int,int>> pii(new pair<int,int>()); * shared_ptr<int> pi(pii, &pii->first); * assert(pii.use_count() == 2); * @endcode @@ -254,6 +256,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) noexcept : __shared_ptr<_Tp>(__r, __p) { } +#if __cplusplus > 201703L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2996. Missing rvalue overloads for shared_ptr operations + /** + * @brief Constructs a `shared_ptr` instance that stores `__p` + * and shares ownership with `__r`. + * @param __r A `shared_ptr`. + * @param __p A pointer that will remain valid while `*__r` is valid. + * @post `get() == __p && !__r.use_count() && !__r.get()` + * + * This can be used to construct a `shared_ptr` to a sub-object + * of an object managed by an existing `shared_ptr`. The complete + * object will remain valid while any `shared_ptr` owns it, even + * if they don't store a pointer to the complete object. + * + * @code + * shared_ptr<pair<int,int>> pii(new pair<int,int>()); + * shared_ptr<int> pi1(pii, &pii->first); + * assert(pii.use_count() == 2); + * shared_ptr<int> pi2(std::move(pii), &pii->second); + * assert(pii.use_count() == 0); + * @endcode + */ + template<typename _Yp> + shared_ptr(shared_ptr<_Yp>&& __r, element_type* __p) noexcept + : __shared_ptr<_Tp>(std::move(__r), __p) { } +#endif /** * @brief If @a __r is empty, constructs an empty %shared_ptr; * otherwise construct a %shared_ptr that shares ownership @@ -568,7 +597,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Sp = shared_ptr<_Tp>; return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get())); } -#endif + +#if __cplusplus > 201703L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2996. Missing rvalue overloads for shared_ptr operations + + /// Convert type of `shared_ptr` rvalue, via `static_cast` + template<typename _Tp, typename _Up> + inline shared_ptr<_Tp> + static_pointer_cast(shared_ptr<_Up>&& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + return _Sp(std::move(__r), + static_cast<typename _Sp::element_type*>(__r.get())); + } + + /// Convert type of `shared_ptr` rvalue, via `const_cast` + template<typename _Tp, typename _Up> + inline shared_ptr<_Tp> + const_pointer_cast(shared_ptr<_Up>&& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + return _Sp(std::move(__r), + const_cast<typename _Sp::element_type*>(__r.get())); + } + + /// Convert type of `shared_ptr` rvalue, via `dynamic_cast` + template<typename _Tp, typename _Up> + inline shared_ptr<_Tp> + dynamic_pointer_cast(shared_ptr<_Up>&& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get())) + return _Sp(std::move(__r), __p); + return _Sp(); + } + + /// Convert type of `shared_ptr` rvalue, via `reinterpret_cast` + template<typename _Tp, typename _Up> + inline shared_ptr<_Tp> + reinterpret_pointer_cast(shared_ptr<_Up>&& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + return _Sp(std::move(__r), + reinterpret_cast<typename _Sp::element_type*>(__r.get())); + } +#endif // C++20 +#endif // C++17 // @} diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h index 968cc9658e2..4acec1cb2c5 100644 --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -1158,12 +1158,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _M_ptr(0), _M_refcount(__p, std::move(__d), std::move(__a)) { } + // Aliasing constructor template<typename _Yp> __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r, element_type* __p) noexcept : _M_ptr(__p), _M_refcount(__r._M_refcount) // never throws { } + // Aliasing constructor + template<typename _Yp> + __shared_ptr(__shared_ptr<_Yp, _Lp>&& __r, + element_type* __p) noexcept + : _M_ptr(__p), _M_refcount() + { + _M_refcount._M_swap(__r._M_refcount); + __r._M_ptr = 0; + } + __shared_ptr(const __shared_ptr&) noexcept = default; __shared_ptr& operator=(const __shared_ptr&) noexcept = default; ~__shared_ptr() = default; diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/casts/1.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/casts/1.cc index d689daf2f3d..f2b8a268259 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/casts/1.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/casts/1.cc @@ -1,4 +1,4 @@ -// { dg-do compile { target c++11 } } +// { dg-do run { target c++11 } } // Copyright (C) 2006-2019 Free Software Foundation, Inc. // @@ -20,12 +20,14 @@ // 20.6.6.2.10 shared_ptr casts [util.smartptr.shared.cast] #include <memory> +#include <testsuite_hooks.h> #include <testsuite_tr1.h> struct MyP { virtual ~MyP() { }; }; struct MyDP : MyP { }; -int main() +void +test01() { using __gnu_test::check_ret_type; using std::shared_ptr; @@ -37,7 +39,50 @@ int main() shared_ptr<const int> spci; shared_ptr<MyP> spa; - check_ret_type<shared_ptr<void> >(static_pointer_cast<void>(spd)); - check_ret_type<shared_ptr<int> >(const_pointer_cast<int>(spci)); - check_ret_type<shared_ptr<MyDP> >(static_pointer_cast<MyDP>(spa)); + check_ret_type<shared_ptr<void>>(static_pointer_cast<void>(spd)); + check_ret_type<shared_ptr<int>>(const_pointer_cast<int>(spci)); + check_ret_type<shared_ptr<MyDP>>(dynamic_pointer_cast<MyDP>(spa)); +} + +void +test02() +{ + using std::shared_ptr; + using std::static_pointer_cast; + using std::const_pointer_cast; + using std::dynamic_pointer_cast; + + int* ptr = new int(1); + shared_ptr<const void> pcv(ptr); + auto pci = static_pointer_cast<const int>(pcv); + VERIFY(pci.use_count() == 2); + VERIFY(pcv.use_count() == 2); + VERIFY(pci.get() == ptr); + VERIFY(pcv.get() == ptr); + auto pi = const_pointer_cast<int>(pci); + VERIFY(pi.use_count() == 3); + VERIFY(pcv.use_count() == 3); + VERIFY(pi.get() == ptr); + VERIFY(pci.get() == ptr); + + MyP* pptr = new MyP; + shared_ptr<MyP> pp(pptr); + auto pdp = dynamic_pointer_cast<MyDP>(pp); + VERIFY(pp.use_count() == 1); + VERIFY(pdp.use_count() == 0); + VERIFY(pdp.get() == nullptr); + VERIFY(pp.get() == pptr); + pptr = new MyDP; + pp.reset(pptr); + pdp = dynamic_pointer_cast<MyDP>(pp); + VERIFY(pp.use_count() == 2); + VERIFY(pdp.use_count() == 2); + VERIFY(pdp.get() == pptr); + VERIFY(pp.get() == pptr); +} + +int main() +{ + test01(); + test02(); } diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/casts/reinterpret.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/casts/reinterpret.cc index b16ac045dad..eae050fd954 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/casts/reinterpret.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/casts/reinterpret.cc @@ -1,5 +1,5 @@ // { dg-options "-std=gnu++17" } -// { dg-do compile { target c++17 } } +// { dg-do run { target c++17 } } // Copyright (C) 2016-2019 Free Software Foundation, Inc. // @@ -21,12 +21,14 @@ // 20.11.2.2.9 shared_ptr casts [util.smartptr.shared.cast] #include <memory> +#include <testsuite_hooks.h> #include <testsuite_tr1.h> struct MyP { virtual ~MyP() { }; }; struct MyDP : MyP { }; -int main() +void +test01() { using __gnu_test::check_ret_type; using std::shared_ptr; @@ -36,7 +38,28 @@ int main() shared_ptr<const int> spci; shared_ptr<MyP> spa; - check_ret_type<shared_ptr<void> >(reinterpret_pointer_cast<void>(spd)); - check_ret_type<shared_ptr<const short> >(reinterpret_pointer_cast<const short>(spci)); - check_ret_type<shared_ptr<MyDP> >(reinterpret_pointer_cast<MyDP>(spa)); + check_ret_type<shared_ptr<void>>(reinterpret_pointer_cast<void>(spd)); + check_ret_type<shared_ptr<const short>>(reinterpret_pointer_cast<const short>(spci)); + check_ret_type<shared_ptr<MyDP>>(reinterpret_pointer_cast<MyDP>(spa)); +} + +void +test02() +{ + using std::shared_ptr; + using std::reinterpret_pointer_cast; + + int* ptr = new int(2); + shared_ptr<int> pi(ptr); + auto pl = reinterpret_pointer_cast<long>(pi); + VERIFY(pi.use_count() == 2); + VERIFY(pl.use_count() == 2); + VERIFY(pi.get() == ptr); + VERIFY(reinterpret_cast<int*>(pl.get()) == ptr); +} + +int main() +{ + test01(); + test02(); } diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/casts/rval.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/casts/rval.cc new file mode 100644 index 00000000000..6f102b21eaa --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/casts/rval.cc @@ -0,0 +1,101 @@ +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +// Copyright (C) 2019 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/>. + +// shared_ptr casts [util.smartptr.shared.cast] + +#include <memory> +#include <testsuite_hooks.h> +#include <testsuite_tr1.h> + +struct MyP { virtual ~MyP() { }; }; +struct MyDP : MyP { }; + +void test01() +{ + using __gnu_test::check_ret_type; + using std::shared_ptr; + using std::static_pointer_cast; + using std::const_pointer_cast; + using std::dynamic_pointer_cast; + using std::reinterpret_pointer_cast; + + shared_ptr<double> spd; + shared_ptr<const int> spci; + shared_ptr<MyP> spa; + + check_ret_type<shared_ptr<void>>(static_pointer_cast<void>(std::move(spd))); + check_ret_type<shared_ptr<int>>(const_pointer_cast<int>(std::move(spci))); + check_ret_type<shared_ptr<MyDP>>(dynamic_pointer_cast<MyDP>(std::move(spa))); + check_ret_type<shared_ptr<void>>(reinterpret_pointer_cast<void>(std::move(spd))); + check_ret_type<shared_ptr<const short>>(reinterpret_pointer_cast<const short>(std::move(spci))); + check_ret_type<shared_ptr<MyDP>>(reinterpret_pointer_cast<MyDP>(std::move(spa))); +} + +void +test02() +{ + using std::shared_ptr; + using std::static_pointer_cast; + using std::const_pointer_cast; + using std::dynamic_pointer_cast; + using std::reinterpret_pointer_cast; + + int* ptr = new int(1); + shared_ptr<const void> pcv(ptr); + auto pci = static_pointer_cast<const int>(std::move(pcv)); + VERIFY(pci.use_count() == 1); + VERIFY(pcv.use_count() == 0); + VERIFY(pci.get() == ptr); + VERIFY(pcv.get() == nullptr); + auto pi = const_pointer_cast<int>(std::move(pci)); + VERIFY(pi.use_count() == 1); + VERIFY(pci.use_count() == 0); + VERIFY(pi.get() == ptr); + VERIFY(pci.get() == nullptr); + + MyP* pptr = new MyP; + shared_ptr<MyP> pp(pptr); + auto pdp = dynamic_pointer_cast<MyDP>(std::move(pp)); + VERIFY(pdp.use_count() == 0); + VERIFY(pp.use_count() == 1); + VERIFY(pdp.get() == nullptr); + VERIFY(pp.get() == pptr); + pptr = new MyDP; + pp.reset(pptr); + pdp = dynamic_pointer_cast<MyDP>(std::move(pp)); + VERIFY(pdp.use_count() == 1); + VERIFY(pp.use_count() == 0); + VERIFY(pdp.get() == pptr); + VERIFY(pp.get() == nullptr); + + ptr = new int(2); + pi.reset(ptr); + auto pl = reinterpret_pointer_cast<long>(std::move(pi)); + VERIFY(pl.use_count() == 1); + VERIFY(pi.use_count() == 0); + VERIFY(reinterpret_cast<int*>(pl.get()) == ptr); + VERIFY(pi.get() == nullptr); +} + +int main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/alias-rval.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/alias-rval.cc new file mode 100644 index 00000000000..205587cde66 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/alias-rval.cc @@ -0,0 +1,101 @@ +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +// Copyright (C) 2019 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/>. + +// Template class shared_ptr [util.smartptr.shared] + +#include <memory> +#include <testsuite_hooks.h> + +struct A +{ + A() : i() { } + virtual ~A() { } + int i; +}; + +struct B : A +{ + B() : A(), a() { } + virtual ~B() { } + A a; +}; + +void deletefunc(A* p) { delete p; } + +// 20.6.6.2.1 shared_ptr constructors [util.smartptr.shared.const] + +// Aliasing constructors + +void +test01() +{ + bool test = true; + + std::shared_ptr<A> a; + std::shared_ptr<bool> b1(std::move(a), &test); + VERIFY( b1.use_count() == 0 ); + VERIFY( b1.get() == &test ); + VERIFY( a.use_count() == 0 ); + VERIFY( a == nullptr ); + + std::shared_ptr<bool> b2(b1); + VERIFY( b2.use_count() == 0 ); + VERIFY( b1 == b2 ); +} + +void +test02() +{ + std::shared_ptr<A> a(new A); + std::shared_ptr<int> i1(std::move(a), &a->i); + VERIFY( i1.use_count() == 1 ); + VERIFY( i1 != nullptr ); + VERIFY( a.use_count() == 0 ); + VERIFY( a == nullptr ); + + std::shared_ptr<int> i2(i1); + VERIFY( i2.use_count() == 2 ); + VERIFY( i2.get() == &a->i ); +} + +void +test03() +{ + std::shared_ptr<B> b1(new B); + std::shared_ptr<B> b2(b1); + std::shared_ptr<A> a1(std::move(b1), b1.get()); + std::shared_ptr<A> a2(b2, &b2->a); + VERIFY( a2.use_count() == 2 ); + VERIFY( a1 != nullptr ); + VERIFY( a2 != nullptr ); + VERIFY( a1 != a2 ); + VERIFY( b1.use_count() == 0 ); + VERIFY( b2.use_count() == 0 ); + VERIFY( b1 == nullptr ); + VERIFY( b2 == nullptr ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/alias.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/alias.cc index 841a51e23af..134a05894a2 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/alias.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/alias.cc @@ -42,7 +42,8 @@ void deletefunc(A* p) { delete p; } // Aliasing constructors -int test01() +void +test01() { bool test = true; @@ -55,11 +56,9 @@ int test01() std::shared_ptr<bool> b2(b1); VERIFY( b2.use_count() == 0 ); VERIFY( b1.get() == b2.get() ); - - return 0; } -int +void test02() { std::shared_ptr<A> a(new A); @@ -69,11 +68,9 @@ test02() std::shared_ptr<int> i2(i1); VERIFY( i2.use_count() == 3 ); VERIFY( i2.get() == &a->i ); - - return 0; } -int +void test03() { std::shared_ptr<B> b(new B); @@ -89,8 +86,6 @@ test03() a3 = a2; VERIFY( a3.get() == &b->a ); - - return 0; } int @@ -99,5 +94,4 @@ main() test01(); test02(); test03(); - return 0; }