xref: /llvm-project/libcxx/test/std/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp (revision ec350ad418a24f70c88758259c774a1e11c06d74)
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 // <any>
12 
13 // template <class ValueType>
14 // ValueType const any_cast(any const&);
15 //
16 // template <class ValueType>
17 // ValueType any_cast(any &);
18 //
19 // template <class ValueType>
20 // ValueType any_cast(any &&);
21 
22 #include <any>
23 #include <type_traits>
24 #include <cassert>
25 
26 #include "any_helpers.h"
27 #include "count_new.h"
28 #include "test_macros.h"
29 
30 // Test that the operators are NOT marked noexcept.
test_cast_is_not_noexcept()31 void test_cast_is_not_noexcept() {
32     std::any a;
33     static_assert(!noexcept(std::any_cast<int>(static_cast<std::any&>(a))), "");
34     static_assert(!noexcept(std::any_cast<int>(static_cast<std::any const&>(a))), "");
35     static_assert(!noexcept(std::any_cast<int>(static_cast<std::any &&>(a))), "");
36 }
37 
38 // Test that the return type of any_cast is correct.
test_cast_return_type()39 void test_cast_return_type() {
40     std::any a;
41     static_assert(std::is_same<decltype(std::any_cast<int>(a)), int>::value, "");
42     static_assert(std::is_same<decltype(std::any_cast<int const>(a)), int>::value, "");
43     static_assert(std::is_same<decltype(std::any_cast<int&>(a)), int&>::value, "");
44     static_assert(std::is_same<decltype(std::any_cast<int const&>(a)), int const&>::value, "");
45     static_assert(std::is_same<decltype(std::any_cast<int&&>(a)), int&&>::value, "");
46     static_assert(std::is_same<decltype(std::any_cast<int const&&>(a)), int const&&>::value, "");
47 
48     static_assert(std::is_same<decltype(std::any_cast<int>(std::move(a))), int>::value, "");
49     static_assert(std::is_same<decltype(std::any_cast<int const>(std::move(a))), int>::value, "");
50     static_assert(std::is_same<decltype(std::any_cast<int&>(std::move(a))), int&>::value, "");
51     static_assert(std::is_same<decltype(std::any_cast<int const&>(std::move(a))), int const&>::value, "");
52     static_assert(std::is_same<decltype(std::any_cast<int&&>(std::move(a))), int&&>::value, "");
53     static_assert(std::is_same<decltype(std::any_cast<int const&&>(std::move(a))), int const&&>::value, "");
54 
55     const std::any& ca = a;
56     static_assert(std::is_same<decltype(std::any_cast<int>(ca)), int>::value, "");
57     static_assert(std::is_same<decltype(std::any_cast<int const>(ca)), int>::value, "");
58     static_assert(std::is_same<decltype(std::any_cast<int const&>(ca)), int const&>::value, "");
59     static_assert(std::is_same<decltype(std::any_cast<int const&&>(ca)), int const&&>::value, "");
60 }
61 
62 template <class Type, class ConstT = Type>
checkThrows(std::any & a)63 void checkThrows(std::any& a)
64 {
65 #if !defined(TEST_HAS_NO_EXCEPTIONS)
66     try {
67         TEST_IGNORE_NODISCARD std::any_cast<Type>(a);
68         assert(false);
69     } catch (const std::bad_any_cast&) {
70         // do nothing
71     } catch (...) {
72         assert(false);
73     }
74 
75     try {
76         TEST_IGNORE_NODISCARD std::any_cast<ConstT>(static_cast<const std::any&>(a));
77         assert(false);
78     } catch (const std::bad_any_cast&) {
79         // do nothing
80     } catch (...) {
81         assert(false);
82     }
83 
84     try {
85         using RefType = typename std::conditional<
86             std::is_lvalue_reference<Type>::value,
87             typename std::remove_reference<Type>::type&&,
88             Type
89         >::type;
90         TEST_IGNORE_NODISCARD std::any_cast<RefType>(static_cast<std::any&&>(a));
91         assert(false);
92     } catch (const std::bad_any_cast&) {
93             // do nothing
94     } catch (...) {
95         assert(false);
96     }
97 #else
98     (TEST_IGNORE_NODISCARD a);
99 #endif
100 }
101 
test_cast_empty()102 void test_cast_empty() {
103     // None of these operations should allocate.
104     DisableAllocationGuard g; (TEST_IGNORE_NODISCARD g);
105     std::any a;
106     checkThrows<int>(a);
107 }
108 
109 template <class Type>
test_cast_to_reference()110 void test_cast_to_reference() {
111     assert(Type::count == 0);
112     Type::reset();
113     {
114         std::any a = Type(42);
115         const std::any& ca = a;
116         assert(Type::count == 1);
117         assert(Type::copied == 0);
118         assert(Type::moved == 1);
119 
120         // Try a cast to a bad type.
121         // NOTE: Type cannot be an int.
122         checkThrows<int>(a);
123         checkThrows<int&, int const&>(a);
124         checkThrows<Type*, Type const*>(a);
125         checkThrows<Type const*>(a);
126 
127         // Check getting a type by reference from a non-const lvalue any.
128         {
129             Type& v = std::any_cast<Type&>(a);
130             assert(v.value == 42);
131 
132             Type const &cv = std::any_cast<Type const&>(a);
133             assert(&cv == &v);
134         }
135         // Check getting a type by reference from a const lvalue any.
136         {
137             Type const& v = std::any_cast<Type const&>(ca);
138             assert(v.value == 42);
139 
140             Type const &cv = std::any_cast<Type const&>(ca);
141             assert(&cv == &v);
142         }
143         // Check getting a type by reference from a const rvalue any.
144         {
145             Type const& v = std::any_cast<Type const&>(std::move(ca));
146             assert(v.value == 42);
147 
148             Type const &cv = std::any_cast<Type const&>(std::move(ca));
149             assert(&cv == &v);
150         }
151         // Check getting a type by reference from a const rvalue any.
152         {
153             Type&& v = std::any_cast<Type&&>(std::move(a));
154             assert(v.value == 42);
155             assert(std::any_cast<Type&>(a).value == 42);
156 
157             Type&& cv = std::any_cast<Type&&>(std::move(a));
158             assert(&cv == &v);
159             assert(std::any_cast<Type&>(a).value == 42);
160         }
161         // Check getting a type by reference from a const rvalue any.
162         {
163             Type const&& v = std::any_cast<Type const&&>(std::move(a));
164             assert(v.value == 42);
165             assert(std::any_cast<Type&>(a).value == 42);
166 
167             Type const&& cv = std::any_cast<Type const&&>(std::move(a));
168             assert(&cv == &v);
169             assert(std::any_cast<Type&>(a).value == 42);
170         }
171         // Check that the original object hasn't been changed.
172         assertContains<Type>(a, 42);
173 
174         // Check that no objects have been created/copied/moved.
175         assert(Type::count == 1);
176         assert(Type::copied == 0);
177         assert(Type::moved == 1);
178     }
179     assert(Type::count == 0);
180 }
181 
182 template <class Type>
test_cast_to_value()183 void test_cast_to_value() {
184     assert(Type::count == 0);
185     Type::reset();
186     {
187         std::any a = Type(42);
188         assert(Type::count == 1);
189         assert(Type::copied == 0);
190         assert(Type::moved == 1);
191 
192         // Try a cast to a bad type.
193         // NOTE: Type cannot be an int.
194         checkThrows<int>(a);
195         checkThrows<int&, int const&>(a);
196         checkThrows<Type*, Type const*>(a);
197         checkThrows<Type const*>(a);
198 
199         Type::reset(); // NOTE: reset does not modify Type::count
200         // Check getting Type by value from a non-const lvalue any.
201         // This should cause the non-const copy constructor to be called.
202         {
203             Type t = std::any_cast<Type>(a);
204 
205             assert(Type::count == 2);
206             assert(Type::copied == 1);
207             assert(Type::const_copied == 0);
208             assert(Type::non_const_copied == 1);
209             assert(Type::moved == 0);
210             assert(t.value == 42);
211         }
212         assert(Type::count == 1);
213         Type::reset();
214         // Check getting const Type by value from a non-const lvalue any.
215         // This should cause the const copy constructor to be called.
216         {
217             Type t = std::any_cast<Type const>(a);
218 
219             assert(Type::count == 2);
220             assert(Type::copied == 1);
221             assert(Type::const_copied == 0);
222             assert(Type::non_const_copied == 1);
223             assert(Type::moved == 0);
224             assert(t.value == 42);
225         }
226         assert(Type::count == 1);
227         Type::reset();
228         // Check getting Type by value from a non-const lvalue any.
229         // This should cause the const copy constructor to be called.
230         {
231             Type t = std::any_cast<Type>(static_cast<const std::any&>(a));
232 
233             assert(Type::count == 2);
234             assert(Type::copied == 1);
235             assert(Type::const_copied == 1);
236             assert(Type::non_const_copied == 0);
237             assert(Type::moved == 0);
238             assert(t.value == 42);
239         }
240         assert(Type::count == 1);
241         Type::reset();
242         // Check getting Type by value from a non-const rvalue any.
243         // This should cause the non-const copy constructor to be called.
244         {
245             Type t = std::any_cast<Type>(static_cast<std::any&&>(a));
246 
247             assert(Type::count == 2);
248             assert(Type::moved == 1);
249             assert(Type::copied == 0);
250             assert(Type::const_copied == 0);
251             assert(Type::non_const_copied == 0);
252             assert(t.value == 42);
253             assert(std::any_cast<Type&>(a).value == 0);
254             std::any_cast<Type&>(a).value = 42; // reset the value
255         }
256         assert(Type::count == 1);
257         Type::reset();
258         // Check getting const Type by value from a non-const rvalue any.
259         // This should cause the const copy constructor to be called.
260         {
261             Type t = std::any_cast<Type const>(static_cast<std::any&&>(a));
262 
263             assert(Type::count == 2);
264             assert(Type::copied == 0);
265             assert(Type::const_copied == 0);
266             assert(Type::non_const_copied == 0);
267             assert(Type::moved == 1);
268             assert(t.value == 42);
269             assert(std::any_cast<Type&>(a).value == 0);
270             std::any_cast<Type&>(a).value = 42; // reset the value
271         }
272         assert(Type::count == 1);
273         Type::reset();
274         // Check getting Type by value from a const rvalue any.
275         // This should cause the const copy constructor to be called.
276         {
277             Type t = std::any_cast<Type>(static_cast<const std::any&&>(a));
278 
279             assert(Type::count == 2);
280             assert(Type::copied == 1);
281             assert(Type::const_copied == 1);
282             assert(Type::non_const_copied == 0);
283             assert(Type::moved == 0);
284             assert(t.value == 42);
285             assert(std::any_cast<Type&>(a).value == 42);
286         }
287         // Ensure we still only have 1 Type object alive.
288         assert(Type::count == 1);
289 
290         // Check that the original object hasn't been changed.
291         assertContains<Type>(a, 42);
292     }
293     assert(Type::count == 0);
294 }
295 
main(int,char **)296 int main(int, char**) {
297     test_cast_is_not_noexcept();
298     test_cast_return_type();
299     test_cast_empty();
300     test_cast_to_reference<small>();
301     test_cast_to_reference<large>();
302     test_cast_to_value<small>();
303     test_cast_to_value<large>();
304 
305   return 0;
306 }
307