On 22 December 2016 at 19:11, Jonathan Wakely <jwak...@redhat.com> wrote: >> /// Default constructor, creates a unique_ptr that owns nothing. >> + template <typename _Up = deleter_type, >> + typename enable_if< >> + __and_<__not_<is_pointer<_Up>>, >> + is_default_constructible<_Up>>::value, >> + bool>::type = false> > > > Instead of repeating this condition half a dozen times, we could put > it in the __uniq_ptr_impl class template and reuse it, as in the > attached patch (and similarly for the unique_ptr<t[]> specialization). > What do you think?
It needs to be a bit more dependent than in that patch, I think. I adjusted the idea a bit, a new patch attached. It cleans up the code a bit, so it's better, but not a huge improvement. >> constexpr unique_ptr() noexcept >> : _M_t() >> - { static_assert(!is_pointer<deleter_type>::value, >> - "constructed with null function pointer deleter"); } >> + { } > The bodies of these constructors should be indented now that they're > templates. Hopefully fixed correctly in the new patch, please double-check. >> --- /dev/null >> +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/default.cc >> @@ -0,0 +1,40 @@ >> +// { dg-do compile { target c++11 } } >> + >> +// Copyright (C) 2011-2016 Free Software Foundation, Inc. > Is this substantially copied from an existing file, or should it just > be 2016? (Not that it really matters, as I don't think we should have Should just be 2016, fixed. 2016-12-29 Ville Voutilainen <ville.voutilai...@gmail.com> Implement 2801, Default-constructibility of unique_ptr. * include/bits/unique_ptr.h (__uniq_ptr_impl::_DeleterConstraint): New. (unique_ptr::_DeleterConstraint): Likewise. (unique_ptr()): Constrain. (unique_ptr(pointer)): Likewise. (unique_ptr(nullptr_t)): Likewise. (unique_ptr<_Tp[], _Dp>::_DeleterConstraint): New. (unique_ptr<_Tp[], _Dp>::unique_ptr()): Constrain. (unique_ptr<_Tp[], _Dp>::unique_ptr(_Up)): Likewise. (unique_ptr<_Tp[], _Dp>::unique_ptr(nullptr_t)): Likewise. * testsuite/20_util/unique_ptr/assign/48635_neg.cc: Adjust. * testsuite/20_util/unique_ptr/cons/cv_qual_neg.cc: Likewise. * testsuite/20_util/unique_ptr/cons/default.cc: New. * testsuite/20_util/unique_ptr/cons/ptr_deleter_neg.cc: Adjust.
diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h index 56e6ec0..f994c59 100644 --- a/libstdc++-v3/include/bits/unique_ptr.h +++ b/libstdc++-v3/include/bits/unique_ptr.h @@ -130,6 +130,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; public: + using _DeleterConstraint = enable_if< + __and_<__not_<is_pointer<_Dp>>, + is_default_constructible<_Dp>>::value>; + using pointer = typename _Ptr<_Tp, _Dp>::type; __uniq_ptr_impl() = default; @@ -152,6 +156,10 @@ _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; + __uniq_ptr_impl<_Tp, _Dp> _M_t; public: @@ -175,10 +183,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Constructors. /// Default constructor, creates a unique_ptr that owns nothing. - constexpr unique_ptr() noexcept - : _M_t() - { static_assert(!is_pointer<deleter_type>::value, - "constructed with null function pointer deleter"); } + template <typename _Up = _Dp, + typename = typename _DeleterConstraint<_Up>::type> + constexpr unique_ptr() noexcept + : _M_t() + { } /** Takes ownership of a pointer. * @@ -186,11 +195,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * * The deleter will be value-initialized. */ - explicit - unique_ptr(pointer __p) noexcept - : _M_t(__p) - { static_assert(!is_pointer<deleter_type>::value, - "constructed with null function pointer deleter"); } + template <typename _Up = _Dp, + typename = typename _DeleterConstraint<_Up>::type> + explicit + unique_ptr(pointer __p) noexcept + : _M_t(__p) + { } /** Takes ownership of a pointer. * @@ -218,7 +228,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION "rvalue deleter bound to reference"); } /// Creates a unique_ptr that owns nothing. - constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { } + template <typename _Up = _Dp, + typename = typename _DeleterConstraint<_Up>::type> + constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { } // Move constructors. @@ -384,6 +396,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Dp> class unique_ptr<_Tp[], _Dp> { + template <typename _Up> + using _DeleterConstraint = + typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint; + __uniq_ptr_impl<_Tp, _Dp> _M_t; template<typename _Up> @@ -432,10 +448,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Constructors. /// Default constructor, creates a unique_ptr that owns nothing. - constexpr unique_ptr() noexcept - : _M_t() - { static_assert(!std::is_pointer<deleter_type>::value, - "constructed with null function pointer deleter"); } + template <typename _Up = _Dp, + typename = typename _DeleterConstraint<_Up>::type> + constexpr unique_ptr() noexcept + : _M_t() + { } /** Takes ownership of a pointer. * @@ -445,13 +462,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * The deleter will be value-initialized. */ template<typename _Up, - typename = typename enable_if< + typename _Vp = _Dp, + typename = typename _DeleterConstraint<_Vp>::type, + typename = typename enable_if< __safe_conversion_raw<_Up>::value, bool>::type> - explicit - unique_ptr(_Up __p) noexcept - : _M_t(__p) - { static_assert(!is_pointer<deleter_type>::value, - "constructed with null function pointer deleter"); } + explicit + unique_ptr(_Up __p) noexcept + : _M_t(__p) + { } /** Takes ownership of a pointer. * @@ -491,7 +509,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _M_t(__u.release(), std::forward<deleter_type>(__u.get_deleter())) { } /// Creates a unique_ptr that owns nothing. - constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { } + template <typename _Up = _Dp, + typename = typename _DeleterConstraint<_Up>::type> + constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { } template<typename _Up, typename _Ep, typename = _Require<__safe_conversion_up<_Up, _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 e9655f1..00f1778 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 *-*-* } 289 } +// { dg-error "no type" "" { target *-*-* } 301 } 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 *-*-* } 540 } +// { dg-error "no type" "" { target *-*-* } 560 } } 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 3e6f41b..406be1a 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 *-*-* } 448 } + // { dg-error "no type" "" { target *-*-* } 467 } } template<typename T> diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/default.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/default.cc new file mode 100644 index 0000000..ceffdcd --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/default.cc @@ -0,0 +1,40 @@ +// { dg-do compile { target c++11 } } + +// 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/>. + +#include <memory> +#include <type_traits> + +static_assert(!std::is_default_constructible<std::unique_ptr<int, + std::default_delete<int>&>>::value, ""); +static_assert(!std::is_default_constructible<std::unique_ptr<int, + void(*)(int*)>>::value, ""); +static_assert(!std::is_constructible<std::unique_ptr<int, + std::default_delete<int>&>, int*>::value, ""); +static_assert(!std::is_constructible<std::unique_ptr<int, + void(*)(int*)>, int*>::value, ""); + +static_assert(!std::is_default_constructible<std::unique_ptr<int[], + std::default_delete<int>&>>::value, ""); +static_assert(!std::is_default_constructible<std::unique_ptr<int[], + void(*)(int*)>>::value, ""); +static_assert(!std::is_constructible<std::unique_ptr<int[], + std::default_delete<int>&>, int*>::value, ""); +static_assert(!std::is_constructible<std::unique_ptr<int[], + void(*)(int*)>, int*>::value, ""); + diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/ptr_deleter_neg.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/ptr_deleter_neg.cc index 1aa8d43..6196b92 100644 --- a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/ptr_deleter_neg.cc +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/ptr_deleter_neg.cc @@ -23,26 +23,31 @@ using std::unique_ptr; -// { dg-prune-output "static assertion failed" } +// { dg-error "no type" "" { target *-*-* } 187 } +// { dg-error "no type" "" { target *-*-* } 199 } +// { dg-error "no type" "" { target *-*-* } 232 } +// { dg-error "no type" "" { target *-*-* } 452 } +// { dg-error "no type" "" { target *-*-* } 466 } +// { dg-error "no type" "" { target *-*-* } 513 } void test01() { - unique_ptr<long, void(*)(long*)> p1; // { dg-error "here" } + unique_ptr<long, void(*)(long*)> p1; // { dg-error "no matching" } - unique_ptr<short, void(*)(short*)> p2(nullptr); // { dg-error "here" } + unique_ptr<short, void(*)(short*)> p2(nullptr); // { dg-error "no matching" } - unique_ptr<int, void(*)(int*)> p3(new int); // { dg-error "here" } + unique_ptr<int, void(*)(int*)> p3(new int); // { dg-error "no matching" } } void test02() { - unique_ptr<long[], void(*)(long*)> p1; // { dg-error "here" } + unique_ptr<long[], void(*)(long*)> p1; // { dg-error "no matching" } - unique_ptr<short[], void(*)(short*)> p2(nullptr); // { dg-error "here" } + unique_ptr<short[], void(*)(short*)> p2(nullptr); // { dg-error "no matching" } - unique_ptr<int[], void(*)(int*)> p3(new int[1]); // { dg-error "here" } + unique_ptr<int[], void(*)(int*)> p3(new int[1]); // { dg-error "no matching" } }