@@ -239,6 +239,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
239
239
} ,
240
240
access_place_error_reported : FxHashSet ( ) ,
241
241
reservation_error_reported : FxHashSet ( ) ,
242
+ moved_error_reported : FxHashSet ( ) ,
242
243
nonlexical_regioncx : opt_regioncx,
243
244
nonlexical_cause_info : None ,
244
245
} ;
@@ -285,6 +286,9 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
285
286
/// but it is currently inconvenient to track down the BorrowIndex
286
287
/// at the time we detect and report a reservation error.
287
288
reservation_error_reported : FxHashSet < Place < ' tcx > > ,
289
+ /// This field keeps track of errors reported in the checking of moved variables,
290
+ /// so that we don't report report seemingly duplicate errors.
291
+ moved_error_reported : FxHashSet < Place < ' tcx > > ,
288
292
/// Non-lexical region inference context, if NLL is enabled. This
289
293
/// contains the results from region inference and lets us e.g.
290
294
/// find out which CFG points are contained in each borrow region.
@@ -368,7 +372,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
368
372
LocalMutationIsAllowed :: No ,
369
373
flow_state,
370
374
) ;
371
- self . check_if_path_is_moved (
375
+ self . check_if_path_or_subpath_is_moved (
372
376
context,
373
377
InitializationRequiringAction :: Use ,
374
378
( output, span) ,
@@ -965,7 +969,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
965
969
// Write of P[i] or *P, or WriteAndRead of any P, requires P init'd.
966
970
match mode {
967
971
MutateMode :: WriteAndRead => {
968
- self . check_if_path_is_moved (
972
+ self . check_if_path_or_subpath_is_moved (
969
973
context,
970
974
InitializationRequiringAction :: Update ,
971
975
place_span,
@@ -1025,7 +1029,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1025
1029
flow_state,
1026
1030
) ;
1027
1031
1028
- self . check_if_path_is_moved (
1032
+ self . check_if_path_or_subpath_is_moved (
1029
1033
context,
1030
1034
InitializationRequiringAction :: Borrow ,
1031
1035
( place, span) ,
@@ -1053,7 +1057,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1053
1057
LocalMutationIsAllowed :: No ,
1054
1058
flow_state,
1055
1059
) ;
1056
- self . check_if_path_is_moved (
1060
+ self . check_if_path_or_subpath_is_moved (
1057
1061
context,
1058
1062
InitializationRequiringAction :: Use ,
1059
1063
( place, span) ,
@@ -1100,7 +1104,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1100
1104
) ;
1101
1105
1102
1106
// Finally, check if path was already moved.
1103
- self . check_if_path_is_moved (
1107
+ self . check_if_path_or_subpath_is_moved (
1104
1108
context,
1105
1109
InitializationRequiringAction :: Use ,
1106
1110
( place, span) ,
@@ -1118,7 +1122,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1118
1122
) ;
1119
1123
1120
1124
// Finally, check if path was already moved.
1121
- self . check_if_path_is_moved (
1125
+ self . check_if_path_or_subpath_is_moved (
1122
1126
context,
1123
1127
InitializationRequiringAction :: Use ,
1124
1128
( place, span) ,
@@ -1269,7 +1273,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1269
1273
LocalMutationIsAllowed :: No ,
1270
1274
flow_state,
1271
1275
) ;
1272
- // We do not need to call `check_if_path_is_moved `
1276
+ // We do not need to call `check_if_path_or_subpath_is_moved `
1273
1277
// again, as we already called it when we made the
1274
1278
// initial reservation.
1275
1279
}
@@ -1304,7 +1308,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1304
1308
}
1305
1309
}
1306
1310
1307
- fn check_if_path_is_moved (
1311
+ fn check_if_full_path_is_moved (
1308
1312
& mut self ,
1309
1313
context : Context ,
1310
1314
desired_action : InitializationRequiringAction ,
@@ -1322,18 +1326,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1322
1326
//
1323
1327
// 1. Move of `a.b.c`, use of `a.b.c`
1324
1328
// 2. Move of `a.b.c`, use of `a.b.c.d` (without first reinitializing `a.b.c.d`)
1325
- // 3. Move of `a.b.c`, use of `a` or `a.b`
1326
- // 4. Uninitialized `(a.b.c: &_)`, use of `*a.b.c`; note that with
1329
+ // 3. Uninitialized `(a.b.c: &_)`, use of `*a.b.c`; note that with
1327
1330
// partial initialization support, one might have `a.x`
1328
1331
// initialized but not `a.b`.
1329
1332
//
1330
1333
// OK scenarios:
1331
1334
//
1332
- // 5 . Move of `a.b.c`, use of `a.b.d`
1333
- // 6 . Uninitialized `a.x`, initialized `a.b`, use of `a.b`
1334
- // 7 . Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b`
1335
+ // 4 . Move of `a.b.c`, use of `a.b.d`
1336
+ // 5 . Uninitialized `a.x`, initialized `a.b`, use of `a.b`
1337
+ // 6 . Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b`
1335
1338
// must have been initialized for the use to be sound.
1336
- // 8 . Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
1339
+ // 7 . Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
1337
1340
1338
1341
// The dataflow tracks shallow prefixes distinctly (that is,
1339
1342
// field-accesses on P distinctly from P itself), in order to
@@ -1352,9 +1355,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1352
1355
// have a MovePath, that should capture the initialization
1353
1356
// state for the place scenario.
1354
1357
//
1355
- // This code covers scenarios 1, 2, and 4 .
1358
+ // This code covers scenarios 1, 2, and 3 .
1356
1359
1357
- debug ! ( "check_if_path_is_moved part1 place: {:?}" , place) ;
1360
+ debug ! ( "check_if_full_path_is_moved place: {:?}" , place) ;
1358
1361
match self . move_path_closest_to ( place) {
1359
1362
Ok ( mpi) => {
1360
1363
if maybe_uninits. contains ( & mpi) {
@@ -1374,18 +1377,52 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1374
1377
// ancestors; dataflow recurs on children when parents
1375
1378
// move (to support partial (re)inits).
1376
1379
//
1377
- // (I.e. querying parents breaks scenario 8 ; but may want
1380
+ // (I.e. querying parents breaks scenario 7 ; but may want
1378
1381
// to do such a query based on partial-init feature-gate.)
1379
1382
}
1383
+ }
1384
+
1385
+ fn check_if_path_or_subpath_is_moved (
1386
+ & mut self ,
1387
+ context : Context ,
1388
+ desired_action : InitializationRequiringAction ,
1389
+ place_span : ( & Place < ' tcx > , Span ) ,
1390
+ flow_state : & Flows < ' cx , ' gcx , ' tcx > ,
1391
+ ) {
1392
+ // FIXME: analogous code in check_loans first maps `place` to
1393
+ // its base_path ... but is that what we want here?
1394
+ let place = self . base_path ( place_span. 0 ) ;
1395
+
1396
+ let maybe_uninits = & flow_state. uninits ;
1397
+ let curr_move_outs = & flow_state. move_outs ;
1398
+
1399
+ // Bad scenarios:
1400
+ //
1401
+ // 1. Move of `a.b.c`, use of `a` or `a.b`
1402
+ // partial initialization support, one might have `a.x`
1403
+ // initialized but not `a.b`.
1404
+ // 2. All bad scenarios from `check_if_full_path_is_moved`
1405
+ //
1406
+ // OK scenarios:
1407
+ //
1408
+ // 3. Move of `a.b.c`, use of `a.b.d`
1409
+ // 4. Uninitialized `a.x`, initialized `a.b`, use of `a.b`
1410
+ // 5. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b`
1411
+ // must have been initialized for the use to be sound.
1412
+ // 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
1413
+
1414
+ self . check_if_full_path_is_moved ( context, desired_action, place_span, flow_state) ;
1380
1415
1381
1416
// A move of any shallow suffix of `place` also interferes
1382
1417
// with an attempt to use `place`. This is scenario 3 above.
1383
1418
//
1384
1419
// (Distinct from handling of scenarios 1+2+4 above because
1385
1420
// `place` does not interfere with suffixes of its prefixes,
1386
1421
// e.g. `a.b.c` does not interfere with `a.b.d`)
1422
+ //
1423
+ // This code covers scenario 1.
1387
1424
1388
- debug ! ( "check_if_path_is_moved part2 place: {:?}" , place) ;
1425
+ debug ! ( "check_if_path_or_subpath_is_moved place: {:?}" , place) ;
1389
1426
if let Some ( mpi) = self . move_path_for_place ( place) {
1390
1427
if let Some ( child_mpi) = maybe_uninits. has_any_child_of ( mpi) {
1391
1428
self . report_use_of_moved_or_uninitialized (
@@ -1445,7 +1482,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1445
1482
( place, span) : ( & Place < ' tcx > , Span ) ,
1446
1483
flow_state : & Flows < ' cx , ' gcx , ' tcx > ,
1447
1484
) {
1448
- // recur down place; dispatch to check_if_path_is_moved when necessary
1485
+ debug ! ( "check_if_assigned_path_is_moved place: {:?}" , place) ;
1486
+ // recur down place; dispatch to external checks when necessary
1449
1487
let mut place = place;
1450
1488
loop {
1451
1489
match * place {
@@ -1456,17 +1494,25 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1456
1494
Place :: Projection ( ref proj) => {
1457
1495
let Projection { ref base, ref elem } = * * proj;
1458
1496
match * elem {
1459
- ProjectionElem :: Deref |
1460
- // assigning to *P requires `P` initialized.
1461
1497
ProjectionElem :: Index ( _/*operand*/ ) |
1462
1498
ProjectionElem :: ConstantIndex { .. } |
1463
- // assigning to P[i] requires `P` initialized .
1499
+ // assigning to P[i] requires P to be valid .
1464
1500
ProjectionElem :: Downcast ( _/*adt_def*/ , _/*variant_idx*/ ) =>
1465
1501
// assigning to (P->variant) is okay if assigning to `P` is okay
1466
1502
//
1467
1503
// FIXME: is this true even if P is a adt with a dtor?
1468
1504
{ }
1469
1505
1506
+ // assigning to (*P) requires P to be initialized
1507
+ ProjectionElem :: Deref => {
1508
+ self . check_if_full_path_is_moved (
1509
+ context, InitializationRequiringAction :: Use ,
1510
+ ( base, span) , flow_state) ;
1511
+ // (base initialized; no need to
1512
+ // recur further)
1513
+ break ;
1514
+ }
1515
+
1470
1516
ProjectionElem :: Subslice { .. } => {
1471
1517
panic ! ( "we don't allow assignments to subslices, context: {:?}" ,
1472
1518
context) ;
@@ -1484,7 +1530,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1484
1530
// check_loans.rs first maps
1485
1531
// `base` to its base_path.
1486
1532
1487
- self . check_if_path_is_moved (
1533
+ self . check_if_path_or_subpath_is_moved (
1488
1534
context, InitializationRequiringAction :: Assignment ,
1489
1535
( base, span) , flow_state) ;
1490
1536
0 commit comments