[libcxx] r303874 - Add support for shared_ptr<FunctionType>

Erik Pilkington via cfe-commits cfe-commits at lists.llvm.org
Thu May 25 08:43:31 PDT 2017


Author: epilk
Date: Thu May 25 10:43:31 2017
New Revision: 303874

URL: http://llvm.org/viewvc/llvm-project?rev=303874&view=rev
Log:
Add support for shared_ptr<FunctionType>

Fixes PR27566.

Differential revision: https://reviews.llvm.org/D30837

Added:
    libcxx/trunk/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/
    libcxx/trunk/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/function_type_default_deleter.fail.cpp
Modified:
    libcxx/trunk/include/memory
    libcxx/trunk/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.pass.cpp

Modified: libcxx/trunk/include/memory
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/memory?rev=303874&r1=303873&r2=303874&view=diff
==============================================================================
--- libcxx/trunk/include/memory (original)
+++ libcxx/trunk/include/memory Thu May 25 10:43:31 2017
@@ -2251,6 +2251,8 @@ void swap(__compressed_pair<_T1, _T2>& _
 
 template <class _Tp>
 struct _LIBCPP_TEMPLATE_VIS default_delete {
+    static_assert(!is_function<_Tp>::value,
+                  "default_delete cannot be instantiated for function types");
 #ifndef _LIBCPP_CXX03_LANG
   _LIBCPP_INLINE_VISIBILITY constexpr default_delete() noexcept = default;
 #else
@@ -3653,6 +3655,18 @@ __shared_ptr_emplace<_Tp, _Alloc>::__on_
     __a.deallocate(_PTraits::pointer_to(*this), 1);
 }
 
+struct __shared_ptr_dummy_rebind_allocator_type;
+template <>
+class _LIBCPP_TEMPLATE_VIS allocator<__shared_ptr_dummy_rebind_allocator_type>
+{
+public:
+    template <class _Other>
+    struct rebind
+    {
+        typedef allocator<_Other> other;
+    };
+};
+
 template<class _Tp> class _LIBCPP_TEMPLATE_VIS enable_shared_from_this;
 
 template<class _Tp>
@@ -3921,6 +3935,17 @@ public:
 #endif  // _LIBCPP_HAS_NO_VARIADICS
 
 private:
+    template <class _Yp, bool = is_function<_Yp>::value>
+        struct __shared_ptr_default_allocator
+        {
+            typedef allocator<_Yp> type;
+        };
+
+    template <class _Yp>
+        struct __shared_ptr_default_allocator<_Yp, true>
+        {
+            typedef allocator<__shared_ptr_dummy_rebind_allocator_type> type;
+        };
 
     template <class _Yp, class _OrigPtr>
         _LIBCPP_INLINE_VISIBILITY
@@ -3939,8 +3964,7 @@ private:
             }
         }
 
-    _LIBCPP_INLINE_VISIBILITY
-    void __enable_weak_this(const volatile void*, const volatile void*) _NOEXCEPT {}
+    _LIBCPP_INLINE_VISIBILITY void __enable_weak_this(...) _NOEXCEPT {}
 
     template <class _Up> friend class _LIBCPP_TEMPLATE_VIS shared_ptr;
     template <class _Up> friend class _LIBCPP_TEMPLATE_VIS weak_ptr;
