Fix std::function allocator constructors in C++03.
authorEric Fiselier <eric@efcs.ca>
Sun, 14 Jun 2015 23:30:09 +0000 (23:30 +0000)
committerEric Fiselier <eric@efcs.ca>
Sun, 14 Jun 2015 23:30:09 +0000 (23:30 +0000)
The C++03 version of function tried to default construct the allocator
in the uses allocator constructors when no allocation was performed. These
constructors would fail to compile when used with allocators that had no
default constructor.

llvm-svn: 239708

libcxx/include/__functional_03
libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp
libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_function.pass.cpp
libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/function_types.h [new file with mode: 0644]
libcxx/test/support/test_allocator.h

index f048ea3..9935483 100644 (file)
@@ -333,7 +333,8 @@ template<class _Fp, class _Alloc, class _Rp>
 __base<_Rp()>*
 __func<_Fp, _Alloc, _Rp()>::__clone() const
 {
-    typedef typename _Alloc::template rebind<__func>::other _Ap;
+    typedef allocator_traits<_Alloc> __alloc_traits;
+    typedef typename __rebind_alloc_helper<__alloc_traits, __func>::type _Ap;
     _Ap __a(__f_.second());
     typedef __allocator_destructor<_Ap> _Dp;
     unique_ptr<__func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1));
@@ -359,7 +360,8 @@ template<class _Fp, class _Alloc, class _Rp>
 void
 __func<_Fp, _Alloc, _Rp()>::destroy_deallocate()
 {
-    typedef typename _Alloc::template rebind<__func>::other _Ap;
+    typedef allocator_traits<_Alloc> __alloc_traits;
+    typedef typename __rebind_alloc_helper<__alloc_traits, __func>::type _Ap;
     _Ap __a(__f_.second());
     __f_.~__compressed_pair<_Fp, _Alloc>();
     __a.deallocate(this, 1);
@@ -417,7 +419,8 @@ template<class _Fp, class _Alloc, class _Rp, class _A0>
 __base<_Rp(_A0)>*
 __func<_Fp, _Alloc, _Rp(_A0)>::__clone() const
 {
-    typedef typename _Alloc::template rebind<__func>::other _Ap;
+    typedef allocator_traits<_Alloc> __alloc_traits;
+    typedef typename __rebind_alloc_helper<__alloc_traits, __func>::type _Ap;
     _Ap __a(__f_.second());
     typedef __allocator_destructor<_Ap> _Dp;
     unique_ptr<__func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1));
@@ -443,7 +446,8 @@ template<class _Fp, class _Alloc, class _Rp, class _A0>
 void
 __func<_Fp, _Alloc, _Rp(_A0)>::destroy_deallocate()
 {
-    typedef typename _Alloc::template rebind<__func>::other _Ap;
+    typedef allocator_traits<_Alloc> __alloc_traits;
+    typedef typename __rebind_alloc_helper<__alloc_traits, __func>::type _Ap;
     _Ap __a(__f_.second());
     __f_.~__compressed_pair<_Fp, _Alloc>();
     __a.deallocate(this, 1);
@@ -501,7 +505,8 @@ template<class _Fp, class _Alloc, class _Rp, class _A0, class _A1>
 __base<_Rp(_A0, _A1)>*
 __func<_Fp, _Alloc, _Rp(_A0, _A1)>::__clone() const
 {
-    typedef typename _Alloc::template rebind<__func>::other _Ap;
+    typedef allocator_traits<_Alloc> __alloc_traits;
+    typedef typename __rebind_alloc_helper<__alloc_traits, __func>::type _Ap;
     _Ap __a(__f_.second());
     typedef __allocator_destructor<_Ap> _Dp;
     unique_ptr<__func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1));
@@ -527,7 +532,8 @@ template<class _Fp, class _Alloc, class _Rp, class _A0, class _A1>
 void
 __func<_Fp, _Alloc, _Rp(_A0, _A1)>::destroy_deallocate()
 {
-    typedef typename _Alloc::template rebind<__func>::other _Ap;
+    typedef allocator_traits<_Alloc> __alloc_traits;
+    typedef typename __rebind_alloc_helper<__alloc_traits, __func>::type _Ap;
     _Ap __a(__f_.second());
     __f_.~__compressed_pair<_Fp, _Alloc>();
     __a.deallocate(this, 1);
@@ -585,7 +591,8 @@ template<class _Fp, class _Alloc, class _Rp, class _A0, class _A1, class _A2>
 __base<_Rp(_A0, _A1, _A2)>*
 __func<_Fp, _Alloc, _Rp(_A0, _A1, _A2)>::__clone() const
 {
-    typedef typename _Alloc::template rebind<__func>::other _Ap;
+    typedef allocator_traits<_Alloc> __alloc_traits;
+    typedef typename __rebind_alloc_helper<__alloc_traits, __func>::type _Ap;
     _Ap __a(__f_.second());
     typedef __allocator_destructor<_Ap> _Dp;
     unique_ptr<__func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1));
