[v3 PATCH] Implement 2801, Default-constructibility of unique_ptr.

Ville Voutilainen ville.voutilainen@gmail.com
Thu Dec 29 20:10:00 GMT 2016


On 29 December 2016 at 21:57, Ville Voutilainen
<ville.voutilainen@gmail.com> wrote:
>> 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.


Gets a bit better by keeping the __uniq_ptr_impl as just an enable_if,
aliasing its ::type locally
and then using the result in the constraints. Also gets rid of a bunch
of dg-errors in
ptr_deleter_neg.cc. This makes me quite happy. The attached _3.diff
shows the cleanup,
the _4.diff shows the full patch with this cleanup applied.
-------------- next part --------------
diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h
index f994c59..211043f 100644
--- a/libstdc++-v3/include/bits/unique_ptr.h
+++ b/libstdc++-v3/include/bits/unique_ptr.h
@@ -158,7 +158,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       template <class _Up>
       using _DeleterConstraint =
-	typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint;
+	typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;
 
       __uniq_ptr_impl<_Tp, _Dp> _M_t;
 
@@ -184,7 +184,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       /// Default constructor, creates a unique_ptr that owns nothing.
       template <typename _Up = _Dp,
-		typename = typename _DeleterConstraint<_Up>::type>
+		typename = _DeleterConstraint<_Up>>
 	constexpr unique_ptr() noexcept
 	: _M_t()
         { }
@@ -196,7 +196,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        * The deleter will be value-initialized.
        */
       template <typename _Up = _Dp,
-		typename = typename _DeleterConstraint<_Up>::type>
+		typename = _DeleterConstraint<_Up>>
 	explicit
 	unique_ptr(pointer __p) noexcept
 	: _M_t(__p)
@@ -229,7 +229,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       /// Creates a unique_ptr that owns nothing.
       template <typename _Up = _Dp,
-		typename = typename _DeleterConstraint<_Up>::type>
+		typename = _DeleterConstraint<_Up>>
 	constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { }
 
       // Move constructors.
@@ -398,7 +398,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       template <typename _Up>
       using _DeleterConstraint =
-	typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint;
+	typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;
 
       __uniq_ptr_impl<_Tp, _Dp> _M_t;
 
@@ -449,7 +449,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       /// Default constructor, creates a unique_ptr that owns nothing.
       template <typename _Up = _Dp,
-		typename = typename _DeleterConstraint<_Up>::type>
+		typename = _DeleterConstraint<_Up>>
 	constexpr unique_ptr() noexcept
 	: _M_t()
         { }
@@ -463,7 +463,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        */
       template<typename _Up,
 	       typename _Vp = _Dp,
-	       typename = typename _DeleterConstraint<_Vp>::type,
+	       typename = _DeleterConstraint<_Vp>,
 	       typename = typename enable_if<
                  __safe_conversion_raw<_Up>::value, bool>::type>
 	explicit
@@ -510,7 +510,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       /// Creates a unique_ptr that owns nothing.
       template <typename _Up = _Dp,
-		typename = typename _DeleterConstraint<_Up>::type>
+		typename = _DeleterConstraint<_Up>>
 	constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { }
 
       template<typename _Up, typename _Ep,
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 6196b92..d0af6b3 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,13 +23,6 @@
 
 using std::unique_ptr;
 
-// { 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()
 {
-------------- next part --------------
diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h
index 56e6ec0..211043f 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::type;
+
       __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 = _DeleterConstraint<_Up>>
+	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 = _DeleterConstraint<_Up>>
+	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 = _DeleterConstraint<_Up>>
+	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::type;
+
       __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 = _DeleterConstraint<_Up>>
+	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 = _DeleterConstraint<_Vp>,
+	       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 = _DeleterConstraint<_Up>>
+	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..d0af6b3 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,24 @@
 
 using std::unique_ptr;
 
-// { dg-prune-output "static assertion failed" }
-
 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" }
 }
 
 


More information about the Libstdc++ mailing list