diff mbox

Prepare shared_ptr for array support

Message ID 20161020144145.GJ2922@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely Oct. 20, 2016, 2:41 p.m. UTC
On 20/10/16 13:08 +0100, Jonathan Wakely wrote:
>This patch doesn't change very much, except for adding
>std::reinterpret_pointer_cast, but it makes it very easy to add array
>support to shared_ptr, as defined for the Library Fundamentals TS by
>https://wg21.link/n3920 and in the process of being added to C++17 by
>https://wg21.link/p0414r1
>
>The main change is to consistently constrain all template constructors
>and assignment operators. In std::shared_ptr we just forward the
>checks to the std::__shared_ptr base class, so all the hard work is
>done there. The base uses traits that can easily be extended to handle
>array types without touching the uses of those traits (I have that
>patch ready).

Here's the patch to add array support, which is as simple as:

- adding new __shared_count ctor that will result in delete[];
- adjusting the two __sp_xxx traits to handle the array cases;
- moving operator* and operator-> into a new base class, and then
  specializing it so shared_ptr<T[]> has operator[] instead;
- changing element_type to be remove_extent<T>::type instead of T;
- disabling the __has_esft_base detection for array types.

That allows us to remove 650 lines from the experimental::shared_ptr
definition and just inherit directly from __shared_ptr.

Note that the *only* change needed to std::shared_ptr or std::weak_ptr
is to add an extension constructor (see below). My changes to trunk
earlier today mean they are ready to suport arrays now. The code
changes are all to the __shared_ptr and __weak_ptr base classes.

Officially this isn't in the C++17 draft yet, but LWG already approved
P0414R1 and it will be in the straw polls at the end of the Issaquah
meeting next month. I'm not committing it to trunk yet, but I probably
will do before the meeting, as I don't anticipate C++17 being
published without this feature.

The bigger question is whether we want to enable array support
unconditionally, or only for C++17. In C++14 today shared_ptr<int[]>
and shared_ptr<int[N]> are valid ... although they're weird and not
very usable. My preference (as shown in the patch) is to enable it
unconditionally, but add some non-standard member functions for
pre-C++17 to help transition. Specifically operator* and operator->
are defined for shared_ptr<array[]> pre-C++17, and you can do this
pre-C++17:

  shared_ptr<int> p( unique_ptr<int[]>(new int[1]) );
  p.get()[0] = 1;
  assert( *p == 1 );

This is valid today, and we even have a test checking it works. The
default_delete<int[]> is copied into the shared_ptr and does delete[]
when the refcount drops to zero. C++17 says this is ill-formed. This
patch adds a non-standard constructor that allows this conversion, and
the dereference, for C++11 and C++14 only.

For C++17 the code needs to be changed to:

  shared_ptr<int[]> p( unique_ptr<int[]>(new int[1]) );
  p.get()[0] = 1;
  assert( p[0] == 1 );
diff mbox

Patch

diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
index a1190bc..6d10ac4 100644
--- a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
+++ b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
@@ -159,14 +159,13 @@  Feature-testing recommendations for C++</link>.
     </row>
 
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry> Library Fundamentals V1 TS Components: <code>shared_ptr&lt;T[]&gt;</code> </entry>
       <entry>
 	<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0220r1.html">
 	P0220R1
 	</link>
       </entry>
-      <entry align="center"> No </entry>
+      <entry align="center"> 7 </entry>
       <entry> <code>__cpp_lib_shared_ptr_arrays >= 201603</code> </entry>
     </row>
 
diff --git a/libstdc++-v3/include/bits/shared_ptr.h b/libstdc++-v3/include/bits/shared_ptr.h
index 9f7a40c..fc4578a 100644
--- a/libstdc++-v3/include/bits/shared_ptr.h
+++ b/libstdc++-v3/include/bits/shared_ptr.h
@@ -277,6 +277,16 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	shared_ptr(unique_ptr<_Yp, _Del>&& __r)
 	: __shared_ptr<_Tp>(std::move(__r)) { }
 
