diff mbox

Fix std::experimental::shared_ptr SFINAE constraints

Message ID 20161019093513.GW2922@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely Oct. 19, 2016, 9:35 a.m. UTC
There are lots of SFINAE checks missing from experimental::shared_ptr,
and we even test that shared_ptr<base[]>(new derived[1]) works, when
it should be ill-formed.

I implemented a new trait for std::shared_ptr to check the
conversions, but I'm not ready to commit that work yet, so this just
adds it to experimental::shared_ptr for now.

	* include/experimental/bits/shared_ptr.h
	(__shared_ptr<__libfund_v1<_Tp, false>, _Lp>::_Compatible): Just use
	is_convertible for non-array specialization.
	(__shared_ptr<__libfund_v1<_Tp, false>, _Lp>::_UniqCompatible): New
	constraint for conversions from unique_ptr.
	(__shared_ptr<__libfund_v1<_Tp, false>, _Lp>::__shared_ptr): Constrain.
	(__shared_ptr<__libfund_v1<_Tp, false>, _Lp>::reset): Likewise.
	(__sp_compatible_v): New variable template for trait.
	(__sp_is_constructible): New trait to check shared_ptr constraints.
	(__sp_is_constructible_v): New variable template for trait.
	(__shared_ptr<__libfund_v1<_Tp, true>, _Lp>::_SafeConv): New
	constraint for construction/reset, using __sp_is_constructible_v.
	(__shared_ptr<__libfund_v1<_Tp, true>, _Lp>::_UniqCompatible): New
	constraint for conversions from unique_ptr.
	(__shared_ptr<__libfund_v1<_Tp, true>, _Lp>::__shared_ptr): Constrain.
	(__shared_ptr<__libfund_v1<_Tp, true>, _Lp>::reset): Likewise.
	(shared_ptr::_SafeConv): Constraint for checking constructors.
	(shared_ptr(Tp1*), shared_ptr(_Tp1, _Deleter))
	(shared_ptr(_Tp1, _Deleter, _Alloc)): Constrain with _SafeConv.
	(shared_ptr(const weak_ptr<_Tp1>&)): Constrain with _Compatible.
	(shared_ptr(auto_ptr<_Tp1>&&)): Fix, remove TODO.
	* testsuite/experimental/memory/shared_ptr/cons/pointer_ctor.cc:
	Remove tests using invalid conversions.
	* testsuite/experimental/memory/shared_ptr/cons/pointer_ctor_neg.cc:
	New test.
	* testsuite/experimental/memory/shared_ptr/cons/torture.cc: New test.
	* testsuite/experimental/memory/shared_ptr/modifiers/reset.cc: Remove
	tests using invalid conversions.
	* testsuite/experimental/memory/shared_ptr/modifiers/reset_neg.cc: New
	test.
	* testsuite/experimental/memory/shared_ptr/observers/use_count.cc:
	Remove tests using invalid conversions.

Tested x86_64-linux, committed to trunk.
commit 53e60f9dc887807a070cacb5931ee2980455ce7e
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Oct 19 10:12:15 2016 +0100

    Fix std::experimental::shared_ptr SFINAE constraints
    
    	* include/experimental/bits/shared_ptr.h
    	(__shared_ptr<__libfund_v1<_Tp, false>, _Lp>::_Compatible): Just use
    	is_convertible for non-array specialization.
    	(__shared_ptr<__libfund_v1<_Tp, false>, _Lp>::_UniqCompatible): New
    	constraint for conversions from unique_ptr.
    	(__shared_ptr<__libfund_v1<_Tp, false>, _Lp>::__shared_ptr): Constrain.
    	(__shared_ptr<__libfund_v1<_Tp, false>, _Lp>::reset): Likewise.
    	(__sp_compatible_v): New variable template for trait.
    	(__sp_is_constructible): New trait to check shared_ptr constraints.
    	(__sp_is_constructible_v): New variable template for trait.
    	(__shared_ptr<__libfund_v1<_Tp, true>, _Lp>::_SafeConv): New
    	constraint for construction/reset, using __sp_is_constructible_v.
    	(__shared_ptr<__libfund_v1<_Tp, true>, _Lp>::_UniqCompatible): New
    	constraint for conversions from unique_ptr.
    	(__shared_ptr<__libfund_v1<_Tp, true>, _Lp>::__shared_ptr): Constrain.
    	(__shared_ptr<__libfund_v1<_Tp, true>, _Lp>::reset): Likewise.
    	(shared_ptr::_SafeConv): Constraint for checking constructors.
    	(shared_ptr(Tp1*), shared_ptr(_Tp1, _Deleter))
    	(shared_ptr(_Tp1, _Deleter, _Alloc)): Constrain with _SafeConv.
    	(shared_ptr(const weak_ptr<_Tp1>&)): Constrain with _Compatible.
    	(shared_ptr(auto_ptr<_Tp1>&&)): Fix, remove TODO.
    	* testsuite/experimental/memory/shared_ptr/cons/pointer_ctor.cc:
    	Remove tests using invalid conversions.
    	* testsuite/experimental/memory/shared_ptr/cons/pointer_ctor_neg.cc:
    	New test.
    	* testsuite/experimental/memory/shared_ptr/cons/torture.cc: New test.
    	* testsuite/experimental/memory/shared_ptr/modifiers/reset.cc: Remove
    	tests using invalid conversions.
    	* testsuite/experimental/memory/shared_ptr/modifiers/reset_neg.cc: New
    	test.
    	* testsuite/experimental/memory/shared_ptr/observers/use_count.cc:
    	Remove tests using invalid conversions.
