diff mbox

std::unique_ptr<T[], D> improvements

Message ID CAH6eHdQCP8DLv35YtXr-QpMtkWUe+p6ryL0h4PwBZa2K0q+NEg@mail.gmail.com
State New
Headers show

Commit Message

Jonathan Wakely Dec. 20, 2012, 9:14 p.m. UTC
This patch started when I noticed that it's not possibly to construct
a shared_ptr<T> from unique_ptr<T[], D>, then I discovered we don't
use D::pointer if it exists, and there were a number of other
non-conformance issues with our std::unique_ptr<T[], D>.  I ended up
fixing them by implementing Geoffrey's proposed resolution for LWG
issue 2118, which isn't official yet but is better than what we had
before so is a step in the right direction, even if it ends up needing
further revision when 2118 is resolved.

        * include/std/functional (_Require): Move to ...
        * include/std/type_traits (_Require): ... here.
        * include/bits/shared_ptr_base.h (__shared_count::_S_create_from_up):
        Handle unique_ptr for arrays or with custom pointer types.
        (__shared_ptr::__shared_ptr(unique_ptr<_Tp1, _Del>&&): Likewise.
        * include/bits/unique_ptr.h (unique_ptr<_Tp[], _Dp>): Use
        _Dp::pointer if defined. Implement proposed resolution of LWG 2118.
        * testsuite/20_util/shared_ptr/cons/unique_ptr_array.cc: New.
        * testsuite/20_util/unique_ptr/assign/cv_qual.cc: New.
        * testsuite/20_util/unique_ptr/cons/array_convertible_neg.cc: New.
        * testsuite/20_util/unique_ptr/cons/convertible_neg.cc: New.
        * testsuite/20_util/unique_ptr/cons/cv_qual.cc: New.
        * testsuite/20_util/unique_ptr/modifiers/cv_qual.cc: New.
        * testsuite/20_util/unique_ptr/requirements/pointer_type_array.cc: New.
        * testsuite/20_util/shared_ptr/cons/unique_ptr.cc: Adjust comments.
        * testsuite/20_util/unique_ptr/cons/pointer_array_convertible_neg.cc:
        Likewise.
        * testsuite/20_util/unique_ptr/requirements/pointer_type.cc: Likewise.
        * testsuite/20_util/bind/ref_neg.cc: Adjust dg-error line number.
        * testsuite/20_util/declval/requirements/1_neg.cc: Likewise.
        * testsuite/20_util/default_delete/48631_neg.cc: Likewise.
        * testsuite/20_util/shared_ptr/cons/43820_neg.cc: Likewise.
        * testsuite/20_util/unique_ptr/assign/48635_neg.cc: Likewise.
        * testsuite/20_util/unique_ptr/modifiers/reset_neg.cc: Adjust
        dg-error text.
        * testsuite/20_util/unique_ptr/cons/ptr_deleter_neg.cc: Use
        different instantiations so static_assert fails for each.

Thanks to Geoffrey and Lawrence for input and test cases.

Tested x86_64-linux, committed to trunk.
commit 907290c8077e6757c56fc64c9160c4bdaea86b90
Author: Jonathan Wakely <jwakely.gcc@gmail.com>
Date:   Thu Dec 20 17:57:33 2012 +0000

    	* include/std/functional (_Require): Move to ...
    	* include/std/type_traits (_Require): ... here.
    	* include/bits/shared_ptr_base.h (__shared_count::_S_create_from_up):
    	Handle unique_ptr for arrays or with custom pointer types.
    	(__shared_ptr::__shared_ptr(unique_ptr<_Tp1, _Del>&&): Likewise.
    	* include/bits/unique_ptr.h (unique_ptr<_Tp[], _Dp>): Use
    	_Dp::pointer if defined. Implement proposed resolution of LWG 2118.
    	* testsuite/20_util/shared_ptr/cons/unique_ptr_array.cc: New.
    	* testsuite/20_util/unique_ptr/assign/cv_qual.cc: New.
    	* testsuite/20_util/unique_ptr/cons/array_convertible_neg.cc: New.
    	* testsuite/20_util/unique_ptr/cons/convertible_neg.cc: New.
    	* testsuite/20_util/unique_ptr/cons/cv_qual.cc: New.
    	* testsuite/20_util/unique_ptr/modifiers/cv_qual.cc: New.
    	* testsuite/20_util/unique_ptr/requirements/pointer_type_array.cc: New.
    	* testsuite/20_util/shared_ptr/cons/unique_ptr.cc: Adjust comments.
    	* testsuite/20_util/unique_ptr/cons/pointer_array_convertible_neg.cc:
    	Likewise.
    	* testsuite/20_util/unique_ptr/requirements/pointer_type.cc: Likewise.
    	* testsuite/20_util/bind/ref_neg.cc: Adjust dg-error line number.
    	* testsuite/20_util/declval/requirements/1_neg.cc: Likewise.
    	* testsuite/20_util/default_delete/48631_neg.cc: Likewise.
    	* testsuite/20_util/shared_ptr/cons/43820_neg.cc: Likewise.
    	* testsuite/20_util/unique_ptr/assign/48635_neg.cc: Likewise.
    	* testsuite/20_util/unique_ptr/modifiers/reset_neg.cc: Adjust
    	dg-error text.
    	* testsuite/20_util/unique_ptr/cons/ptr_deleter_neg.cc: Use
    	different instantiations so static_assert fails for each.

Comments

Lawrence Crowl Dec. 28, 2012, 1:51 a.m. UTC | #1
On 12/20/12, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> This patch started when I noticed that it's not possibly to construct
> a shared_ptr<T> from unique_ptr<T[], D>, then I discovered we don't
> use D::pointer if it exists, and there were a number of other
> non-conformance issues with our std::unique_ptr<T[], D>.  I ended up
> fixing them by implementing Geoffrey's proposed resolution for LWG
> issue 2118, which isn't official yet but is better than what we had
> before so is a step in the right direction, even if it ends up needing
> further revision when 2118 is resolved.
>
>         * include/std/functional (_Require): Move to ...
>         * include/std/type_traits (_Require): ... here.
>         * include/bits/shared_ptr_base.h
> (__shared_count::_S_create_from_up):
>         Handle unique_ptr for arrays or with custom pointer types.
>         (__shared_ptr::__shared_ptr(unique_ptr<_Tp1, _Del>&&): Likewise.
>         * include/bits/unique_ptr.h (unique_ptr<_Tp[], _Dp>): Use
>         _Dp::pointer if defined. Implement proposed resolution of LWG 2118.
>         * testsuite/20_util/shared_ptr/cons/unique_ptr_array.cc: New.
>         * testsuite/20_util/unique_ptr/assign/cv_qual.cc: New.
>         * testsuite/20_util/unique_ptr/cons/array_convertible_neg.cc: New.
>         * testsuite/20_util/unique_ptr/cons/convertible_neg.cc: New.
>         * testsuite/20_util/unique_ptr/cons/cv_qual.cc: New.
>         * testsuite/20_util/unique_ptr/modifiers/cv_qual.cc: New.
>         * testsuite/20_util/unique_ptr/requirements/pointer_type_array.cc:
> New.
>         * testsuite/20_util/shared_ptr/cons/unique_ptr.cc: Adjust comments.
>         *
> testsuite/20_util/unique_ptr/cons/pointer_array_convertible_neg.cc:
>         Likewise.
>         * testsuite/20_util/unique_ptr/requirements/pointer_type.cc:
> Likewise.
>         * testsuite/20_util/bind/ref_neg.cc: Adjust dg-error line number.
>         * testsuite/20_util/declval/requirements/1_neg.cc: Likewise.
>         * testsuite/20_util/default_delete/48631_neg.cc: Likewise.
>         * testsuite/20_util/shared_ptr/cons/43820_neg.cc: Likewise.
>         * testsuite/20_util/unique_ptr/assign/48635_neg.cc: Likewise.
>         * testsuite/20_util/unique_ptr/modifiers/reset_neg.cc: Adjust
>         dg-error text.
>         * testsuite/20_util/unique_ptr/cons/ptr_deleter_neg.cc: Use
>         different instantiations so static_assert fails for each.
>
> Thanks to Geoffrey and Lawrence for input and test cases.
>
> Tested x86_64-linux, committed to trunk.

I'm not getting errors when converting from derived to base.
E.g. the following compiles, when it should not.

std::unique_ptr<const base []> acb_ad(new derived[3]);
Jonathan Wakely Dec. 28, 2012, 2:53 p.m. UTC | #2
On 28 December 2012 01:51, Lawrence Crowl wrote:
>
> I'm not getting errors when converting from derived to base.
> E.g. the following compiles, when it should not.
>
> std::unique_ptr<const base []> acb_ad(new derived[3]);

I get an error:

shm$ cat up.cc
#include <memory>
struct base { };
struct derived : base { virtual ~derived() = default; };
std::unique_ptr<const base []> acb_ad(new derived[3]);
shm$
shm$ g++11 up.cc -c
up.cc:4:53: error: use of deleted function ‘std::unique_ptr<_Tp [],
_Dp>::unique_ptr(_Up*) [with _Up = derived; <template-parameter-2-2> =
void; _Tp = const base; _Dp = std::default_delete<const base []>]’
 std::unique_ptr<const base []> acb_ad(new derived[3]);
                                                     ^
In file included from /home/redi/gcc/4.x/include/c++/4.8.0/memory:81:0,
                 from up.cc:1:
/home/redi/gcc/4.x/include/c++/4.8.0/bits/unique_ptr.h:343:2: error:
declared here
  unique_ptr(_Up* __p) = delete;
  ^
Lawrence Crowl Jan. 1, 2013, 8:40 p.m. UTC | #3
On 12/28/12, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> On 28 December 2012 01:51, Lawrence Crowl wrote:
>> I'm not getting errors when converting from derived to base.
>> E.g. the following compiles, when it should not.
>>
>> std::unique_ptr<const base []> acb_ad(new derived[3]);
>
> I get an error:
>
> shm$ cat up.cc
> #include <memory>
> struct base { };
> struct derived : base { virtual ~derived() = default; };
> std::unique_ptr<const base []> acb_ad(new derived[3]);
> shm$
> shm$ g++11 up.cc -c
> up.cc:4:53: error: use of deleted function ‘std::unique_ptr<_Tp [],
> _Dp>::unique_ptr(_Up*) [with _Up = derived; <template-parameter-2-2> =
> void; _Tp = const base; _Dp = std::default_delete<const base []>]’
>  std::unique_ptr<const base []> acb_ad(new derived[3]);
>                                                      ^
> In file included from /home/redi/gcc/4.x/include/c++/4.8.0/memory:81:0,
>                  from up.cc:1:
> /home/redi/gcc/4.x/include/c++/4.8.0/bits/unique_ptr.h:343:2: error:
> declared here
>   unique_ptr(_Up* __p) = delete;
>   ^

That was pilot error on my part.  However, I've been having trouble
when the argument to the constructor or reset has a conversion
operator.  The code does distinquish between a safe conversion to
base and an unsafe conversion to derived.

Here is a simplified version of the problem.  The code as is fails
to reject the last two calls to accept.  The primary reason is that
is_convertable permits both the invocation of the conversion operator
and the derived to base conversion.  At present, I see no way to
get a handle on the 'natural' return type of the conversion operator.

#include <type_traits>

struct base { };
struct derived : base { };

template <typename T, typename F>
typename std::enable_if<
                std::is_convertible< F, T* >::value,
                T*
        >::type
accept(F arg) { return arg; }

template <typename T, typename F>
typename std::enable_if<
                !std::is_convertible< F(*)[], T(*)[] >::value,
                T*
        >::type
accept(F* arg) = delete;

struct cvt_b {
  operator base*() { return 0; }
};

struct cvt_d {
  operator derived*() { return 0; }
};

int main()
{
  // should PASS
  accept< base >( (base*)0 );
  accept< const base >( (base*)0 );
  accept< base >( cvt_b() );
  accept< const base >( cvt_b() );
  // should FAIL
  accept< base >( (derived*)0 );
  accept< const base >( (derived*)0 );
  accept< base >( cvt_d() );
  accept< const base >( cvt_d() );
}
Jonathan Wakely Jan. 1, 2013, 9:27 p.m. UTC | #4
On 1 January 2013 20:40, Lawrence Crowl wrote:
>
> That was pilot error on my part.  However, I've been having trouble
> when the argument to the constructor or reset has a conversion
> operator.  The code does distinquish between a safe conversion to
> base and an unsafe conversion to derived.
>
> Here is a simplified version of the problem.  The code as is fails
> to reject the last two calls to accept.  The primary reason is that
> is_convertable permits both the invocation of the conversion operator
> and the derived to base conversion.  At present, I see no way to
> get a handle on the 'natural' return type of the conversion operator.

Is the issue here that Geoffrey's proposed resolution allows any
conversions (safe or not) if the source type is not a built-in
pointer, i.e. is some user-defined type?  So a user-defined type that
refers an array of derived classes is allowed to be converted to an
array of base, even though that's not safe.  Howard has strongly
objected to this part of the P/R.
Lawrence Crowl Jan. 1, 2013, 9:35 p.m. UTC | #5
On 1/1/13, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> On 1 January 2013 20:40, Lawrence Crowl wrote:
>> That was pilot error on my part.  However, I've been having trouble
>> when the argument to the constructor or reset has a conversion
>> operator.  The code does distinquish between a safe conversion to
>> base and an unsafe conversion to derived.
>>
>> Here is a simplified version of the problem.  The code as is fails
>> to reject the last two calls to accept.  The primary reason is that
>> is_convertable permits both the invocation of the conversion operator
>> and the derived to base conversion.  At present, I see no way to
>> get a handle on the 'natural' return type of the conversion operator.
>
> Is the issue here that Geoffrey's proposed resolution allows any
> conversions (safe or not) if the source type is not a built-in
> pointer, i.e. is some user-defined type?  So a user-defined type that
> refers an array of derived classes is allowed to be converted to an
> array of base, even though that's not safe.  Howard has strongly
> objected to this part of the P/R.

Yes.  I see no way to distinguish between objects with safe conversion
operators and unsafe conversion operators.
Lawrence Crowl Jan. 4, 2013, 12:08 a.m. UTC | #6
On 1/1/13, Geoffrey Romer <gromer@google.com> wrote:
> AFAICT there's no way to distinguish between safe and unsafe
> conversions of user-defined pointers, because that's a property
> of the pointer implementation, not the type itself. My PR errs on
> the side of trusting the implementation to provide only correct
> conversions. As Jonathan notes, Howard has objected to that part
> of the PR, so it's possible the eventual resolution will differ
> in that respect; I intend to pick up that discussion next week
> when I'm back from vacation.

BTW, I've attached my latest set of tests.
diff mbox

Patch

diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h
index ead3728..9d9fecb 100644
--- a/libstdc++-v3/include/bits/shared_ptr_base.h
+++ b/libstdc++-v3/include/bits/shared_ptr_base.h
@@ -616,7 +616,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	_S_create_from_up(std::unique_ptr<_Tp, _Del>&& __r,
 	  typename std::enable_if<!std::is_reference<_Del>::value>::type* = 0)
 	{
-	  return new _Sp_counted_deleter<_Tp*, _Del, std::allocator<void>,
+	  typedef typename unique_ptr<_Tp, _Del>::pointer _Ptr;
+	  return new _Sp_counted_deleter<_Ptr, _Del, std::allocator<void>,
 	    _Lp>(__r.get(), __r.get_deleter());
 	}
 
@@ -625,9 +626,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	_S_create_from_up(std::unique_ptr<_Tp, _Del>&& __r,
 	  typename std::enable_if<std::is_reference<_Del>::value>::type* = 0)
 	{
+	  typedef typename unique_ptr<_Tp, _Del>::pointer _Ptr;
 	  typedef typename std::remove_reference<_Del>::type _Del1;
 	  typedef std::reference_wrapper<_Del1> _Del2;
-	  return new _Sp_counted_deleter<_Tp*, _Del2, std::allocator<void>,
+	  return new _Sp_counted_deleter<_Ptr, _Del2, std::allocator<void>,
 	    _Lp>(__r.get(), std::ref(__r.get_deleter()));
 	}
 
@@ -846,7 +848,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	: _M_ptr(__r.get()), _M_refcount()
 	{
 	  __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
-	  _Tp1* __tmp = __r.get();
+	  auto __tmp = std::__addressof(*__r.get());
 	  _M_refcount = __shared_count<_Lp>(std::move(__r));
 	  __enable_shared_from_this_helper(_M_refcount, __tmp, __tmp);
 	}
diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h
index 37eae25..e17a4dc 100644
--- a/libstdc++-v3/include/bits/unique_ptr.h
+++ b/libstdc++-v3/include/bits/unique_ptr.h
@@ -56,7 +56,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr default_delete() noexcept = default;
 
       template<typename _Up, typename = typename
-	       std::enable_if<std::is_convertible<_Up*, _Tp*>::value>::type>
+	       enable_if<is_convertible<_Up*, _Tp*>::value>::type>
         default_delete(const default_delete<_Up>&) noexcept { }
 
       void
@@ -74,8 +74,23 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct default_delete<_Tp[]>
     {
+    private:
+      template<typename _Up>
+	using __remove_cv = typename remove_cv<_Up>::type;
+
+      // Like is_base_of<_Tp, _Up> but false if unqualified types are the same
+      template<typename _Up>
+	using __is_derived_Tp
+	  = __and_< is_base_of<_Tp, _Up>,
+		    __not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >;
+
+    public:
       constexpr default_delete() noexcept = default;
 
+      template<typename _Up, typename = typename
+	       enable_if<!__is_derived_Tp<_Up>::value>::type>
+        default_delete(const default_delete<_Up[]>&) noexcept { }
+
       void
       operator()(_Tp* __ptr) const
       {
@@ -84,7 +99,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	delete [] __ptr;
       }
 
-      template<typename _Up> void operator()(_Up*) const = delete;
+      template<typename _Up>
+	typename enable_if<__is_derived_Tp<_Up>::value>::type
+	operator()(_Up*) const = delete;
     };
 
   /// 20.7.1.2 unique_ptr for single objects.
@@ -103,7 +120,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	typedef typename remove_reference<_Dp>::type _Del;
 
       public:
-	typedef decltype( __test<_Del>(0)) type;
+	typedef decltype(__test<_Del>(0)) type;
       };
 
       typedef std::tuple<typename _Pointer::type, _Dp>  __tuple_type;
@@ -117,54 +134,45 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // Constructors.
       constexpr unique_ptr() noexcept
       : _M_t()
-      { static_assert(!std::is_pointer<deleter_type>::value,
+      { static_assert(!is_pointer<deleter_type>::value,
 		     "constructed with null function pointer deleter"); }
 
       explicit
       unique_ptr(pointer __p) noexcept
       : _M_t(__p, deleter_type())
-      { static_assert(!std::is_pointer<deleter_type>::value,
+      { static_assert(!is_pointer<deleter_type>::value,
 		     "constructed with null function pointer deleter"); }
 
       unique_ptr(pointer __p,
-	  typename std::conditional<std::is_reference<deleter_type>::value,
+	  typename conditional<is_reference<deleter_type>::value,
 	    deleter_type, const deleter_type&>::type __d) noexcept
       : _M_t(__p, __d) { }
 
       unique_ptr(pointer __p,
-	  typename std::remove_reference<deleter_type>::type&& __d) noexcept
+	  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"); }
 
-      constexpr unique_ptr(nullptr_t) noexcept
-      : _M_t()
-      { static_assert(!std::is_pointer<deleter_type>::value,
-		     "constructed with null function pointer deleter"); }
+      constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { }
 
       // Move constructors.
       unique_ptr(unique_ptr&& __u) noexcept
       : _M_t(__u.release(), std::forward<deleter_type>(__u.get_deleter())) { }
 
-      template<typename _Up, typename _Ep, typename = typename
-	std::enable_if
-	  <std::is_convertible<typename unique_ptr<_Up, _Ep>::pointer,
-			       pointer>::value
-	   && !std::is_array<_Up>::value
-	   && ((std::is_reference<_Dp>::value
-		&& std::is_same<_Ep, _Dp>::value)
-	       || (!std::is_reference<_Dp>::value
-		   && std::is_convertible<_Ep, _Dp>::value))>
-	     ::type>
+      template<typename _Up, typename _Ep, typename = _Require<
+	       is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>,
+	       __not_<is_array<_Up>>,
+	       typename conditional<is_reference<_Dp>::value,
+				    is_same<_Ep, _Dp>,
+				    is_convertible<_Ep, _Dp>>::type>>
 	unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
 	: _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
 	{ }
 
 #if _GLIBCXX_USE_DEPRECATED
-      template<typename _Up, typename = typename
-	std::enable_if<std::is_convertible<_Up*, _Tp*>::value
-		       && std::is_same<_Dp,
-				       default_delete<_Tp>>::value>::type>
+      template<typename _Up, typename = _Require<
+	       is_convertible<_Up*, _Tp*>, is_same<_Dp, default_delete<_Tp>>>>
 	unique_ptr(auto_ptr<_Up>&& __u) noexcept;
 #endif
 
@@ -186,12 +194,12 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return *this;
       }
 
-      template<typename _Up, typename _Ep, typename = typename
-	std::enable_if
-	  <std::is_convertible<typename unique_ptr<_Up, _Ep>::pointer,
-			       pointer>::value
-	   && !std::is_array<_Up>::value>::type>
-	unique_ptr&
+      template<typename _Up, typename _Ep>
+	typename enable_if< __and_<
+	  is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>,
+	  __not_<is_array<_Up>>
+	  >::value,
+	  unique_ptr&>::type
 	operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
 	{
 	  reset(__u.release());
@@ -207,7 +215,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
       // Observers.
-      typename std::add_lvalue_reference<element_type>::type
+      typename add_lvalue_reference<element_type>::type
       operator*() const
       {
 	_GLIBCXX_DEBUG_ASSERT(get() != pointer());
@@ -273,11 +281,47 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp, typename _Dp>
     class unique_ptr<_Tp[], _Dp>
     {
-      typedef std::tuple<_Tp*, _Dp>  	__tuple_type;
-      __tuple_type 			_M_t;
+      // use SFINAE to determine whether _Del::pointer exists
+      class _Pointer
+      {
+	template<typename _Up>
+	  static typename _Up::pointer __test(typename _Up::pointer*);
+
+	template<typename _Up>
+	  static _Tp* __test(...);
+
+	typedef typename remove_reference<_Dp>::type _Del;
+
+      public:
+	typedef decltype(__test<_Del>(0)) type;
+      };
+
+      typedef std::tuple<typename _Pointer::type, _Dp>  __tuple_type;
+      __tuple_type                                      _M_t;
+
+      template<typename _Up>
+	using __remove_cv = typename remove_cv<_Up>::type;
+
+      // like is_base_of<_Tp, _Up> but false if unqualified types are the same
+      template<typename _Up>
+	using __is_derived_Tp
+	  = __and_< is_base_of<_Tp, _Up>,
+		    __not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >;
+
+      template<typename _Up, typename _Ep,
+	       typename _Tp_pointer = typename _Pointer::type,
+	       typename _Up_pointer = typename unique_ptr<_Up, _Ep>::pointer>
+	using __safe_conversion = __and_<
+	    is_convertible<_Up_pointer, _Tp_pointer>,
+	    is_array<_Up>,
+	    __or_<__not_<is_pointer<_Up_pointer>>,
+		  __not_<is_pointer<_Tp_pointer>>,
+		  __not_<__is_derived_Tp<typename remove_extent<_Up>::type>>
+	    >
+	  >;
 
     public:
-      typedef _Tp*		 	pointer;
+      typedef typename _Pointer::type	pointer;
       typedef _Tp		 	element_type;
       typedef _Dp                       deleter_type;
 
@@ -285,35 +329,42 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr unique_ptr() noexcept
       : _M_t()
       { static_assert(!std::is_pointer<deleter_type>::value,
-		     "constructed with null function pointer deleter"); }
+		      "constructed with null function pointer deleter"); }
 
       explicit
       unique_ptr(pointer __p) noexcept
       : _M_t(__p, deleter_type())
-      { static_assert(!std::is_pointer<deleter_type>::value,
-		     "constructed with null function pointer deleter"); }
+      { static_assert(!is_pointer<deleter_type>::value,
+		      "constructed with null function pointer deleter"); }
+
+      template<typename _Up, typename = _Require<is_pointer<pointer>,
+	       is_convertible<_Up*, pointer>, __is_derived_Tp<_Up>>>
+	explicit
+	unique_ptr(_Up* __p) = delete;
 
       unique_ptr(pointer __p,
-	  typename std::conditional<std::is_reference<deleter_type>::value,
+	  typename conditional<is_reference<deleter_type>::value,
 	      deleter_type, const deleter_type&>::type __d) noexcept
       : _M_t(__p, __d) { }
 
       unique_ptr(pointer __p, typename
-		 std::remove_reference<deleter_type>::type && __d) noexcept
+		 remove_reference<deleter_type>::type&& __d) noexcept
       : _M_t(std::move(__p), std::move(__d))
-      { static_assert(!std::is_reference<deleter_type>::value,
+      { static_assert(!is_reference<deleter_type>::value,
 		      "rvalue deleter bound to reference"); }
 
-      constexpr unique_ptr(nullptr_t) noexcept
-      : _M_t()
-      { static_assert(!std::is_pointer<deleter_type>::value,
-		     "constructed with null function pointer deleter"); }
-
-      // Move constructors.
+      // Move constructor.
       unique_ptr(unique_ptr&& __u) noexcept
       : _M_t(__u.release(), std::forward<deleter_type>(__u.get_deleter())) { }
 
-      template<typename _Up, typename _Ep>
+      constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { }
+
+      template<typename _Up, typename _Ep,
+	       typename = _Require<__safe_conversion<_Up, _Ep>,
+		 typename conditional<is_reference<_Dp>::value,
+				      is_same<_Ep, _Dp>,
+				      is_convertible<_Ep, _Dp>>::type
+	       >>
 	unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
 	: _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
 	{ }
@@ -337,7 +388,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
       template<typename _Up, typename _Ep>
-	unique_ptr&
+	typename
+	enable_if<__safe_conversion<_Up, _Ep>::value, unique_ptr&>::type
 	operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
 	{
 	  reset(__u.release());
@@ -385,26 +437,21 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
       void
-      reset(pointer __p = pointer()) noexcept
-      {
-	using std::swap;
-	swap(std::get<0>(_M_t), __p);
-	if (__p != nullptr)
-	  get_deleter()(__p);
-      }
+      reset() noexcept
+      { reset(pointer()); }
 
       void
-      reset(nullptr_t) noexcept
+      reset(pointer __p) noexcept
       {
-	pointer __p = get();
-	std::get<0>(_M_t) = pointer();
+	using std::swap;
+	swap(std::get<0>(_M_t), __p);
 	if (__p != nullptr)
 	  get_deleter()(__p);
       }
 
-      // DR 821.
-      template<typename _Up>
-	void reset(_Up) = delete;
+      template<typename _Up, typename = _Require<is_pointer<pointer>,
+	       is_convertible<_Up*, pointer>, __is_derived_Tp<_Up>>>
+	void reset(_Up*) = delete;
 
       void
       swap(unique_ptr& __u) noexcept
@@ -418,23 +465,16 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       unique_ptr& operator=(const unique_ptr&) = delete;
 
       // Disable construction from convertible pointer types.
-      // (N2315 - 20.7.1.3.1)
-      template<typename _Up>
+      template<typename _Up, typename = _Require<is_pointer<pointer>,
+	       is_convertible<_Up*, pointer>, __is_derived_Tp<_Up>>>
 	unique_ptr(_Up*, typename
-		   std::conditional<std::is_reference<deleter_type>::value,
-		   deleter_type, const deleter_type&>::type,
-		   typename std::enable_if<std::is_convertible<_Up*,
-		   pointer>::value>::type* = 0) = delete;
-
-      template<typename _Up>
-	unique_ptr(_Up*, typename std::remove_reference<deleter_type>::type&&,
-		   typename std::enable_if<std::is_convertible<_Up*,
-		   pointer>::value>::type* = 0) = delete;
+		   conditional<is_reference<deleter_type>::value,
+		   deleter_type, const deleter_type&>::type) = delete;
 
-      template<typename _Up>
-	explicit
-	unique_ptr(_Up*, typename std::enable_if<std::is_convertible<_Up*,
-		   pointer>::value>::type* = 0) = delete;
+      template<typename _Up, typename = _Require<is_pointer<pointer>,
+	       is_convertible<_Up*, pointer>, __is_derived_Tp<_Up>>>
+	unique_ptr(_Up*, typename
+		   remove_reference<deleter_type>::type&&) = delete;
     };
 
   template<typename _Tp, typename _Dp>
diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index 604481b..3ec2e1e 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -501,9 +501,6 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
 
   // @} group functors
 
-  template<typename... _Cond>
-    using _Require = typename enable_if<__and_<_Cond...>::value>::type;
-
   template<typename... _Types>
     struct _Pack : integral_constant<size_t, sizeof...(_Types)>
     { };
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cd7d728..e274727 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1771,6 +1771,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct enable_if<true, _Tp>
     { typedef _Tp type; };
 
+  template<typename... _Cond>
+    using _Require = typename enable_if<__and_<_Cond...>::value>::type;
 
   // Primary template.
   /// Define a member typedef @c type to one of two argument types.
diff --git a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc
index bae0a86..9854176 100644
--- a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc
@@ -30,10 +30,10 @@  void test01()
 {
   const int dummy = 0;
   std::bind(&inc, _1)(0);               // { dg-error  "no match" }
-  // { dg-error "rvalue|const" "" { target *-*-* } 1349 }
-  // { dg-error "rvalue|const" "" { target *-*-* } 1363 }
-  // { dg-error "rvalue|const" "" { target *-*-* } 1377 }
-  // { dg-error "rvalue|const" "" { target *-*-* } 1391 }
+  // { dg-error "rvalue|const" "" { target *-*-* } 1346 }
+  // { dg-error "rvalue|const" "" { target *-*-* } 1360 }
+  // { dg-error "rvalue|const" "" { target *-*-* } 1374 }
+  // { dg-error "rvalue|const" "" { target *-*-* } 1388 }
   std::bind(&inc, std::ref(dummy))();	// { dg-error  "no match" }
 }
 
diff --git a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
index 91d3553..015f39e 100644
--- a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
@@ -19,7 +19,7 @@ 
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { dg-error "static assertion failed" "" { target *-*-* } 1869 }
+// { dg-error "static assertion failed" "" { target *-*-* } 1871 }
 
 #include <utility>
 
diff --git a/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc b/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc
index a9bba97..fa2e3d1 100644
--- a/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc
@@ -27,4 +27,4 @@  struct D : B { };
 D d;
 std::default_delete<B[]> db;
 typedef decltype(db(&d)) type; // { dg-error "use of deleted function" }
-// { dg-error "declared here" "" { target *-*-* } 87 }
+// { dg-error "declared here" "" { target *-*-* } 104 }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc
index 179932f..380861c 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc
@@ -32,7 +32,7 @@  void test01()
 {
   X* px = 0;
   std::shared_ptr<X> p1(px);   // { dg-error "here" }
-  // { dg-error "incomplete" "" { target *-*-* } 769 }
+  // { dg-error "incomplete" "" { target *-*-* } 771 }
 
   std::shared_ptr<X> p9(ap());  // { dg-error "here" }
   // { dg-error "incomplete" "" { target *-*-* } 307 }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr.cc
index cfca90d..d6a25a0 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr.cc
@@ -1,6 +1,6 @@ 
-// { dg-options "-std=gnu++0x" }
+// { dg-options "-std=gnu++11" }
 
-// Copyright (C) 2008, 2009 Free Software Foundation
+// Copyright (C) 2008-2012 Free Software Foundation
 //
 // 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
@@ -17,14 +17,14 @@ 
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// 20.7.12.2 Template class shared_ptr [util.smartptr.shared]
+// 20.7.2.2 Class template shared_ptr [util.smartptr.shared]
 
 #include <memory>
 #include <testsuite_hooks.h>
 
 struct A { };
 
-// 20.7.12.2.1 shared_ptr constructors [util.smartptr.shared.const]
+// 20.7.2.2.1 shared_ptr constructors [util.smartptr.shared.const]
 
 // Construction from unique_ptr
 int
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr_array.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr_array.cc
new file mode 100644
index 0000000..dc07920
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr_array.cc
@@ -0,0 +1,59 @@ 
+// { dg-options "-std=gnu++11" }
+
+// Copyright (C) 2012 Free Software Foundation
+//
+// 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/>.
+
+// 20.7.2.2 Class template shared_ptr [util.smartptr.shared]
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+int destroyed = 0;
+
+struct A : std::enable_shared_from_this<A>
+{
+  ~A() { ++destroyed; }
+};
+
+// 20.7.2.2.1 shared_ptr constructors [util.smartptr.shared.const]
+
+// Construction from unique_ptr<A[]>
+int
+test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  std::unique_ptr<A[]> up(new A[2]);
+  std::shared_ptr<A> sp(std::move(up));
+  VERIFY( up.get() == 0 );
+  VERIFY( sp.get() != 0 );
+  VERIFY( sp.use_count() == 1 );
+
+  VERIFY( sp->shared_from_this() != nullptr );
+
+  sp.reset();
+  VERIFY( destroyed == 2 );
+
+  return 0;
+}
+
+int
+main()
+{
+  test01();
+  return 0;
+}
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 3a4f9b4..624c225 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
@@ -41,10 +41,10 @@  void f()
   std::unique_ptr<int, B&> ub(nullptr, b);
   std::unique_ptr<int, D&> ud(nullptr, d);
   ub = std::move(ud);
-// { dg-error "use of deleted function" "" { target *-*-* } 198 }
+// { dg-error "use of deleted function" "" { target *-*-* } 206 }
 
   std::unique_ptr<int[], B&> uba(nullptr, b);
   std::unique_ptr<int[], D&> uda(nullptr, d);
   uba = std::move(uda);
-// { dg-error "use of deleted function" "" { target *-*-* } 344 }
+// { dg-error "use of deleted function" "" { target *-*-* } 396 }
 }
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/cv_qual.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/cv_qual.cc
new file mode 100644
index 0000000..1b47a9f
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/cv_qual.cc
@@ -0,0 +1,89 @@ 
+// { dg-options "-std=gnu++11" }
+// { dg-do compile }
+
+// Copyright (C) 2012 Free Software Foundation
+//
+// 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/>.
+
+// 20.7.1 Class template unique_ptr [unique.ptr]
+
+#include <memory>
+
+struct A { virtual ~A() = default; };
+
+struct B : A { };
+
+// Assignment from objects with different cv-qualification
+
+void
+test01()
+{
+  std::unique_ptr<A> upA;
+
+  std::unique_ptr<const A> cA;
+  cA = std::move(upA);
+  std::unique_ptr<volatile A> vA;
+  vA = std::move(upA);
+  std::unique_ptr<const volatile A> cvA;
+  cvA = std::move(upA);
+}
+
+void
+test02()
+{
+  std::unique_ptr<B> upB;
+
+  std::unique_ptr<const A> cA;
+  cA = std::move(upB);
+  std::unique_ptr<volatile A> vA;
+  vA = std::move(upB);
+  std::unique_ptr<const volatile A> cvA;
+  cvA = std::move(upB);
+}
+
+void
+test03()
+{
+  std::unique_ptr<A[]> upA;
+
+  std::unique_ptr<const A[]> cA;
+  cA = std::move(upA);
+  std::unique_ptr<volatile A[]> vA;
+  vA = std::move(upA);
+  std::unique_ptr<const volatile A[]> cvA;
+  cvA = std::move(upA);
+}
+
+struct A_pointer { operator A*() const { return nullptr; } };
+
+template<typename T>
+struct deleter
+{
+  deleter() = default;
+  template<typename U>
+    deleter(const deleter<U>) { }
+  typedef T pointer;
+  void operator()(T) const { }
+};
+
+void
+test04()
+{
+  // Allow conversions from user-defined pointer-like types
+  std::unique_ptr<B[], deleter<A_pointer>> p;
+  std::unique_ptr<A[], deleter<A*>> upA;
+  upA = std::move(p);
+}
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/array_convertible_neg.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/array_convertible_neg.cc
new file mode 100644
index 0000000..15a1f31
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/array_convertible_neg.cc
@@ -0,0 +1,58 @@ 
+// { dg-do compile }
+// { dg-options "-std=gnu++11" }
+
+// Copyright (C) 2012 Free Software Foundation
+//
+// 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>
+
+struct A
+{
+};
+
+struct B : A
+{
+  virtual ~B() { }
+};
+
+// 20.7.1.3 unique_ptr for array objects [unique.ptr.runtime]
+
+struct D
+{
+  template<typename T>
+    void operator()(const T* p) const { delete[] p; }
+};
+
+// Conversion from different type of unique_ptr<T[], D>
+void
+test01()
+{
+  std::unique_ptr<B[], D> b(new B[1]);
+  std::unique_ptr<A[], D> a(std::move(b)); //{ dg-error "no matching function" }
+  a = std::move(b); //{ dg-error "no match" }
+}
+
+// Conversion from non-array form of unique_ptr
+void
+test02()
+{
+  std::unique_ptr<A> nonarray(new A);
+  std::unique_ptr<A[]> array(std::move(nonarray)); //{ dg-error "no matching function" }
+  array = std::move(nonarray); //{ dg-error "no match" }
+}
+
+// { dg-prune-output "include" }
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/convertible_neg.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/convertible_neg.cc
new file mode 100644
index 0000000..5e6591d
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/convertible_neg.cc
@@ -0,0 +1,38 @@ 
+// { dg-do compile }
+// { dg-options "-std=gnu++11" }
+
+// Copyright (C) 2012 Free Software Foundation
+//
+// 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>
+
+struct A
+{
+};
+
+// 20.7.1.3 unique_ptr for array objects [unique.ptr.runtime]
+
+// Conversion to non-array form of unique_ptr
+void
+test01()
+{
+  std::unique_ptr<A[]> array(new A[1]);
+  std::unique_ptr<A> nonarray(std::move(array)); //{ dg-error "no matching function" }
+  nonarray = std::move(array); //{ dg-error "no match" }
+}
+
+// { dg-prune-output "include" }
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual.cc
new file mode 100644
index 0000000..c1d3dad
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual.cc
@@ -0,0 +1,115 @@ 
+// { dg-options "-std=gnu++11" }
+// { dg-do compile }
+
+// Copyright (C) 2012 Free Software Foundation
+//
+// 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/>.
+
+// 20.7.1 Class template unique_ptr [unique.ptr]
+
+#include <memory>
+
+struct A { virtual ~A() = default; };
+
+struct B : A { };
+
+// Construction from objects with different cv-qualification
+
+void
+test01()
+{
+  std::unique_ptr<const A> cA(new A);
+  std::unique_ptr<volatile A> vA(new A);
+  std::unique_ptr<const volatile A> cvA(new A);
+}
+
+void
+test02()
+{
+  std::unique_ptr<const A> cB(new B);
+  std::unique_ptr<volatile A> vB(new B);
+  std::unique_ptr<const volatile A> cvB(new B);
+}
+
+void
+test03()
+{
+  std::unique_ptr<A> upA;
+
+  std::unique_ptr<const A> cA(std::move(upA));
+  std::unique_ptr<volatile A> vA(std::move(upA));
+  std::unique_ptr<const volatile A> cvA(std::move(upA));
+}
+
+void
+test04()
+{
+  std::unique_ptr<B> upB;
+
+  std::unique_ptr<const A> cA(std::move(upB));
+  std::unique_ptr<volatile A> vA(std::move(upB));
+  std::unique_ptr<const volatile A> cvA(std::move(upB));
+}
+
+void
+test05()
+{
+  std::unique_ptr<const A[]> cA(new A[1]);
+  std::unique_ptr<volatile A[]> vA(new A[1]);
+  std::unique_ptr<const volatile A[]> cvA(new A[1]);
+}
+
+void
+test06()
+{
+  std::unique_ptr<A[]> upA;
+
+  std::unique_ptr<const A[]> cA(std::move(upA));
+  std::unique_ptr<volatile A[]> vA(std::move(upA));
+  std::unique_ptr<const volatile A[]> cvA(std::move(upA));
+}
+
+struct A_pointer { operator A*() const { return nullptr; } };
+
+void
+test07()
+{
+  // Allow conversions from user-defined pointer-like types
+  A_pointer p;
+  std::unique_ptr<A[]> upA(p);
+  std::unique_ptr<const A[]> cA(p);
+  std::unique_ptr<volatile A[]> vA(p);
+  std::unique_ptr<const volatile A[]> cvA(p);
+}
+
+template<typename T>
+struct deleter
+{
+  deleter() = default;
+  template<typename U>
+    deleter(const deleter<U>) { }
+  typedef T pointer;
+  void operator()(T) const { }
+};
+
+void
+test08()
+{
+  // Allow conversions from user-defined pointer-like types
+  std::unique_ptr<B[], deleter<A_pointer>> p;
+  std::unique_ptr<A[], deleter<A*>> upA(std::move(p));
+}
+
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/pointer_array_convertible_neg.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/pointer_array_convertible_neg.cc
index 2a4a89b..42f1eca 100644
--- a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/pointer_array_convertible_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/pointer_array_convertible_neg.cc
@@ -1,7 +1,7 @@ 
 // { dg-do compile }
-// { dg-options "-std=gnu++0x" }
+// { dg-options "-std=gnu++11" }
 
-// Copyright (C) 2008, 2009 Free Software Foundation
+// Copyright (C) 2008-2012 Free Software Foundation
 //
 // 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
@@ -29,7 +29,7 @@  struct B : A
   virtual ~B() { }
 };
 
-// 20.4.5.1 unique_ptr constructors [unique.ptr.cons]
+// 20.7.1.3.1 unique_ptr constructors [unique.ptr.runtime.ctor]
 
 // Construction from pointer of derived type
 void
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 312ecbe..e2be105 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
@@ -1,7 +1,7 @@ 
 // { dg-options "-std=gnu++0x" }
 // { dg-do compile }
 
-// Copyright (C) 2010 Free Software Foundation
+// Copyright (C) 2010-2012 Free Software Foundation
 //
 // 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
@@ -18,10 +18,9 @@ 
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// 20.6.11 Template class unique_ptr [unique.ptr]
+// 20.7.1 Class template unique_ptr [unique.ptr]
 
 #include <memory>
-#include <testsuite_hooks.h>
 
 using std::unique_ptr;
 
@@ -30,9 +29,9 @@  using std::unique_ptr;
 void
 test01()
 {
-  unique_ptr<int, void(*)(int*)> p1; // { dg-error "here" }
+  unique_ptr<long, void(*)(long*)> p1; // { dg-error "here" }
 
-  unique_ptr<int, void(*)(int*)> p2(nullptr); // { dg-error "here" }
+  unique_ptr<short, void(*)(short*)> p2(nullptr); // { dg-error "here" }
 
   unique_ptr<int, void(*)(int*)> p3(new int); // { dg-error "here" }
 }
@@ -40,9 +39,9 @@  test01()
 void
 test02()
 {
-  unique_ptr<int[], void(*)(int*)> p1; // { dg-error "here" }
+  unique_ptr<long[], void(*)(long*)> p1; // { dg-error "here" }
 
-  unique_ptr<int[], void(*)(int*)> p2(nullptr); // { dg-error "here" }
+  unique_ptr<short[], void(*)(short*)> p2(nullptr); // { dg-error "here" }
 
   unique_ptr<int[], void(*)(int*)> p3(new int[1]); // { dg-error "here" }
 }
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/cv_qual.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/cv_qual.cc
new file mode 100644
index 0000000..c5afa7e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/cv_qual.cc
@@ -0,0 +1,79 @@ 
+// { dg-options "-std=gnu++11" }
+// { dg-do compile }
+
+// Copyright (C) 2012 Free Software Foundation
+//
+// 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/>.
+
+// 20.7.1 Class template unique_ptr [unique.ptr]
+
+#include <memory>
+
+struct A { virtual ~A() = default; };
+
+struct B : A { };
+
+// Construction from objects with different cv-qualification
+
+void
+test01()
+{
+  std::unique_ptr<const A> cA;
+  cA.reset(new A);
+  std::unique_ptr<volatile A> vA;
+  vA.reset(new A);
+  std::unique_ptr<const volatile A> cvA;
+  cvA.reset(new A);
+}
+
+void
+test02()
+{
+  std::unique_ptr<const A> cB;
+  cB.reset(new B);
+  std::unique_ptr<volatile A> vB;
+  vB.reset(new B);
+  std::unique_ptr<const volatile A> cvB;
+  cvB.reset(new B);
+}
+
+void
+test03()
+{
+  std::unique_ptr<const A[]> cA;
+  cA.reset(new A[1]);
+  std::unique_ptr<volatile A[]> vA;
+  vA.reset(new A[1]);
+  std::unique_ptr<const volatile A[]> cvA;
+  cvA.reset(new A[1]);
+}
+
+struct A_pointer { operator A*() const { return nullptr; } };
+
+void
+test07()
+{
+  // Allow conversions from user-defined pointer-like types
+  A_pointer p;
+  std::unique_ptr<A[]> upA;
+  upA.reset(p);
+  std::unique_ptr<const A[]> cA;
+  cA.reset(p);
+  std::unique_ptr<volatile A[]> vA;
+  vA.reset(p);
+  std::unique_ptr<const volatile A[]> cvA;
+  cvA.reset(p);
+}
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/reset_neg.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/reset_neg.cc
index 29bb57d..2f5e639 100644
--- a/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/reset_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/reset_neg.cc
@@ -1,7 +1,7 @@ 
 // { dg-do compile }
 // { dg-options "-std=gnu++0x" }
 
-// Copyright (C) 2008, 2009, 2010 Free Software Foundation
+// Copyright (C) 2008-2012 Free Software Foundation
 //
 // 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
@@ -32,7 +32,7 @@  struct B : A
 void test01()
 {
   std::unique_ptr<B[]> up;
-  up.reset(new A[3]);		// { dg-error "deleted" }
+  up.reset(new A[3]);		// { dg-error "invalid conversion" }
 }
 
 // { dg-prune-output "include" }
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/requirements/pointer_type.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/requirements/pointer_type.cc
index 55f28ca..ee2105d 100644
--- a/libstdc++-v3/testsuite/20_util/unique_ptr/requirements/pointer_type.cc
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/requirements/pointer_type.cc
@@ -1,7 +1,7 @@ 
 // { dg-do compile }
-// { dg-options "-std=gnu++0x" }
+// { dg-options "-std=gnu++11" }
 
-// Copyright (C) 2010, 2011 Free Software Foundation
+// Copyright (C) 2010-2012 Free Software Foundation
 //
 // 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
@@ -18,10 +18,9 @@ 
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// 20.6.11 Template class unique_ptr [unique.ptr.single]
+// 20.7.1.2 unique_ptr for single objects [unique.ptr.single]
 
 #include <memory>
-#include <testsuite_hooks.h>
 
 struct A
 {
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/requirements/pointer_type_array.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/requirements/pointer_type_array.cc
new file mode 100644
index 0000000..0f1a8e5
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/requirements/pointer_type_array.cc
@@ -0,0 +1,49 @@ 
+// { dg-do compile }
+// { dg-options "-std=gnu++11" }
+
+// Copyright (C) 2010-2012 Free Software Foundation
+//
+// 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/>.
+
+// 20.7.1.3 unique_ptr for array objects [unique.ptr.runtime]
+
+#include <memory>
+
+struct A
+{
+  void operator()(void*) const { }
+};
+
+struct B
+{
+  typedef char* pointer;
+  void operator()(pointer) const { }
+};
+
+int main()
+{
+  typedef std::unique_ptr<int[]>     up;
+  typedef std::unique_ptr<int[], A>  upA;
+  typedef std::unique_ptr<int[], B>  upB;
+  typedef std::unique_ptr<int[], A&> upAr;
+  typedef std::unique_ptr<int[], B&> upBr;
+
+  static_assert( std::is_same< up::pointer, int*>::value, "" );
+  static_assert( std::is_same< upA::pointer, int*>::value, "" );
+  static_assert( std::is_same< upB::pointer, char*>::value, "" );
+  static_assert( std::is_same< upAr::pointer, int*>::value, "" );
+  static_assert( std::is_same< upBr::pointer, char*>::value, "" );
+}