about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorFelix S. Klock II <pnkfelix@pnkfx.org>2017-07-04 15:57:55 +0200
committerFelix S. Klock II <pnkfelix@pnkfx.org>2017-08-16 15:53:27 +0200
commit869f05a5215242d90733bb6cb5455959f01effcd (patch)
treea554d56e10975e72dd10f77fa229544d73bcde0a /src
parent9b8b8c6aebcc581bf2e74d9a0d3bf65a0ebb2742 (diff)
Factored `MoveData` construction code into `builder` submodule.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs332
-rw-r--r--src/librustc_mir/dataflow/move_paths/mod.rs315
2 files changed, 334 insertions, 313 deletions
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
new file mode 100644
index 00000000000..c45c91011d9
--- /dev/null
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -0,0 +1,332 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::ty::{self, TyCtxt};
+use rustc::mir::*;
+use rustc::mir::tcx::RvalueInitializationState;
+use rustc::util::nodemap::FxHashMap;
+use rustc_data_structures::indexed_vec::{IndexVec};
+
+use syntax::codemap::DUMMY_SP;
+
+use std::collections::hash_map::Entry;
+use std::mem;
+
+use super::abs_domain::Lift;
+
+use super::{LocationMap, MoveData, MovePath, MovePathLookup, MovePathIndex, MoveOut, MoveOutIndex};
+
+pub(super) struct MoveDataBuilder<'a, 'tcx: 'a> {
+    mir: &'a Mir<'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    data: MoveData<'tcx>,
+}
+
+pub enum MovePathError {
+    IllegalMove,
+    UnionMove { path: MovePathIndex },
+}
+
+impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
+    fn new(mir: &'a Mir<'tcx>,
+           tcx: TyCtxt<'a, 'tcx, 'tcx>,
+           param_env: ty::ParamEnv<'tcx>)
+           -> Self {
+        let mut move_paths = IndexVec::new();
+        let mut path_map = IndexVec::new();
+
+        MoveDataBuilder {
+            mir,
+            tcx,
+            param_env,
+            data: MoveData {
+                moves: IndexVec::new(),
+                loc_map: LocationMap::new(mir),
+                rev_lookup: MovePathLookup {
+                    locals: mir.local_decls.indices().map(Lvalue::Local).map(|v| {
+                        Self::new_move_path(&mut move_paths, &mut path_map, None, v)
+                    }).collect(),
+                    projections: FxHashMap(),
+                },
+                move_paths,
+                path_map,
+            }
+        }
+    }
+
+    fn new_move_path(move_paths: &mut IndexVec<MovePathIndex, MovePath<'tcx>>,
+                     path_map: &mut IndexVec<MovePathIndex, Vec<MoveOutIndex>>,
+                     parent: Option<MovePathIndex>,
+                     lvalue: Lvalue<'tcx>)
+                     -> MovePathIndex
+    {
+        let move_path = move_paths.push(MovePath {
+            next_sibling: None,
+            first_child: None,
+            parent,
+            lvalue,
+        });
+
+        if let Some(parent) = parent {
+            let next_sibling =
+                mem::replace(&mut move_paths[parent].first_child, Some(move_path));
+            move_paths[move_path].next_sibling = next_sibling;
+        }
+
+        let path_map_ent = path_map.push(vec![]);
+        assert_eq!(path_map_ent, move_path);
+        move_path
+    }
+
+    /// This creates a MovePath for a given lvalue, returning an `MovePathError`
+    /// if that lvalue can't be moved from.
+    ///
+    /// NOTE: lvalues behind references *do not* get a move path, which is
+    /// problematic for borrowck.
+    ///
+    /// Maybe we should have separate "borrowck" and "moveck" modes.
+    fn move_path_for(&mut self, lval: &Lvalue<'tcx>)
+                     -> Result<MovePathIndex, MovePathError>
+    {
+        debug!("lookup({:?})", lval);
+        match *lval {
+            Lvalue::Local(local) => Ok(self.data.rev_lookup.locals[local]),
+            // error: can't move out of a static
+            Lvalue::Static(..) => Err(MovePathError::IllegalMove),
+            Lvalue::Projection(ref proj) => {
+                self.move_path_for_projection(lval, proj)
+            }
+        }
+    }
+
+    fn create_move_path(&mut self, lval: &Lvalue<'tcx>) {
+        // This is an assignment, not a move, so this not being a valid
+        // move path is OK.
+        let _ = self.move_path_for(lval);
+    }
+
+    fn move_path_for_projection(&mut self,
+                                lval: &Lvalue<'tcx>,
+                                proj: &LvalueProjection<'tcx>)
+                                -> Result<MovePathIndex, MovePathError>
+    {
+        let base = try!(self.move_path_for(&proj.base));
+        let lv_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
+        match lv_ty.sty {
+            // error: can't move out of borrowed content
+            ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove),
+            // error: can't move out of struct with destructor
+            ty::TyAdt(adt, _) if adt.has_dtor(self.tcx) && !adt.is_box() =>
+                return Err(MovePathError::IllegalMove),
+            // move out of union - always move the entire union
+            ty::TyAdt(adt, _) if adt.is_union() =>
+                return Err(MovePathError::UnionMove { path: base }),
+            // error: can't move out of a slice
+            ty::TySlice(..) =>
+                return Err(MovePathError::IllegalMove),
+            ty::TyArray(..) => match proj.elem {
+                // error: can't move out of an array
+                ProjectionElem::Index(..) => return Err(MovePathError::IllegalMove),
+                _ => {
+                    // FIXME: still badly broken
+                }
+            },
+            _ => {}
+        };
+        match self.data.rev_lookup.projections.entry((base, proj.elem.lift())) {
+            Entry::Occupied(ent) => Ok(*ent.get()),
+            Entry::Vacant(ent) => {
+                let path = Self::new_move_path(
+                    &mut self.data.move_paths,
+                    &mut self.data.path_map,
+                    Some(base),
+                    lval.clone()
+                );
+                ent.insert(path);
+                Ok(path)
+            }
+        }
+    }
+
+    fn finalize(self) -> MoveData<'tcx> {
+        debug!("{}", {
+            debug!("moves for {:?}:", self.mir.span);
+            for (j, mo) in self.data.moves.iter_enumerated() {
+                debug!("    {:?} = {:?}", j, mo);
+            }
+            debug!("move paths for {:?}:", self.mir.span);
+            for (j, path) in self.data.move_paths.iter_enumerated() {
+                debug!("    {:?} = {:?}", j, path);
+            }
+            "done dumping moves"
+        });
+        self.data
+    }
+}
+
+pub(super) fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>,
+                                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                     param_env: ty::ParamEnv<'tcx>)
+                                     -> MoveData<'tcx> {
+    let mut builder = MoveDataBuilder::new(mir, tcx, param_env);
+
+    for (bb, block) in mir.basic_blocks().iter_enumerated() {
+        for (i, stmt) in block.statements.iter().enumerate() {
+            let source = Location { block: bb, statement_index: i };
+            builder.gather_statement(source, stmt);
+        }
+
+        let terminator_loc = Location {
+            block: bb,
+            statement_index: block.statements.len()
+        };
+        builder.gather_terminator(terminator_loc, block.terminator());
+    }
+
+    builder.finalize()
+}
+
+impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
+    fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) {
+        debug!("gather_statement({:?}, {:?})", loc, stmt);
+        match stmt.kind {
+            StatementKind::Assign(ref lval, ref rval) => {
+                self.create_move_path(lval);
+                if let RvalueInitializationState::Shallow = rval.initialization_state() {
+                    // Box starts out uninitialized - need to create a separate
+                    // move-path for the interior so it will be separate from
+                    // the exterior.
+                    self.create_move_path(&lval.clone().deref());
+                }
+                self.gather_rvalue(loc, rval);
+            }
+            StatementKind::StorageLive(_) |
+            StatementKind::StorageDead(_) => {}
+            StatementKind::SetDiscriminant{ .. } => {
+                span_bug!(stmt.source_info.span,
+                          "SetDiscriminant should not exist during borrowck");
+            }
+            StatementKind::InlineAsm { .. } |
+            StatementKind::EndRegion(_) |
+            StatementKind::Validate(..) |
+            StatementKind::Nop => {}
+        }
+    }
+
+    fn gather_rvalue(&mut self, loc: Location, rvalue: &Rvalue<'tcx>) {
+        match *rvalue {
+            Rvalue::Use(ref operand) |
+            Rvalue::Repeat(ref operand, _) |
+            Rvalue::Cast(_, ref operand, _) |
+            Rvalue::UnaryOp(_, ref operand) => {
+                self.gather_operand(loc, operand)
+            }
+            Rvalue::BinaryOp(ref _binop, ref lhs, ref rhs) |
+            Rvalue::CheckedBinaryOp(ref _binop, ref lhs, ref rhs) => {
+                self.gather_operand(loc, lhs);
+                self.gather_operand(loc, rhs);
+            }
+            Rvalue::Aggregate(ref _kind, ref operands) => {
+                for operand in operands {
+                    self.gather_operand(loc, operand);
+                }
+            }
+            Rvalue::Ref(..) |
+            Rvalue::Discriminant(..) |
+            Rvalue::Len(..) |
+            Rvalue::NullaryOp(NullOp::SizeOf, _) |
+            Rvalue::NullaryOp(NullOp::Box, _) => {
+                // This returns an rvalue with uninitialized contents. We can't
+                // move out of it here because it is an rvalue - assignments always
+                // completely initialize their lvalue.
+                //
+                // However, this does not matter - MIR building is careful to
+                // only emit a shallow free for the partially-initialized
+                // temporary.
+                //
+                // In any case, if we want to fix this, we have to register a
+                // special move and change the `statement_effect` functions.
+            }
+        }
+    }
+
+    fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) {
+        debug!("gather_terminator({:?}, {:?})", loc, term);
+        match term.kind {
+            TerminatorKind::Goto { target: _ } |
+            TerminatorKind::Resume |
+            TerminatorKind::Unreachable => { }
+
+            TerminatorKind::Return => {
+                self.gather_move(loc, &Lvalue::Local(RETURN_POINTER));
+            }
+
+            TerminatorKind::Assert { .. } |
+            TerminatorKind::SwitchInt { .. } => {
+                // branching terminators - these don't move anything
+            }
+
+            TerminatorKind::Drop { ref location, target: _, unwind: _ } => {
+                self.gather_move(loc, location);
+            }
+            TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
+                self.create_move_path(location);
+                self.gather_operand(loc, value);
+            }
+            TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => {
+                self.gather_operand(loc, func);
+                for arg in args {
+                    self.gather_operand(loc, arg);
+                }
+                if let Some((ref destination, _bb)) = *destination {
+                    self.create_move_path(destination);
+                }
+            }
+        }
+    }
+
+    fn gather_operand(&mut self, loc: Location, operand: &Operand<'tcx>) {
+        match *operand {
+            Operand::Constant(..) => {} // not-a-move
+            Operand::Consume(ref lval) => { // a move
+                self.gather_move(loc, lval);
+            }
+        }
+    }
+
+    fn gather_move(&mut self, loc: Location, lval: &Lvalue<'tcx>) {
+        debug!("gather_move({:?}, {:?})", loc, lval);
+
+        let lv_ty = lval.ty(self.mir, self.tcx).to_ty(self.tcx);
+        if !lv_ty.moves_by_default(self.tcx, self.param_env, DUMMY_SP) {
+            debug!("gather_move({:?}, {:?}) - {:?} is Copy. skipping", loc, lval, lv_ty);
+            return
+        }
+
+        let path = match self.move_path_for(lval) {
+            Ok(path) | Err(MovePathError::UnionMove { path }) => path,
+            Err(MovePathError::IllegalMove) => {
+                // Moving out of a bad path. Eventually, this should be a MIR
+                // borrowck error instead of a bug.
+                span_bug!(self.mir.span,
+                          "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}",
+                          lval, lv_ty, loc);
+            }
+        };
+        let move_out = self.data.moves.push(MoveOut { path: path, source: loc });
+
+        debug!("gather_move({:?}, {:?}): adding move {:?} of {:?}",
+               loc, lval, move_out, path);
+
+        self.data.path_map[path].push(move_out);
+        self.data.loc_map[loc].push(move_out);
+    }
+}
diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs
index 0685b1dc256..c7f8b349134 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -11,15 +11,10 @@
 
 use rustc::ty::{self, TyCtxt};
 use rustc::mir::*;