diff mbox

Patch

diff --git a/libstdc++-v3/include/experimental/bits/shared_ptr.h b/libstdc++-v3/include/experimental/bits/shared_ptr.h
index e0ec00c..2e3da62 100644
--- a/libstdc++-v3/include/experimental/bits/shared_ptr.h
+++ b/libstdc++-v3/include/experimental/bits/shared_ptr.h
@@ -69,53 +69,48 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template <typename _Tp, bool = is_array<_Tp>::value>
     struct __libfund_v1 { using type = _Tp; };
 
-  // helper for _Compatible
-  template<typename _From_type, typename _To_type>
-    struct __sp_compatible
-    : is_convertible<_From_type*, _To_type*>::type
-    { };
-
-  template<size_t _Nm, typename _Tp>
-    struct __sp_compatible<_Tp[_Nm], _Tp[]>
-    : true_type
-    { };
-
-  template<size_t _Nm, typename _Tp>
-    struct __sp_compatible<_Tp[_Nm], const _Tp[]>
-    : true_type
-    { };
-
   // Partial specialization for base class of experimental::shared_ptr<T>
   // (i.e. the non-array form of experimental::shared_ptr)
   template<typename _Tp, _Lock_policy _Lp>
     class __shared_ptr<__libfund_v1<_Tp, false>, _Lp>
     : private __shared_ptr<_Tp, _Lp>
     {
-      template<typename _Tp1, typename _Res = void>
+      // For non-arrays, Y* is compatible with T* if Y* is convertible to T*.
+      template<typename _Yp, typename _Res = void>
 	using _Compatible
-	  = enable_if_t<__sp_compatible<_Tp1, _Tp>::value, _Res>;
+	  = enable_if_t<experimental::is_convertible_v<_Yp*, _Tp*>, _Res>;
+
+      template<typename _Yp, typename _Del,
+	       typename _Ptr = typename unique_ptr<_Yp, _Del>::pointer,
+	       typename _Res = void>
+	using _UniqCompatible = enable_if_t<
+	  experimental::is_convertible_v<_Yp*, _Tp*>
+	  && experimental::is_convertible_v<_Ptr, _Tp*>,
+	  _Res>;
 
       using _Base_type = __shared_ptr<_Tp>;
 
-      _Base_type&  _M_get_base() { return *this;}
-      const _Base_type&  _M_get_base() const { return *this;}
+      _Base_type&  _M_get_base() { return *this; }
+      const _Base_type&  _M_get_base() const { return *this; }
 
     public:
       using element_type = _Tp;
 
       constexpr __shared_ptr() noexcept = default;
 
-      template<typename _Tp1>
-	explicit __shared_ptr(_Tp1* __p)
+      template<typename _Tp1, typename = _Compatible<_Tp1>>
+	explicit
+	__shared_ptr(_Tp1* __p)
 	: _Base_type(__p)
 	{ }
 
-      template<typename _Tp1, typename _Deleter>
+      template<typename _Tp1, typename _Deleter, typename = _Compatible<_Tp1>>
 	__shared_ptr(_Tp1* __p, _Deleter __d)
 	: _Base_type(__p, __d)
 	{ }
 
-      template<typename _Tp1, typename _Deleter, typename _Alloc>
+      template<typename _Tp1, typename _Deleter, typename _Alloc,
+	       typename = _Compatible<_Tp1>>
 	__shared_ptr(_Tp1* __p, _Deleter __d, _Alloc __a)
 	: _Base_type(__p, __d, __a)
 	{ }
@@ -152,21 +147,21 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	: _Base_type(std::move((__r._M_get_base())))
 	{ }
 
-      template<typename _Tp1>
-	explicit __shared_ptr(const __weak_ptr<__libfund_v1<_Tp1>, _Lp>& __r)
+      template<typename _Tp1, typename = _Compatible<_Tp1>>
+	explicit
+	__shared_ptr(const __weak_ptr<__libfund_v1<_Tp1>, _Lp>& __r)
 	: _Base_type(__r._M_get_base())
 	{ }
 
-      template<typename _Tp1, typename _Del, typename
-	      = _Compatible<remove_pointer_t<
-			    typename unique_ptr<_Tp1, _Del>::pointer>>>
-	  __shared_ptr(std::unique_ptr<_Tp1, _Del>&& __r)
-	  : _Base_type(std::move(__r))
-	  { }
+      template<typename _Tp1, typename _Del,
+	       typename = _UniqCompatible<_Tp1, _Del>>
+	__shared_ptr(unique_ptr<_Tp1, _Del>&& __r)
+	: _Base_type(std::move(__r))
+	{ }
 
 #if _GLIBCXX_USE_DEPRECATED
       // Postcondition: use_count() == 1 and __r.get() == 0
-      template<typename _Tp1>
+      template<typename _Tp1, typename = _Compatible<_Tp1>>
 	__shared_ptr(std::auto_ptr<_Tp1>&& __r)
         : _Base_type(std::move(__r))
 	{ }
@@ -180,7 +175,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { __shared_ptr(nullptr).swap(*this); }
 
       template<typename _Tp1>
-	void
+	_Compatible<_Tp1>
 	reset(_Tp1* __p)
 	{
 	  _GLIBCXX_DEBUG_ASSERT(__p == 0 || __p != get());
@@ -188,12 +183,12 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
 
       template<typename _Tp1, typename _Deleter>
-	void
+	_Compatible<_Tp1>
 	reset(_Tp1* __p, _Deleter __d)
 	{ __shared_ptr(__p, __d).swap(*this); }
 
       template<typename _Tp1, typename _Deleter, typename _Alloc>
-	void
+	_Compatible<_Tp1>
 	reset(_Tp1* __p, _Deleter __d, _Alloc __a)
 	{ __shared_ptr(__p, __d, std::move(__a)).swap(*this); }
 
@@ -216,9 +211,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  return *this;
 	}
 
-      template<typename _Tp1>
-	_Compatible<_Tp1, __shared_ptr&>
-	operator=(std::unique_ptr<_Tp1>&& __r)
+      template<typename _Tp1, typename _Del>
+	_UniqCompatible<_Tp1, _Del, __shared_ptr&>
+	operator=(unique_ptr<_Tp1, _Del>&& __r)
 	{
 	  _Base_type::operator=(std::move(__r));
 	  return *this;
@@ -282,6 +277,77 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&) noexcept;
     };
 
