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