about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSantiago Pastorino <spastorino@gmail.com>2018-08-30 18:54:32 -0300
committerSantiago Pastorino <spastorino@gmail.com>2018-08-30 19:14:31 -0300
commit373fc932aa7adecb9c2e78455835cb6341b73552 (patch)
tree9a75b291f325465fad5dcd4595a890f6fef2df1a
parent685fb543174f8f2cadc38ec0b2c6df635eb1c087 (diff)
downloadrust-373fc932aa7adecb9c2e78455835cb6341b73552.tar.gz
rust-373fc932aa7adecb9c2e78455835cb6341b73552.zip
Make move out computation lazy
-rw-r--r--src/librustc/mir/mod.rs22
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs90
-rw-r--r--src/librustc_mir/borrow_check/flows.rs18
-rw-r--r--src/librustc_mir/borrow_check/mod.rs16
-rw-r--r--src/librustc_mir/dataflow/impls/mod.rs129
-rw-r--r--src/librustc_mir/dataflow/mod.rs16
-rw-r--r--src/test/ui/hygiene/fields-move.nll.stderr8
7 files changed, 110 insertions, 189 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 0840f333c87..c9374b6bfc7 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -204,6 +204,28 @@ impl<'tcx> Mir<'tcx> {
     }
 
     #[inline]
+    pub fn predecessor_locations(&self, loc: Location) -> impl Iterator<Item = Location> + '_ {
+        let if_zero_locations = if loc.statement_index == 0 {
+            let predecessor_blocks = self.predecessors_for(loc.block);
+            let num_predecessor_blocks = predecessor_blocks.len();
+            Some((0 .. num_predecessor_blocks)
+                .map(move |i| predecessor_blocks[i])
+                .map(move |bb| self.terminator_loc(bb))
+            )
+        } else {
+            None
+        };
+
+        let if_not_zero_locations = if loc.statement_index == 0 {
+            None
+        } else {
+            Some(Location { block: loc.block, statement_index: loc.statement_index - 1 })
+        };
+
+        if_zero_locations.into_iter().flatten().chain(if_not_zero_locations)
+    }
+
+    #[inline]
     pub fn dominators(&self) -> Dominators<BasicBlock> {
         dominators(self)
     }
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index f1df135f7ee..efd80498306 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -15,6 +15,7 @@ use rustc::mir::{BindingForm, BorrowKind, ClearCrossCrate, Field, Local};
 use rustc::mir::{LocalDecl, LocalKind, Location, Operand, Place};
 use rustc::mir::{ProjectionElem, Rvalue, Statement, StatementKind};
 use rustc::ty;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::DiagnosticBuilder;
@@ -24,8 +25,9 @@ use super::borrow_set::BorrowData;
 use super::{Context, MirBorrowckCtxt};
 use super::{InitializationRequiringAction, PrefixSet};
 
+use dataflow::drop_flag_effects;
 use dataflow::move_paths::MovePathIndex;
-use dataflow::{FlowAtLocation, MovingOutStatements};
+use dataflow::move_paths::indexes::MoveOutIndex;
 use util::borrowck_errors::{BorrowckErrors, Origin};
 
 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