+  // Helper traits for shared_ptr of array:
+
+  // Trait that tests if Y* is compatible with T*, for shared_ptr purposes.
+  template<typename _Yp, typename _Tp>
+    struct __sp_compatible
+    : is_convertible<_Yp*, _Tp*>::type
+    { };
+
+  template<size_t _Nm, typename _Tp>
+    struct __sp_compatible<_Tp[_Nm], _Tp[]>
+    : true_type
+    { };
+
+  template<size_t _Nm, typename _Tp>
+    struct __sp_compatible<_Tp[_Nm], const _Tp[]>
+    : true_type
+    { };
+
+  template<typename _Yp, typename _Tp>
+    constexpr bool __sp_compatible_v
+      = __sp_compatible<_Yp, _Tp>::value;
+
+  // Test conversion from Y(*)[N] to U(*)[N] without forming invalid type Y[N].
+  template<typename _Up, size_t _Nm, typename _Yp, typename = void>
+    struct __sp_is_constructible_arrN
+    : false_type
+    { };
+
+  template<typename _Up, size_t _Nm, typename _Yp>
+    struct __sp_is_constructible_arrN<_Up, _Nm, _Yp, __void_t<_Yp[_Nm]>>
+    : is_convertible<_Yp(*)[_Nm], _Up(*)[_Nm]>::type
+    { };
+
+  // Test conversion from Y(*)[] to U(*)[] without forming invalid type Y[].
+  template<typename _Up, typename _Yp, typename = void>
+    struct __sp_is_constructible_arr
+    : false_type
+    { };
+
+  template<typename _Up, typename _Yp>
+    struct __sp_is_constructible_arr<_Up, _Yp, __void_t<_Yp[]>>
+    : is_convertible<_Yp(*)[], _Up(*)[]>::type
+    { };
+
+  // Trait to check if shared_ptr<T> can be constructed from Y*.
+  template<typename _Tp, typename _Yp>
+    struct __sp_is_constructible;
+
+  // When T is U[N], Y(*)[N] shall be convertible to T*;
+  template<typename _Up, size_t _Nm, typename _Yp>
+    struct __sp_is_constructible<_Up[_Nm], _Yp>
+    : __sp_is_constructible_arrN<_Up, _Nm, _Yp>::type
+    { };
+
+  // when T is U[], Y(*)[] shall be convertible to T*;
+  template<typename _Up, typename _Yp>
+    struct __sp_is_constructible<_Up[], _Yp>
+    : __sp_is_constructible_arr<_Up, _Yp>::type
+    { };
+
+  // otherwise, Y* shall be convertible to T*.
+  template<typename _Tp, typename _Yp>
+    struct __sp_is_constructible
+    : is_convertible<_Yp*, _Tp*>::type
+    { };
+
+  template<typename _Tp, typename _Yp>
+    constexpr bool __sp_is_constructible_v
+      = __sp_is_constructible<_Tp, _Yp>::value;
+
+
   // Partial specialization for base class of experimental::shared_ptr<T[N]>
   // and experimental::shared_ptr<T[]> (i.e. the array forms).
   template<typename _Tp, _Lock_policy _Lp>
