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 // <optional>
11 
12 // From LWG2451:
13 // template<class U>
14 //   optional<T>& operator=(const optional<U>& rhs);
15 
16 #include <optional>
17 #include <type_traits>
18 #include <cassert>
19 
20 #include "test_macros.h"
21 #include "archetypes.h"
22 
23 using std::optional;
24 
25 struct X
26 {
27     static bool throw_now;
28 
29     X() = default;
XX30     X(int)
31     {
32         if (throw_now)
33             TEST_THROW(6);
34     }
35 };
36 
37 bool X::throw_now = false;
38 
39 struct Y1
40 {
41     Y1() = default;
Y1Y142     Y1(const int&) {}
43     Y1& operator=(const Y1&) = delete;
44 };
45 
46 struct Y2
47 {
48     Y2() = default;
49     Y2(const int&) = delete;
operator =Y250     Y2& operator=(const int&) { return *this; }
51 };
52 
53 template <class T>
54 struct AssignableFrom {
55   static int type_constructed;
56   static int type_assigned;
57 static int int_constructed;
58   static int int_assigned;
59 
resetAssignableFrom60   static void reset() {
61       type_constructed = int_constructed = 0;
62       type_assigned = int_assigned = 0;
63   }
64 
65   AssignableFrom() = default;
66 
AssignableFromAssignableFrom67   explicit AssignableFrom(T) { ++type_constructed; }
operator =AssignableFrom68   AssignableFrom& operator=(T) { ++type_assigned; return *this; }
69 
AssignableFromAssignableFrom70   AssignableFrom(int) { ++int_constructed; }
operator =AssignableFrom71   AssignableFrom& operator=(int) { ++int_assigned; return *this; }
72 private:
73   AssignableFrom(AssignableFrom const&) = delete;
74   AssignableFrom& operator=(AssignableFrom const&) = delete;
75 };
76 
77 template <class T> int AssignableFrom<T>::type_constructed = 0;
78 template <class T> int AssignableFrom<T>::type_assigned = 0;
79 template <class T> int AssignableFrom<T>::int_constructed = 0;
80 template <class T> int AssignableFrom<T>::int_assigned = 0;
81 
82 
test_with_test_type()83 void test_with_test_type() {
84     using T = TestTypes::TestType;
85     T::reset();
86     { // non-empty to empty
87         T::reset_constructors();
88         optional<T> opt;
89         const optional<int> other(42);
90         opt = other;
91         assert(T::alive == 1);
92         assert(T::constructed == 1);
93         assert(T::value_constructed == 1);
94         assert(T::assigned == 0);
95         assert(T::destroyed == 0);
96         assert(static_cast<bool>(other) == true);
97         assert(*other == 42);
98         assert(static_cast<bool>(opt) == true);
99         assert(*opt == T(42));
100     }
101     assert(T::alive == 0);
102     { // non-empty to non-empty
103         optional<T> opt(101);
104         const optional<int> other(42);
105         T::reset_constructors();
106         opt = other;
107         assert(T::alive == 1);
108         assert(T::constructed == 0);
109         assert(T::assigned == 1);
110         assert(T::value_assigned == 1);
111         assert(T::destroyed == 0);
112         assert(static_cast<bool>(other) == true);
113         assert(*other == 42);
114         assert(static_cast<bool>(opt) == true);
115         assert(*opt == T(42));
116     }
117     assert(T::alive == 0);
118     { // empty to non-empty
119         optional<T> opt(101);
120         const optional<int> other;
121         T::reset_constructors();
122         opt = other;
123         assert(T::alive == 0);
124         assert(T::constructed == 0);
125         assert(T::assigned == 0);
126         assert(T::destroyed == 1);
127         assert(static_cast<bool>(other) == false);
128         assert(static_cast<bool>(opt) == false);
129     }
130     assert(T::alive == 0);
131     { // empty to empty
132         optional<T> opt;
133         const optional<int> other;
134         T::reset_constructors();
135         opt = other;
136         assert(T::alive == 0);
137         assert(T::constructed == 0);
138         assert(T::assigned == 0);
139         assert(T::destroyed == 0);
140         assert(static_cast<bool>(other) == false);
141         assert(static_cast<bool>(opt) == false);
142     }
143     assert(T::alive == 0);
144 }
145 
test_ambiguous_assign()146 void test_ambiguous_assign() {
147     using OptInt = std::optional<int>;
148     {
149         using T = AssignableFrom<OptInt const&>;
150         const OptInt a(42);
151         T::reset();
152         {
153             std::optional<T> t;
154             t = a;
155             assert(T::type_constructed == 1);
156             assert(T::type_assigned == 0);
157             assert(T::int_constructed == 0);
158             assert(T::int_assigned == 0);
159         }
160         T::reset();
161         {
162             std::optional<T> t(42);
163             t = a;
164             assert(T::type_constructed == 0);
165             assert(T::type_assigned == 1);
166             assert(T::int_constructed == 1);
167             assert(T::int_assigned == 0);
168         }
169         T::reset();
170         {
171             std::optional<T> t(42);
172             t = std::move(a);
173             assert(T::type_constructed == 0);
174             assert(T::type_assigned == 1);
175             assert(T::int_constructed == 1);
176             assert(T::int_assigned == 0);
177         }
178     }
179     {
180         using T = AssignableFrom<OptInt&>;
181         OptInt a(42);
182         T::reset();
183         {
184             std::optional<T> t;
185             t = a;
186             assert(T::type_constructed == 1);
187             assert(T::type_assigned == 0);
188             assert(T::int_constructed == 0);
189             assert(T::int_assigned == 0);
190         }
191         {
192             using Opt = std::optional<T>;
193             static_assert(!std::is_assignable_v<Opt&, OptInt const&>, "");
194         }
195     }
196 }
197 
198 
main(int,char **)199 int main(int, char**)
200 {
201     test_with_test_type();
202     test_ambiguous_assign();
203     {
204         optional<int> opt;
205         constexpr optional<short> opt2;
206         opt = opt2;
207         static_assert(static_cast<bool>(opt2) == false, "");
208         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
209     }
210     {
211         optional<int> opt;
212         constexpr optional<short> opt2(short{2});
213         opt = opt2;
214         static_assert(static_cast<bool>(opt2) == true, "");
215         static_assert(*opt2 == 2, "");
216         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
217         assert(*opt == *opt2);
218     }
219     {
220         optional<int> opt(3);
221         constexpr optional<short> opt2;
222         opt = opt2;
223         static_assert(static_cast<bool>(opt2) == false, "");
224         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
225     }
226     {
227         optional<int> opt(3);
228         constexpr optional<short> opt2(short{2});
229         opt = opt2;
230         static_assert(static_cast<bool>(opt2) == true, "");
231         static_assert(*opt2 == 2, "");
232         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
233         assert(*opt == *opt2);
234     }
235 #ifndef TEST_HAS_NO_EXCEPTIONS
236     {
237         optional<X> opt;
238         optional<int> opt2(42);
239         assert(static_cast<bool>(opt2) == true);
240         try
241         {
242             X::throw_now = true;
243             opt = opt2;
244             assert(false);
245         }
246         catch (int i)
247         {
248             assert(i == 6);
249             assert(static_cast<bool>(opt) == false);
250         }
251     }
252 #endif
253 
254   return 0;
255 }
256