From fb3fc4bded8d934b603a7f07ab3cfe3b644ee971 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Thu, 23 May 2019 22:41:02 +0100 Subject: [PATCH] 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. From-SVN: r271583 --- libstdc++-v3/ChangeLog | 16 +++ libstdc++-v3/doc/html/manual/api.html | 3 + libstdc++-v3/doc/html/manual/bugs.html | 10 ++ libstdc++-v3/doc/xml/manual/intro.xml | 8 ++ libstdc++-v3/include/bits/shared_ptr.h | 93 ++++++++++++++-- libstdc++-v3/include/bits/shared_ptr_base.h | 11 ++ .../testsuite/20_util/shared_ptr/casts/1.cc | 55 +++++++++- .../20_util/shared_ptr/casts/reinterpret.cc | 33 +++++- .../20_util/shared_ptr/casts/rval.cc | 101 ++++++++++++++++++ .../20_util/shared_ptr/cons/alias-rval.cc | 101 ++++++++++++++++++ .../20_util/shared_ptr/cons/alias.cc | 14 +-- 11 files changed, 416 insertions(+), 29 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/shared_ptr/casts/rval.cc create mode 100644 libstdc++-v3/testsuite/20_util/shared_ptr/cons/alias-rval.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index e230f24ca13..48b519e9cd0 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,21 @@ 2019-05-23 Jonathan Wakely + * 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. + * doc/xml/manual/evolution.xml: Document LWG DR 2921 change. * doc/xml/manual/intro.xml: Likewise. * include/std/future (__create_task_state): Add default arguments diff --git a/libstdc++-v3/doc/html/manual/api.html b/libstdc++-v3/doc/html/manual/api.html index bb131d3010c..345c58802a4 100644 --- a/libstdc++-v3/doc/html/manual/api.html +++ b/libstdc++-v3/doc/html/manual/api.html @@ -393,4 +393,7 @@ now defaults to zero. <experimental/timer>.

10

Deprecated features removed:

  • Profile Mode
  • __gnu_cxx::array_allocator

+

+ The std::packaged_task constructors taking + an allocator argument are only defined for C++11 and C++14.

\ No newline at end of file diff --git a/libstdc++-v3/doc/html/manual/bugs.html b/libstdc++-v3/doc/html/manual/bugs.html index f72404baedb..db300482039 100644 --- a/libstdc++-v3/doc/html/manual/bugs.html +++ b/libstdc++-v3/doc/html/manual/bugs.html @@ -565,11 +565,21 @@ shared_ptr constructor requirements for a deleter

Use rvalues for deleters. +

2921: + packaged_task and type-erased allocators + +

For C++17 mode, remove the constructors taking + an allocator argument.

2942: LWG 2873's resolution missed weak_ptr::owner_before

Add noexcept. +

2996: + Missing rvalue overloads for + shared_ptr operations + +

Add additional constructor and cast overloads.

