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 // UNSUPPORTED: c++03, c++11, c++14
10
11 // Throwing bad_any_cast is supported starting in macosx10.13
12 // XFAIL: with_system_cxx_lib=macosx10.12 && !no-exceptions
13 // XFAIL: with_system_cxx_lib=macosx10.11 && !no-exceptions
14 // XFAIL: with_system_cxx_lib=macosx10.10 && !no-exceptions
15 // XFAIL: with_system_cxx_lib=macosx10.9 && !no-exceptions
16
17 // <any>
18
19 // template <class T, class ...Args> T& emplace(Args&&...);
20 // template <class T, class U, class ...Args>
21 // T& emplace(initializer_list<U>, Args&&...);
22
23 #include <any>
24 #include <cassert>
25
26 #include "any_helpers.h"
27 #include "count_new.h"
28 #include "test_macros.h"
29
30 using std::any;
31 using std::any_cast;
32
33 struct Tracked {
34 static int count;
TrackedTracked35 Tracked() {++count;}
~TrackedTracked36 ~Tracked() { --count; }
37 };
38 int Tracked::count = 0;
39
40 template <class Type>
test_emplace_type()41 void test_emplace_type() {
42 // constructing from a small type should perform no allocations.
43 DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
44 assert(Type::count == 0);
45 Type::reset();
46 {
47 any a(std::in_place_type<Tracked>);
48 assert(Tracked::count == 1);
49
50 auto &v = a.emplace<Type>();
51 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
52 assert(&v == std::any_cast<Type>(&a));
53
54 assert(Tracked::count == 0);
55 assert(Type::count == 1);
56 assert(Type::copied == 0);
57 assert(Type::moved == 0);
58 assertContains<Type>(a, 0);
59 }
60 assert(Type::count == 0);
61 Type::reset();
62 {
63 any a(std::in_place_type<Tracked>);
64 assert(Tracked::count == 1);
65
66 auto &v = a.emplace<Type>(101);
67 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
68 assert(&v == std::any_cast<Type>(&a));
69
70 assert(Tracked::count == 0);
71 assert(Type::count == 1);
72 assert(Type::copied == 0);
73 assert(Type::moved == 0);
74 assertContains<Type>(a, 101);
75 }
76 assert(Type::count == 0);
77 Type::reset();
78 {
79 any a(std::in_place_type<Tracked>);
80 assert(Tracked::count == 1);
81
82 auto &v = a.emplace<Type>(-1, 42, -1);
83 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
84 assert(&v == std::any_cast<Type>(&a));
85
86 assert(Tracked::count == 0);
87 assert(Type::count == 1);
88 assert(Type::copied == 0);
89 assert(Type::moved == 0);
90 assertContains<Type>(a, 42);
91 }
92 assert(Type::count == 0);
93 Type::reset();
94 }
95
96 template <class Type>
test_emplace_type_tracked()97 void test_emplace_type_tracked() {
98 // constructing from a small type should perform no allocations.
99 DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
100 {
101 any a(std::in_place_type<Tracked>);
102 assert(Tracked::count == 1);
103 auto &v = a.emplace<Type>();
104 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
105 assert(&v == std::any_cast<Type>(&a));
106
107 assert(Tracked::count == 0);
108 assertArgsMatch<Type>(a);
109 }
110 {
111 any a(std::in_place_type<Tracked>);
112 assert(Tracked::count == 1);
113 auto &v = a.emplace<Type>(-1, 42, -1);
114 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
115 assert(&v == std::any_cast<Type>(&a));
116
117 assert(Tracked::count == 0);
118 assertArgsMatch<Type, int, int, int>(a);
119 }
120 // initializer_list constructor tests
121 {
122 any a(std::in_place_type<Tracked>);
123 assert(Tracked::count == 1);
124 auto &v = a.emplace<Type>({-1, 42, -1});
125 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
126 assert(&v == std::any_cast<Type>(&a));
127
128 assert(Tracked::count == 0);
129 assertArgsMatch<Type, std::initializer_list<int>>(a);
130 }
131 {
132 int x = 42;
133 any a(std::in_place_type<Tracked>);
134 assert(Tracked::count == 1);
135 auto &v = a.emplace<Type>({-1, 42, -1}, x);
136 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
137 assert(&v == std::any_cast<Type>(&a));
138
139 assert(Tracked::count == 0);
140 assertArgsMatch<Type, std::initializer_list<int>, int&>(a);
141 }
142 }
143
144 #ifndef TEST_HAS_NO_EXCEPTIONS
145
146 struct SmallThrows {
SmallThrowsSmallThrows147 SmallThrows(int) { throw 42; }
SmallThrowsSmallThrows148 SmallThrows(std::initializer_list<int>, int) { throw 42; }
149 };
150 static_assert(IsSmallObject<SmallThrows>::value, "");
151
152 struct LargeThrows {
LargeThrowsLargeThrows153 LargeThrows(int) { throw 42; }
LargeThrowsLargeThrows154 LargeThrows(std::initializer_list<int>, int) { throw 42; }
155 int data[sizeof(std::any)];
156 };
157 static_assert(!IsSmallObject<LargeThrows>::value, "");
158
159 template <class Type>
test_emplace_throws()160 void test_emplace_throws()
161 {
162 // any stores small type
163 {
164 std::any a(small{42});
165 assert(small::count == 1);
166 try {
167 auto &v = a.emplace<Type>(101);
168 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
169 assert(false);
170 } catch (int const&) {
171 }
172 assert(small::count == 0);
173 }
174 {
175 std::any a(small{42});
176 assert(small::count == 1);
177 try {
178 auto &v = a.emplace<Type>({1, 2, 3}, 101);
179 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
180 assert(false);
181 } catch (int const&) {
182 }
183 assert(small::count == 0);
184 }
185 // any stores large type
186 {
187 std::any a(large{42});
188 assert(large::count == 1);
189 try {
190 auto &v = a.emplace<Type>(101);
191 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
192 assert(false);
193 } catch (int const&) {
194 }
195 assert(large::count == 0);
196 }
197 {
198 std::any a(large{42});
199 assert(large::count == 1);
200 try {
201 auto &v = a.emplace<Type>({1, 2, 3}, 101);
202 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
203 assert(false);
204 } catch (int const&) {
205 }
206 assert(large::count == 0);
207 }
208 }
209
210 #endif
211
212 template <class T, class ...Args>
has_emplace(int)213 constexpr auto has_emplace(int)
214 -> decltype(std::any{}.emplace<T>(std::declval<Args>()...), true) { return true; }
215
216 template <class ...Args>
has_emplace(long)217 constexpr bool has_emplace(long) { return false; }
218
219 template <class ...Args>
has_emplace()220 constexpr bool has_emplace() { return has_emplace<Args...>(0); }
221
222
223 template <class T, class IT, class ...Args>
has_emplace_init_list(int)224 constexpr auto has_emplace_init_list(int)
225 -> decltype(std::any{}.emplace<T>(
226 {std::declval<IT>(), std::declval<IT>(), std::declval<IT>()},
227 std::declval<Args>()...), true) { return true; }
228
229 template <class ...Args>
has_emplace_init_list(long)230 constexpr bool has_emplace_init_list(long) { return false; }
231
232 template <class ...Args>
has_emplace_init_list()233 constexpr bool has_emplace_init_list() { return has_emplace_init_list<Args...>(0); }
234
235
test_emplace_sfinae_constraints()236 void test_emplace_sfinae_constraints() {
237 {
238 static_assert(has_emplace<int>(), "");
239 static_assert(has_emplace<int, int>(), "");
240 static_assert(!has_emplace<int, int, int>(), "not constructible");
241 static_assert(!has_emplace_init_list<int, int>(), "not constructible from il");
242 }
243 {
244 static_assert(has_emplace<small>(), "");
245 static_assert(has_emplace<large>(), "");
246 static_assert(!has_emplace<small, void*>(), "");
247 static_assert(!has_emplace<large, void*>(), "");
248
249 static_assert(has_emplace_init_list<small, int>(), "");
250 static_assert(has_emplace_init_list<large, int>(), "");
251 static_assert(!has_emplace_init_list<small, void*>(), "");
252 static_assert(!has_emplace_init_list<large, void*>(), "");
253 }
254 {
255 // Test that the emplace SFINAE's away when the
256 // argument is non-copyable
257 struct NoCopy {
258 NoCopy() = default;
259 NoCopy(NoCopy const&) = delete;
260 NoCopy(int) {}
261 NoCopy(std::initializer_list<int>, int, int) {}
262 };
263 static_assert(!has_emplace<NoCopy>(), "");
264 static_assert(!has_emplace<NoCopy, int>(), "");
265 static_assert(!has_emplace_init_list<NoCopy, int, int, int>(), "");
266 static_assert(!has_emplace<NoCopy&>(), "");
267 static_assert(!has_emplace<NoCopy&, int>(), "");
268 static_assert(!has_emplace_init_list<NoCopy&, int, int, int>(), "");
269 static_assert(!has_emplace<NoCopy&&>(), "");
270 static_assert(!has_emplace<NoCopy&&, int>(), "");
271 static_assert(!has_emplace_init_list<NoCopy&&, int, int, int>(), "");
272
273 }
274 }
275
main(int,char **)276 int main(int, char**) {
277 test_emplace_type<small>();
278 test_emplace_type<large>();
279 test_emplace_type<small_throws_on_copy>();
280 test_emplace_type<large_throws_on_copy>();
281 test_emplace_type<throws_on_move>();
282 test_emplace_type_tracked<small_tracked_t>();
283 test_emplace_type_tracked<large_tracked_t>();
284 test_emplace_sfinae_constraints();
285 #ifndef TEST_HAS_NO_EXCEPTIONS
286 test_emplace_throws<SmallThrows>();
287 test_emplace_throws<LargeThrows>();
288 #endif
289
290 return 0;
291 }
292