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