From b05f0599c09772f2946c67ccfcc76d5d9af7ece5 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Sun, 14 Jun 2015 23:30:09 +0000 Subject: [PATCH] Fix std::function allocator constructors in C++03. 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. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@239708 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/__functional_03 | 32 ++-- .../func.wrap.func.con/alloc_F.pass.cpp | 128 ++++++++------- .../alloc_function.pass.cpp | 154 ++++++++++-------- .../func.wrap/func.wrap.func/function_types.h | 57 +++++++ test/support/test_allocator.h | 12 +- 5 files changed, 239 insertions(+), 144 deletions(-) create mode 100644 test/std/utilities/function.objects/func.wrap/func.wrap.func/function_types.h diff --git a/include/__functional_03 b/include/__functional_03 index f048ea324..993548342 100644 --- a/include/__functional_03 +++ b/include/__functional_03 @@ -333,7 +333,8 @@ template __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 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 __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 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 __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 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 __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 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 { diff --git a/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp b/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp index 741a3b9a9..352ecfc60 100644 --- a/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp +++ b/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp @@ -17,84 +17,90 @@ #include #include "min_allocator.h" +#include "test_allocator.h" +#include "count_new.hpp" +#include "../function_types.h" -class A +class DummyClass {}; + +template +void test_FunctionObject(AllocType& alloc) { - int data_[10]; -public: - static int count; - - A() + 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 f2(std::allocator_arg, alloc, target); + assert(FunctionObject::count == 2); + assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(f2.template target()); + assert(f2.template target() == 0); + assert(f2.template target() == 0); } + assert(FunctionObject::count == 0); + assert(globalMemCounter.checkOutstandingNewEq(0)); +} - A(const A&) {++count;} - ~A() {--count;} - - int operator()(int i) const +template +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 f2(std::allocator_arg, alloc, target); + assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(f2.template target()); + assert(*f2.template target() == target); + assert(f2.template target() == 0); + assert(f2.template target() == 0); } + assert(globalMemCounter.checkOutstandingNewEq(0)); +} - int foo(int) const {return 1;} -}; +template +void test_MemFunClass(AllocType& alloc) +{ + assert(globalMemCounter.checkOutstandingNewEq(0)); + { + TargetType target = &MemFunClass::foo; + assert(globalMemCounter.checkOutstandingNewEq(0)); + std::function f2(std::allocator_arg, alloc, target); + assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(f2.template target()); + assert(*f2.template target() == target); + assert(f2.template target() == 0); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); +} -int A::count = 0; +template +void test_for_alloc(Alloc& alloc) { + test_FunctionObject(alloc); + test_FunctionObject(alloc); + test_FunctionObject(alloc); + test_FunctionObject(alloc); -int g(int) {return 0;} + test_FreeFunction(alloc); + test_FreeFunction(alloc); + test_FreeFunction(alloc); + test_FreeFunction(alloc); -class Foo { -public: - void bar(int k) { } -}; + test_MemFunClass(alloc); + test_MemFunClass(alloc); + test_MemFunClass(alloc); +} int main() { { - std::function f(std::allocator_arg, bare_allocator(), A()); - assert(A::count == 1); - assert(f.target()); - assert(f.target() == 0); - } - assert(A::count == 0); - { - std::function f(std::allocator_arg, bare_allocator(), g); - assert(f.target()); - assert(f.target() == 0); + bare_allocator bare_alloc; + test_for_alloc(bare_alloc); } { - std::function f(std::allocator_arg, bare_allocator(), - (int (*)(int))0); - assert(!f); - assert(f.target() == 0); - assert(f.target() == 0); - } - { - std::function f(std::allocator_arg, - bare_allocator(), - &A::foo); - assert(f); - assert(f.target() != 0); - } -#if __cplusplus >= 201103L - { - Foo f; - std::function fun = std::bind(&Foo::bar, &f, std::placeholders::_1); - fun(10); - } -#endif - { - std::function fun(std::allocator_arg, - bare_allocator(), - &g); - assert(fun); - assert(fun.target() != 0); - fun(10); + non_default_test_allocator non_default_alloc(42); + test_for_alloc(non_default_alloc); } } diff --git a/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_function.pass.cpp b/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_function.pass.cpp index e89636a69..371eb98de 100644 --- a/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_function.pass.cpp +++ b/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_function.pass.cpp @@ -20,81 +20,105 @@ #include "min_allocator.h" #include "test_allocator.h" #include "count_new.hpp" +#include "../function_types.h" -class A +class DummyClass {}; + +template +void test_FunctionObject(AllocType& alloc) { - int data_[10]; -public: - static int count; - - A() + assert(globalMemCounter.checkOutstandingNewEq(0)); { - ++count; - for (int i = 0; i < 10; ++i) - data_[i] = i; + // Construct function from FunctionObject. + std::function f = FunctionObject(); + assert(FunctionObject::count == 1); + assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(f.template target()); + assert(f.template target() == 0); + assert(f.template target() == 0); + // Copy function with allocator + std::function f2(std::allocator_arg, alloc, f); + assert(FunctionObject::count == 2); + assert(globalMemCounter.checkOutstandingNewEq(2)); + assert(f2.template target()); + assert(f2.template target() == 0); + assert(f2.template target() == 0); } + assert(FunctionObject::count == 0); + assert(globalMemCounter.checkOutstandingNewEq(0)); +} - A(const A&) {++count;} - - ~A() {--count;} - - int operator()(int i) const +template +void test_FreeFunction(AllocType& alloc) +{ + assert(globalMemCounter.checkOutstandingNewEq(0)); { - for (int j = 0; j < 10; ++j) - i += data_[j]; - return i; + // Construct function from function pointer. + FuncType* target = &FreeFunction; + std::function f = target; + assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(f.template target()); + assert(*f.template target() == target); + assert(f.template target() == 0); + // Copy function with allocator + std::function f2(std::allocator_arg, alloc, f); + assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(f2.template target()); + assert(*f2.template target() == target); + assert(f2.template target() == 0); } -}; + assert(globalMemCounter.checkOutstandingNewEq(0)); +} -int A::count = 0; +template +void test_MemFunClass(AllocType& alloc) +{ + assert(globalMemCounter.checkOutstandingNewEq(0)); + { + // Construct function from function pointer. + TargetType target = &MemFunClass::foo; + std::function f = target; + assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(f.template target()); + assert(*f.template target() == target); + assert(f.template target() == 0); + // Copy function with allocator + std::function f2(std::allocator_arg, alloc, f); + assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(f2.template target()); + assert(*f2.template target() == target); + assert(f2.template target() == 0); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); +} -int g(int) {return 0;} +template +void test_for_alloc(Alloc& alloc) +{ + // Large FunctionObject -- Allocation should occur + test_FunctionObject(alloc); + test_FunctionObject(alloc); + test_FunctionObject(alloc); + test_FunctionObject(alloc); + // Free function -- No allocation should occur + test_FreeFunction(alloc); + test_FreeFunction(alloc); + test_FreeFunction(alloc); + test_FreeFunction(alloc); + // Member function -- No allocation should occur. + test_MemFunClass(alloc); + test_MemFunClass(alloc); + test_MemFunClass(alloc); +} int main() { - assert(globalMemCounter.checkOutstandingNewEq(0)); - { - std::function f = A(); - assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); - assert(f.target()); - assert(f.target() == 0); - std::function f2(std::allocator_arg, bare_allocator(), f); - assert(A::count == 2); - assert(globalMemCounter.checkOutstandingNewEq(2)); - assert(f2.target()); - assert(f2.target() == 0); - } - assert(A::count == 0); - assert(globalMemCounter.checkOutstandingNewEq(0)); - { - std::function f = g; - assert(globalMemCounter.checkOutstandingNewEq(0)); - assert(f.target()); - assert(f.target() == 0); - std::function f2(std::allocator_arg, bare_allocator(), f); - assert(globalMemCounter.checkOutstandingNewEq(0)); - assert(f2.target()); - assert(f2.target() == 0); - } - assert(globalMemCounter.checkOutstandingNewEq(0)); - { - assert(globalMemCounter.checkOutstandingNewEq(0)); - non_default_test_allocator > al(1); - std::function f2(std::allocator_arg, al, g); - assert(globalMemCounter.checkOutstandingNewEq(0)); - assert(f2.target()); - assert(f2.target() == 0); - } - assert(globalMemCounter.checkOutstandingNewEq(0)); - { - std::function f; - assert(globalMemCounter.checkOutstandingNewEq(0)); - assert(f.target() == 0); - assert(f.target() == 0); - std::function f2(std::allocator_arg, bare_allocator(), f); - assert(globalMemCounter.checkOutstandingNewEq(0)); - assert(f2.target() == 0); - assert(f2.target() == 0); - } + { + bare_allocator alloc; + test_for_alloc(alloc); + } + { + non_default_test_allocator alloc(42); + test_for_alloc(alloc); + } } diff --git a/test/std/utilities/function.objects/func.wrap/func.wrap.func/function_types.h b/test/std/utilities/function.objects/func.wrap/func.wrap.func/function_types.h new file mode 100644 index 000000000..55eb80f43 --- /dev/null +++ b/test/std/utilities/function.objects/func.wrap/func.wrap.func/function_types.h @@ -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 diff --git a/test/support/test_allocator.h b/test/support/test_allocator.h index 03bd39056..47ef1d556 100644 --- a/test/support/test_allocator.h +++ b/test/support/test_allocator.h @@ -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 other_allocator(const other_allocator& 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);}