@@ -299,31 +365,46 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	{ delete [] __p; }
       };
 
+      // Constraint for constructing/resetting with a pointer of type _Yp*:
+      template<typename _Yp>
+	using _SafeConv = enable_if_t<__sp_is_constructible_v<_Tp, _Yp>>;
+
+      // Constraint for constructing/assigning from smart_pointer<_Tp1>:
       template<typename _Tp1, typename _Res = void>
-	using _Compatible
-	  = enable_if_t<__sp_compatible<_Tp1, _Tp>::value, _Res>;
+	using _Compatible = enable_if_t<__sp_compatible_v<_Tp1, _Tp>, _Res>;
+
+      // Constraint for constructing/assigning from unique_ptr<_Tp1, _Del>:
+      template<typename _Tp1, typename _Del,
+	       typename _Ptr = typename unique_ptr<_Tp1, _Del>::pointer,
+	       typename _Res = void>
+	using _UniqCompatible = enable_if_t<
+	  __sp_compatible_v<_Tp1, _Tp>
+	  && experimental::is_convertible_v<_Ptr, element_type*>,
+	  _Res>;
 
       using _Base_type = __shared_ptr<element_type>;
 
-      _Base_type&  _M_get_base() { return *this;}
-      const _Base_type&  _M_get_base() const { return *this;}
+      _Base_type&  _M_get_base() { return *this; }
+      const _Base_type&  _M_get_base() const { return *this; }
 
     public:
       constexpr __shared_ptr() noexcept
       : _Base_type()
       { }
 
-      template<typename _Tp1>
-	explicit __shared_ptr(_Tp1* __p)
+      template<typename _Tp1, typename = _SafeConv<_Tp1>>
+	explicit
+	__shared_ptr(_Tp1* __p)
 	: _Base_type(__p, _Array_deleter())
 	{ }
 
-      template<typename _Tp1, typename _Deleter>
+      template<typename _Tp1, typename _Deleter, typename = _SafeConv<_Tp1>>
 	__shared_ptr(_Tp1* __p, _Deleter __d)
 	: _Base_type(__p, __d)
 	{ }
 
-      template<typename _Tp1, typename _Deleter, typename _Alloc>
+      template<typename _Tp1, typename _Deleter, typename _Alloc,
+	       typename = _SafeConv<_Tp1>>
 	__shared_ptr(_Tp1* __p, _Deleter __d, _Alloc __a)
 	: _Base_type(__p, __d, __a)
 	{ }
@@ -360,22 +441,22 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	: _Base_type(std::move((__r._M_get_base())))
 	{ }
 
-      template<typename _Tp1>
-	explicit __shared_ptr(const __weak_ptr<__libfund_v1<_Tp1>, _Lp>& __r)
+      template<typename _Tp1, typename = _Compatible<_Tp1>>
+	explicit
+	__shared_ptr(const __weak_ptr<__libfund_v1<_Tp1>, _Lp>& __r)
 	: _Base_type(__r._M_get_base())
 	{ }
 
