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