@@ -17,6 +17,8 @@ using namespace std;
17
17
enum class IsDefaultConstructible : bool { Not, Yes };
18
18
enum class IsTriviallyCopyConstructible : bool { Not, Yes };
19
19
enum class IsTriviallyMoveConstructible : bool { Not, Yes };
20
+ enum class IsTriviallyCopyAssignable : bool { Not, Yes };
21
+ enum class IsTriviallyMoveAssignable : bool { Not, Yes };
20
22
enum class IsTriviallyDestructible : bool { Not, Yes };
21
23
22
24
enum class IsNothrowConstructible : bool { Not, Yes };
@@ -1186,6 +1188,170 @@ namespace test_expected {
1186
1188
test_assignment<NCC::Yes, NMC::Yes, NCA::Yes, NMA::Yes>();
1187
1189
}
1188
1190
1191
+ // Only test the triviality scenarios that occur in practice.
1192
+ template <IsTriviallyCopyConstructible CC, IsTriviallyMoveConstructible MC, IsTriviallyCopyAssignable CA,
1193
+ IsTriviallyMoveAssignable MA, IsTriviallyDestructible D>
1194
+ struct TrivialityScenario {
1195
+ static constexpr auto CopyCtorTriviality = CC;
1196
+ static constexpr auto MoveCtorTriviality = MC;
1197
+ static constexpr auto CopyAssignTriviality = CA;
1198
+ static constexpr auto MoveAssignTriviality = MA;
1199
+ static constexpr auto DtorTriviality = D;
1200
+ };
1201
+
1202
+ // No operations are trivial.
1203
+ using TrivialityScenario1 = TrivialityScenario<IsTriviallyCopyConstructible::Not, IsTriviallyMoveConstructible::Not,
1204
+ IsTriviallyCopyAssignable::Not, IsTriviallyMoveAssignable::Not, IsTriviallyDestructible::Not>;
1205
+
1206
+ // Only destruction is trivial.
1207
+ using TrivialityScenario2 = TrivialityScenario<IsTriviallyCopyConstructible::Not, IsTriviallyMoveConstructible::Not,
1208
+ IsTriviallyCopyAssignable::Not, IsTriviallyMoveAssignable::Not, IsTriviallyDestructible::Yes>;
1209
+
1210
+ // Only destruction and move construction are trivial.
1211
+ using TrivialityScenario3 = TrivialityScenario<IsTriviallyCopyConstructible::Not, IsTriviallyMoveConstructible::Yes,
1212
+ IsTriviallyCopyAssignable::Not, IsTriviallyMoveAssignable::Not, IsTriviallyDestructible::Yes>;
1213
+
1214
+ // Only destruction and move construction/assignment are trivial.
1215
+ using TrivialityScenario4 = TrivialityScenario<IsTriviallyCopyConstructible::Not, IsTriviallyMoveConstructible::Yes,
1216
+ IsTriviallyCopyAssignable::Not, IsTriviallyMoveAssignable::Yes, IsTriviallyDestructible::Yes>;
1217
+
1218
+ // Only destruction and copy/move construction are trivial.
1219
+ using TrivialityScenario5 = TrivialityScenario<IsTriviallyCopyConstructible::Yes, IsTriviallyMoveConstructible::Yes,
1220
+ IsTriviallyCopyAssignable::Not, IsTriviallyMoveAssignable::Not, IsTriviallyDestructible::Yes>;
1221
+
1222
+ // All operations are trivial.
1223
+ using TrivialityScenario6 = TrivialityScenario<IsTriviallyCopyConstructible::Yes, IsTriviallyMoveConstructible::Yes,
1224
+ IsTriviallyCopyAssignable::Yes, IsTriviallyMoveAssignable::Yes, IsTriviallyDestructible::Yes>;
1225
+
1226
+ // per LWG-4026, see also LLVM-74768
1227
+ template <class PODType , class Scenario >
1228
+ struct TrivialityTester {
1229
+ PODType val{};
1230
+
1231
+ TrivialityTester () = default ;
1232
+
1233
+ constexpr explicit TrivialityTester (PODType v) noexcept : val{v} {}
1234
+
1235
+ constexpr TrivialityTester (const TrivialityTester& other) noexcept : val{other.val } {}
1236
+ constexpr TrivialityTester (const TrivialityTester&)
1237
+ requires (Scenario::CopyCtorTriviality == IsTriviallyCopyConstructible::Yes)
1238
+ = default;
1239
+
1240
+ constexpr TrivialityTester (TrivialityTester&& other) noexcept : val{other.val } {}
1241
+ TrivialityTester (TrivialityTester&&)
1242
+ requires (Scenario::MoveCtorTriviality == IsTriviallyMoveConstructible::Yes)
1243
+ = default ;
1244
+
1245
+ constexpr TrivialityTester& operator =(const TrivialityTester& other) noexcept {
1246
+ val = other.val ;
1247
+ return *this ;
1248
+ }
1249
+ TrivialityTester& operator =(const TrivialityTester&)
1250
+ requires (Scenario::CopyAssignTriviality == IsTriviallyCopyAssignable::Yes)
1251
+ = default ;
1252
+
1253
+ constexpr TrivialityTester& operator =(TrivialityTester&& other) noexcept {
1254
+ val = other.val ;
1255
+ return *this ;
1256
+ }
1257
+ TrivialityTester& operator =(TrivialityTester&&)
1258
+ requires (Scenario::MoveAssignTriviality == IsTriviallyMoveAssignable::Yes)
1259
+ = default ;
1260
+
1261
+ constexpr ~TrivialityTester () {}
1262
+ ~TrivialityTester ()
1263
+ requires (Scenario::DtorTriviality == IsTriviallyDestructible::Yes)
1264
+ = default ;
1265
+ };
1266
+
1267
+ template <class Val1 , class OtherScenario >
1268
+ constexpr void test_triviality_of_assignment_binary () {
1269
+ using Val2 = TrivialityTester<char , OtherScenario>;
1270
+ using E = expected<Val1, Val2>;
1271
+
1272
+ static_assert (is_trivially_copy_assignable_v<E>
1273
+ == (is_trivially_copy_constructible_v<Val1> && is_trivially_copy_assignable_v<Val1>
1274
+ && is_trivially_destructible_v<Val1> && is_trivially_copy_constructible_v<Val2>
1275
+ && is_trivially_copy_assignable_v<Val2> && is_trivially_destructible_v<Val2>) );
1276
+ static_assert (is_trivially_move_assignable_v<E>
1277
+ == (is_trivially_move_constructible_v<Val1> && is_trivially_move_assignable_v<Val1>
1278
+ && is_trivially_destructible_v<Val1> && is_trivially_move_constructible_v<Val2>
1279
+ && is_trivially_move_assignable_v<Val2> && is_trivially_destructible_v<Val2>) );
1280
+
1281
+ {
1282
+ E e1 {Val1{42 }};
1283
+ E e2 {unexpect, Val2{' ^' }};
1284
+ e1 = e2 ;
1285
+ assert (!e1 .has_value ());
1286
+ assert (e1 .error ().val == ' ^' );
1287
+ }
1288
+ {
1289
+ E e1 {Val1{42 }};
1290
+ E e2 {unexpect, Val2{' ^' }};
1291
+ e1 = move (e2 );
1292
+ assert (!e1 .has_value ());
1293
+ assert (e1 .error ().val == ' ^' );
1294
+ }
1295
+ {
1296
+ E e1 {Val1{42 }};
1297
+ E e2 {unexpect, Val2{' ^' }};
1298
+ e2 = e1 ;
1299
+ assert (e2 .has_value ());
1300
+ assert (e2 .value ().val == 42 );
1301
+ }
1302
+ {
1303
+ E e1 {Val1{42 }};
1304
+ E e2 {unexpect, Val2{' ^' }};
1305
+ e2 = move (e1 );
1306
+ assert (e2 .has_value ());
1307
+ assert (e2 .value ().val == 42 );
1308
+ }
1309
+ }
1310
+
1311
+ template <class Scenario >
1312
+ constexpr void test_triviality_of_assignment () {
1313
+ using Val = TrivialityTester<int , Scenario>;
1314
+ using E = expected<void , Val>;
1315
+
1316
+ static_assert (is_trivially_copy_assignable_v<E>
1317
+ == (is_trivially_copy_constructible_v<Val> && is_trivially_copy_assignable_v<Val>
1318
+ && is_trivially_destructible_v<Val>) );
1319
+ static_assert (is_trivially_move_assignable_v<E>
1320
+ == (is_trivially_move_constructible_v<Val> && is_trivially_move_assignable_v<Val>
1321
+ && is_trivially_destructible_v<Val>) );
1322
+
1323
+ {
1324
+ E e1 {};
1325
+ E e2 {unexpect, Val{42 }};
1326
+ e1 = e2 ;
1327
+ assert (!e1 .has_value ());
1328
+ assert (e1 .error ().val == 42 );
1329
+ }
1330
+ {
1331
+ E e1 {};
1332
+ E e2 {unexpect, Val{42 }};
1333
+ e1 = move (e2 );
1334
+ assert (!e1 .has_value ());
1335
+ assert (e1 .error ().val == 42 );
1336
+ }
1337
+
1338
+ test_triviality_of_assignment_binary<Val, TrivialityScenario1>();
1339
+ test_triviality_of_assignment_binary<Val, TrivialityScenario2>();
1340
+ test_triviality_of_assignment_binary<Val, TrivialityScenario3>();
1341
+ test_triviality_of_assignment_binary<Val, TrivialityScenario4>();
1342
+ test_triviality_of_assignment_binary<Val, TrivialityScenario5>();
1343
+ test_triviality_of_assignment_binary<Val, TrivialityScenario6>();
1344
+ }
1345
+
1346
+ constexpr void test_triviality_of_assignment_all () {
1347
+ test_triviality_of_assignment<TrivialityScenario1>();
1348
+ test_triviality_of_assignment<TrivialityScenario2>();
1349
+ test_triviality_of_assignment<TrivialityScenario3>();
1350
+ test_triviality_of_assignment<TrivialityScenario4>();
1351
+ test_triviality_of_assignment<TrivialityScenario5>();
1352
+ test_triviality_of_assignment<TrivialityScenario6>();
1353
+ }
1354
+
1189
1355
constexpr void test_emplace () noexcept {
1190
1356
struct payload_emplace {
1191
1357
constexpr payload_emplace (bool & destructor_called) noexcept : _destructor_called(destructor_called) {}
@@ -2020,6 +2186,7 @@ namespace test_expected {
2020
2186
test_special_members ();
2021
2187
test_constructors ();
2022
2188
test_assignment ();
2189
+ test_triviality_of_assignment_all (); // per LWG-4026, see also LLVM-74768
2023
2190
test_emplace ();
2024
2191
test_swap ();
2025
2192
test_access ();
0 commit comments