@@ -35,17 +37,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         desired_action: InitializationRequiringAction,
         (place, span): (&Place<'tcx>, Span),
         mpi: MovePathIndex,
-        curr_move_out: &FlowAtLocation<MovingOutStatements<'_, 'gcx, 'tcx>>,
     ) {
         let use_spans = self
             .move_spans(place, context.loc)
             .or_else(|| self.borrow_spans(span, context.loc));
         let span = use_spans.args_or_use();
 
-        let mois = self.move_data.path_map[mpi]
-            .iter()
-            .filter(|moi| curr_move_out.contains(moi))
-            .collect::<Vec<_>>();
+        let mois = self.get_moved_indexes(context, mpi);
+        debug!("report_use_of_moved_or_uninitialized: mois={:?}", mois);
 
         if mois.is_empty() {
             let root_place = self.prefixes(&place, PrefixSet::All).last().unwrap();
@@ -93,7 +92,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
             let mut is_loop_move = false;
             for moi in &mois {
-                let move_out = self.move_data.moves[**moi];
+                let move_out = self.move_data.moves[*moi];
                 let moved_place = &self.move_data.move_paths[move_out.path].place;
 
                 let move_spans = self.move_spans(moved_place, move_out.source);
@@ -148,7 +147,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 };
 
                 if needs_note {
-                    let mpi = self.move_data.moves[*mois[0]].path;
+                    let mpi = self.move_data.moves[mois[0]].path;
                     let place = &self.move_data.move_paths[mpi].place;
 
                     if let Some(ty) = self.retrieve_type_for_place(place) {
@@ -521,6 +520,81 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         err
     }
 
+    fn get_moved_indexes(
+        &mut self,
+        context: Context,
+        mpi: MovePathIndex,
+    ) -> Vec<MoveOutIndex> {
+        let mir = self.mir;
+
+        let mut stack = Vec::new();
+        stack.extend(mir.predecessor_locations(context.loc));
+
+        let mut visited = FxHashSet();
+        let mut result = vec![];
+
+        'dfs:
+        while let Some(l) = stack.pop() {
+            debug!("report_use_of_moved_or_uninitialized: current_location={:?}", l);
+
+            if !visited.insert(l) {
+                continue;
+            }
+
+            // check for moves
+            let stmt_kind = mir[l.block].statements.get(l.statement_index).map(|s| &s.kind);
+            if let Some(StatementKind::StorageDead(..)) = stmt_kind {
+                // this analysis only tries to find moves explicitly
+                // written by the user, so we ignore the move-outs
+                // created by `StorageDead` and at the beginning
+                // of a function.
+            } else {
+                for moi in &self.move_data.loc_map[l] {
+                    debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
+                    if self.move_data.moves[*moi].path == mpi {
+                        debug!("report_use_of_moved_or_uninitialized: found");
+                        result.push(*moi);
+
+                        // Strictly speaking, we could continue our DFS here. There may be
+                        // other moves that can reach the point of error. But it is kind of
+                        // confusing to highlight them.
+                        //
+                        // Example:
+                        //
+                        // ```
+                        // let a = vec![];
+                        // let b = a;
+                        // let c = a;
+                        // drop(a); // <-- current point of error
+                        // ```
+                        //
+                        // Because we stop the DFS here, we only highlight `let c = a`,
+                        // and not `let b = a`. We will of course also report an error at
+                        // `let c = a` which highlights `let b = a` as the move.
+                        continue 'dfs;
+                    }
+                }
+            }
+
+            // check for inits
+            let mut any_match = false;
+            drop_flag_effects::for_location_inits(
+                self.tcx,
+                self.mir,
+                self.move_data,
+                l,
+                |m| if m == mpi { any_match = true; },
+            );
+            if any_match {
+                continue 'dfs;
+            }
+
+            stack.extend(mir.predecessor_locations(l));
+        }
+
+        result
+    }
+
     pub(super) fn report_illegal_mutation_of_borrowed(
         &mut self,
         context: Context,
diff --git a/src/librustc_mir/borrow_check/flows.rs b/src/librustc_mir/borrow_check/flows.rs
index 192fa2b9eea..6b964fec74f 100644
--- a/src/librustc_mir/borrow_check/flows.rs
+++ b/src/librustc_mir/borrow_check/flows.rs
@@ -24,7 +24,7 @@ use polonius_engine::Output;
 use dataflow::move_paths::indexes::BorrowIndex;
 use dataflow::move_paths::HasMoveData;
 use dataflow::Borrows;
-use dataflow::{EverInitializedPlaces, MovingOutStatements};
+use dataflow::EverInitializedPlaces;
 use dataflow::{FlowAtLocation, FlowsAtLocation};
 use dataflow::MaybeUninitializedPlaces;
 use either::Either;
@@ -35,7 +35,6 @@ use std::rc::Rc;
 crate struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
     borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
     pub uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
-    pub move_outs: FlowAtLocation<MovingOutStatements<'b, 'gcx, 'tcx>>,
     pub ever_inits: FlowAtLocation<EverInitializedPlaces<'b, 'gcx, 'tcx>>,
 
     /// Polonius Output
@@ -46,14 +45,12 @@ impl<'b, 'gcx, 'tcx> Flows<'b, 'gcx, 'tcx> {
     crate fn new(
         borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
         uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
-        move_outs: FlowAtLocation<MovingOutStatements<'b, 'gcx, 'tcx>>,
         ever_inits: FlowAtLocation<EverInitializedPlaces<'b, 'gcx, 'tcx>>,
         polonius_output: Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
     ) -> Self {
         Flows {
             borrows,
             uninits,
-            move_outs,
             ever_inits,
             polonius_output,
         }
@@ -79,7 +76,6 @@ macro_rules! each_flow {
     ($this:ident, $meth:ident($arg:ident)) => {
         FlowAtLocation::$meth(&mut $this.borrows, $arg);
         FlowAtLocation::$meth(&mut $this.uninits, $arg);
-        FlowAtLocation::$meth(&mut $this.move_outs, $arg);
         FlowAtLocation::$meth(&mut $this.ever_inits, $arg);
     };
 }
@@ -146,18 +142,6 @@ impl<'b, 'gcx, 'tcx> fmt::Display for Flows<'b, 'gcx, 'tcx> {
         });
         s.push_str("] ");
 
-        s.push_str("move_out: [");
-        let mut saw_one = false;
-        self.move_outs.each_state_bit(|mpi_move_out| {
-            if saw_one {
-                s.push_str(", ");
-            };
-            saw_one = true;
-            let move_out = &self.move_outs.operator().move_data().moves[mpi_move_out];
-            s.push_str(&format!("{:?}", move_out));
-        });
-        s.push_str("] ");
-
         s.push_str("ever_init: [");
         let mut saw_one = false;
         self.ever_inits.each_state_bit(|mpi_ever_init| {
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 16d34082642..3536947b25e 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -43,7 +43,7 @@ use dataflow::DataflowResultsConsumer;
 use dataflow::FlowAtLocation;
 use dataflow::MoveDataParamEnv;
 use dataflow::{do_dataflow, DebugFormatted};
-use dataflow::{EverInitializedPlaces, MovingOutStatements};
+use dataflow::EverInitializedPlaces;
 use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
 use util::borrowck_errors::{BorrowckErrors, Origin};
 
@@ -186,15 +186,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         MaybeUninitializedPlaces::new(tcx, mir, &mdpe),
         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
     ));
-    let flow_move_outs = FlowAtLocation::new(do_dataflow(
-        tcx,
-        mir,
-        id,
-        &attributes,
-        &dead_unwinds,
-        MovingOutStatements::new(tcx, mir, &mdpe),
-        |bd, i| DebugFormatted::new(&bd.move_data().moves[i]),
-    ));
     let flow_ever_inits = FlowAtLocation::new(do_dataflow(
         tcx,
         mir,
@@ -268,7 +259,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
     let mut state = Flows::new(
         flow_borrows,
         flow_uninits,
-        flow_move_outs,
         flow_ever_inits,
         polonius_output,
     );
@@ -1617,7 +1607,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         let place = self.base_path(place_span.0);
 
         let maybe_uninits = &flow_state.uninits;
-        let curr_move_outs = &flow_state.move_outs;
 
         // Bad scenarios:
         //
@@ -1663,7 +1652,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                         desired_action,
                         place_span,
                         mpi,
-                        curr_move_outs,
                     );
                     return; // don't bother finding other problems.
                 }
@@ -1691,7 +1679,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         let place = self.base_path(place_span.0);
 
         let maybe_uninits = &flow_state.uninits;
-        let curr_move_outs = &flow_state.move_outs;
 
         // Bad scenarios:
         //
@@ -1727,7 +1714,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     desired_action,
                     place_span,
                     child_mpi,
-                    curr_move_outs,
                 );
                 return; // don't bother finding other problems.
             }
diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs
index ee3bba840c6..62c6018809f 100644
--- a/src/librustc_mir/dataflow/impls/mod.rs
+++ b/src/librustc_mir/dataflow/impls/mod.rs
@@ -22,13 +22,13 @@ use super::MoveDataParamEnv;
 
 use util::elaborate_drops::DropFlagState;
 
-use super::move_paths::{HasMoveData, MoveData, MoveOutIndex, MovePathIndex, InitIndex};
+use super::move_paths::{HasMoveData, MoveData, MovePathIndex, InitIndex};
 use super::move_paths::{LookupResult, InitKind};
 use super::{BitDenotation, BlockSets, InitialFlow};
 
 use super::drop_flag_effects_for_function_entry;
 use super::drop_flag_effects_for_location;
-use super::{on_lookup_result_bits, for_location_inits};
+use super::on_lookup_result_bits;
 
 mod storage_liveness;
 
@@ -211,40 +211,6 @@ impl<'a, 'gcx, 'tcx: 'a> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, '
     fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
 }
 
-/// `MovingOutStatements` tracks the statements that perform moves out
-/// of particular places. More precisely, it tracks whether the
-/// *effect* of such moves (namely, the uninitialization of the
-/// place in question) can reach some point in the control-flow of
-/// the function, or if that effect is "killed" by some intervening
-/// operation reinitializing that place.
-///
-/// The resulting dataflow is a more enriched version of
-/// `MaybeUninitializedPlaces`. Both structures on their own only tell
-/// you if a place *might* be uninitialized at a given point in the
-/// control flow. But `MovingOutStatements` also includes the added
-/// data of *which* particular statement causing the deinitialization
-/// that the borrow checker's error message may need to report.
-#[allow(dead_code)]
-pub struct MovingOutStatements<'a, 'gcx: 'tcx, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    mir: &'a Mir<'tcx>,
-    mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>,
-}
-
-impl<'a, 'gcx: 'tcx, 'tcx: 'a> MovingOutStatements<'a, 'gcx, 'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-               mir: &'a Mir<'tcx>,
-               mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>)
-               -> Self
-    {
-        MovingOutStatements { tcx: tcx, mir: mir, mdpe: mdpe }
-    }
-}
-
-impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for MovingOutStatements<'a, 'gcx, 'tcx> {
-    fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
-}
-
 /// `EverInitializedPlaces` tracks all places that might have ever been
 /// initialized upon reaching a particular point in the control flow
 /// for a function, without an intervening `Storage Dead`.