@@ -3972,8 +3996,9 @@ shared_ptr<_Tp>::shared_ptr(_Yp* __p,
     : __ptr_(__p)
 {
     unique_ptr<_Yp> __hold(__p);
-    typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, allocator<_Yp> > _CntrlBlk;
-    __cntrl_ = new _CntrlBlk(__p, default_delete<_Yp>(), allocator<_Yp>());
+    typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT;
+    typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, _AllocT > _CntrlBlk;
+    __cntrl_ = new _CntrlBlk(__p, default_delete<_Yp>(), _AllocT());
     __hold.release();
     __enable_weak_this(__p, __p);
 }
@@ -3988,8 +4013,9 @@ shared_ptr<_Tp>::shared_ptr(_Yp* __p, _D
     try
     {
 #endif  // _LIBCPP_NO_EXCEPTIONS
-        typedef __shared_ptr_pointer<_Yp*, _Dp, allocator<_Yp> > _CntrlBlk;
-        __cntrl_ = new _CntrlBlk(__p, __d, allocator<_Yp>());
+        typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT;
+        typedef __shared_ptr_pointer<_Yp*, _Dp, _AllocT > _CntrlBlk;
+        __cntrl_ = new _CntrlBlk(__p, __d, _AllocT());
         __enable_weak_this(__p, __p);
 #ifndef _LIBCPP_NO_EXCEPTIONS
     }
@@ -4010,8 +4036,9 @@ shared_ptr<_Tp>::shared_ptr(nullptr_t __
     try
     {
 #endif  // _LIBCPP_NO_EXCEPTIONS
-        typedef __shared_ptr_pointer<nullptr_t, _Dp, allocator<_Tp> > _CntrlBlk;
-        __cntrl_ = new _CntrlBlk(__p, __d, allocator<_Tp>());
+        typedef typename __shared_ptr_default_allocator<_Tp>::type _AllocT;
+        typedef __shared_ptr_pointer<nullptr_t, _Dp, _AllocT > _CntrlBlk;
+        __cntrl_ = new _CntrlBlk(__p, __d, _AllocT());
 #ifndef _LIBCPP_NO_EXCEPTIONS
     }
     catch (...)
@@ -4179,8 +4206,9 @@ shared_ptr<_Tp>::shared_ptr(unique_ptr<_
     else
 #endif
     {
-        typedef __shared_ptr_pointer<_Yp*, _Dp, allocator<_Yp> > _CntrlBlk;
-        __cntrl_ = new _CntrlBlk(__r.get(), __r.get_deleter(), allocator<_Yp>());
+        typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT;
+        typedef __shared_ptr_pointer<_Yp*, _Dp, _AllocT > _CntrlBlk;
+        __cntrl_ = new _CntrlBlk(__r.get(), __r.get_deleter(), _AllocT());
         __enable_weak_this(__r.get(), __r.get());
     }
     __r.release();
@@ -4208,10 +4236,11 @@ shared_ptr<_Tp>::shared_ptr(unique_ptr<_
     else
 #endif
     {
+        typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT;
         typedef __shared_ptr_pointer<_Yp*,
                                      reference_wrapper<typename remove_reference<_Dp>::type>,
-                                     allocator<_Yp> > _CntrlBlk;
-        __cntrl_ = new _CntrlBlk(__r.get(), ref(__r.get_deleter()), allocator<_Yp>());
+                                     _AllocT > _CntrlBlk;
+        __cntrl_ = new _CntrlBlk(__r.get(), ref(__r.get_deleter()), _AllocT());
         __enable_weak_this(__r.get(), __r.get());
     }
     __r.release();

Added: libcxx/trunk/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/function_type_default_deleter.fail.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/function_type_default_deleter.fail.cpp?rev=303874&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/function_type_default_deleter.fail.cpp (added)
+++ libcxx/trunk/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/function_type_default_deleter.fail.cpp Thu May 25 10:43:31 2017
@@ -0,0 +1,40 @@
+#include <memory>
+
+template <int> struct Tag {};
+
+template <int ID>
+using SPtr = std::shared_ptr<void(Tag<ID>)>;
+
+template <int ID>
+using FnType = void(Tag<ID>);
+
+template <int ID>
+void TestFn(Tag<ID>) {}
+
+template <int ID>
+FnType<ID>* getFn() {
+  return &TestFn<ID>;
+}
+
+struct Deleter {
+  template <class Tp>
+  void operator()(Tp) const {
+    using RawT = typename std::remove_pointer<Tp>::type;
+    static_assert(std::is_function<RawT>::value ||
+                  std::is_null_pointer<RawT>::value, "");
+  }
+};
+
+int main() {
+  {
+    SPtr<0> s; // OK
+    SPtr<1> s1(nullptr); // OK
+    SPtr<2> s2(getFn<2>(), Deleter{}); // OK
+    SPtr<3> s3(nullptr, Deleter{}); // OK
+  }
+  // expected-error at memory:* 2 {{static_assert failed "default_delete cannot be instantiated for function types"}}
+  {
+    SPtr<4> s4(getFn<4>()); // expected-note {{requested here}}
+    SPtr<5> s5(getFn<5>(), std::default_delete<FnType<5>>{}); // expected-note {{requested here}}
+  }
+}

Modified: libcxx/trunk/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.pass.cpp?rev=303874&r1=303873&r2=303874&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.pass.cpp Thu May 25 10:43:31 2017
@@ -45,6 +45,13 @@ struct Foo
     virtual ~Foo() = default;
 };
 
+struct Result {};
+static Result theFunction() { return Result(); }
+static int resultDeletorCount;
+static void resultDeletor(Result (*pf)()) {
+  assert(pf == theFunction);
+  ++resultDeletorCount;
+}
 
 int main()
 {
@@ -65,7 +72,11 @@ int main()
     std::shared_ptr<const Foo> p2 = std::make_shared<const Foo>();
     assert(p2.get());
     }
-
+    { // https://bugs.llvm.org/show_bug.cgi?id=27566
+      std::shared_ptr<Result()> x(&theFunction, &resultDeletor);
+      std::shared_ptr<Result()> y(theFunction, resultDeletor);
+    }
+    assert(resultDeletorCount == 2);
 #if TEST_STD_VER >= 11
     nc = globalMemCounter.outstanding_new;
     {




More information about the cfe-commits mailing list