+#if __cplusplus <= 201402L && _GLIBCXX_USE_DEPRECATED
+      // This non-standard constructor exists to support conversions that
+      // were possible in C++11 and C++14 but are ill-formed in C++17.
+      // If an exception is thrown this constructor has no effect.
+      template<typename _Yp, typename _Del,
+		_Constructible<unique_ptr<_Yp, _Del>, __sp_array_delete>* = 0>
+	shared_ptr(unique_ptr<_Yp, _Del>&& __r)
+	: __shared_ptr<_Tp>(std::move(__r), __sp_array_delete()) { }
+#endif
+
       /**
        *  @brief  Construct an empty %shared_ptr.
        *  @post   use_count() == 0 && get() == nullptr
diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h
index c74c92a..fc36676 100644
--- a/libstdc++-v3/include/bits/shared_ptr_base.h
+++ b/libstdc++-v3/include/bits/shared_ptr_base.h
@@ -558,6 +558,12 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _Impl _M_impl;
     };
 
+  // The default deleter for shared_ptr<T[]> and shared_ptr<T[N]>.
+  struct __sp_array_delete
+  {
+    template<typename _Yp>
+      void operator()(_Yp* __p) const { delete[] __p; }
+  };
 
   template<_Lock_policy _Lp>
     class __shared_count
@@ -581,6 +587,16 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    }
 	}
 
+      template<typename _Ptr>
+	__shared_count(_Ptr __p, /* is_array = */ false_type)
+	: __shared_count(__p)
+	{ }
+
+      template<typename _Ptr>
+	__shared_count(_Ptr __p, /* is_array = */ true_type)
+	: __shared_count(__p, __sp_array_delete{}, allocator<void>())
+	{ }
+
       template<typename _Ptr, typename _Deleter>
 	__shared_count(_Ptr __p, _Deleter __d)
 	: __shared_count(__p, std::move(__d), allocator<void>())
@@ -847,8 +863,12 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  _M_pi = nullptr;
     }
 
-  // Helper traits for shared_ptr
+#define __cpp_lib_shared_ptr_arrays 201603
+
+  // Helper traits for shared_ptr of array:
 
+  // A pointer type Y* is said to be compatible with a pointer type T* when
+  // either Y* is convertible to T* or Y is U[N] and T is U cv [].
   template<typename _Yp_ptr, typename _Tp_ptr>
     struct __sp_compatible_with
     : false_type
@@ -859,17 +879,161 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : is_convertible<_Yp*, _Tp*>::type
     { };
 
+  template<typename _Up, size_t _Nm>
+    struct __sp_compatible_with<_Up(*)[_Nm], _Up(*)[]>
+    : true_type
+    { };
+
+  template<typename _Up, size_t _Nm>
+    struct __sp_compatible_with<_Up(*)[_Nm], const _Up(*)[]>
+    : true_type
+    { };
+
+  template<typename _Up, size_t _Nm>
+    struct __sp_compatible_with<_Up(*)[_Nm], volatile _Up(*)[]>
+    : true_type
+    { };
+
+  template<typename _Up, size_t _Nm>
+    struct __sp_compatible_with<_Up(*)[_Nm], const volatile _Up(*)[]>
+    : true_type
+    { };
+
+  // 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
+    { };
+
+
+  // Define operator* and operator-> for shared_ptr<T>.
+  template<typename _Tp, _Lock_policy _Lp,
+	   bool = is_array<_Tp>::value, bool = is_void<_Tp>::value>
+    class __shared_ptr_access
+    {
+    public:
+      using element_type = _Tp;
+
+      element_type&
+      operator*() const noexcept
+      {
+	__glibcxx_assert(_M_get() != nullptr);
+	return *_M_get();
+      }
+
+      element_type*
+      operator->() const noexcept
+      {
+	_GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr);
+	return _M_get();
+      }
+
+    private:
+      element_type*
+      _M_get() const noexcept
+      { return static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); }
+    };
+
+  // Define operator-> for shared_ptr<cv void>.
   template<typename _Tp, _Lock_policy _Lp>