-      template<typename _Tp1, typename _Del, typename
-	      = _Compatible<remove_pointer_t<
-			    typename unique_ptr<_Tp1, _Del>::pointer>>>
-	  __shared_ptr(std::unique_ptr<_Tp1, _Del>&& __r)
-	  : _Base_type(std::move(__r))
-	  { }
+      template<typename _Tp1, typename _Del,
+	       typename = _UniqCompatible<_Tp1, _Del>>
+	__shared_ptr(unique_ptr<_Tp1, _Del>&& __r)
+	: _Base_type(std::move(__r))
+	{ }
 
 #if _GLIBCXX_USE_DEPRECATED
       // Postcondition: use_count() == 1 and __r.get() == 0
-      template<typename _Tp1>
-	__shared_ptr(std::auto_ptr<_Tp1>&& __r)
+      template<typename _Tp1, typename = _Compatible<_Tp1>>
+	__shared_ptr(auto_ptr<_Tp1>&& __r)
         : _Base_type(std::move(__r))
 	{ }
 #endif
@@ -388,7 +469,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { __shared_ptr(nullptr).swap(*this); }
 
       template<typename _Tp1>
-	void
+	_SafeConv<_Tp1>
 	reset(_Tp1* __p)
 	{
 	  _GLIBCXX_DEBUG_ASSERT(__p == 0 || __p != get());
@@ -396,12 +477,12 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
 
       template<typename _Tp1, typename _Deleter>
-	void
+	_SafeConv<_Tp1>
 	reset(_Tp1* __p, _Deleter __d)
 	{ __shared_ptr(__p, __d).swap(*this); }
 
       template<typename _Tp1, typename _Deleter, typename _Alloc>
-	void
+	_SafeConv<_Tp1>
 	reset(_Tp1* __p, _Deleter __d, _Alloc __a)
 	{ __shared_ptr(__p, __d, std::move(__a)).swap(*this); }
 
@@ -428,9 +509,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  return *this;
 	}
 
