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