-    class __shared_ptr
+    class __shared_ptr_access<_Tp, _Lp, false, true>
     {
     public:
       using element_type = _Tp;
 
+      element_type*
+      operator->() const noexcept
+      {
+	_GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr);
+	return static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get();
+      }
+    };
+
+  // Define operator[] for shared_ptr<T[]> and shared_ptr<T[N]>.
+  template<typename _Tp, _Lock_policy _Lp>
+    class __shared_ptr_access<_Tp, _Lp, true, false>
+    {
+    public:
+      using element_type = typename remove_extent<_Tp>::type;
+
+#if __cplusplus <= 201402L
+      [[__deprecated__("shared_ptr<T[]>::operator* is absent from C++17")]]
+      element_type&
+      operator*() const noexcept
+      {
+	__glibcxx_assert(_M_ptr != nullptr);
+	return *_M_get();
+      }
+
+      [[__deprecated__("shared_ptr<T[]>::operator-> is absent from C++17")]]
+      element_type*
+      operator->() const noexcept
+      {
+	_GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr);
+	return _M_get();
+      }
+#endif
+
+      element_type&
+      operator[](ptrdiff_t __i) const
+      {
+	__glibcxx_assert(_M_get() != nullptr);
+	__glibcxx_assert(!extent<_Tp>::value || __i < extent<_Tp>::value);
+	return _M_get()[__i];
+      }
+
     private:
-      // Trait to check if shared_ptr<T> can be constructed from Y*.
-      template<typename _Tp1, typename _Yp>
-	using __sp_is_constructible = is_convertible<_Yp*, _Tp1*>;
+      element_type*
+      _M_get() const noexcept
+      { return static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); }
+    };
 
+  template<typename _Tp, _Lock_policy _Lp>
+    class __shared_ptr
+    : public __shared_ptr_access<_Tp, _Lp>
+    {
+    public:
+      using element_type = typename remove_extent<_Tp>::type;
+
+    private:
       // Constraint for taking ownership of a pointer of type _Yp*:
       template<typename _Yp>
 	using _SafeConv
@@ -887,9 +1051,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // Constraint for construction from unique_ptr:
       template<typename _Yp, typename _Del, typename _Res = void,
 	       typename _Ptr = typename unique_ptr<_Yp, _Del>::pointer>
-	using _UniqCompatible = typename enable_if<
-	  is_convertible<_Ptr, element_type*>::value
-	  , _Res>::type;
+	using _UniqCompatible = typename enable_if<__and_<
+	  __sp_compatible_with<_Yp*, _Tp*>, is_convertible<_Ptr, element_type*>
+	  >::value, _Res>::type;
 
       // Constraint for assignment from unique_ptr:
       template<typename _Yp, typename _Del>
@@ -908,7 +1072,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Yp, typename = _SafeConv<_Yp>>
 	explicit
 	__shared_ptr(_Yp* __p)
-	: _M_ptr(__p), _M_refcount(__p)
+	: _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type())
 	{
 	  static_assert( !is_void<_Yp>::value, "incomplete type" );
 	  static_assert( sizeof(_Yp) > 0, "incomplete type" );
@@ -994,6 +1158,24 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  _M_enable_shared_from_this_with(__raw);
 	}
 
+#if __cplusplus <= 201402L && _GLIBCXX_USE_DEPRECATED
+    protected:
+      // If an exception is thrown this constructor has no effect.
+      template<typename _Tp1, typename _Del,
+	       typename enable_if<__and_<
+		 __not_<is_array<_Tp>>, is_array<_Tp1>,
+	         is_convertible<typename unique_ptr<_Tp1, _Del>::pointer, _Tp*>
+	       >::value, bool>::type = true>
+	__shared_ptr(unique_ptr<_Tp1, _Del>&& __r, __sp_array_delete)
+	: _M_ptr(__r.get()), _M_refcount()
+	{
+	  auto __raw = _S_raw_ptr(__r.get());
+	  _M_refcount = __shared_count<_Lp>(std::move(__r));
+	  _M_enable_shared_from_this_with(__raw);
+	}
+    public:
+#endif
+
 #if _GLIBCXX_USE_DEPRECATED
       // Postcondition: use_count() == 1 and __r.get() == 0
       template<typename _Yp, typename = _Compatible<_Yp>>
@@ -1067,21 +1249,6 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	reset(_Yp* __p, _Deleter __d, _Alloc __a)
         { __shared_ptr(__p, __d, std::move(__a)).swap(*this); }
 
-      // Allow class instantiation when _Tp is [cv-qual] void.
-      typename std::add_lvalue_reference<element_type>::type
-      operator*() const noexcept
-      {
-	__glibcxx_assert(_M_ptr != 0);
-	return *_M_ptr;
-      }
-
-      element_type*
-      operator->() const noexcept
-      {
-	_GLIBCXX_DEBUG_PEDASSERT(_M_ptr != 0);
-	return _M_ptr;
-      }
-
       element_type*
       get() const noexcept
       { return _M_ptr; }