@@ -488,83 +454,6 @@ impl<'a, 'gcx, 'tcx> BitDenotation for DefinitelyInitializedPlaces<'a, 'gcx, 'tc
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitDenotation for MovingOutStatements<'a, 'gcx, 'tcx> {
-    type Idx = MoveOutIndex;
-    fn name() -> &'static str { "moving_out" }
-    fn bits_per_block(&self) -> usize {
-        self.move_data().moves.len()
-    }
-
-    fn start_block_effect(&self, _sets: &mut IdxSet<MoveOutIndex>) {
-        // no move-statements have been executed prior to function
-        // execution, so this method has no effect on `_sets`.
-    }
-
-    fn statement_effect(&self,
-                        sets: &mut BlockSets<MoveOutIndex>,
-                        location: Location) {
-        let (tcx, mir, move_data) = (self.tcx, self.mir, self.move_data());
-        let stmt = &mir[location.block].statements[location.statement_index];
-        let loc_map = &move_data.loc_map;
-        let path_map = &move_data.path_map;
-
-        match stmt.kind {
-            // this analysis only tries to find moves explicitly
-            // written by the user, so we ignore the move-outs
-            // created by `StorageDead` and at the beginning
-            // of a function.
-            mir::StatementKind::StorageDead(_) => {}
-            _ => {
-                debug!("stmt {:?} at loc {:?} moves out of move_indexes {:?}",
-                       stmt, location, &loc_map[location]);
-                // Every path deinitialized by a *particular move*
-                // has corresponding bit, "gen'ed" (i.e. set)
-                // here, in dataflow vector
-                sets.gen_all_and_assert_dead(&loc_map[location]);
-            }
-        }
-
-        for_location_inits(tcx, mir, move_data, location,
-                           |mpi| sets.kill_all(&path_map[mpi]));
-    }
-
-    fn terminator_effect(&self,
-                         sets: &mut BlockSets<MoveOutIndex>,
-                         location: Location)
-    {
-        let (tcx, mir, move_data) = (self.tcx, self.mir, self.move_data());
-        let term = mir[location.block].terminator();
-        let loc_map = &move_data.loc_map;
-        let path_map = &move_data.path_map;
-
-        debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}",
-               term, location, &loc_map[location]);
-        sets.gen_all_and_assert_dead(&loc_map[location]);
-
-        for_location_inits(tcx, mir, move_data, location,
-                           |mpi| sets.kill_all(&path_map[mpi]));
-    }
-
-    fn propagate_call_return(&self,
-                             in_out: &mut IdxSet<MoveOutIndex>,
-                             _call_bb: mir::BasicBlock,
-                             _dest_bb: mir::BasicBlock,
-                             dest_place: &mir::Place) {
-        let move_data = self.move_data();
-        let bits_per_block = self.bits_per_block();
-
-        let path_map = &move_data.path_map;
-        on_lookup_result_bits(self.tcx,
-                              self.mir,
-                              move_data,
-                              move_data.rev_lookup.find(dest_place),
-                              |mpi| for moi in &path_map[mpi] {
-                                  assert!(moi.index() < bits_per_block);
-                                  in_out.remove(&moi);
-                              });
-    }
-}
-
 impl<'a, 'gcx, 'tcx> BitDenotation for EverInitializedPlaces<'a, 'gcx, 'tcx> {
     type Idx = InitIndex;
     fn name() -> &'static str { "ever_init" }
@@ -682,13 +571,6 @@ impl<'a, 'gcx, 'tcx> BitwiseOperator for DefinitelyInitializedPlaces<'a, 'gcx, '
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitwiseOperator for MovingOutStatements<'a, 'gcx, 'tcx> {
-    #[inline]
-    fn join(&self, pred1: Word, pred2: Word) -> Word {
-        pred1 | pred2 // moves from both preds are in scope
-    }
-}
-
 impl<'a, 'gcx, 'tcx> BitwiseOperator for EverInitializedPlaces<'a, 'gcx, 'tcx> {
     #[inline]
     fn join(&self, pred1: Word, pred2: Word) -> Word {
@@ -727,13 +609,6 @@ impl<'a, 'gcx, 'tcx> InitialFlow for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx>
     }
 }
 