-      template<typename _Tp1>
-	_Compatible<_Tp1, __shared_ptr&>
-	operator=(std::unique_ptr<_Tp1>&& __r)
+      template<typename _Tp1, typename _Del>
+	_UniqCompatible<_Tp1, _Del, __shared_ptr&>
+	operator=(unique_ptr<_Tp1, _Del>&& __r)
 	{
 	  _Base_type::operator=(std::move(__r));
 	  return *this;
@@ -439,7 +520,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if _GLIBCXX_USE_DEPRECATED
       template<typename _Tp1>
 	_Compatible<_Tp1, __shared_ptr&>
-	operator=(std::auto_ptr<_Tp1>&& __r)
+	operator=(auto_ptr<_Tp1>&& __r)
 	{
 	  _Base_type::operator=(std::move(__r));
 	  return *this;
@@ -501,11 +582,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       template<typename _Tp1, typename _Res = void>
 	using _Compatible
-	  = enable_if_t<__sp_compatible<_Tp1, _Tp>::value, _Res>;
+	  = enable_if_t<__sp_compatible_v<_Tp1, _Tp>, _Res>;
 
       using _Base_type = __weak_ptr<remove_extent_t<_Tp>>;
 
-      _Base_type&  _M_get_base() { return *this;}
+      _Base_type&  _M_get_base() { return *this; }
       const _Base_type&  _M_get_base() const { return *this; }
 
     public:
@@ -630,26 +711,43 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     class shared_ptr : public __shared_ptr<_Tp>
     {
-      template<typename _Tp1, typename _Res = void>
-	using _Compatible
-	  = enable_if_t<__sp_compatible<_Tp1, _Tp>::value, _Res>;
-
       using _Base_type = __shared_ptr<_Tp>;
 
     public:
       using element_type = typename _Base_type::element_type;
 
+    private:
+      // Constraint for construction from a pointer of type _Yp*:
+      template<typename _Yp>
+	using _SafeConv = enable_if_t<__sp_is_constructible_v<_Tp, _Yp>>;
+
+      template<typename _Tp1, typename _Res = void>
+	using _Compatible
+	  = enable_if_t<__sp_compatible_v<_Tp1, _Tp>, _Res>;
+
+      template<typename _Tp1, typename _Del,
+	       typename _Ptr = typename unique_ptr<_Tp1, _Del>::pointer,
+	       typename _Res = void>
+	using _UniqCompatible = enable_if_t<
+	  __sp_compatible_v<_Tp1, _Tp>
+	  && experimental::is_convertible_v<_Ptr, element_type*>,
+	  _Res>;
+
+    public:
+
       // 8.2.1.1, shared_ptr constructors
       constexpr shared_ptr() noexcept = default;
 
-      template<typename _Tp1>
-	explicit shared_ptr(_Tp1* __p) : _Base_type(__p) { }
+      template<typename _Tp1, typename = _SafeConv<_Tp1>>
+	explicit
+	shared_ptr(_Tp1* __p) : _Base_type(__p) { }
 
-      template<typename _Tp1, typename _Deleter>
+      template<typename _Tp1, typename _Deleter, typename = _SafeConv<_Tp1>>
 	shared_ptr(_Tp1* __p, _Deleter __d)
 	: _Base_type(__p, __d) { }
 
-      template<typename _Tp1, typename _Deleter, typename _Alloc>
+      template<typename _Tp1, typename _Deleter, typename _Alloc,
+	       typename = _SafeConv<_Tp1>>
 	shared_ptr(_Tp1* __p, _Deleter __d, _Alloc __a)
 	: _Base_type(__p, __d, __a) { }
 
@@ -679,20 +777,20 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	shared_ptr(shared_ptr<_Tp1>&& __r) noexcept
 	: _Base_type(std::move(__r)) { }
 
-      template<typename _Tp1>
-	explicit shared_ptr(const weak_ptr<_Tp1>& __r)
+      template<typename _Tp1, typename = _Compatible<_Tp1>>
+	explicit
+	shared_ptr(const weak_ptr<_Tp1>& __r)
 	: _Base_type(__r) { }
 
 #if _GLIBCXX_USE_DEPRECATED
-      template<typename _Tp1>
+      template<typename _Tp1, typename = _Compatible<_Tp1>>
 	shared_ptr(std::auto_ptr<_Tp1>&& __r)
-	: _Base_type() { } // TODO
+	: _Base_type(std::move(__r)) { }
 #endif
 
-      template<typename _Tp1, typename _Del, typename
-	= _Compatible<remove_pointer_t<
-		      typename unique_ptr<_Tp1, _Del>::pointer>>>
-	shared_ptr(std::unique_ptr<_Tp1, _Del>&& __r)
+      template<typename _Tp1, typename _Del,
+	       typename = _UniqCompatible<_Tp1, _Del>>
+	shared_ptr(unique_ptr<_Tp1, _Del>&& __r)
 	: _Base_type(std::move(__r)) { }
 
       constexpr shared_ptr(nullptr_t __p)
@@ -738,7 +836,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
       template <typename _Tp1, typename _Del>
-	_Compatible<_Tp1, shared_ptr&>
+	_UniqCompatible<_Tp1, _Del, shared_ptr&>
 	operator=(unique_ptr<_Tp1, _Del>&& __r)
 	{
 	  _Base_type::operator=(std::move(__r));
@@ -752,10 +850,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
     private:
       template<typename _Alloc, typename... _Args>
-      shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
-		 _Args&&... __args)
-      : _Base_type(__tag, __a, std::forward<_Args>(__args)...)
-      { }
+	shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
+		   _Args&&... __args)
+	: _Base_type(__tag, __a, std::forward<_Args>(__args)...)
+	{ }
 
       template<typename _Tp1, typename _Alloc, typename... _Args>
 	friend shared_ptr<_Tp1>
@@ -926,8 +1024,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     class weak_ptr : public __weak_ptr<_Tp>
     {
       template<typename _Tp1, typename _Res = void>
-	using _Compatible
-	  = enable_if_t<__sp_compatible<_Tp1, _Tp>::value, _Res>;
+	using _Compatible = enable_if_t<__sp_compatible_v<_Tp1, _Tp>, _Res>;
 
       using _Base_type = __weak_ptr<_Tp>;
 
@@ -1147,6 +1244,14 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       shared_from_this() const
       { return shared_ptr<const _Tp>(this->_M_weak_this); }
 
+      weak_ptr<_Tp>
+      weak_from_this() noexcept
+      { return _M_weak_this; }
+
+      weak_ptr<const _Tp>
+      weak_from_this() const noexcept
+      { return _M_weak_this; }
+
     private:
       template<typename _Tp1>
 	void
diff --git a/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/pointer_ctor.cc b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/pointer_ctor.cc
index 5a14f7c..1fff022 100644
--- a/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/pointer_ctor.cc
+++ b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/pointer_ctor.cc
@@ -23,40 +23,35 @@ 
 #include <testsuite_hooks.h>
 
 struct A { };
-struct B : A { };
 
 // 8.2.1.1 shared_ptr constructors [memory.smartptr.shared.const]
 
 // Construction from pointer
-int
+void
 test01()
 {
-  A * const a = 0;
+  A * const a = new A;
   std::experimental::shared_ptr<A> p(a);
-  VERIFY( p.get() == 0 );
+  VERIFY( p.get() == a );
   VERIFY( p.use_count() == 1 );
-  return 0;
 }
 
-int
+void
 test02()
 {
   A * const a = new A[5];
   std::experimental::shared_ptr<A[5]> p(a);
   VERIFY( p.get() == a );
   VERIFY( p.use_count() == 1 );
-  return 0;
 }
 
-int
+void
 test03()
 {
-  B * const b = new B[5];
-  std::experimental::shared_ptr<A[5]> p(b);
-  VERIFY( p.get() == b );
+  A * const a = new A[5];
+  std::experimental::shared_ptr<A[]> p(a);
+  VERIFY( p.get() == a );
   VERIFY( p.use_count() == 1 );
-
-  return 0;
 }
 
 int
diff --git a/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/pointer_ctor_neg.cc b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/pointer_ctor_neg.cc
new file mode 100644
index 0000000..8fcd40c
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/pointer_ctor_neg.cc
@@ -0,0 +1,51 @@ 
+// { dg-do compile { target c++14 } }
+
+// 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/>.
+
+// 8.2.1 Class template shared_ptr [memory.smartptr.shared]
+
+#include <experimental/memory>
+
+struct A { };
+struct B : A { };
+struct C { };
+struct D { void operator()(B* p) const { delete[] p; } };
+
+// 8.2.1.1 shared_ptr constructors [memory.smartptr.shared.const]
+
+// Construction from pointer
+void
+test01()
+{
+  C * const c = nullptr;
+  std::experimental::shared_ptr<A> p(c); // { dg-error "no match" }
+}
+
+void
+test02()
+{
+  B * const b = nullptr;
+  std::experimental::shared_ptr<A[5]> p(b); // { dg-error "no match" }
+}
+
+void
+test03()
+{
+  B * const b = nullptr;
+  std::experimental::shared_ptr<A[]> p(b); // { dg-error "no match" }
+}
diff --git a/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/torture.cc b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/torture.cc
new file mode 100644
index 0000000..bade9d8
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/torture.cc
@@ -0,0 +1,53 @@ 
+// { dg-do compile { target c++14 } }
+
+// 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/>.
+
+// 8.2.1 Class template shared_ptr [memory.smartptr.shared]
+
+#include <experimental/memory>
+
+using namespace std::experimental;
+
+static_assert( !is_constructible_v<shared_ptr<int>, void*>,
+    "can query constructibility without forming invalid type void[]");
+static_assert( !is_constructible_v<shared_ptr<int[2]>, void*>,
+    "can query constructibility without forming invalid type void[]");
+static_assert( !is_constructible_v<shared_ptr<int[]>, void*>,
+    "can query constructibility without forming invalid type void[]");
+
+static_assert( !is_constructible_v<shared_ptr<int>, void()>,
+    "can query constructibility without forming invalid type void()[]");
+static_assert( !is_constructible_v<shared_ptr<int[2]>, void()>,
+    "can query constructibility without forming invalid type void()[]");
+static_assert( !is_constructible_v<shared_ptr<int[]>, void()>,
+    "can query constructibility without forming invalid type void()[]");
+
+static_assert( !is_constructible_v<shared_ptr<int>, void()>,
+    "can query constructibility without forming invalid type void(*)()[]");
+static_assert( !is_constructible_v<shared_ptr<int[2]>, void()>,
+    "can query constructibility without forming invalid type void(*)()[]");
+static_assert( !is_constructible_v<shared_ptr<int[]>, void()>,
+    "can query constructibility without forming invalid type void(*)()[]");
+
+using A = int[];
+static_assert( !is_constructible_v<shared_ptr<int>, A*>,
+    "can query constructibility without forming invalid type int[][]");
+static_assert( !is_constructible_v<shared_ptr<int[2]>, A*>,
+    "can query constructibility without forming invalid type int[][]");
+static_assert( !is_constructible_v<shared_ptr<int[]>, A*>,
+    "can query constructibility without forming invalid type int[][]");
diff --git a/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/unique_ptr_ctor.cc b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/unique_ptr_ctor.cc
index 5b4938b..631212f 100644
--- a/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/unique_ptr_ctor.cc
+++ b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/unique_ptr_ctor.cc
@@ -26,17 +26,17 @@  int destroyed = 0;
 
 struct A : std::experimental::enable_shared_from_this<A>
 {
-    ~A() { ++destroyed; }
+  ~A() { ++destroyed; }
 };
 
 // 8.2.1.1 shared_ptr constructors [memory.smartptr.shared.const]
 
 // Construction from unique_ptr<A[]>
 
-int
+void
 test01()
 {
-  std::unique_ptr<A[]> up(new A[5]);
+  std::unique_ptr<A> up(new A);
   std::experimental::shared_ptr<A> sp(std::move(up));
   VERIFY( up.get() == 0 );
   VERIFY( sp.get() != 0 );
@@ -45,14 +45,28 @@  test01()
   VERIFY( sp->shared_from_this() != nullptr );
 
   sp.reset();
-  VERIFY( destroyed == 5 );
+  VERIFY( destroyed == 1 );
+  destroyed = 0;
+}
 
-  return 0;
+void
+test02()
+{
+  std::unique_ptr<A[]> up(new A[5]);
+  std::experimental::shared_ptr<A[]> sp(std::move(up));
+  VERIFY( up.get() == 0 );
+  VERIFY( sp.get() != 0 );
+  VERIFY( sp.use_count() == 1 );
+
+  VERIFY( sp[0].shared_from_this() != nullptr );
+
+  sp.reset();
+  VERIFY( destroyed == 5 );
 }
 
 int
 main()
 {
   test01();
-  return 0;
+  test02();
 }
diff --git a/libstdc++-v3/testsuite/experimental/memory/shared_ptr/modifiers/reset.cc b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/modifiers/reset.cc
index e0be63b..8df0602 100644
--- a/libstdc++-v3/testsuite/experimental/memory/shared_ptr/modifiers/reset.cc
+++ b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/modifiers/reset.cc
@@ -23,10 +23,9 @@ 
 #include <testsuite_hooks.h>
 
 struct A { };
-struct B : A { };
 struct D
 {
-  void operator()(B* p) { delete [] p; ++delete_count; }
+  void operator()(A* p) { delete [] p; ++delete_count; }
   static long delete_count;
 };
 long D::delete_count = 0;
@@ -51,7 +50,7 @@  int
 test02()
 {
   A * const a = new A[5];
-  B * const b = new B[5];
+  A * const b = new A[5];
   std::experimental::shared_ptr<A[5]> p1(a);
   std::experimental::shared_ptr<A[5]> p2(p1);
   p1.reset(b);
@@ -66,7 +65,7 @@  test03()
 {
   {
     std::experimental::shared_ptr<A[5]> p1;
-    p1.reset(new B[5], D());
+    p1.reset(new A[5], D());
   }
   VERIFY( D::delete_count == 1 );
 
diff --git a/libstdc++-v3/testsuite/experimental/memory/shared_ptr/modifiers/reset_neg.cc b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/modifiers/reset_neg.cc
new file mode 100644
index 0000000..0332c4e
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/modifiers/reset_neg.cc
@@ -0,0 +1,45 @@ 
+// { dg-do compile { target c++14 } }
+
+// 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/>.
+
+// 8.2.1 Class template shared_ptr [memory.smartptr.shared]
+
+#include <experimental/memory>
+
+struct A { };
+struct B : A { };
+struct D
+{
+  void operator()(A* p) { delete [] p; ++delete_count; }
+  static long delete_count;
+};
+long D::delete_count = 0;
+
+// C++14 ยง20.8.2.2.4
+
+// reset
+void
+test01()
+{
+  std::experimental::shared_ptr<A[5]> p1(new A[5]);
+  p1.reset(new B[1]);           // { dg-error "no matching function" }
+  p1.reset(new B[5], D());      // { dg-error "no matching function" }
+  using constA = const A;
+  p1.reset(new constA[5]);      // { dg-error "no matching function" }
+  p1.reset(new constA[5], D()); // { dg-error "no matching function" }
+}
diff --git a/libstdc++-v3/testsuite/experimental/memory/shared_ptr/observers/use_count.cc b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/observers/use_count.cc
index b591a7e..a91a92a 100644
--- a/libstdc++-v3/testsuite/experimental/memory/shared_ptr/observers/use_count.cc
+++ b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/observers/use_count.cc
@@ -23,7 +23,6 @@ 
 #include <testsuite_hooks.h>
 
 struct A { };
-struct B : A { };
 
 // 8.2.1.2 shared_ptr observers [memory.smartptr.shared.obs]
 
@@ -52,7 +51,7 @@  test03()
 {
   std::experimental::shared_ptr<A[5]> p1(new A[5]);
   std::experimental::shared_ptr<A[5]> p2(p1);
-  p2.reset(new B[5]);
+  p2.reset(new A[5]);
   VERIFY( p1.use_count() == 1 );
   VERIFY( p2.use_count() == 1 );
 }