@@ -1192,7 +1359,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       template<typename _Yp>
 	struct __has_esft_base<_Yp, __void_t<__esft_base_t<_Yp>>>
-	: true_type { };
+	: __not_<is_array<_Tp>> { }; // No enable shared_from_this for arrays
 
       template<typename _Yp>
 	typename enable_if<__has_esft_base<_Yp>::value>::type
@@ -1427,7 +1594,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	using _Assignable = _Compatible<_Yp, __weak_ptr&>;
 
     public:
-      using element_type = _Tp;
+      using element_type = typename remove_extent<_Tp>::type;
 
       constexpr __weak_ptr() noexcept
       : _M_ptr(nullptr), _M_refcount()
diff --git a/libstdc++-v3/include/experimental/bits/shared_ptr.h b/libstdc++-v3/include/experimental/bits/shared_ptr.h
index e8c533e..8a1fc52 100644
--- a/libstdc++-v3/include/experimental/bits/shared_ptr.h
+++ b/libstdc++-v3/include/experimental/bits/shared_ptr.h
@@ -46,665 +46,20 @@  namespace experimental
 inline namespace fundamentals_v2
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
-  template<typename _Tp> class enable_shared_from_this;
-_GLIBCXX_END_NAMESPACE_VERSION
-} // namespace fundamentals_v2
-} // namespace experimental
-
-#define __cpp_lib_experimental_shared_ptr_arrays 201406
-
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
-  /*
-   * The specification of std::experimental::shared_ptr is slightly different
-   * to std::shared_ptr (specifically in terms of "compatible" pointers) so
-   * to implement std::experimental::shared_ptr without too much duplication
-   * we make it derive from a partial specialization of std::__shared_ptr
-   * using a special tag type, __libfund_v1.
-   *
-   * There are two partial specializations for the tag type, supporting the
-   * different interfaces of the array and non-array forms.
-  */
-
-  template <typename _Tp, bool = is_array<_Tp>::value>
-    struct __libfund_v1 { using type = _Tp; };
-
-  // 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>
-    {
-      // 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<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; }
-
-    public:
-      using element_type = _Tp;
-
-      constexpr __shared_ptr() noexcept = default;
-
-      template<typename _Tp1, typename = _Compatible<_Tp1>>
-	explicit
-	__shared_ptr(_Tp1* __p)
-	: _Base_type(__p)
-	{ }
-
-      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,
-	       typename = _Compatible<_Tp1>>
-	__shared_ptr(_Tp1* __p, _Deleter __d, _Alloc __a)
-	: _Base_type(__p, __d, __a)
-	{ }
-
-      template<typename _Deleter>
-	__shared_ptr(nullptr_t __p, _Deleter __d)
-	: _Base_type(__p, __d)
-	{ }
-
-      template<typename _Deleter, typename _Alloc>
-	__shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
-	: _Base_type(__p, __d, __a)
-	{ }
-
-      template<typename _Tp1>
-	__shared_ptr(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r,
-		     element_type* __p) noexcept
-	: _Base_type(__r._M_get_base(), __p)
-	{ }
-
-      __shared_ptr(const __shared_ptr&) noexcept = default;
-      __shared_ptr(__shared_ptr&&) noexcept = default;
-      __shared_ptr& operator=(const __shared_ptr&) noexcept = default;
-      __shared_ptr& operator=(__shared_ptr&&) noexcept = default;
-      ~__shared_ptr() = default;
-
-      template<typename _Tp1, typename = _Compatible<_Tp1>>
-	__shared_ptr(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r) noexcept
-	: _Base_type(__r._M_get_base())
-	{ }
-
-      template<typename _Tp1, typename = _Compatible<_Tp1>>
-	__shared_ptr(__shared_ptr<__libfund_v1<_Tp1>, _Lp>&& __r) noexcept
-	: _Base_type(std::move((__r._M_get_base())))
-	{ }
-
-      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 = _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, typename = _Compatible<_Tp1>>
-	__shared_ptr(std::auto_ptr<_Tp1>&& __r)
-        : _Base_type(std::move(__r))
-	{ }
-#endif
-
-      constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { }
-
-      // reset
-      void
-      reset() noexcept
-      { __shared_ptr(nullptr).swap(*this); }
-
-      template<typename _Tp1>
-	_Compatible<_Tp1>
-	reset(_Tp1* __p)
-	{
-	  _GLIBCXX_DEBUG_ASSERT(__p == 0 || __p != get());
-	  __shared_ptr(__p).swap(*this);
-	}
-
-      template<typename _Tp1, typename _Deleter>
-	_Compatible<_Tp1>
-	reset(_Tp1* __p, _Deleter __d)
-	{ __shared_ptr(__p, __d).swap(*this); }
-
-      template<typename _Tp1, typename _Deleter, typename _Alloc>
-	_Compatible<_Tp1>
-	reset(_Tp1* __p, _Deleter __d, _Alloc __a)
-	{ __shared_ptr(__p, __d, std::move(__a)).swap(*this); }
-
-      using _Base_type::operator*;
-      using _Base_type::operator->;
-
-      template<typename _Tp1>
-	_Compatible<_Tp1, __shared_ptr&>
-	operator=(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r) noexcept
-	{
-	  _Base_type::operator=(__r._M_get_base());
-	  return *this;
-	}
-
-      template<class _Tp1>
-	_Compatible<_Tp1, __shared_ptr&>
-	operator=(__shared_ptr<__libfund_v1<_Tp1>, _Lp>&& __r) noexcept
-	{
-	  _Base_type::operator=(std::move(__r._M_get_base()));
-	  return *this;
-	}
-
-      template<typename _Tp1, typename _Del>
-	_UniqCompatible<_Tp1, _Del, __shared_ptr&>
-	operator=(unique_ptr<_Tp1, _Del>&& __r)
-	{
-	  _Base_type::operator=(std::move(__r));
-	  return *this;
-	}
-
-#if _GLIBCXX_USE_DEPRECATED
-      template<typename _Tp1>
-	_Compatible<_Tp1, __shared_ptr&>
-	operator=(std::auto_ptr<_Tp1>&& __r)
-	{
-	  _Base_type::operator=(std::move(__r));
-	  return *this;
-	}
-#endif
-
-      void
-      swap(__shared_ptr& __other) noexcept
-      { _Base_type::swap(__other); }
-
-      template<typename _Tp1>
-	bool
-	owner_before(__shared_ptr<__libfund_v1<_Tp1>, _Lp> const& __rhs) const
-	{ return _Base_type::owner_before(__rhs._M_get_base()); }
-
-      template<typename _Tp1>
-	bool
-	owner_before(__weak_ptr<__libfund_v1<_Tp1>, _Lp> const& __rhs) const
-	{ return _Base_type::owner_before(__rhs._M_get_base()); }
-
-      using _Base_type::operator bool;
-      using _Base_type::get;
-      using _Base_type::unique;
-      using _Base_type::use_count;
-
-    protected:
-
-      // make_shared not yet support for shared_ptr_arrays
-      //template<typename _Alloc, typename... _Args>
-      //  __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
-      //	             _Args&&... __args)
-      //	: _M_ptr(), _M_refcount(__tag, (_Tp*)0, __a,
-      //	                        std::forward<_Args>(__args)...)
-      //	{
-      //	  void* __p = _M_refcount._M_get_deleter(typeid(__tag));
-      //	  _M_ptr = static_cast<_Tp*>(__p);
-      //	}
-
-      // __weak_ptr::lock()
-      __shared_ptr(const __weak_ptr<__libfund_v1<_Tp>, _Lp>& __r,
-		   std::nothrow_t)
-      : _Base_type(__r._M_get_base(), std::nothrow)
-      { }
-
-    private:
-      template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;
-      template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
-
-      // TODO
-      template<typename _Del, typename _Tp1, _Lock_policy _Lp1>
-	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
-    { };
+  // 8.2.1
 
-  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 _Tp> class shared_ptr;
+  template<typename _Tp> class weak_ptr;
+  template<typename _Tp> class enable_shared_from_this;
 
   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
-    { };
+      = std::__sp_compatible_with<_Yp*, _Tp*>::value;
 
   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>
-    class __shared_ptr<__libfund_v1<_Tp, true>, _Lp>
-    : private __shared_ptr<remove_extent_t<_Tp>, _Lp>
-    {
-    public:
-      using element_type = remove_extent_t<_Tp>;
-
-    private:
-      struct _Array_deleter
-      {
-	void
-	operator()(element_type const *__p) const
-	{ 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_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; }
-
-    public:
-      constexpr __shared_ptr() noexcept
-      : _Base_type()
-      { }
-
-      template<typename _Tp1, typename = _SafeConv<_Tp1>>
-	explicit
-	__shared_ptr(_Tp1* __p)
-	: _Base_type(__p, _Array_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,
-	       typename = _SafeConv<_Tp1>>
-	__shared_ptr(_Tp1* __p, _Deleter __d, _Alloc __a)
-	: _Base_type(__p, __d, __a)
-	{ }
-
-      template<typename _Deleter>
-	__shared_ptr(nullptr_t __p, _Deleter __d)
-	: _Base_type(__p, __d)
-	{ }
-
-      template<typename _Deleter, typename _Alloc>
-	__shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
-	: _Base_type(__p, __d, __a)
-	{ }
-
-      template<typename _Tp1>
-	__shared_ptr(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r,
-		     element_type* __p) noexcept
-	: _Base_type(__r._M_get_base(), __p)
-	{ }
-
-      __shared_ptr(const __shared_ptr&) noexcept = default;
-      __shared_ptr(__shared_ptr&&) noexcept = default;
-      __shared_ptr& operator=(const __shared_ptr&) noexcept = default;
-      __shared_ptr& operator=(__shared_ptr&&) noexcept = default;
-      ~__shared_ptr() = default;
-
-      template<typename _Tp1, typename = _Compatible<_Tp1>>
-	__shared_ptr(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r) noexcept
-	: _Base_type(__r._M_get_base())
-	{ }
-
-      template<typename _Tp1, typename = _Compatible<_Tp1>>
-	__shared_ptr(__shared_ptr<__libfund_v1<_Tp1>, _Lp>&& __r) noexcept
-	: _Base_type(std::move((__r._M_get_base())))
-	{ }
-
-      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 = _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, typename = _Compatible<_Tp1>>
-	__shared_ptr(auto_ptr<_Tp1>&& __r)
-        : _Base_type(std::move(__r))
-	{ }
-#endif
-
-      constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { }
-
-      // reset
-      void
-      reset() noexcept
-      { __shared_ptr(nullptr).swap(*this); }
-
-      template<typename _Tp1>
-	_SafeConv<_Tp1>
-	reset(_Tp1* __p)
-	{
-	  _GLIBCXX_DEBUG_ASSERT(__p == 0 || __p != get());
-	  __shared_ptr(__p, _Array_deleter()).swap(*this);
-	}
-
-      template<typename _Tp1, typename _Deleter>
-	_SafeConv<_Tp1>
-	reset(_Tp1* __p, _Deleter __d)
-	{ __shared_ptr(__p, __d).swap(*this); }
-
-      template<typename _Tp1, typename _Deleter, typename _Alloc>
-	_SafeConv<_Tp1>
-	reset(_Tp1* __p, _Deleter __d, _Alloc __a)
-	{ __shared_ptr(__p, __d, std::move(__a)).swap(*this); }
-
-      element_type&
-      operator[](ptrdiff_t i) const noexcept
-      {
-	_GLIBCXX_DEBUG_ASSERT(get() != 0 && i >= 0);
-	return get()[i];
-      }
-
-      template<typename _Tp1>
-	_Compatible<_Tp1, __shared_ptr&>
-	operator=(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r) noexcept
-	{
-	  _Base_type::operator=(__r._M_get_base());
-	  return *this;
-	}
-
-      template<class _Tp1>
-	_Compatible<_Tp1, __shared_ptr&>
-	operator=(__shared_ptr<__libfund_v1<_Tp1>, _Lp>&& __r) noexcept
-	{
-	  _Base_type::operator=(std::move(__r._M_get_base()));
-	  return *this;
-	}
-
-      template<typename _Tp1, typename _Del>
-	_UniqCompatible<_Tp1, _Del, __shared_ptr&>
-	operator=(unique_ptr<_Tp1, _Del>&& __r)
-	{
-	  _Base_type::operator=(std::move(__r));
-	  return *this;
-	}
-
-#if _GLIBCXX_USE_DEPRECATED
-      template<typename _Tp1>
-	_Compatible<_Tp1, __shared_ptr&>
-	operator=(auto_ptr<_Tp1>&& __r)
-	{
-	  _Base_type::operator=(std::move(__r));
-	  return *this;
-	}
-#endif
-
-      void
-      swap(__shared_ptr& __other) noexcept
-      { _Base_type::swap(__other); }
-
-      template<typename _Tp1>
-	bool
-	owner_before(__shared_ptr<__libfund_v1<_Tp1>, _Lp> const& __rhs) const
-	{ return _Base_type::owner_before(__rhs._M_get_base()); }
-
-      template<typename _Tp1>
-	bool
-	owner_before(__weak_ptr<__libfund_v1<_Tp1>, _Lp> const& __rhs) const
-	{ return _Base_type::owner_before(__rhs._M_get_base()); }
-
-      using _Base_type::operator bool;
-      using _Base_type::get;
-      using _Base_type::unique;
-      using _Base_type::use_count;
-
-    protected:
-
-      // make_shared not yet support for shared_ptr_arrays
-      //template<typename _Alloc, typename... _Args>
-      //  __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
-      //	             _Args&&... __args)
-      //	: _M_ptr(), _M_refcount(__tag, (_Tp*)0, __a,
-      //	                        std::forward<_Args>(__args)...)
-      //	{
-      //	  void* __p = _M_refcount._M_get_deleter(typeid(__tag));
-      //	  _M_ptr = static_cast<_Tp*>(__p);
-      //	}
-
-      // __weak_ptr::lock()
-      __shared_ptr(const __weak_ptr<__libfund_v1<_Tp>, _Lp>& __r,
-		   std::nothrow_t)
-      : _Base_type(__r._M_get_base(), std::nothrow)
-      { }
-
-    private:
-      template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;
-      template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
-
-      // TODO
-      template<typename _Del, typename _Tp1, _Lock_policy _Lp1>
-	friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&) noexcept;
-    };
-
-  // weak_ptr specialization for __shared_ptr array
-  template<typename _Tp, _Lock_policy _Lp>
-    class __weak_ptr<__libfund_v1<_Tp>, _Lp>
-    : __weak_ptr<remove_extent_t<_Tp>, _Lp>
-    {
-      template<typename _Tp1, typename _Res = void>
-	using _Compatible
-	  = 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; }
-      const _Base_type&  _M_get_base() const { return *this; }
-
-    public:
-      using element_type = remove_extent_t<_Tp>;
-
-      constexpr __weak_ptr() noexcept
-      : _Base_type()
-      { }
-
-      __weak_ptr(const __weak_ptr&) noexcept = default;
-
-      ~__weak_ptr() = default;
-
-      template<typename _Tp1, typename = _Compatible<_Tp1>>
-	__weak_ptr(const __weak_ptr<__libfund_v1<_Tp1>, _Lp>& __r) noexcept
-	: _Base_type(__r._M_get_base())
-	{ }
-
-      template<typename _Tp1, typename = _Compatible<_Tp1>>
-	__weak_ptr(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r) noexcept
-	: _Base_type(__r._M_get_base())
-	{ }
-
-      __weak_ptr(__weak_ptr&& __r) noexcept
-      : _Base_type(std::move(__r))
-      { }
-
-      template<typename _Tp1, typename = _Compatible<_Tp1>>
-	__weak_ptr(__weak_ptr<__libfund_v1<_Tp1>, _Lp>&& __r) noexcept
-	: _Base_type(std::move(__r._M_get_base()))
-	{ }
-
-      __weak_ptr&
-      operator=(const __weak_ptr& __r) noexcept = default;
-
-      template<typename _Tp1>
-	_Compatible<_Tp1, __weak_ptr&>
-	operator=(const __weak_ptr<__libfund_v1<_Tp1>, _Lp>& __r) noexcept
-	{
-	  this->_Base_type::operator=(__r._M_get_base());
-	  return *this;
-	}
-
-      template<typename _Tp1>
-	_Compatible<_Tp1, __weak_ptr&>
-	operator=(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
-	{
-	  this->_Base_type::operator=(__r._M_get_base());
-	  return *this;
-	}
-
-      __weak_ptr&
-      operator=(__weak_ptr&& __r) noexcept
-      {
-	this->_Base_type::operator=(std::move(__r));
-	return *this;
-      }
-
-      template<typename _Tp1>
-	_Compatible<_Tp1, __weak_ptr&>
-	operator=(__weak_ptr<_Tp1, _Lp>&& __r) noexcept
-	{
-	  this->_Base_type::operator=(std::move(__r._M_get_base()));
-	  return *this;
-	}
-
-      void
-      swap(__weak_ptr& __other) noexcept
-      { this->_Base_type::swap(__other); }
-
-      template<typename _Tp1>
-	bool
-	owner_before(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __rhs) const
-	{ return _Base_type::owner_before(__rhs._M_get_base()); }
-
-      template<typename _Tp1>
-	bool
-	owner_before(const __weak_ptr<__libfund_v1<_Tp1>, _Lp>& __rhs) const
-	{ return _Base_type::owner_before(__rhs._M_get_base()); }
-
-      __shared_ptr<__libfund_v1<_Tp>, _Lp>
-      lock() const noexcept  // should not be element_type
-      { return __shared_ptr<__libfund_v1<_Tp>, _Lp>(*this, std::nothrow); }
-
-      using _Base_type::use_count;
-      using _Base_type::expired;
-      using _Base_type::reset;
-
-    private:
-      // Used by __enable_shared_from_this.
-      void
-      _M_assign(element_type* __ptr,
-		const __shared_count<_Lp>& __refcount) noexcept
-      { this->_Base_type::_M_assign(__ptr, __refcount); }
-
-      template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
-      template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;
-      friend class __enable_shared_from_this<_Tp, _Lp>;
-      friend class experimental::enable_shared_from_this<_Tp>;
-      friend class enable_shared_from_this<_Tp>;
-    };
-
-_GLIBCXX_END_NAMESPACE_VERSION
-
-namespace experimental
-{
-inline namespace fundamentals_v2
-{
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
-    // 8.2.1
-
-  template<typename _Tp> class shared_ptr;
-  template<typename _Tp> class weak_ptr;
-
-  template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
-    using __shared_ptr = std::__shared_ptr<__libfund_v1<_Tp>, _Lp>;
-
-  template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
-    using __weak_ptr = std::__weak_ptr<__libfund_v1<_Tp>, _Lp>;
+      = std::__sp_is_constructible<_Tp, _Yp>::value;
 
   template<typename _Tp>
     class shared_ptr : public __shared_ptr<_Tp>
@@ -1128,16 +483,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { __a.swap(__b); }
 
   /// C++14 ??20.8.2.2.10
-  template<typename _Del, typename _Tp, _Lock_policy _Lp>
+  template<typename _Del, typename _Tp>
     inline _Del*
-    get_deleter(const __shared_ptr<_Tp, _Lp>& __p) noexcept
+    get_deleter(const shared_ptr<_Tp>& __p) noexcept
     { return std::get_deleter<_Del>(__p); }
 
   // C++14 ??20.8.2.2.11
-  template<typename _Ch, typename _Tr, typename _Tp, _Lock_policy _Lp>
+  template<typename _Ch, typename _Tr, typename _Tp>
     inline std::basic_ostream<_Ch, _Tr>&
-    operator<<(std::basic_ostream<_Ch, _Tr>& __os,
-	       const __shared_ptr<_Tp, _Lp>& __p)
+    operator<<(std::basic_ostream<_Ch, _Tr>& __os, const shared_ptr<_Tp>& __p)
     {
       __os << __p.get();
       return __os;
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
index 72eed47..bc1fcf1 100644
--- 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
@@ -22,6 +22,13 @@ 
 #include <memory>
 #include <testsuite_hooks.h>
 
+#if __cpp_lib_shared_ptr_arrays >= 201603
+# define SHARED_PTR_ARRAYS
+#endif
+#if __cpp_lib_enable_shared_from_this >= 201603
+# define WEAK_FROM_THIS
+#endif
+
 int destroyed = 0;
 
 struct A : std::enable_shared_from_this<A>
@@ -36,12 +43,22 @@  int
 test01()
 {
   std::unique_ptr<A[]> up(new A[2]);
+#ifdef SHARED_PTR_ARRAYS
+  std::shared_ptr<A[]> sp(std::move(up));
+#else
   std::shared_ptr<A> sp(std::move(up));
+#endif
   VERIFY( up.get() == 0 );
   VERIFY( sp.get() != 0 );
   VERIFY( sp.use_count() == 1 );
 
+#ifdef SHARED_PTR_ARRAYS
+# ifdef WEAK_FROM_THIS
+  VERIFY( sp[0].weak_from_this().expired() );
+# endif
+#else
   VERIFY( sp->shared_from_this() != nullptr );
+#endif
 
   sp.reset();
   VERIFY( destroyed == 2 );