diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2018-09-11 11:55:49 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2018-09-11 11:55:49 +0100 |
commit | 86fc6ec9f366fd95d976c01bfa24c6775537ba62 (patch) | |
tree | ce28f3d56213828fb0d7b4202d9c1940bcb5feab /libstdc++-v3 | |
parent | 9356a18eb4aa927c9e44245075b82fa0c6001789 (diff) | |
download | gcc-86fc6ec9f366fd95d976c01bfa24c6775537ba62.zip gcc-86fc6ec9f366fd95d976c01bfa24c6775537ba62.tar.gz gcc-86fc6ec9f366fd95d976c01bfa24c6775537ba62.tar.bz2 |
Implement LWG 2905 changes to constrain unique_ptr constructors
LWG DR 2905 says that is_constructible_v<unique_ptr<P, D>, P, D const &>
should be false when D is not copy constructible. This commit implements
the changes from the DR and simplifies the signatures as per
https://github.com/cplusplus/draft/issues/1530
* include/bits/unique_ptr.h (__uniq_ptr_impl): Add assertions to
check deleter type.
(unique_ptr::unique_ptr(pointer, const deleter_type&)): Add copy
constructible constraint.
(unique_ptr::unique_ptr(pointer, deleter_type&&)): Disable for
deleters of reference type and add move constructible constraint.
(unique_ptr::unique_ptr(pointer, remove_reference_t<deleter_type>&&)):
Disable for deleters of non-reference type. Define as deleted.
(unique_ptr<T[], D>): Likewise.
* testsuite/20_util/unique_ptr/assign/48635_neg.cc: Replace dg-error
directives with unstable line numbers with dg-prune-output.
* testsuite/20_util/unique_ptr/cons/cv_qual_neg.cc: Likewise.
* testsuite/20_util/unique_ptr/cons/lwg2905.cc: New test.
* testsuite/20_util/unique_ptr/specialized_algorithms/swap_cxx17.cc:
Make deleter types invocable.
From-SVN: r264206
Diffstat (limited to 'libstdc++-v3')
6 files changed, 160 insertions, 42 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 3de9031..1a1a535 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,22 @@ +2018-09-11 Jonathan Wakely <jwakely@redhat.com> + + Implement LWG 2905 changes to constrain unique_ptr constructors + * include/bits/unique_ptr.h (__uniq_ptr_impl): Add assertions to + check deleter type. + (unique_ptr::unique_ptr(pointer, const deleter_type&)): Add copy + constructible constraint. + (unique_ptr::unique_ptr(pointer, deleter_type&&)): Disable for + deleters of reference type and add move constructible constraint. + (unique_ptr::unique_ptr(pointer, remove_reference_t<deleter_type>&&)): + Disable for deleters of non-reference type. Define as deleted. + (unique_ptr<T[], D>): Likewise. + * testsuite/20_util/unique_ptr/assign/48635_neg.cc: Replace dg-error + directives with unstable line numbers with dg-prune-output. + * testsuite/20_util/unique_ptr/cons/cv_qual_neg.cc: Likewise. + * testsuite/20_util/unique_ptr/cons/lwg2905.cc: New test. + * testsuite/20_util/unique_ptr/specialized_algorithms/swap_cxx17.cc: + Make deleter types invocable. + 2018-09-05 Jonathan Wakely <jwakely@redhat.com> * libsupc++/cxxabi.h (__cxa_demangle): Clarify doxygen comment. diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h index 4c99a9c..ddc6ae0 100644 --- a/libstdc++-v3/include/bits/unique_ptr.h +++ b/libstdc++-v3/include/bits/unique_ptr.h @@ -139,6 +139,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using pointer = typename _Ptr<_Tp, _Dp>::type; + static_assert( !is_rvalue_reference<_Dp>::value, + "unique_ptr's deleter type must be a function object type" + " or an lvalue reference type" ); + static_assert( __is_invocable<_Dp&, pointer&>::value, + "unique_ptr's deleter must be invocable with a pointer" ); + __uniq_ptr_impl() = default; __uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; } @@ -159,9 +165,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template <typename _Tp, typename _Dp = default_delete<_Tp>> class unique_ptr { - template <class _Up> - using _DeleterConstraint = - typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type; + template <typename _Up> + using _DeleterConstraint = + typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type; __uniq_ptr_impl<_Tp, _Dp> _M_t; @@ -170,6 +176,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using element_type = _Tp; using deleter_type = _Dp; + private: // helper template for detecting a safe conversion from another // unique_ptr template<typename _Up, typename _Ep> @@ -183,11 +190,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > >; + public: // Constructors. /// Default constructor, creates a unique_ptr that owns nothing. - template <typename _Up = _Dp, - typename = _DeleterConstraint<_Up>> + template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> constexpr unique_ptr() noexcept : _M_t() { } @@ -198,8 +205,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * * The deleter will be value-initialized. */ - template <typename _Up = _Dp, - typename = _DeleterConstraint<_Up>> + template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> explicit unique_ptr(pointer __p) noexcept : _M_t(__p) @@ -212,27 +218,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * * The deleter will be initialized with @p __d */ - unique_ptr(pointer __p, - typename conditional<is_reference<deleter_type>::value, - deleter_type, const deleter_type&>::type __d) noexcept - : _M_t(__p, __d) { } + template<typename _Del = deleter_type, + typename = _Require<is_copy_constructible<_Del>>> + unique_ptr(pointer __p, const deleter_type& __d) noexcept + : _M_t(__p, __d) { } /** Takes ownership of a pointer. * * @param __p A pointer to an object of @c element_type - * @param __d An rvalue reference to a deleter. + * @param __d An rvalue reference to a (non-reference) deleter. * * The deleter will be initialized with @p std::move(__d) */ - unique_ptr(pointer __p, - typename remove_reference<deleter_type>::type&& __d) noexcept - : _M_t(std::move(__p), std::move(__d)) - { static_assert(!std::is_reference<deleter_type>::value, - "rvalue deleter bound to reference"); } + template<typename _Del = deleter_type, + typename = _Require<is_move_constructible<_Del>>> + unique_ptr(pointer __p, + __enable_if_t<!is_lvalue_reference<_Del>::value, + _Del&&> __d) noexcept + : _M_t(__p, std::move(__d)) + { } + + template<typename _Del = deleter_type, + typename _DelUnref = typename remove_reference<_Del>::type> + unique_ptr(pointer, + __enable_if_t<is_lvalue_reference<_Del>::value, + _DelUnref&&>) = delete; /// Creates a unique_ptr that owns nothing. - template <typename _Up = _Dp, - typename = _DeleterConstraint<_Up>> + template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { } // Move constructors. @@ -454,8 +467,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Constructors. /// Default constructor, creates a unique_ptr that owns nothing. - template <typename _Up = _Dp, - typename = _DeleterConstraint<_Up>> + template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> constexpr unique_ptr() noexcept : _M_t() { } @@ -485,12 +497,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * * The deleter will be initialized with @p __d */ - template<typename _Up, - typename = typename enable_if< - __safe_conversion_raw<_Up>::value, bool>::type> - unique_ptr(_Up __p, - typename conditional<is_reference<deleter_type>::value, - deleter_type, const deleter_type&>::type __d) noexcept + template<typename _Up, typename _Del = deleter_type, + typename = _Require<__safe_conversion_raw<_Up>, + is_copy_constructible<_Del>>> + unique_ptr(_Up __p, const deleter_type& __d) noexcept : _M_t(__p, __d) { } /** Takes ownership of a pointer. @@ -501,22 +511,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * * The deleter will be initialized with @p std::move(__d) */ - template<typename _Up, - typename = typename enable_if< - __safe_conversion_raw<_Up>::value, bool>::type> - unique_ptr(_Up __p, typename - remove_reference<deleter_type>::type&& __d) noexcept - : _M_t(std::move(__p), std::move(__d)) - { static_assert(!is_reference<deleter_type>::value, - "rvalue deleter bound to reference"); } + template<typename _Up, typename _Del = deleter_type, + typename = _Require<__safe_conversion_raw<_Up>, + is_move_constructible<_Del>>> + unique_ptr(_Up __p, + __enable_if_t<!is_lvalue_reference<_Del>::value, + _Del&&> __d) noexcept + : _M_t(std::move(__p), std::move(__d)) + { } + + template<typename _Up, typename _Del = deleter_type, + typename _DelUnref = typename remove_reference<_Del>::type, + typename = _Require<__safe_conversion_raw<_Up>>> + unique_ptr(_Up, + __enable_if_t<is_lvalue_reference<_Del>::value, + _DelUnref&&>) = delete; /// Move constructor. unique_ptr(unique_ptr&& __u) noexcept : _M_t(__u.release(), std::forward<deleter_type>(__u.get_deleter())) { } /// Creates a unique_ptr that owns nothing. - template <typename _Up = _Dp, - typename = _DeleterConstraint<_Up>> + template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { } template<typename _Up, typename _Ep, 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 b22d0e1..0c8f8b3 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<int, D&> ud(nullptr, d); ub = std::move(ud); // { dg-error "no match" } ub2 = ud; // { dg-error "no match" } -// { dg-error "no type" "" { target *-*-* } 307 } std::unique_ptr<int[], B&> uba(nullptr, b); std::unique_ptr<int[], D&> uda(nullptr, d); uba = std::move(uda); // { dg-error "no match" } -// { dg-error "no type" "" { target *-*-* } 566 } } + +// { dg-prune-output "no type" } diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual_neg.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual_neg.cc index c1b1c9e..7e820ba 100644 --- a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual_neg.cc +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual_neg.cc @@ -39,7 +39,7 @@ test07() 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<const volatile A[]> cvA3(p); // { dg-error "no matching function" } - // { dg-error "no type" "" { target *-*-* } 473 } + // { dg-prune-output "no type" } } template<typename T> diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/lwg2905.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/lwg2905.cc new file mode 100644 index 0000000..8700630 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/lwg2905.cc @@ -0,0 +1,78 @@ +// 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 compile { target c++11 } } + +#include <memory> + +template<typename T, typename D, typename P, typename E> +constexpr bool check() +{ return std::is_constructible<std::unique_ptr<T, D>, P, E>::value; } + +struct Del { void operator()(void*) const { } }; + +static_assert( ! check<int, Del&, int*, Del>(), "" ); +static_assert( check<int, Del&, int*, Del&>(), "" ); +static_assert( check<int, const Del&, int*, Del&>(), "" ); +static_assert( ! check<int, Del&, int*, const Del&>(), "" ); +static_assert( check<int, Del, int*, const Del&>(), "" ); +static_assert( check<int, Del, int*, Del>(), "" ); + +static_assert( ! check<int[], Del&, int*, Del>(), "" ); +static_assert( check<int[], Del&, int*, Del&>(), "" ); +static_assert( check<int[], const Del&, int*, Del&>(), "" ); +static_assert( ! check<int[], Del&, int*, const Del&>(), "" ); +static_assert( check<int[], Del, int*, const Del&>(), "" ); +static_assert( check<int[], Del, int*, Del>(), "" ); + +struct DelNoCopy { + DelNoCopy() = default; + DelNoCopy(const DelNoCopy&) = delete; + DelNoCopy(DelNoCopy&&) = default; + void operator()(void*) const { } +}; + +static_assert( ! check<int, DelNoCopy&, int*, DelNoCopy>(), "" ); +static_assert( check<int, DelNoCopy&, int*, DelNoCopy&>(), "" ); +static_assert( check<int, const DelNoCopy&, int*, DelNoCopy&>(), "" ); +static_assert( ! check<int, DelNoCopy&, int*, const DelNoCopy&>(), "" ); +static_assert( ! check<int, DelNoCopy, int*, const DelNoCopy&>(), "" ); +static_assert( check<int, DelNoCopy, int*, DelNoCopy>(), "" ); + +static_assert( ! check<int[], DelNoCopy&, int*, DelNoCopy>(), "" ); +static_assert( check<int[], DelNoCopy&, int*, DelNoCopy&>(), "" ); +static_assert( check<int[], const DelNoCopy&, int*, DelNoCopy&>(), "" ); +static_assert( ! check<int[], DelNoCopy&, int*, const DelNoCopy&>(), "" ); +static_assert( ! check<int[], DelNoCopy, int*, const DelNoCopy&>(), "" ); +static_assert( check<int[], DelNoCopy, int*, DelNoCopy>(), "" ); + +struct Base { virtual ~Base() { } }; +struct Derived : Base { }; + +static_assert( ! check<Base[], Del&, Base*, Del>(), "" ); +static_assert( check<Base[], Del&, Base*, Del&>(), "" ); +static_assert( check<Base[], const Del&, Base*, Del&>(), "" ); +static_assert( ! check<Base[], Del&, Base*, const Del&>(), "" ); +static_assert( check<Base[], Del, Base*, const Del&>(), "" ); +static_assert( check<Base[], Del, Base*, Del>(), "" ); + +static_assert( ! check<Base[], Del&, Derived*, Del>(), "" ); +static_assert( ! check<Base[], Del&, Derived*, Del&>(), "" ); +static_assert( ! check<Base[], const Del&, Derived*, Del&>(), "" ); +static_assert( ! check<Base[], Del&, Derived*, const Del&>(), "" ); +static_assert( ! check<Base[], Del, Derived*, const Del&>(), "" ); +static_assert( ! check<Base[], Del, Derived*, Del>(), "" ); diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/specialized_algorithms/swap_cxx17.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/specialized_algorithms/swap_cxx17.cc index 298d951..604685c 100644 --- a/libstdc++-v3/testsuite/20_util/unique_ptr/specialized_algorithms/swap_cxx17.cc +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/specialized_algorithms/swap_cxx17.cc @@ -21,13 +21,18 @@ #include <memory> // Not swappable, and unique_ptr not swappable via the generic std::swap. -struct C { }; +struct C { + void operator()(void*) const { } +}; void swap(C&, C&) = delete; static_assert( !std::is_swappable_v<std::unique_ptr<int, C>> ); // Not swappable, and unique_ptr not swappable via the generic std::swap. -struct D { D(D&&) = delete; }; +struct D { + D(D&&) = delete; + void operator()(void*) const { } +}; static_assert( !std::is_swappable_v<std::unique_ptr<int, D>> ); |