@@ -33,17 +33,17 @@ struct Dummy {
33
33
34
34
struct ThrowsCtorT {
35
35
ThrowsCtorT (int ) noexcept (false ) {}
36
- ThrowsCtorT & operator =(int ) noexcept { return *this ; }
36
+ ThrowsCtorT& operator =(int ) noexcept { return *this ; }
37
37
};
38
38
39
39
struct ThrowsAssignT {
40
40
ThrowsAssignT (int ) noexcept {}
41
- ThrowsAssignT & operator =(int ) noexcept (false ) { return *this ; }
41
+ ThrowsAssignT& operator =(int ) noexcept (false ) { return *this ; }
42
42
};
43
43
44
44
struct NoThrowT {
45
45
NoThrowT (int ) noexcept {}
46
- NoThrowT & operator =(int ) noexcept { return *this ; }
46
+ NoThrowT& operator =(int ) noexcept { return *this ; }
47
47
};
48
48
49
49
} // namespace MetaHelpers
@@ -55,7 +55,7 @@ struct ThrowsCtorT {
55
55
int value;
56
56
ThrowsCtorT () : value(0 ) {}
57
57
ThrowsCtorT (int ) noexcept (false ) { throw 42 ; }
58
- ThrowsCtorT & operator =(int v) noexcept {
58
+ ThrowsCtorT& operator =(int v) noexcept {
59
59
value = v;
60
60
return *this ;
61
61
}
@@ -64,9 +64,12 @@ struct ThrowsCtorT {
64
64
struct MoveCrashes {
65
65
int value;
66
66
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 {
70
73
value = v;
71
74
return *this ;
72
75
}
@@ -76,8 +79,8 @@ struct ThrowsCtorTandMove {
76
79
int value;
77
80
ThrowsCtorTandMove () : value(0 ) {}
78
81
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 {
81
84
value = v;
82
85
return *this ;
83
86
}
@@ -87,14 +90,14 @@ struct ThrowsAssignT {
87
90
int value;
88
91
ThrowsAssignT () : value(0 ) {}
89
92
ThrowsAssignT (int v) noexcept : value(v) {}
90
- ThrowsAssignT & operator =(int ) noexcept (false ) { throw 42 ; }
93
+ ThrowsAssignT& operator =(int ) noexcept (false ) { throw 42 ; }
91
94
};
92
95
93
96
struct NoThrowT {
94
97
int value;
95
98
NoThrowT () : value(0 ) {}
96
99
NoThrowT (int v) noexcept : value(v) {}
97
- NoThrowT & operator =(int v) noexcept {
100
+ NoThrowT& operator =(int v) noexcept {
98
101
value = v;
99
102
return *this ;
100
103
}
@@ -103,7 +106,7 @@ struct NoThrowT {
103
106
#endif // !defined(TEST_HAS_NO_EXCEPTIONS)
104
107
} // namespace RuntimeHelpers
105
108
106
- void test_T_assignment_noexcept () {
109
+ constexpr void test_T_assignment_noexcept () {
107
110
using namespace MetaHelpers ;
108
111
{
109
112
using V = std::variant<Dummy, NoThrowT>;
@@ -119,17 +122,17 @@ void test_T_assignment_noexcept() {
119
122
}
120
123
}
121
124
122
- void test_T_assignment_sfinae () {
125
+ constexpr void test_T_assignment_sfinae () {
123
126
{
124
127
using V = std::variant<long , long long >;
125
128
static_assert (!std::is_assignable<V, int >::value, " ambiguous" );
126
129
}
127
130
{
128
131
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" );
130
133
}
131
134
{
132
- using V = std::variant<std::string, void *>;
135
+ using V = std::variant<std::string, void *>;
133
136
static_assert (!std::is_assignable<V, int >::value, " no matching operator=" );
134
137
}
135
138
{
@@ -138,8 +141,7 @@ void test_T_assignment_sfinae() {
138
141
}
139
142
{
140
143
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=" );
143
145
struct X {
144
146
operator void *();
145
147
};
@@ -152,12 +154,11 @@ void test_T_assignment_sfinae() {
152
154
operator X ();
153
155
};
154
156
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=" );
157
158
}
158
159
}
159
160
160
- void test_T_assignment_basic () {
161
+ TEST_CONSTEXPR_CXX20 void test_T_assignment_basic () {
161
162
{
162
163
std::variant<int > v (43 );
163
164
v = 42 ;
@@ -184,19 +185,146 @@ void test_T_assignment_basic() {
184
185
}
185
186
{
186
187
std::variant<std::string, bool > v = true ;
187
- v = " bar" ;
188
+ v = " bar" ;
188
189
assert (v.index () == 0 );
189
190
assert (std::get<0 >(v) == " bar" );
190
191
}
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 () {
191
243
{
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 );
196
292
}
197
293
}
198
294
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 () {
200
328
using namespace RuntimeHelpers ;
201
329
#ifndef TEST_HAS_NO_EXCEPTIONS
202
330
{
@@ -220,7 +348,7 @@ void test_T_assignment_performs_construction() {
220
348
#endif // TEST_HAS_NO_EXCEPTIONS
221
349
}
222
350
223
- void test_T_assignment_performs_assignment () {
351
+ void test_T_assignment_performs_assignment_throw () {
224
352
using namespace RuntimeHelpers ;
225
353
#ifndef TEST_HAS_NO_EXCEPTIONS
226
354
{
@@ -262,21 +390,37 @@ void test_T_assignment_performs_assignment() {
262
390
#endif // TEST_HAS_NO_EXCEPTIONS
263
391
}
264
392
265
- void test_T_assignment_vector_bool () {
393
+ TEST_CONSTEXPR_CXX20 void test_T_assignment_vector_bool () {
266
394
std::vector<bool > vec = {true };
267
395
std::variant<bool , int > v;
268
396
v = vec[0 ];
269
397
assert (v.index () == 0 );
270
398
assert (std::get<0 >(v) == true );
271
399
}
272
400
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 () {
274
408
test_T_assignment_basic ();
275
409
test_T_assignment_performs_construction ();
276
410
test_T_assignment_performs_assignment ();
277
411
test_T_assignment_noexcept ();
278
412
test_T_assignment_sfinae ();
279
413
test_T_assignment_vector_bool ();
280
414
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
281
425
return 0 ;
282
426
}
0 commit comments