[libcxx] r206623 - Bug #19473. If you pass an allocator to std::function, we should use that allocator, not construct one from scratch. Add a test to make sure

Marshall Clow mclow.lists at gmail.com
Fri Apr 18 10:23:36 PDT 2014


Author: marshall
Date: Fri Apr 18 12:23:36 2014
New Revision: 206623

URL: http://llvm.org/viewvc/llvm-project?rev=206623&view=rev
Log:
Bug #19473. If you pass an allocator to std::function, we should use that allocator, not construct one from scratch. Add a test to make sure

Modified:
    libcxx/trunk/include/functional
    libcxx/trunk/test/support/test_allocator.h
    libcxx/trunk/test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_function.pass.cpp

Modified: libcxx/trunk/include/functional
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/functional?rev=206623&r1=206622&r2=206623&view=diff
==============================================================================
--- libcxx/trunk/include/functional (original)
+++ libcxx/trunk/include/functional Fri Apr 18 12:23:36 2014
@@ -1617,21 +1617,22 @@ function<_Rp(_ArgTypes...)>::function(al
     if (__not_null(__f))
     {
         typedef __function::__func<_Fp, _Alloc, _Rp(_ArgTypes...)> _FF;
-        if (sizeof(_FF) <= sizeof(__buf_) && is_nothrow_copy_constructible<_Fp>::value)
+        typedef typename __alloc_traits::template
+#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
+            rebind_alloc<_FF>
+#else
+            rebind_alloc<_FF>::other
+#endif
+            _Ap;
+        _Ap __a(__a0);
+        if (sizeof(_FF) <= sizeof(__buf_) && 
+            is_nothrow_copy_constructible<_Fp>::value && is_nothrow_copy_constructible<_Ap>::value)
         {
             __f_ = (__base*)&__buf_;
-            ::new (__f_) _FF(_VSTD::move(__f));
+            ::new (__f_) _FF(_VSTD::move(__f), _Alloc(__a));
         }
         else
         {
-            typedef typename __alloc_traits::template
-#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
-                rebind_alloc<_FF>
-#else
-                rebind_alloc<_FF>::other
-#endif
-                                                         _Ap;
-            _Ap __a(__a0);
             typedef __allocator_destructor<_Ap> _Dp;
             unique_ptr<__base, _Dp> __hold(__a.allocate(1), _Dp(__a, 1));
             ::new (__hold.get()) _FF(_VSTD::move(__f), _Alloc(__a));

Modified: libcxx/trunk/test/support/test_allocator.h
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/test_allocator.h?rev=206623&r1=206622&r2=206623&view=diff
==============================================================================
--- libcxx/trunk/test/support/test_allocator.h (original)
+++ libcxx/trunk/test/support/test_allocator.h Fri Apr 18 12:23:36 2014
@@ -92,6 +92,66 @@ public:
         {return !(x == y);}
 };
 
+template <class T>
+class non_default_test_allocator
+    : public test_alloc_base
+{
+    int data_;
+
+    template <class U> friend class non_default_test_allocator;
+public:
+
+    typedef unsigned                                                   size_type;
+    typedef int                                                        difference_type;
+    typedef T                                                          value_type;
+    typedef value_type*                                                pointer;
+    typedef const value_type*                                          const_pointer;
+    typedef typename std::add_lvalue_reference<value_type>::type       reference;
+    typedef typename std::add_lvalue_reference<const value_type>::type const_reference;
+
+    template <class U> struct rebind {typedef non_default_test_allocator<U> other;};
+
+//    non_default_test_allocator() throw() : data_(0) {++count;}
+    explicit non_default_test_allocator(int i) throw() : data_(i) {++count;}
+    non_default_test_allocator(const non_default_test_allocator& a) throw()
+        : data_(a.data_) {++count;}
+    template <class U> non_default_test_allocator(const non_default_test_allocator<U>& a) throw()
+        : data_(a.data_) {++count;}
+    ~non_default_test_allocator() throw() {assert(data_ >= 0); --count; data_ = -1;}
+    pointer address(reference x) const {return &x;}
+    const_pointer address(const_reference x) const {return &x;}
+    pointer allocate(size_type n, const void* = 0)
+        {
+            assert(data_ >= 0);
+            if (time_to_throw >= throw_after) {
+#ifndef _LIBCPP_NO_EXCEPTIONS
+                throw std::bad_alloc();
+#else
+                std::terminate();
+#endif
+            }
+            ++time_to_throw;
+            ++alloc_count;
+            return (pointer)std::malloc(n * sizeof(T));
+        }
+    void deallocate(pointer p, size_type n)
+        {assert(data_ >= 0); --alloc_count; std::free(p);}
+    size_type max_size() const throw()
+        {return UINT_MAX / sizeof(T);}
+    void construct(pointer p, const T& val)
+        {::new(p) T(val);}
+#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+    void construct(pointer p, T&& val)
+        {::new(p) T(std::move(val));}
+#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+    void destroy(pointer p) {p->~T();}
+
+    friend bool operator==(const non_default_test_allocator& x, const non_default_test_allocator& y)
+        {return x.data_ == y.data_;}
+    friend bool operator!=(const non_default_test_allocator& x, const non_default_test_allocator& y)
+        {return !(x == y);}
+};
+
 template <>
 class test_allocator<void>
     : public test_alloc_base

Modified: libcxx/trunk/test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_function.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_function.pass.cpp?rev=206623&r1=206622&r2=206623&view=diff
==============================================================================
--- libcxx/trunk/test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_function.pass.cpp (original)
+++ libcxx/trunk/test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_function.pass.cpp Fri Apr 18 12:23:36 2014
@@ -92,6 +92,15 @@ int main()
     }
     assert(new_called == 0);
     {
+    assert(new_called == 0);
+    non_default_test_allocator<std::function<int(int)>> al(1);
+    std::function<int(int)> f2(std::allocator_arg, al, g);
+    assert(new_called == 0);
+    assert(f2.target<int(*)(int)>());
+    assert(f2.target<A>() == 0);
+    }
+    assert(new_called == 0);
+    {
     std::function<int(int)> f;
     assert(new_called == 0);
     assert(f.target<int(*)(int)>() == 0);





More information about the cfe-commits mailing list