[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