@@ -33,17 +33,17 @@ struct Dummy {
3333
3434struct ThrowsCtorT {
3535 ThrowsCtorT (int ) noexcept (false ) {}
36- ThrowsCtorT & operator =(int ) noexcept { return *this ; }
36+ ThrowsCtorT& operator =(int ) noexcept { return *this ; }
3737};
3838
3939struct ThrowsAssignT {
4040 ThrowsAssignT (int ) noexcept {}
41- ThrowsAssignT & operator =(int ) noexcept (false ) { return *this ; }
41+ ThrowsAssignT& operator =(int ) noexcept (false ) { return *this ; }
4242};
4343
4444struct NoThrowT {
4545 NoThrowT (int ) noexcept {}
46- NoThrowT & operator =(int ) noexcept { return *this ; }
46+ NoThrowT& operator =(int ) noexcept { return *this ; }
4747};
4848
4949} // namespace MetaHelpers
@@ -55,7 +55,7 @@ struct ThrowsCtorT {
5555 int value;
5656 ThrowsCtorT () : value(0 ) {}
5757 ThrowsCtorT (int ) noexcept (false ) { throw 42 ; }
58- ThrowsCtorT & operator =(int v) noexcept {
58+ ThrowsCtorT& operator =(int v) noexcept {
5959 value = v;
6060 return *this ;
6161 }
@@ -64,9 +64,12 @@ struct ThrowsCtorT {
6464struct MoveCrashes {
6565 int value;
6666 MoveCrashes (int v = 0 ) noexcept : value{v} {}
67- MoveCrashes (MoveCrashes &&) noexcept { assert (false ); }
68- MoveCrashes &operator =(MoveCrashes &&) noexcept { assert (false ); return *this ; }
69- MoveCrashes &operator =(int v) noexcept {
67+ MoveCrashes (MoveCrashes&&) noexcept { assert (false ); }
68+ MoveCrashes& operator =(MoveCrashes&&) noexcept {
69+ assert (false );
70+ return *this ;
71+ }
72+ MoveCrashes& operator =(int v) noexcept {
7073 value = v;
7174 return *this ;
7275 }
@@ -76,8 +79,8 @@ struct ThrowsCtorTandMove {
7679 int value;
7780 ThrowsCtorTandMove () : value(0 ) {}
7881 ThrowsCtorTandMove (int ) noexcept (false ) { throw 42 ; }
79- ThrowsCtorTandMove (ThrowsCtorTandMove &&) noexcept (false ) { assert (false ); }
80- ThrowsCtorTandMove & operator =(int v) noexcept {
82+ ThrowsCtorTandMove (ThrowsCtorTandMove&&) noexcept (false ) { assert (false ); }
83+ ThrowsCtorTandMove& operator =(int v) noexcept {
8184 value = v;
8285 return *this ;
8386 }
@@ -87,14 +90,14 @@ struct ThrowsAssignT {
8790 int value;
8891 ThrowsAssignT () : value(0 ) {}
8992 ThrowsAssignT (int v) noexcept : value(v) {}
90- ThrowsAssignT & operator =(int ) noexcept (false ) { throw 42 ; }
93+ ThrowsAssignT& operator =(int ) noexcept (false ) { throw 42 ; }
9194};
9295
9396struct NoThrowT {
9497 int value;
9598 NoThrowT () : value(0 ) {}
9699 NoThrowT (int v) noexcept : value(v) {}
97- NoThrowT & operator =(int v) noexcept {
100+ NoThrowT& operator =(int v) noexcept {
98101 value = v;
99102 return *this ;
100103 }
@@ -103,7 +106,7 @@ struct NoThrowT {
103106#endif // !defined(TEST_HAS_NO_EXCEPTIONS)
104107} // namespace RuntimeHelpers
105108
106- void test_T_assignment_noexcept () {
109+ constexpr void test_T_assignment_noexcept () {
107110 using namespace MetaHelpers ;
108111 {
109112 using V = std::variant<Dummy, NoThrowT>;
@@ -119,17 +122,17 @@ void test_T_assignment_noexcept() {
119122 }
120123}
121124
122- void test_T_assignment_sfinae () {
125+ constexpr void test_T_assignment_sfinae () {
123126 {
124127 using V = std::variant<long , long long >;
125128 static_assert (!std::is_assignable<V, int >::value, " ambiguous" );
126129 }
127130 {
128131 using V = std::variant<std::string, std::string>;
129- static_assert (!std::is_assignable<V, const char *>::value, " ambiguous" );
132+ static_assert (!std::is_assignable<V, const char *>::value, " ambiguous" );
130133 }
131134 {
132- using V = std::variant<std::string, void *>;
135+ using V = std::variant<std::string, void *>;
133136 static_assert (!std::is_assignable<V, int >::value, " no matching operator=" );
134137 }
135138 {
@@ -138,8 +141,7 @@ void test_T_assignment_sfinae() {
138141 }
139142 {
140143 using V = std::variant<std::unique_ptr<int >, bool >;
141- static_assert (!std::is_assignable<V, std::unique_ptr<char >>::value,
142- " no explicit bool in operator=" );
144+ static_assert (!std::is_assignable<V, std::unique_ptr<char >>::value, " no explicit bool in operator=" );
143145 struct X {
144146 operator void *();
145147 };
@@ -152,12 +154,11 @@ void test_T_assignment_sfinae() {
152154 operator X ();
153155 };
154156 using V = std::variant<X>;
155- static_assert (std::is_assignable<V, Y>::value,
156- " regression on user-defined conversions in operator=" );
157+ static_assert (std::is_assignable<V, Y>::value, " regression on user-defined conversions in operator=" );
157158 }
158159}
159160
160- void test_T_assignment_basic () {
161+ TEST_CONSTEXPR_CXX20 void test_T_assignment_basic () {
161162 {
162163 std::variant<int > v (43 );
163164 v = 42 ;
@@ -184,19 +185,146 @@ void test_T_assignment_basic() {
184185 }
185186 {
186187 std::variant<std::string, bool > v = true ;
187- v = " bar" ;
188+ v = " bar" ;
188189 assert (v.index () == 0 );
189190 assert (std::get<0 >(v) == " bar" );
190191 }
192+ }
193+
194+ void test_T_assignment_basic_no_constexpr () {
195+ std::variant<bool , std::unique_ptr<int >> v;
196+ v = nullptr ;
197+ assert (v.index () == 1 );
198+ assert (std::get<1 >(v) == nullptr );
199+ }
200+
201+ struct TraceStat {
202+ int construct = 0 ;
203+ int copy_construct = 0 ;
204+ int copy_assign = 0 ;
205+ int move_construct = 0 ;
206+ int move_assign = 0 ;
207+ int T_copy_assign = 0 ;
208+ int T_move_assign = 0 ;
209+ int destroy = 0 ;
210+ };
211+
212+ template <bool CtorNoexcept, bool MoveCtorNoexcept>
213+ struct Trace {
214+ struct T {};
215+
216+ constexpr Trace (TraceStat* s) noexcept (CtorNoexcept) : stat(s) { ++s->construct ; }
217+ constexpr Trace (T) noexcept (CtorNoexcept) : stat(nullptr ) {}
218+ constexpr Trace (const Trace& o) : stat(o.stat) { ++stat->copy_construct ; }
219+ constexpr Trace (Trace&& o) noexcept (MoveCtorNoexcept) : stat(o.stat) { ++stat->move_construct ; }
220+ constexpr Trace& operator =(const Trace&) {
221+ ++stat->copy_assign ;
222+ return *this ;
223+ }
224+ constexpr Trace& operator =(Trace&&) noexcept {
225+ ++stat->move_assign ;
226+ return *this ;
227+ }
228+
229+ constexpr Trace& operator =(const T&) {
230+ ++stat->T_copy_assign ;
231+ return *this ;
232+ }
233+ constexpr Trace& operator =(T&&) noexcept {
234+ ++stat->T_move_assign ;
235+ return *this ;
236+ }
237+ TEST_CONSTEXPR_CXX20 ~Trace () { ++stat->destroy ; }
238+
239+ TraceStat* stat;
240+ };
241+
242+ TEST_CONSTEXPR_CXX20 void test_T_assignment_performs_construction () {
191243 {
192- std::variant<bool , std::unique_ptr<int >> v;
193- v = nullptr ;
194- assert (v.index () == 1 );
195- assert (std::get<1 >(v) == nullptr );
244+ using V = std::variant<int , Trace<false , false >>;
245+ TraceStat stat;
246+ V v{1 };
247+ v = &stat;
248+ assert (stat.construct == 1 );
249+ assert (stat.copy_construct == 0 );
250+ assert (stat.move_construct == 0 );
251+ assert (stat.copy_assign == 0 );
252+ assert (stat.move_assign == 0 );
253+ assert (stat.destroy == 0 );
254+ }
255+ {
256+ using V = std::variant<int , Trace<false , true >>;
257+ TraceStat stat;
258+ V v{1 };
259+ v = &stat;
260+ assert (stat.construct == 1 );
261+ assert (stat.copy_construct == 0 );
262+ assert (stat.move_construct == 1 );
263+ assert (stat.copy_assign == 0 );
264+ assert (stat.move_assign == 0 );
265+ assert (stat.destroy == 1 );
266+ }
267+
268+ {
269+ using V = std::variant<int , Trace<true , false >>;
270+ TraceStat stat;
271+ V v{1 };
272+ v = &stat;
273+ assert (stat.construct == 1 );
274+ assert (stat.copy_construct == 0 );
275+ assert (stat.move_construct == 0 );
276+ assert (stat.copy_assign == 0 );
277+ assert (stat.move_assign == 0 );
278+ assert (stat.destroy == 0 );
279+ }
280+
281+ {
282+ using V = std::variant<int , Trace<true , true >>;
283+ TraceStat stat;
284+ V v{1 };
285+ v = &stat;
286+ assert (stat.construct == 1 );
287+ assert (stat.copy_construct == 0 );
288+ assert (stat.move_construct == 0 );
289+ assert (stat.copy_assign == 0 );
290+ assert (stat.move_assign == 0 );
291+ assert (stat.destroy == 0 );
196292 }
197293}
198294
199- void test_T_assignment_performs_construction () {
295+ TEST_CONSTEXPR_CXX20 void test_T_assignment_performs_assignment () {
296+ {
297+ using V = std::variant<int , Trace<false , false >>;
298+ TraceStat stat;
299+ V v{&stat};
300+ v = Trace<false , false >::T{};
301+ assert (stat.construct == 1 );
302+ assert (stat.copy_construct == 0 );
303+ assert (stat.move_construct == 0 );
304+ assert (stat.copy_assign == 0 );
305+ assert (stat.move_assign == 0 );
306+ assert (stat.T_copy_assign == 0 );
307+ assert (stat.T_move_assign == 1 );
308+ assert (stat.destroy == 0 );
309+ }
310+ {
311+ using V = std::variant<int , Trace<false , false >>;
312+ TraceStat stat;
313+ V v{&stat};
314+ Trace<false , false >::T t;
315+ v = t;
316+ assert (stat.construct == 1 );
317+ assert (stat.copy_construct == 0 );
318+ assert (stat.move_construct == 0 );
319+ assert (stat.copy_assign == 0 );
320+ assert (stat.move_assign == 0 );
321+ assert (stat.T_copy_assign == 1 );
322+ assert (stat.T_move_assign == 0 );
323+ assert (stat.destroy == 0 );
324+ }
325+ }
326+
327+ void test_T_assignment_performs_construction_throw () {
200328 using namespace RuntimeHelpers ;
201329#ifndef TEST_HAS_NO_EXCEPTIONS
202330 {
@@ -220,7 +348,7 @@ void test_T_assignment_performs_construction() {
220348#endif // TEST_HAS_NO_EXCEPTIONS
221349}
222350
223- void test_T_assignment_performs_assignment () {
351+ void test_T_assignment_performs_assignment_throw () {
224352 using namespace RuntimeHelpers ;
225353#ifndef TEST_HAS_NO_EXCEPTIONS
226354 {
@@ -262,21 +390,37 @@ void test_T_assignment_performs_assignment() {
262390#endif // TEST_HAS_NO_EXCEPTIONS
263391}
264392
265- void test_T_assignment_vector_bool () {
393+ TEST_CONSTEXPR_CXX20 void test_T_assignment_vector_bool () {
266394 std::vector<bool > vec = {true };
267395 std::variant<bool , int > v;
268396 v = vec[0 ];
269397 assert (v.index () == 0 );
270398 assert (std::get<0 >(v) == true );
271399}
272400
273- int main (int , char **) {
401+ void non_constexpr_test () {
402+ test_T_assignment_basic_no_constexpr ();
403+ test_T_assignment_performs_construction_throw ();
404+ test_T_assignment_performs_assignment_throw ();
405+ }
406+
407+ TEST_CONSTEXPR_CXX20 bool test () {
274408 test_T_assignment_basic ();
275409 test_T_assignment_performs_construction ();
276410 test_T_assignment_performs_assignment ();
277411 test_T_assignment_noexcept ();
278412 test_T_assignment_sfinae ();
279413 test_T_assignment_vector_bool ();
280414
415+ return true ;
416+ }
417+
418+ int main (int , char **) {
419+ test ();
420+ non_constexpr_test ();
421+
422+ #if TEST_STD_VER >= 20
423+ static_assert (test ());
424+ #endif
281425 return 0 ;
282426}
0 commit comments