• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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