@@ -239,6 +239,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
239239 } ,
240240 access_place_error_reported : FxHashSet ( ) ,
241241 reservation_error_reported : FxHashSet ( ) ,
242+ moved_error_reported : FxHashSet ( ) ,
242243 nonlexical_regioncx : opt_regioncx,
243244 nonlexical_cause_info : None ,
244245 } ;
@@ -285,6 +286,9 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
285286 /// but it is currently inconvenient to track down the BorrowIndex
286287 /// at the time we detect and report a reservation error.
287288 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 > > ,
288292 /// Non-lexical region inference context, if NLL is enabled. This
289293 /// contains the results from region inference and lets us e.g.
290294 /// 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
368372 LocalMutationIsAllowed :: No ,
369373 flow_state,
370374 ) ;
371- self . check_if_path_is_moved (
375+ self . check_if_path_or_subpath_is_moved (
372376 context,
373377 InitializationRequiringAction :: Use ,
374378 ( output, span) ,
@@ -963,7 +967,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
963967 // Write of P[i] or *P, or WriteAndRead of any P, requires P init'd.
964968 match mode {
965969 MutateMode :: WriteAndRead => {
966- self . check_if_path_is_moved (
970+ self . check_if_path_or_subpath_is_moved (
967971 context,
968972 InitializationRequiringAction :: Update ,
969973 place_span,
@@ -1023,7 +1027,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
10231027 flow_state,
10241028 ) ;
10251029
1026- self . check_if_path_is_moved (
1030+ self . check_if_path_or_subpath_is_moved (
10271031 context,
10281032 InitializationRequiringAction :: Borrow ,
10291033 ( place, span) ,
@@ -1051,7 +1055,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
10511055 LocalMutationIsAllowed :: No ,
10521056 flow_state,
10531057 ) ;
1054- self . check_if_path_is_moved (
1058+ self . check_if_path_or_subpath_is_moved (
10551059 context,
10561060 InitializationRequiringAction :: Use ,
10571061 ( place, span) ,
@@ -1098,7 +1102,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
10981102 ) ;
10991103
11001104 // Finally, check if path was already moved.
1101- self . check_if_path_is_moved (
1105+ self . check_if_path_or_subpath_is_moved (
11021106 context,
11031107 InitializationRequiringAction :: Use ,
11041108 ( place, span) ,
@@ -1116,7 +1120,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
11161120 ) ;
11171121
11181122 // Finally, check if path was already moved.
1119- self . check_if_path_is_moved (
1123+ self . check_if_path_or_subpath_is_moved (
11201124 context,
11211125 InitializationRequiringAction :: Use ,
11221126 ( place, span) ,
@@ -1267,7 +1271,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
12671271 LocalMutationIsAllowed :: No ,
12681272 flow_state,
12691273 ) ;
1270- // We do not need to call `check_if_path_is_moved `
1274+ // We do not need to call `check_if_path_or_subpath_is_moved `
12711275 // again, as we already called it when we made the
12721276 // initial reservation.
12731277 }
@@ -1320,18 +1324,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
13201324 //
13211325 // 1. Move of `a.b.c`, use of `a.b.c`
13221326 // 2. Move of `a.b.c`, use of `a.b.c.d` (without first reinitializing `a.b.c.d`)
1323- // 3. Move of `a.b.c`, use of `a` or `a.b`
1324- // 4. Uninitialized `(a.b.c: &_)`, use of `*a.b.c`; note that with
1327+ // 3. Uninitialized `(a.b.c: &_)`, use of `*a.b.c`; note that with
13251328 // partial initialization support, one might have `a.x`
13261329 // initialized but not `a.b`.
13271330 //
13281331 // OK scenarios:
13291332 //
1330- // 5 . Move of `a.b.c`, use of `a.b.d`
1331- // 6 . Uninitialized `a.x`, initialized `a.b`, use of `a.b`
1332- // 7 . Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b`
1333+ // 4 . Move of `a.b.c`, use of `a.b.d`
1334+ // 5 . Uninitialized `a.x`, initialized `a.b`, use of `a.b`
1335+ // 6 . Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b`
13331336 // must have been initialized for the use to be sound.
1334- // 8 . Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
1337+ // 7 . Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
13351338
13361339 // The dataflow tracks shallow prefixes distinctly (that is,
13371340 // field-accesses on P distinctly from P itself), in order to
@@ -1350,9 +1353,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
13501353 // have a MovePath, that should capture the initialization
13511354 // state for the place scenario.
13521355 //
1353- // This code covers scenarios 1, 2, and 4 .
1356+ // This code covers scenarios 1, 2, and 3 .
13541357
1355- debug ! ( "check_if_path_is_moved part1 place: {:?}" , place) ;
1358+ debug ! ( "check_if_path_is_moved place: {:?}" , place) ;
13561359 match self . move_path_closest_to ( place) {
13571360 Ok ( mpi) => {
13581361 if maybe_uninits. contains ( & mpi) {
@@ -1372,18 +1375,52 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
13721375 // ancestors; dataflow recurs on children when parents
13731376 // move (to support partial (re)inits).
13741377 //
1375- // (I.e. querying parents breaks scenario 8 ; but may want
1378+ // (I.e. querying parents breaks scenario 7 ; but may want
13761379 // to do such a query based on partial-init feature-gate.)
13771380 }
1381+ }
1382+
1383+ fn check_if_path_or_subpath_is_moved (
1384+ & mut self ,
1385+ context : Context ,
1386+ desired_action : InitializationRequiringAction ,
1387+ place_span : ( & Place < ' tcx > , Span ) ,
1388+ flow_state : & Flows < ' cx , ' gcx , ' tcx > ,
1389+ ) {
1390+ // FIXME: analogous code in check_loans first maps `place` to
1391+ // its base_path ... but is that what we want here?
1392+ let place = self . base_path ( place_span. 0 ) ;
1393+
1394+ let maybe_uninits = & flow_state. uninits ;
1395+ let curr_move_outs = & flow_state. move_outs ;
1396+
1397+ // Bad scenarios:
1398+ //
1399+ // 1. Move of `a.b.c`, use of `a` or `a.b`
1400+ // partial initialization support, one might have `a.x`
1401+ // initialized but not `a.b`.
1402+ // 2. All bad scenarios from `check_if_path_is_moved`
1403+ //
1404+ // OK scenarios:
1405+ //
1406+ // 3. Move of `a.b.c`, use of `a.b.d`
1407+ // 4. Uninitialized `a.x`, initialized `a.b`, use of `a.b`
1408+ // 5. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b`
1409+ // must have been initialized for the use to be sound.
1410+ // 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
1411+
1412+ self . check_if_path_is_moved ( context, desired_action, place_span, flow_state) ;
13781413
13791414 // A move of any shallow suffix of `place` also interferes
13801415 // with an attempt to use `place`. This is scenario 3 above.
13811416 //
13821417 // (Distinct from handling of scenarios 1+2+4 above because
13831418 // `place` does not interfere with suffixes of its prefixes,
13841419 // e.g. `a.b.c` does not interfere with `a.b.d`)
1420+ //
1421+ // This code covers scenario 1.
13851422
1386- debug ! ( "check_if_path_is_moved part2 place: {:?}" , place) ;
1423+ debug ! ( "check_if_path_or_subpath_is_moved place: {:?}" , place) ;
13871424 if let Some ( mpi) = self . move_path_for_place ( place) {
13881425 if let Some ( child_mpi) = maybe_uninits. has_any_child_of ( mpi) {
13891426 self . report_use_of_moved_or_uninitialized (
@@ -1443,7 +1480,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
14431480 ( place, span) : ( & Place < ' tcx > , Span ) ,
14441481 flow_state : & Flows < ' cx , ' gcx , ' tcx > ,
14451482 ) {
1446- // recur down place; dispatch to check_if_path_is_moved when necessary
1483+ debug ! ( "check_if_assigned_path_is_moved place: {:?}" , place) ;
1484+ // recur down place; dispatch to external checks when necessary
14471485 let mut place = place;
14481486 loop {
14491487 match * place {
@@ -1454,8 +1492,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
14541492 Place :: Projection ( ref proj) => {
14551493 let Projection { ref base, ref elem } = * * proj;
14561494 match * elem {
1457- ProjectionElem :: Deref |
1458- // assigning to *P requires `P` initialized.
14591495 ProjectionElem :: Index ( _/*operand*/ ) |
14601496 ProjectionElem :: ConstantIndex { .. } |
14611497 // assigning to P[i] requires `P` initialized.
@@ -1465,6 +1501,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
14651501 // FIXME: is this true even if P is a adt with a dtor?
14661502 { }
14671503
1504+ ProjectionElem :: Deref => {
1505+ self . check_if_path_is_moved (
1506+ context, InitializationRequiringAction :: Use ,
1507+ ( base, span) , flow_state) ;
1508+ }
1509+
14681510 ProjectionElem :: Subslice { .. } => {
14691511 panic ! ( "we don't allow assignments to subslices, context: {:?}" ,
14701512 context) ;
@@ -1482,7 +1524,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
14821524 // check_loans.rs first maps
14831525 // `base` to its base_path.
14841526
1485- self . check_if_path_is_moved (
1527+ self . check_if_path_or_subpath_is_moved (
14861528 context, InitializationRequiringAction :: Assignment ,
14871529 ( base, span) , flow_state) ;
14881530
0 commit comments