-impl<'a, 'gcx, 'tcx> InitialFlow for MovingOutStatements<'a, 'gcx, 'tcx> {
-    #[inline]
-    fn bottom_value() -> bool {
-        false // bottom = no loans in scope by default
-    }
-}
-
 impl<'a, 'gcx, 'tcx> InitialFlow for EverInitializedPlaces<'a, 'gcx, 'tcx> {
     #[inline]
     fn bottom_value() -> bool {
diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs
index fd6569feb5c..bee7d443c85 100644
--- a/src/librustc_mir/dataflow/mod.rs
+++ b/src/librustc_mir/dataflow/mod.rs
@@ -28,7 +28,7 @@ use std::usize;
 
 pub use self::impls::{MaybeStorageLive};
 pub use self::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
-pub use self::impls::{DefinitelyInitializedPlaces, MovingOutStatements};
+pub use self::impls::DefinitelyInitializedPlaces;
 pub use self::impls::EverInitializedPlaces;
 pub use self::impls::borrows::Borrows;
 pub use self::impls::HaveBeenBorrowedLocals;
@@ -38,7 +38,7 @@ pub(crate) use self::drop_flag_effects::*;
 use self::move_paths::MoveData;
 
 mod at_location;
-mod drop_flag_effects;
+pub mod drop_flag_effects;
 mod graphviz;
 mod impls;
 pub mod move_paths;
@@ -511,18 +511,6 @@ impl<'a, E:Idx> BlockSets<'a, E> {
         }
     }
 
-    fn gen_all_and_assert_dead<I>(&mut self, i: I)
-        where I: IntoIterator,
-        I::Item: Borrow<E>
-    {
-        for j in i {
-            let j = j.borrow();
-            let retval = self.gen_set.add(j);
-            self.kill_set.remove(j);
-            assert!(retval);
-        }
-    }
-
     fn kill(&mut self, e: &E) {
         self.gen_set.remove(e);
         self.kill_set.add(e);
diff --git a/src/test/ui/hygiene/fields-move.nll.stderr b/src/test/ui/hygiene/fields-move.nll.stderr
index 56b77714991..9b25a865f92 100644
--- a/src/test/ui/hygiene/fields-move.nll.stderr
+++ b/src/test/ui/hygiene/fields-move.nll.stderr
@@ -1,9 +1,6 @@
 error[E0382]: use of moved value: `foo.x`
   --> $DIR/fields-move.rs:28:9
    |
-LL |    $foo.x
-   |    ------ value moved here
-...
 LL |         $foo.x //~ ERROR use of moved value: `foo.x`
    |         ^^^^^^ value used here after move
 ...
@@ -28,14 +25,9 @@ LL |     assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved val
 error[E0382]: use of moved value: `foo.x`
   --> $DIR/fields-move.rs:39:42
    |
-LL |    $foo.x
-   |    ------ value moved here
-...
 LL |         $foo.x //~ ERROR use of moved value: `foo.x`
    |         ------ value moved here
 ...
-LL |     assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
-   |                                          ----- value moved here
 LL |     assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
    |                                          ^^^^^ value used here after move
    |