@@ -611,7 +618,8 @@ template<class _Fp, class _Alloc, class _Rp, class _A0, class _A1, class _A2>
 void
 __func<_Fp, _Alloc, _Rp(_A0, _A1, _A2)>::destroy_deallocate()
 {
-    typedef typename _Alloc::template rebind<__func>::other _Ap;
+    typedef allocator_traits<_Alloc> __alloc_traits;
+    typedef typename __rebind_alloc_helper<__alloc_traits, __func>::type _Ap;
     _Ap __a(__f_.second());
     __f_.~__compressed_pair<_Fp, _Alloc>();
     __a.deallocate(this, 1);
@@ -794,7 +802,7 @@ function<_Rp()>::function(allocator_arg_t, const _Alloc& __a0, _Fp __f,
         if (sizeof(_FF) <= sizeof(__buf_))
         {
             __f_ = (__base*)&__buf_;
-            ::new (__f_) _FF(__f);
+            ::new (__f_) _FF(__f, __a0);
         }
         else
         {
@@ -1091,7 +1099,7 @@ function<_Rp(_A0)>::function(allocator_arg_t, const _Alloc& __a0, _Fp __f,
         if (sizeof(_FF) <= sizeof(__buf_))
         {
             __f_ = (__base*)&__buf_;
-            ::new (__f_) _FF(__f);
+            ::new (__f_) _FF(__f, __a0);
         }
         else
         {
@@ -1388,7 +1396,7 @@ function<_Rp(_A0, _A1)>::function(allocator_arg_t, const _Alloc& __a0, _Fp __f,
         if (sizeof(_FF) <= sizeof(__buf_))
         {
             __f_ = (__base*)&__buf_;
-            ::new (__f_) _FF(__f);
+            ::new (__f_) _FF(__f, __a0);
         }
         else
         {
@@ -1685,7 +1693,7 @@ function<_Rp(_A0, _A1, _A2)>::function(allocator_arg_t, const _Alloc& __a0, _Fp
         if (sizeof(_FF) <= sizeof(__buf_))
         {
             __f_ = (__base*)&__buf_;
-            ::new (__f_) _FF(__f);
+            ::new (__f_) _FF(__f, __a0);
         }
         else
         {
index 741a3b9..352ecfc 100644 (file)
 #include <cassert>
 
 #include "min_allocator.h"
+#include "test_allocator.h"
+#include "count_new.hpp"
+#include "../function_types.h"
 
-class A
-{
-    int data_[10];
-public:
-    static int count;
+class DummyClass {};
 
-    A()
+template <class FuncType, class AllocType>
+void test_FunctionObject(AllocType& alloc)
+{
+    assert(globalMemCounter.checkOutstandingNewEq(0));
     {
-        ++count;
-        for (int i = 0; i < 10; ++i)
-            data_[i] = i;
+    FunctionObject target;
+    assert(FunctionObject::count == 1);
+    assert(globalMemCounter.checkOutstandingNewEq(0));
+    std::function<FuncType> f2(std::allocator_arg, alloc, target);
+    assert(FunctionObject::count == 2);
+    assert(globalMemCounter.checkOutstandingNewEq(1));
+    assert(f2.template target<FunctionObject>());
+    assert(f2.template target<FuncType>() == 0);
+    assert(f2.template target<FuncType*>() == 0);
     }
+    assert(FunctionObject::count == 0);
+    assert(globalMemCounter.checkOutstandingNewEq(0));
+}
 
-    A(const A&) {++count;}
-
-    ~A() {--count;}
 
-    int operator()(int i) const
+template <class FuncType, class AllocType>
+void test_FreeFunction(AllocType& alloc)
+{
+    assert(globalMemCounter.checkOutstandingNewEq(0));
     {
-        for (int j = 0; j < 10; ++j)
-            i += data_[j];
-        return i;
+    FuncType* target = &FreeFunction;
+    assert(globalMemCounter.checkOutstandingNewEq(0));
+    std::function<FuncType> f2(std::allocator_arg, alloc, target);
+    assert(globalMemCounter.checkOutstandingNewEq(0));
+    assert(f2.template target<FuncType*>());
+    assert(*f2.template target<FuncType*>() == target);
+    assert(f2.template target<FuncType>() == 0);
+    assert(f2.template target<DummyClass>() == 0);
     }
+    assert(globalMemCounter.checkOutstandingNewEq(0));
+}
 
-    int foo(int) const {return 1;}
-};
+template <class TargetType, class FuncType, class AllocType>
+void test_MemFunClass(AllocType& alloc)
+{
+    assert(globalMemCounter.checkOutstandingNewEq(0));
+    {
+    TargetType target = &MemFunClass::foo;
+    assert(globalMemCounter.checkOutstandingNewEq(0));
+    std::function<FuncType> f2(std::allocator_arg, alloc, target);
+    assert(globalMemCounter.checkOutstandingNewEq(0));
+    assert(f2.template target<TargetType>());
+    assert(*f2.template target<TargetType>() == target);
+    assert(f2.template target<FuncType*>() == 0);
+    }
+    assert(globalMemCounter.checkOutstandingNewEq(0));
+}
 
-int A::count = 0;
+template <class Alloc>
+void test_for_alloc(Alloc& alloc) {
+    test_FunctionObject<int()>(alloc);
+    test_FunctionObject<int(int)>(alloc);
+    test_FunctionObject<int(int, int)>(alloc);
+    test_FunctionObject<int(int, int, int)>(alloc);
 
-int g(int) {return 0;}
+    test_FreeFunction<int()>(alloc);
+    test_FreeFunction<int(int)>(alloc);
+    test_FreeFunction<int(int, int)>(alloc);
+    test_FreeFunction<int(int, int, int)>(alloc);
 
-class Foo {
-public:
-  void bar(int k) { }
-};
+    test_MemFunClass<int(MemFunClass::*)() const, int(MemFunClass&)>(alloc);
+    test_MemFunClass<int(MemFunClass::*)(int) const, int(MemFunClass&, int)>(alloc);
+    test_MemFunClass<int(MemFunClass::*)(int, int) const, int(MemFunClass&, int, int)>(alloc);
+}
 
 int main()
 {
     {
-    std::function<int(int)> f(std::allocator_arg, bare_allocator<A>(), A());
-    assert(A::count == 1);
-    assert(f.target<A>());
-    assert(f.target<int(*)(int)>() == 0);
-    }
-    assert(A::count == 0);
-    {
-    std::function<int(int)> f(std::allocator_arg, bare_allocator<int(*)(int)>(), g);
-    assert(f.target<int(*)(int)>());
-    assert(f.target<A>() == 0);
-    }
-    {
-    std::function<int(int)> f(std::allocator_arg, bare_allocator<int(*)(int)>(),
-                              (int (*)(int))0);
-    assert(!f);
-    assert(f.target<int(*)(int)>() == 0);
-    assert(f.target<A>() == 0);
-    }
-    {
-    std::function<int(const A*, int)> f(std::allocator_arg,
-                                        bare_allocator<int(A::*)(int)const>(),
-                                        &A::foo);
-    assert(f);
-    assert(f.target<int (A::*)(int) const>() != 0);
-    }
-#if __cplusplus >= 201103L
-    {
-    Foo f;
-    std::function<void(int)> fun = std::bind(&Foo::bar, &f, std::placeholders::_1);
-    fun(10);
+        bare_allocator<DummyClass> bare_alloc;
+        test_for_alloc(bare_alloc);
     }
-#endif
     {
-    std::function<void(int)> fun(std::allocator_arg,
-                                 bare_allocator<int(*)(int)>(),
-                                 &g);
-    assert(fun);
-    assert(fun.target<int(*)(int)>() != 0);
-    fun(10);
+        non_default_test_allocator<DummyClass> non_default_alloc(42);
+        test_for_alloc(non_default_alloc);
     }
 }
index e89636a..371eb98 100644 (file)
 #include "min_allocator.h"
 #include "test_allocator.h"
 #include "count_new.hpp"
+#include "../function_types.h"
 
-class A
-{
-    int data_[10];
-public:
-    static int count;
-
-    A()
-    {
-        ++count;
-        for (int i = 0; i < 10; ++i)
-            data_[i] = i;
-    }
-
-    A(const A&) {++count;}
-
-    ~A() {--count;}
-
-    int operator()(int i) const
-    {
-        for (int j = 0; j < 10; ++j)
-            i += data_[j];
-        return i;
-    }
-};
-
-int A::count = 0;
+class DummyClass {};
 
-int g(int) {return 0;}
-
-int main()
+template <class FuncType, class AllocType>
+void test_FunctionObject(AllocType& alloc)
 {
     assert(globalMemCounter.checkOutstandingNewEq(0));
     {
-    std::function<int(int)> f = A();
-    assert(A::count == 1);
+    // Construct function from FunctionObject.
+    std::function<FuncType> f = FunctionObject();
+    assert(FunctionObject::count == 1);
     assert(globalMemCounter.checkOutstandingNewEq(1));
-    assert(f.target<A>());
-    assert(f.target<int(*)(int)>() == 0);
-    std::function<int(int)> f2(std::allocator_arg, bare_allocator<A>(), f);
-    assert(A::count == 2);
+    assert(f.template target<FunctionObject>());
+    assert(f.template target<FuncType>() == 0);
+    assert(f.template target<FuncType*>() == 0);
+    // Copy function with allocator
+    std::function<FuncType> f2(std::allocator_arg, alloc, f);
+    assert(FunctionObject::count == 2);
     assert(globalMemCounter.checkOutstandingNewEq(2));
-    assert(f2.target<A>());
-    assert(f2.target<int(*)(int)>() == 0);
+    assert(f2.template target<FunctionObject>());
+    assert(f2.template target<FuncType>() == 0);
+    assert(f2.template target<FuncType*>() == 0);
     }
-    assert(A::count == 0);
+    assert(FunctionObject::count == 0);
     assert(globalMemCounter.checkOutstandingNewEq(0));
-    {
-    std::function<int(int)> f = g;
-    assert(globalMemCounter.checkOutstandingNewEq(0));
-    assert(f.target<int(*)(int)>());
-    assert(f.target<A>() == 0);
-    std::function<int(int)> f2(std::allocator_arg, bare_allocator<int(*)(int)>(), f);
-    assert(globalMemCounter.checkOutstandingNewEq(0));
-    assert(f2.target<int(*)(int)>());
-    assert(f2.target<A>() == 0);
-    }
+}
+
+template <class FuncType, class AllocType>
+void test_FreeFunction(AllocType& alloc)
+{
     assert(globalMemCounter.checkOutstandingNewEq(0));
     {
+    // Construct function from function pointer.
+    FuncType* target = &FreeFunction;
+    std::function<FuncType> f = target;
     assert(globalMemCounter.checkOutstandingNewEq(0));
-    non_default_test_allocator<std::function<int(int)> > al(1);
-    std::function<int(int)> f2(std::allocator_arg, al, g);
+    assert(f.template target<FuncType*>());
+    assert(*f.template target<FuncType*>() == target);
+    assert(f.template target<FuncType>() == 0);
+    // Copy function with allocator
+    std::function<FuncType> f2(std::allocator_arg, alloc, f);
     assert(globalMemCounter.checkOutstandingNewEq(0));
-    assert(f2.target<int(*)(int)>());
-    assert(f2.target<A>() == 0);
+    assert(f2.template target<FuncType*>());
+    assert(*f2.template target<FuncType*>() == target);
+    assert(f2.template target<FuncType>() == 0);
     }
     assert(globalMemCounter.checkOutstandingNewEq(0));
+}
+
+template <class TargetType, class FuncType, class AllocType>
+void test_MemFunClass(AllocType& alloc)
+{
+    assert(globalMemCounter.checkOutstandingNewEq(0));
     {
-    std::function<int(int)> f;
+    // Construct function from function pointer.
+    TargetType target = &MemFunClass::foo;
+    std::function<FuncType> f = target;
     assert(globalMemCounter.checkOutstandingNewEq(0));
-    assert(f.target<int(*)(int)>() == 0);
-    assert(f.target<A>() == 0);
-    std::function<int(int)> f2(std::allocator_arg, bare_allocator<int>(), f);
+    assert(f.template target<TargetType>());
+    assert(*f.template target<TargetType>() == target);
+    assert(f.template target<FuncType*>() == 0);
+    // Copy function with allocator
+    std::function<FuncType> f2(std::allocator_arg, alloc, f);
     assert(globalMemCounter.checkOutstandingNewEq(0));
-    assert(f2.target<int(*)(int)>() == 0);
-    assert(f2.target<A>() == 0);
+    assert(f2.template target<TargetType>());
+    assert(*f2.template target<TargetType>() == target);
+    assert(f2.template target<FuncType*>() == 0);
     }
+    assert(globalMemCounter.checkOutstandingNewEq(0));
+}
+
+template <class Alloc>
+void test_for_alloc(Alloc& alloc)
+{
+    // Large FunctionObject -- Allocation should occur
+    test_FunctionObject<int()>(alloc);
+    test_FunctionObject<int(int)>(alloc);
+    test_FunctionObject<int(int, int)>(alloc);
+    test_FunctionObject<int(int, int, int)>(alloc);
+    // Free function -- No allocation should occur
+    test_FreeFunction<int()>(alloc);
+    test_FreeFunction<int(int)>(alloc);
+    test_FreeFunction<int(int, int)>(alloc);
+    test_FreeFunction<int(int, int, int)>(alloc);
+    // Member function -- No allocation should occur.
+    test_MemFunClass<int(MemFunClass::*)() const, int(MemFunClass&)>(alloc);
+    test_MemFunClass<int(MemFunClass::*)(int) const, int(MemFunClass&, int)>(alloc);
+    test_MemFunClass<int(MemFunClass::*)(int, int) const, int(MemFunClass&, int, int)>(alloc);
+}
+
+int main()
+{
+  {
+    bare_allocator<DummyClass> alloc;
+    test_for_alloc(alloc);
+  }
+  {
+    non_default_test_allocator<DummyClass> alloc(42);
+    test_for_alloc(alloc);
+  }
 }
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/function_types.h b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/function_types.h
new file mode 100644 (file)
index 0000000..55eb80f
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef FUNCTION_TYPES_H
+#define FUNCTION_TYPES_H
+
+
+class FunctionObject
+{
+    int data_[10]; // dummy variable to prevent small object optimization in
+                   // std::function
+public:
+    static int count;
+
+    FunctionObject() {
+        ++count;
+        for (int i = 0; i < 10; ++i) data_[i] = i;
+    }
+
+    FunctionObject(const FunctionObject&) {++count;}
+    ~FunctionObject() {--count; ((void)data_); }
+
+    int operator()() const { return 42; }
+    int operator()(int i) const { return i; }
+    int operator()(int i, int) const { return i; }
+    int operator()(int i, int, int) const { return i; }
+};
+
+int FunctionObject::count = 0;
+
+class MemFunClass
+{
+    int data_[10]; // dummy variable to prevent small object optimization in
+                   // std::function
+public:
+    static int count;
+
+    MemFunClass() {
+        ++count;
+        for (int i = 0; i < 10; ++i) data_[i] = 0;
+    }
+
+    MemFunClass(const MemFunClass&) {++count; ((void)data_); }
+
+    ~MemFunClass() {--count;}
+
+    int foo() const { return 42; }
+    int foo(int i) const { return i; }
+    int foo(int i, int) const { return i; }
+    int foo(int i, int, int) const { return i; }
+};
+
+int MemFunClass::count = 0;
+
+int FreeFunction() { return 42; }
+int FreeFunction(int i) {return i;}
+int FreeFunction(int i, int) { return i; }
+int FreeFunction(int i, int, int) { return i; }
+
+#endif // FUNCTION_TYPES_H
index 03bd390..47ef1d5 100644 (file)
@@ -74,10 +74,10 @@ public:
             }
             ++time_to_throw;
             ++alloc_count;
-            return (pointer)std::malloc(n * sizeof(T));
+            return (pointer)::operator new(n * sizeof(T));
         }
     void deallocate(pointer p, size_type n)
-        {assert(data_ >= 0); --alloc_count; std::free(p);}
+        {assert(data_ >= 0); --alloc_count; ::operator delete((void*)p);}
     size_type max_size() const throw()
         {return UINT_MAX / sizeof(T);}
     void construct(pointer p, const T& val)
@@ -134,10 +134,10 @@ public:
             }
             ++time_to_throw;
             ++alloc_count;
-            return (pointer)std::malloc(n * sizeof(T));
+            return (pointer)::operator new (n * sizeof(T));
         }
     void deallocate(pointer p, size_type n)
-        {assert(data_ >= 0); --alloc_count; std::free(p);}
+        {assert(data_ >= 0); --alloc_count; ::operator delete((void*)p); }
     size_type max_size() const throw()
         {return UINT_MAX / sizeof(T);}
     void construct(pointer p, const T& val)
@@ -200,9 +200,9 @@ public:
     template <class U> other_allocator(const other_allocator<U>& a)
         : data_(a.data_) {}
     T* allocate(std::size_t n)
-        {return (T*)std::malloc(n * sizeof(T));}
+        {return (T*)::operator new(n * sizeof(T));}
     void deallocate(T* p, std::size_t n)
-        {std::free(p);}
+        {::operator delete((void*)p);}
 
     other_allocator select_on_container_copy_construction() const
         {return other_allocator(-2);}