2993: reference_wrapper<T> conversion from T&& 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. Add noexcept. + 2996: + Missing rvalue overloads for + shared_ptr operations + + + Add additional constructor and cast overloads. + + 2993: reference_wrapper<T> conversion from T&& 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 > pii(new pair()); + * shared_ptr> pii(new pair()); * shared_ptr 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> pii(new pair()); + * shared_ptr pi1(pii, &pii->first); + * assert(pii.use_count() == 2); + * shared_ptr pi2(std::move(pii), &pii->second); + * assert(pii.use_count() == 0); + * @endcode + */ + template + 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(__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 + inline shared_ptr<_Tp> + static_pointer_cast(shared_ptr<_Up>&& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + return _Sp(std::move(__r), + static_cast(__r.get())); + } + + /// Convert type of `shared_ptr` rvalue, via `const_cast` + template + inline shared_ptr<_Tp> + const_pointer_cast(shared_ptr<_Up>&& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + return _Sp(std::move(__r), + const_cast(__r.get())); + } + + /// Convert type of `shared_ptr` rvalue, via `dynamic_cast` + template + inline shared_ptr<_Tp> + dynamic_pointer_cast(shared_ptr<_Up>&& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + if (auto* __p = dynamic_cast(__r.get())) + return _Sp(std::move(__r), __p); + return _Sp(); + } + + /// Convert type of `shared_ptr` rvalue, via `reinterpret_cast` + template + inline shared_ptr<_Tp> + reinterpret_pointer_cast(shared_ptr<_Up>&& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + return _Sp(std::move(__r), + reinterpret_cast(__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 __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 + __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 +#include #include 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 spci; shared_ptr spa; - check_ret_type >(static_pointer_cast(spd)); - check_ret_type >(const_pointer_cast(spci)); - check_ret_type >(static_pointer_cast(spa)); + check_ret_type>(static_pointer_cast(spd)); + check_ret_type>(const_pointer_cast(spci)); + check_ret_type>(dynamic_pointer_cast(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 pcv(ptr); + auto pci = static_pointer_cast(pcv); + VERIFY(pci.use_count() == 2); + VERIFY(pcv.use_count() == 2); + VERIFY(pci.get() == ptr); + VERIFY(pcv.get() == ptr); + auto pi = const_pointer_cast(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 pp(pptr); + auto pdp = dynamic_pointer_cast(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(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 +#include #include 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 spci; shared_ptr spa; - check_ret_type >(reinterpret_pointer_cast(spd)); - check_ret_type >(reinterpret_pointer_cast(spci)); - check_ret_type >(reinterpret_pointer_cast(spa)); + check_ret_type>(reinterpret_pointer_cast(spd)); + check_ret_type>(reinterpret_pointer_cast(spci)); + check_ret_type>(reinterpret_pointer_cast(spa)); +} + +void +test02() +{ + using std::shared_ptr; + using std::reinterpret_pointer_cast; + + int* ptr = new int(2); + shared_ptr pi(ptr); + auto pl = reinterpret_pointer_cast(pi); + VERIFY(pi.use_count() == 2); + VERIFY(pl.use_count() == 2); + VERIFY(pi.get() == ptr); + VERIFY(reinterpret_cast(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 +// . + +// shared_ptr casts [util.smartptr.shared.cast] + +#include +#include +#include + +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 spd; + shared_ptr spci; + shared_ptr spa; + + check_ret_type>(static_pointer_cast(std::move(spd))); + check_ret_type>(const_pointer_cast(std::move(spci))); + check_ret_type>(dynamic_pointer_cast(std::move(spa))); + check_ret_type>(reinterpret_pointer_cast(std::move(spd))); + check_ret_type>(reinterpret_pointer_cast(std::move(spci))); + check_ret_type>(reinterpret_pointer_cast(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 pcv(ptr); + auto pci = static_pointer_cast(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(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 pp(pptr); + auto pdp = dynamic_pointer_cast(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(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(std::move(pi)); + VERIFY(pl.use_count() == 1); + VERIFY(pi.use_count() == 0); + VERIFY(reinterpret_cast(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 +// . + +// Template class shared_ptr [util.smartptr.shared] + +#include +#include + +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; + std::shared_ptr 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 b2(b1); + VERIFY( b2.use_count() == 0 ); + VERIFY( b1 == b2 ); +} + +void +test02() +{ + std::shared_ptr a(new A); + std::shared_ptr 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 i2(i1); + VERIFY( i2.use_count() == 2 ); + VERIFY( i2.get() == &a->i ); +} + +void +test03() +{ + std::shared_ptr b1(new B); + std::shared_ptr b2(b1); + std::shared_ptr a1(std::move(b1), b1.get()); + std::shared_ptr 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 b2(b1); VERIFY( b2.use_count() == 0 ); VERIFY( b1.get() == b2.get() ); - - return 0; } -int +void test02() { std::shared_ptr a(new A); @@ -69,11 +68,9 @@ test02() std::shared_ptr i2(i1); VERIFY( i2.use_count() == 3 ); VERIFY( i2.get() == &a->i ); - - return 0; } -int +void test03() { std::shared_ptr 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; } -- 2.30.2