-use rustc::mir::tcx::RvalueInitializationState;
 use rustc::util::nodemap::FxHashMap;
 use rustc_data_structures::indexed_vec::{IndexVec};
 
-use syntax::codemap::DUMMY_SP;
-
-use std::collections::hash_map::Entry;
 use std::fmt;
-use std::mem;
 use std::ops::{Index, IndexMut};
 
 use self::abs_domain::{AbstractElem, Lift};
@@ -194,154 +189,7 @@ pub struct MovePathLookup<'tcx> {
     projections: FxHashMap<(MovePathIndex, AbstractElem<'tcx>), MovePathIndex>
 }
 
-pub(super) struct MoveDataBuilder<'a, 'tcx: 'a> {
-    mir: &'a Mir<'tcx>,
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    data: MoveData<'tcx>,
-}
-
-pub enum MovePathError {
-    IllegalMove,
-    UnionMove { path: MovePathIndex },
-}
-
-impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
-    fn new(mir: &'a Mir<'tcx>,
-           tcx: TyCtxt<'a, 'tcx, 'tcx>,
-           param_env: ty::ParamEnv<'tcx>)
-           -> Self {
-        let mut move_paths = IndexVec::new();
-        let mut path_map = IndexVec::new();
-
-        MoveDataBuilder {
-            mir,
-            tcx,
-            param_env,
-            data: MoveData {
-                moves: IndexVec::new(),
-                loc_map: LocationMap::new(mir),
-                rev_lookup: MovePathLookup {
-                    locals: mir.local_decls.indices().map(Lvalue::Local).map(|v| {
-                        Self::new_move_path(&mut move_paths, &mut path_map, None, v)
-                    }).collect(),
-                    projections: FxHashMap(),
-                },
-                move_paths,
-                path_map,
-            }
-        }
-    }
-
-    fn new_move_path(move_paths: &mut IndexVec<MovePathIndex, MovePath<'tcx>>,
-                     path_map: &mut IndexVec<MovePathIndex, Vec<MoveOutIndex>>,
-                     parent: Option<MovePathIndex>,
-                     lvalue: Lvalue<'tcx>)
-                     -> MovePathIndex
-    {
-        let move_path = move_paths.push(MovePath {
-            next_sibling: None,
-            first_child: None,
-            parent,
-            lvalue,
-        });
-
-        if let Some(parent) = parent {
-            let next_sibling =
-                mem::replace(&mut move_paths[parent].first_child, Some(move_path));
-            move_paths[move_path].next_sibling = next_sibling;
-        }
-
-        let path_map_ent = path_map.push(vec![]);
-        assert_eq!(path_map_ent, move_path);
-        move_path
-    }
-
-    /// This creates a MovePath for a given lvalue, returning an `MovePathError`
-    /// if that lvalue can't be moved from.
-    ///
-    /// NOTE: lvalues behind references *do not* get a move path, which is
-    /// problematic for borrowck.
-    ///
-    /// Maybe we should have separate "borrowck" and "moveck" modes.
-    fn move_path_for(&mut self, lval: &Lvalue<'tcx>)
-                     -> Result<MovePathIndex, MovePathError>
-    {
-        debug!("lookup({:?})", lval);
-        match *lval {
-            Lvalue::Local(local) => Ok(self.data.rev_lookup.locals[local]),
-            // error: can't move out of a static
-            Lvalue::Static(..) => Err(MovePathError::IllegalMove),
-            Lvalue::Projection(ref proj) => {
-                self.move_path_for_projection(lval, proj)
-            }
-        }
-    }
-
-    fn create_move_path(&mut self, lval: &Lvalue<'tcx>) {
-        // This is an assignment, not a move, so this not being a valid
-        // move path is OK.
-        let _ = self.move_path_for(lval);
-    }
-
-    fn move_path_for_projection(&mut self,
-                                lval: &Lvalue<'tcx>,
-                                proj: &LvalueProjection<'tcx>)
-                                -> Result<MovePathIndex, MovePathError>
-    {
-        let base = try!(self.move_path_for(&proj.base));
-        let lv_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
-        match lv_ty.sty {
-            // error: can't move out of borrowed content
-            ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove),
-            // error: can't move out of struct with destructor
-            ty::TyAdt(adt, _) if adt.has_dtor(self.tcx) && !adt.is_box() =>
-                return Err(MovePathError::IllegalMove),
-            // move out of union - always move the entire union
-            ty::TyAdt(adt, _) if adt.is_union() =>
-                return Err(MovePathError::UnionMove { path: base }),
-            // error: can't move out of a slice
-            ty::TySlice(..) =>
-                return Err(MovePathError::IllegalMove),
-            ty::TyArray(..) => match proj.elem {
-                // error: can't move out of an array
-                ProjectionElem::Index(..) => return Err(MovePathError::IllegalMove),
-                _ => {
-                    // FIXME: still badly broken
-                }
-            },
-            _ => {}
-        };
-        match self.data.rev_lookup.projections.entry((base, proj.elem.lift())) {
-            Entry::Occupied(ent) => Ok(*ent.get()),
-            Entry::Vacant(ent) => {
-                let path = Self::new_move_path(
-                    &mut self.data.move_paths,
-                    &mut self.data.path_map,
-                    Some(base),
-                    lval.clone()
-                );
-                ent.insert(path);
-                Ok(path)
-            }
-        }
-    }
-
-    fn finalize(self) -> MoveData<'tcx> {
-        debug!("{}", {
-            debug!("moves for {:?}:", self.mir.span);
-            for (j, mo) in self.data.moves.iter_enumerated() {
-                debug!("    {:?} = {:?}", j, mo);
-            }
-            debug!("move paths for {:?}:", self.mir.span);
-            for (j, path) in self.data.move_paths.iter_enumerated() {
-                debug!("    {:?} = {:?}", j, path);
-            }
-            "done dumping moves"
-        });
-        self.data
-    }
-}
+mod builder;
 
 #[derive(Copy, Clone, Debug)]
 pub enum LookupResult {
@@ -378,165 +226,6 @@ impl<'a, 'tcx> MoveData<'tcx> {
                         tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         param_env: ty::ParamEnv<'tcx>)
                         -> Self {
-        gather_moves(mir, tcx, param_env)
-    }
-}
-
-fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>,
-                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          param_env: ty::ParamEnv<'tcx>)
-                          -> MoveData<'tcx> {
-    let mut builder = MoveDataBuilder::new(mir, tcx, param_env);
-
-    for (bb, block) in mir.basic_blocks().iter_enumerated() {
-        for (i, stmt) in block.statements.iter().enumerate() {
-            let source = Location { block: bb, statement_index: i };
-            builder.gather_statement(source, stmt);
-        }
-
-        let terminator_loc = Location {
-            block: bb,
-            statement_index: block.statements.len()
-        };
-        builder.gather_terminator(terminator_loc, block.terminator());
-    }
-
-    builder.finalize()
-}
-
-impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
-    fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) {
-        debug!("gather_statement({:?}, {:?})", loc, stmt);
-        match stmt.kind {
-            StatementKind::Assign(ref lval, ref rval) => {
-                self.create_move_path(lval);
-                if let RvalueInitializationState::Shallow = rval.initialization_state() {
-                    // Box starts out uninitialized - need to create a separate
-                    // move-path for the interior so it will be separate from
-                    // the exterior.
-                    self.create_move_path(&lval.clone().deref());
-                }
-                self.gather_rvalue(loc, rval);
-            }
-            StatementKind::StorageLive(_) |
-            StatementKind::StorageDead(_) => {}
-            StatementKind::SetDiscriminant{ .. } => {
-                span_bug!(stmt.source_info.span,
-                          "SetDiscriminant should not exist during borrowck");
-            }
-            StatementKind::InlineAsm { .. } |
-            StatementKind::EndRegion(_) |
-            StatementKind::Validate(..) |
-            StatementKind::Nop => {}
-        }
-    }
-
-    fn gather_rvalue(&mut self, loc: Location, rvalue: &Rvalue<'tcx>) {
-        match *rvalue {
-            Rvalue::Use(ref operand) |
-            Rvalue::Repeat(ref operand, _) |
-            Rvalue::Cast(_, ref operand, _) |
-            Rvalue::UnaryOp(_, ref operand) => {
-                self.gather_operand(loc, operand)
-            }
-            Rvalue::BinaryOp(ref _binop, ref lhs, ref rhs) |
-            Rvalue::CheckedBinaryOp(ref _binop, ref lhs, ref rhs) => {
-                self.gather_operand(loc, lhs);
-                self.gather_operand(loc, rhs);
-            }
-            Rvalue::Aggregate(ref _kind, ref operands) => {
-                for operand in operands {
-                    self.gather_operand(loc, operand);
-                }
-            }
-            Rvalue::Ref(..) |
-            Rvalue::Discriminant(..) |
-            Rvalue::Len(..) |
-            Rvalue::NullaryOp(NullOp::SizeOf, _) |
-            Rvalue::NullaryOp(NullOp::Box, _) => {
-                // This returns an rvalue with uninitialized contents. We can't
-                // move out of it here because it is an rvalue - assignments always
-                // completely initialize their lvalue.
-                //
-                // However, this does not matter - MIR building is careful to
-                // only emit a shallow free for the partially-initialized
-                // temporary.
-                //
-                // In any case, if we want to fix this, we have to register a
-                // special move and change the `statement_effect` functions.
-            }
-        }
-    }
-
-    fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) {
-        debug!("gather_terminator({:?}, {:?})", loc, term);
-        match term.kind {
-            TerminatorKind::Goto { target: _ } |
-            TerminatorKind::Resume |
-            TerminatorKind::Unreachable => { }
-
-            TerminatorKind::Return => {
-                self.gather_move(loc, &Lvalue::Local(RETURN_POINTER));
-            }
-
-            TerminatorKind::Assert { .. } |
-            TerminatorKind::SwitchInt { .. } => {
-                // branching terminators - these don't move anything
-            }
-
-            TerminatorKind::Drop { ref location, target: _, unwind: _ } => {
-                self.gather_move(loc, location);
-            }
-            TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
-                self.create_move_path(location);
-                self.gather_operand(loc, value);
-            }
-            TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => {
-                self.gather_operand(loc, func);
-                for arg in args {
-                    self.gather_operand(loc, arg);
-                }
-                if let Some((ref destination, _bb)) = *destination {
-                    self.create_move_path(destination);
-                }
-            }
-        }
-    }
-
-    fn gather_operand(&mut self, loc: Location, operand: &Operand<'tcx>) {
-        match *operand {
-            Operand::Constant(..) => {} // not-a-move
-            Operand::Consume(ref lval) => { // a move
-                self.gather_move(loc, lval);
-            }
-        }
-    }
-
-    fn gather_move(&mut self, loc: Location, lval: &Lvalue<'tcx>) {
-        debug!("gather_move({:?}, {:?})", loc, lval);
-
-        let lv_ty = lval.ty(self.mir, self.tcx).to_ty(self.tcx);
-        if !lv_ty.moves_by_default(self.tcx, self.param_env, DUMMY_SP) {
-            debug!("gather_move({:?}, {:?}) - {:?} is Copy. skipping", loc, lval, lv_ty);
-            return
-        }
-
-        let path = match self.move_path_for(lval) {
-            Ok(path) | Err(MovePathError::UnionMove { path }) => path,
-            Err(MovePathError::IllegalMove) => {
-                // Moving out of a bad path. Eventually, this should be a MIR
-                // borrowck error instead of a bug.
-                span_bug!(self.mir.span,
-                          "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}",
-                          lval, lv_ty, loc);
-            }
-        };
-        let move_out = self.data.moves.push(MoveOut { path: path, source: loc });
-
-        debug!("gather_move({:?}, {:?}): adding move {:?} of {:?}",
-               loc, lval, move_out, path);
-
-        self.data.path_map[path].push(move_out);
-        self.data.loc_map[loc].push(move_out);
+        builder::gather_moves(mir, tcx, param_env)
     }
 }