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