1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // FIXME: In MSVC mode, even "std::function<int(int)> f(aref);" causes |
10 | // allocations. |
11 | // XFAIL: target=x86_64-pc-windows-msvc && stdlib=libc++ && libcpp-abi-version=1 |
12 | |
13 | // UNSUPPORTED: c++03 |
14 | |
15 | // <functional> |
16 | |
17 | // class function<R(ArgTypes...)> |
18 | |
19 | // function(const function& f); |
20 | // function(function&& f); // noexcept in C++20 |
21 | |
22 | #include <functional> |
23 | #include <memory> |
24 | #include <cstdlib> |
25 | #include <cassert> |
26 | #include <utility> |
27 | |
28 | #include "test_macros.h" |
29 | #include "count_new.h" |
30 | |
31 | class A |
32 | { |
33 | int data_[10]; |
34 | public: |
35 | static int count; |
36 | |
37 | A() |
38 | { |
39 | ++count; |
40 | for (int i = 0; i < 10; ++i) |
41 | data_[i] = i; |
42 | } |
43 | |
44 | A(const A&) {++count;} |
45 | |
46 | ~A() {--count;} |
47 | |
48 | int operator()(int i) const |
49 | { |
50 | for (int j = 0; j < 10; ++j) |
51 | i += data_[j]; |
52 | return i; |
53 | } |
54 | }; |
55 | |
56 | int A::count = 0; |
57 | |
58 | int g(int) {return 0;} |
59 | |
60 | int main(int, char**) |
61 | { |
62 | globalMemCounter.reset(); |
63 | assert(globalMemCounter.checkOutstandingNewEq(0)); |
64 | { |
65 | std::function<int(int)> f = A(); |
66 | assert(A::count == 1); |
67 | assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); |
68 | RTTI_ASSERT(f.target<A>()); |
69 | RTTI_ASSERT(f.target<int(*)(int)>() == 0); |
70 | std::function<int(int)> f2 = f; |
71 | assert(A::count == 2); |
72 | assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(2)); |
73 | RTTI_ASSERT(f2.target<A>()); |
74 | RTTI_ASSERT(f2.target<int(*)(int)>() == 0); |
75 | } |
76 | assert(A::count == 0); |
77 | assert(globalMemCounter.checkOutstandingNewEq(0)); |
78 | { |
79 | std::function<int(int)> f = g; |
80 | assert(globalMemCounter.checkOutstandingNewEq(0)); |
81 | RTTI_ASSERT(f.target<int(*)(int)>()); |
82 | RTTI_ASSERT(f.target<A>() == 0); |
83 | std::function<int(int)> f2 = f; |
84 | assert(globalMemCounter.checkOutstandingNewEq(0)); |
85 | RTTI_ASSERT(f2.target<int(*)(int)>()); |
86 | RTTI_ASSERT(f2.target<A>() == 0); |
87 | } |
88 | assert(globalMemCounter.checkOutstandingNewEq(0)); |
89 | { |
90 | std::function<int(int)> f; |
91 | assert(globalMemCounter.checkOutstandingNewEq(0)); |
92 | RTTI_ASSERT(f.target<int(*)(int)>() == 0); |
93 | RTTI_ASSERT(f.target<A>() == 0); |
94 | std::function<int(int)> f2 = f; |
95 | assert(globalMemCounter.checkOutstandingNewEq(0)); |
96 | RTTI_ASSERT(f2.target<int(*)(int)>() == 0); |
97 | RTTI_ASSERT(f2.target<A>() == 0); |
98 | } |
99 | { |
100 | std::function<int(int)> f; |
101 | assert(globalMemCounter.checkOutstandingNewEq(0)); |
102 | RTTI_ASSERT(f.target<int(*)(int)>() == 0); |
103 | RTTI_ASSERT(f.target<A>() == 0); |
104 | assert(!f); |
105 | std::function<long(int)> g = f; |
106 | assert(globalMemCounter.checkOutstandingNewEq(0)); |
107 | RTTI_ASSERT(g.target<long(*)(int)>() == 0); |
108 | RTTI_ASSERT(g.target<A>() == 0); |
109 | assert(!g); |
110 | } |
111 | #if TEST_STD_VER >= 11 |
112 | assert(globalMemCounter.checkOutstandingNewEq(0)); |
113 | { // Test rvalue references |
114 | std::function<int(int)> f = A(); |
115 | assert(A::count == 1); |
116 | assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); |
117 | RTTI_ASSERT(f.target<A>()); |
118 | RTTI_ASSERT(f.target<int(*)(int)>() == 0); |
119 | LIBCPP_ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f))); |
120 | #if TEST_STD_VER > 17 |
121 | ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f))); |
122 | #endif |
123 | std::function<int(int)> f2 = std::move(f); |
124 | assert(A::count == 1); |
125 | assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); |
126 | RTTI_ASSERT(f2.target<A>()); |
127 | RTTI_ASSERT(f2.target<int(*)(int)>() == 0); |
128 | RTTI_ASSERT(f.target<A>() == 0); |
129 | RTTI_ASSERT(f.target<int(*)(int)>() == 0); |
130 | } |
131 | assert(globalMemCounter.checkOutstandingNewEq(0)); |
132 | { |
133 | // Test that moving a function constructed from a reference wrapper |
134 | // is done without allocating. |
135 | DisableAllocationGuard g; |
136 | using Ref = std::reference_wrapper<A>; |
137 | A a; |
138 | Ref aref(a); |
139 | std::function<int(int)> f(aref); |
140 | assert(A::count == 1); |
141 | RTTI_ASSERT(f.target<A>() == nullptr); |
142 | RTTI_ASSERT(f.target<Ref>()); |
143 | LIBCPP_ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f))); |
144 | #if TEST_STD_VER > 17 |
145 | ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f))); |
146 | #endif |
147 | std::function<int(int)> f2(std::move(f)); |
148 | assert(A::count == 1); |
149 | RTTI_ASSERT(f2.target<A>() == nullptr); |
150 | RTTI_ASSERT(f2.target<Ref>()); |
151 | #if defined(_LIBCPP_VERSION) |
152 | RTTI_ASSERT(f.target<Ref>()); // f is unchanged because the target is small |
153 | #endif |
154 | } |
155 | { |
156 | // Test that moving a function constructed from a function pointer |
157 | // is done without allocating |
158 | DisableAllocationGuard guard; |
159 | using Ptr = int(*)(int); |
160 | Ptr p = g; |
161 | std::function<int(int)> f(p); |
162 | RTTI_ASSERT(f.target<A>() == nullptr); |
163 | RTTI_ASSERT(f.target<Ptr>()); |
164 | LIBCPP_ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f))); |
165 | #if TEST_STD_VER > 17 |
166 | ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f))); |
167 | #endif |
168 | std::function<int(int)> f2(std::move(f)); |
169 | RTTI_ASSERT(f2.target<A>() == nullptr); |
170 | RTTI_ASSERT(f2.target<Ptr>()); |
171 | #if defined(_LIBCPP_VERSION) |
172 | RTTI_ASSERT(f.target<Ptr>()); // f is unchanged because the target is small |
173 | #endif |
174 | } |
175 | #endif // TEST_STD_VER >= 11 |
176 | |
177 | return 0; |
178 | } |
179 | |