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 ValueType>
20 // any& operator=(ValueType&&);
21
22 // Test value copy and move assignment.
23
24 #include <any>
25 #include <cassert>
26
27 #include "any_helpers.h"
28 #include "count_new.h"
29 #include "test_macros.h"
30
31 using std::any;
32 using std::any_cast;
33
34 template <class LHS, class RHS>
test_assign_value()35 void test_assign_value() {
36 assert(LHS::count == 0);
37 assert(RHS::count == 0);
38 LHS::reset();
39 RHS::reset();
40 {
41 any lhs(LHS(1));
42 any const rhs(RHS(2));
43
44 assert(LHS::count == 1);
45 assert(RHS::count == 1);
46 assert(RHS::copied == 0);
47
48 lhs = rhs;
49
50 assert(RHS::copied == 1);
51 assert(LHS::count == 0);
52 assert(RHS::count == 2);
53
54 assertContains<RHS>(lhs, 2);
55 assertContains<RHS>(rhs, 2);
56 }
57 assert(LHS::count == 0);
58 assert(RHS::count == 0);
59 LHS::reset();
60 RHS::reset();
61 {
62 any lhs(LHS(1));
63 any rhs(RHS(2));
64
65 assert(LHS::count == 1);
66 assert(RHS::count == 1);
67 assert(RHS::moved == 1);
68
69 lhs = std::move(rhs);
70
71 assert(RHS::moved >= 1);
72 assert(RHS::copied == 0);
73 assert(LHS::count == 0);
74 assert(RHS::count == 1 + rhs.has_value());
75 LIBCPP_ASSERT(!rhs.has_value());
76
77 assertContains<RHS>(lhs, 2);
78 if (rhs.has_value())
79 assertContains<RHS>(rhs, 0);
80 }
81 assert(LHS::count == 0);
82 assert(RHS::count == 0);
83 }
84
85 template <class RHS>
test_assign_value_empty()86 void test_assign_value_empty() {
87 assert(RHS::count == 0);
88 RHS::reset();
89 {
90 any lhs;
91 RHS rhs(42);
92 assert(RHS::count == 1);
93 assert(RHS::copied == 0);
94
95 lhs = rhs;
96
97 assert(RHS::count == 2);
98 assert(RHS::copied == 1);
99 assert(RHS::moved >= 0);
100 assertContains<RHS>(lhs, 42);
101 }
102 assert(RHS::count == 0);
103 RHS::reset();
104 {
105 any lhs;
106 RHS rhs(42);
107 assert(RHS::count == 1);
108 assert(RHS::moved == 0);
109
110 lhs = std::move(rhs);
111
112 assert(RHS::count == 2);
113 assert(RHS::copied == 0);
114 assert(RHS::moved >= 1);
115 assertContains<RHS>(lhs, 42);
116 }
117 assert(RHS::count == 0);
118 RHS::reset();
119 }
120
121
122 template <class Tp, bool Move = false>
test_assign_throws()123 void test_assign_throws() {
124 #if !defined(TEST_HAS_NO_EXCEPTIONS)
125 auto try_throw =
126 [](any& lhs, Tp& rhs) {
127 try {
128 Move ? lhs = std::move(rhs)
129 : lhs = rhs;
130 assert(false);
131 } catch (my_any_exception const &) {
132 // do nothing
133 } catch (...) {
134 assert(false);
135 }
136 };
137 // const lvalue to empty
138 {
139 any lhs;
140 Tp rhs(1);
141 assert(Tp::count == 1);
142
143 try_throw(lhs, rhs);
144
145 assert(Tp::count == 1);
146 assertEmpty<Tp>(lhs);
147 }
148 {
149 any lhs((small(2)));
150 Tp rhs(1);
151 assert(small::count == 1);
152 assert(Tp::count == 1);
153
154 try_throw(lhs, rhs);
155
156 assert(small::count == 1);
157 assert(Tp::count == 1);
158 assertContains<small>(lhs, 2);
159 }
160 {
161 any lhs((large(2)));
162 Tp rhs(1);
163 assert(large::count == 1);
164 assert(Tp::count == 1);
165
166 try_throw(lhs, rhs);
167
168 assert(large::count == 1);
169 assert(Tp::count == 1);
170 assertContains<large>(lhs, 2);
171 }
172 #endif
173 }
174
175
176 // Test that any& operator=(ValueType&&) is *never* selected for:
177 // * std::in_place type.
178 // * Non-copyable types
test_sfinae_constraints()179 void test_sfinae_constraints() {
180 { // Only the constructors are required to SFINAE on in_place_t
181 using Tag = std::in_place_type_t<int>;
182 using RawTag = std::remove_reference_t<Tag>;
183 static_assert(std::is_assignable<std::any, RawTag&&>::value, "");
184 }
185 {
186 struct Dummy { Dummy() = delete; };
187 using T = std::in_place_type_t<Dummy>;
188 static_assert(std::is_assignable<std::any, T>::value, "");
189 }
190 {
191 // Test that the ValueType&& constructor SFINAE's away when the
192 // argument is non-copyable
193 struct NoCopy {
194 NoCopy() = default;
195 NoCopy(NoCopy const&) = delete;
196 NoCopy(NoCopy&&) = default;
197 };
198 static_assert(!std::is_assignable<std::any, NoCopy>::value, "");
199 static_assert(!std::is_assignable<std::any, NoCopy&>::value, "");
200 }
201 }
202
main(int,char **)203 int main(int, char**) {
204 test_assign_value<small1, small2>();
205 test_assign_value<large1, large2>();
206 test_assign_value<small, large>();
207 test_assign_value<large, small>();
208 test_assign_value_empty<small>();
209 test_assign_value_empty<large>();
210 test_assign_throws<small_throws_on_copy>();
211 test_assign_throws<large_throws_on_copy>();
212 test_assign_throws<throws_on_move, /* Move = */ true>();
213 test_sfinae_constraints();
214
215 return 0;
216 }
217