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 Value> any(Value &&)
17 
18 // Test construction from a value.
19 // Concerns:
20 // ---------
21 // 1. The value is properly move/copied depending on the value category.
22 // 2. Both small and large values are properly handled.
23 
24 
25 #include <any>
26 #include <cassert>
27 
28 #include "any_helpers.h"
29 #include "count_new.h"
30 #include "test_macros.h"
31 
32 using std::any;
33 using std::any_cast;
34 
35 template <class Type>
36 void test_copy_value_throws()
37 {
38 #if !defined(TEST_HAS_NO_EXCEPTIONS)
39     assert(Type::count == 0);
40     {
41         Type const t(42);
42         assert(Type::count == 1);
43         try {
44             any const a2(t);
45             assert(false);
46         } catch (my_any_exception const &) {
47             // do nothing
48         } catch (...) {
49             assert(false);
50         }
51         assert(Type::count == 1);
52         assert(t.value == 42);
53     }
54     assert(Type::count == 0);
55 #endif
56 }
57 
58 void test_move_value_throws()
59 {
60 #if !defined(TEST_HAS_NO_EXCEPTIONS)
61     assert(throws_on_move::count == 0);
62     {
63         throws_on_move v;
64         assert(throws_on_move::count == 1);
65         try {
66             any const a(std::move(v));
67             assert(false);
68         } catch (my_any_exception const &) {
69             // do nothing
70         } catch (...) {
71             assert(false);
72         }
73         assert(throws_on_move::count == 1);
74     }
75     assert(throws_on_move::count == 0);
76 #endif
77 }
78 
79 template <class Type>
80 void test_copy_move_value() {
81     // constructing from a small type should perform no allocations.
82     DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
83     assert(Type::count == 0);
84     Type::reset();
85     {
86         Type t(42);
87         assert(Type::count == 1);
88 
89         any a(t);
90 
91         assert(Type::count == 2);
92         assert(Type::copied == 1);
93         assert(Type::moved == 0);
94         assertContains<Type>(a, 42);
95     }
96     assert(Type::count == 0);
97     Type::reset();
98     {
99         Type t(42);
100         assert(Type::count == 1);
101 
102         any a(std::move(t));
103 
104         assert(Type::count == 2);
105         assert(Type::copied == 0);
106         assert(Type::moved == 1);
107         assertContains<Type>(a, 42);
108     }
109 }
110 
111 // Test that any(ValueType&&) is *never* selected for a std::in_place_type_t specialization.
112 void test_sfinae_constraints() {
113     using BadTag = std::in_place_type_t<int>;
114     using OKTag = std::in_place_t;
115     // Test that the tag type is properly handled in SFINAE
116     BadTag t = std::in_place_type<int>;
117     OKTag ot = std::in_place;
118     {
119         std::any a(t);
120         assertContains<int>(a, 0);
121     }
122     {
123         std::any a(std::move(t));
124         assertContains<int>(a, 0);
125     }
126     {
127         std::any a(ot);
128         assert(containsType<OKTag>(a));
129     }
130     {
131         struct Dummy { Dummy() = delete; };
132         using T = std::in_place_type_t<Dummy>;
133         static_assert(!std::is_constructible<std::any, T>::value, "");
134     }
135     {
136         // Test that the ValueType&& constructor SFINAE's away when the
137         // argument is non-copyable
138         struct NoCopy {
139           NoCopy() = default;
140           NoCopy(NoCopy const&) = delete;
141           NoCopy(int) {}
142         };
143         static_assert(!std::is_constructible<std::any, NoCopy>::value, "");
144         static_assert(!std::is_constructible<std::any, NoCopy&>::value, "");
145         static_assert(!std::is_convertible<NoCopy, std::any>::value, "");
146     }
147 }
148 
149 int main(int, char**) {
150     test_copy_move_value<small>();
151     test_copy_move_value<large>();
152     test_copy_value_throws<small_throws_on_copy>();
153     test_copy_value_throws<large_throws_on_copy>();
154     test_move_value_throws();
155     test_sfinae_constraints();
156 
157   return 0;
158 }
159