about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-09-05 04:56:03 +0000
committerbors <bors@rust-lang.org>2017-09-05 04:56:03 +0000
commit2f1ef9ef1181298d46e79d5dde6bafeb6483926f (patch)
tree6272a0b66cddf2541dd368c6e8828b2a0ae9ed68 /src
parent2f681bf6024b551c2bea777ae6df3e6fafaa985f (diff)
parente74f96e43fc1611a3abb09457e8ed852af3c167e (diff)
downloadrust-2f1ef9ef1181298d46e79d5dde6bafeb6483926f.tar.gz
rust-2f1ef9ef1181298d46e79d5dde6bafeb6483926f.zip
Auto merge of #44308 - eddyb:local-index, r=arielb1
[MIR] Restrict ProjectionElem::Index and Storage{Live,Dead} to Local.

(see #44285)

r? @nikomatsakis
Diffstat (limited to 'src')
-rw-r--r--src/librustc/mir/mod.rs24
-rw-r--r--src/librustc/mir/visit.rs18
-rw-r--r--src/librustc/ty/structural_impls.rs2
-rw-r--r--src/librustc_mir/borrow_check.rs29
-rw-r--r--src/librustc_mir/build/expr/as_lvalue.rs9
-rw-r--r--src/librustc_mir/build/expr/as_operand.rs2
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs12
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs16
-rw-r--r--src/librustc_mir/build/expr/into.rs2
-rw-r--r--src/librustc_mir/build/matches/mod.rs2
-rw-r--r--src/librustc_mir/build/scope.rs2
-rw-r--r--src/librustc_mir/dataflow/move_paths/abs_domain.rs7
-rw-r--r--src/librustc_mir/shim.rs28
-rw-r--r--src/librustc_mir/transform/copy_prop.rs3
-rw-r--r--src/librustc_mir/transform/generator.rs26
-rw-r--r--src/librustc_mir/transform/inline.rs55
-rw-r--r--src/librustc_mir/transform/promote_consts.rs96
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs53
-rw-r--r--src/librustc_mir/transform/simplify.rs27
-rw-r--r--src/librustc_mir/transform/type_check.rs18
-rw-r--r--src/librustc_mir/util/def_use.rs54
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs21
-rw-r--r--src/librustc_mir/util/liveness.rs76
-rw-r--r--src/librustc_trans/mir/analyze.rs77
-rw-r--r--src/librustc_trans/mir/constant.rs3
-rw-r--r--src/librustc_trans/mir/lvalue.rs3
-rw-r--r--src/librustc_trans/mir/statement.rs16
27 files changed, 319 insertions, 362 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 1ea6c461fc1..cf3d7c3642a 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -901,10 +901,10 @@ pub enum StatementKind<'tcx> {
     SetDiscriminant { lvalue: Lvalue<'tcx>, variant_index: usize },
 
     /// Start a live range for the storage of the local.
-    StorageLive(Lvalue<'tcx>),
+    StorageLive(Local),
 
     /// End the current live range for the storage of the local.
-    StorageDead(Lvalue<'tcx>),
+    StorageDead(Local),
 
     /// Execute a piece of inline Assembly.
     InlineAsm {
@@ -1077,12 +1077,12 @@ pub enum ProjectionElem<'tcx, V, T> {
 }
 
 /// Alias for projections as they appear in lvalues, where the base is an lvalue
-/// and the index is an operand.
-pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Operand<'tcx>, Ty<'tcx>>;
+/// and the index is a local.
+pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Local, Ty<'tcx>>;
 
 /// Alias for projections as they appear in lvalues, where the base is an lvalue
-/// and the index is an operand.
-pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Operand<'tcx>, Ty<'tcx>>;
+/// and the index is a local.
+pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Local, Ty<'tcx>>;
 
 newtype_index!(Field, "field");
 
@@ -1099,7 +1099,7 @@ impl<'tcx> Lvalue<'tcx> {
         self.elem(ProjectionElem::Downcast(adt_def, variant_index))
     }
 
-    pub fn index(self, index: Operand<'tcx>) -> Lvalue<'tcx> {
+    pub fn index(self, index: Local) -> Lvalue<'tcx> {
         self.elem(ProjectionElem::Index(index))
     }
 
@@ -1701,8 +1701,8 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
                 lvalue: lvalue.fold_with(folder),
                 variant_index,
             },
-            StorageLive(ref lval) => StorageLive(lval.fold_with(folder)),
-            StorageDead(ref lval) => StorageDead(lval.fold_with(folder)),
+            StorageLive(ref local) => StorageLive(local.fold_with(folder)),
+            StorageDead(ref local) => StorageDead(local.fold_with(folder)),
             InlineAsm { ref asm, ref outputs, ref inputs } => InlineAsm {
                 asm: asm.clone(),
                 outputs: outputs.fold_with(folder),
@@ -1732,9 +1732,9 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
 
         match self.kind {
             Assign(ref lval, ref rval) => { lval.visit_with(visitor) || rval.visit_with(visitor) }
-            SetDiscriminant { ref lvalue, .. } |
-            StorageLive(ref lvalue) |
-            StorageDead(ref lvalue) => lvalue.visit_with(visitor),
+            SetDiscriminant { ref lvalue, .. } => lvalue.visit_with(visitor),
+            StorageLive(ref local) |
+            StorageDead(ref local) => local.visit_with(visitor),
             InlineAsm { ref outputs, ref inputs, .. } =>
                 outputs.visit_with(visitor) || inputs.visit_with(visitor),
 
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 6589e824187..f26505c6d02 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -256,7 +256,9 @@ macro_rules! make_mir_visitor {
             }
 
             fn visit_local(&mut self,
-                                _local: & $($mutability)* Local) {
+                            _local: & $($mutability)* Local,
+                            _context: LvalueContext<'tcx>,
+                            _location: Location) {
             }
 
             fn visit_visibility_scope(&mut self,
@@ -358,11 +360,11 @@ macro_rules! make_mir_visitor {
                     StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
                         self.visit_lvalue(lvalue, LvalueContext::Store, location);
                     }
-                    StatementKind::StorageLive(ref $($mutability)* lvalue) => {
-                        self.visit_lvalue(lvalue, LvalueContext::StorageLive, location);
+                    StatementKind::StorageLive(ref $($mutability)* local) => {
+                        self.visit_local(local, LvalueContext::StorageLive, location);
                     }
-                    StatementKind::StorageDead(ref $($mutability)* lvalue) => {
-                        self.visit_lvalue(lvalue, LvalueContext::StorageDead, location);
+                    StatementKind::StorageDead(ref $($mutability)* local) => {
+                        self.visit_local(local, LvalueContext::StorageDead, location);
                     }
                     StatementKind::InlineAsm { ref $($mutability)* outputs,
                                                ref $($mutability)* inputs,
@@ -610,7 +612,7 @@ macro_rules! make_mir_visitor {
                             location: Location) {
                 match *lvalue {
                     Lvalue::Local(ref $($mutability)* local) => {
-                        self.visit_local(local);
+                        self.visit_local(local, context, location);
                     }
                     Lvalue::Static(ref $($mutability)* static_) => {
                         self.visit_static(static_, context, location);
@@ -662,8 +664,8 @@ macro_rules! make_mir_visitor {
                     ProjectionElem::Field(_field, ref $($mutability)* ty) => {
                         self.visit_ty(ty, Lookup::Loc(location));
                     }
-                    ProjectionElem::Index(ref $($mutability)* operand) => {
-                        self.visit_operand(operand, location);
+                    ProjectionElem::Index(ref $($mutability)* local) => {
+                        self.visit_local(local, LvalueContext::Consume, location);
                     }
                     ProjectionElem::ConstantIndex { offset: _,
                                                     min_length: _,
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index ae05568ab41..44b505e1965 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -421,7 +421,7 @@ macro_rules! CopyImpls {
     }
 }
 
-CopyImpls! { (), hir::Unsafety, abi::Abi, hir::def_id::DefId }
+CopyImpls! { (), hir::Unsafety, abi::Abi, hir::def_id::DefId, ::mir::Local }
 
 impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> (T, U) {
diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs
index af550aea07e..063cbc77559 100644
--- a/src/librustc_mir/borrow_check.rs
+++ b/src/librustc_mir/borrow_check.rs
@@ -212,11 +212,11 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> DataflowResultsConsumer<'b, 'gcx>
                 // ignored by borrowck
             }
 
-            StatementKind::StorageDead(ref lvalue) => {
+            StatementKind::StorageDead(local) => {
                 // causes non-drop values to be dropped.
                 self.consume_lvalue(ContextKind::StorageDead.new(location),
                                     ConsumeKind::Consume,
-                                    (lvalue, span),
+                                    (&Lvalue::Local(local), span),
                                     flow_state)
             }
         }
@@ -710,7 +710,7 @@ mod restrictions {
 
     use rustc::hir;
     use rustc::ty::{self, TyCtxt};
-    use rustc::mir::{Lvalue, Mir, Operand, ProjectionElem};
+    use rustc::mir::{Lvalue, Mir, ProjectionElem};
 
     pub(super) struct Restrictions<'c, 'tcx: 'c> {
         mir: &'c Mir<'tcx>,
@@ -809,12 +809,7 @@ mod restrictions {
                         ProjectionElem::Downcast(..) |
                         ProjectionElem::Subslice { .. } |
                         ProjectionElem::ConstantIndex { .. } |
-                        ProjectionElem::Index(Operand::Constant(..)) => {
-                            cursor = &proj.base;
-                            continue 'cursor;
-                        }
-                        ProjectionElem::Index(Operand::Consume(ref index)) => {
-                            self.lvalue_stack.push(index); // FIXME: did old borrowck do this?
+                        ProjectionElem::Index(_) => {
                             cursor = &proj.base;
                             continue 'cursor;
                         }
@@ -1004,7 +999,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
                         ("",   format!(""), None), // (dont emit downcast info)
                     ProjectionElem::Field(field, _ty) =>
                         ("",   format!(".{}", field.index()), None),
-                    ProjectionElem::Index(ref index) =>
+                    ProjectionElem::Index(index) =>
                         ("",   format!(""), Some(index)),
                     ProjectionElem::ConstantIndex { offset, min_length, from_end: true } =>
                         ("",   format!("[{} of {}]", offset, min_length), None),
@@ -1021,23 +1016,11 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
                 self.append_lvalue_to_string(&proj.base, buf);
                 if let Some(index) = index_operand {
                     buf.push_str("[");
-                    self.append_operand_to_string(index, buf);
+                    self.append_lvalue_to_string(&Lvalue::Local(index), buf);
                     buf.push_str("]");
                 } else {
                     buf.push_str(&suffix);
                 }
-
-            }
-        }
-    }
-
-    fn append_operand_to_string(&self, operand: &Operand, buf: &mut String) {
-        match *operand {
-            Operand::Consume(ref lvalue) => {
-                self.append_lvalue_to_string(lvalue, buf);
-            }
-            Operand::Constant(ref constant) => {
-                buf.push_str(&format!("{:?}", constant));
             }
         }
     }
diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs
index 01b76af1576..9cbaff2c113 100644
--- a/src/librustc_mir/build/expr/as_lvalue.rs
+++ b/src/librustc_mir/build/expr/as_lvalue.rs
@@ -61,7 +61,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // region_scope=None so lvalue indexes live forever. They are scalars so they
                 // do not need storage annotations, and they are often copied between
                 // places.
-                let idx = unpack!(block = this.as_operand(block, None, index));
+                let idx = unpack!(block = this.as_temp(block, None, index));
 
                 // bounds check:
                 let (len, lt) = (this.temp(usize_ty.clone(), expr_span),
@@ -70,12 +70,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                      &len, Rvalue::Len(slice.clone()));
                 this.cfg.push_assign(block, source_info, // lt = idx < len
                                      &lt, Rvalue::BinaryOp(BinOp::Lt,
-                                                           idx.clone(),
+                                                           Operand::Consume(Lvalue::Local(idx)),
                                                            Operand::Consume(len.clone())));
 
                 let msg = AssertMessage::BoundsCheck {
                     len: Operand::Consume(len),
-                    index: idx.clone()
+                    index: Operand::Consume(Lvalue::Local(idx))
                 };
                 let success = this.assert(block, Operand::Consume(lt), true,
                                           msg, expr_span);
@@ -127,7 +127,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     Some(Category::Lvalue) => false,
                     _ => true,
                 });
-                this.as_temp(block, expr.temp_lifetime, expr)
+                let temp = unpack!(block = this.as_temp(block, expr.temp_lifetime, expr));
+                block.and(Lvalue::Local(temp))
             }
         }
     }
diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs
index ea1b53add5e..0a72ce8d05e 100644
--- a/src/librustc_mir/build/expr/as_operand.rs
+++ b/src/librustc_mir/build/expr/as_operand.rs
@@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             Category::Rvalue(..) => {
                 let operand =
                     unpack!(block = this.as_temp(block, scope, expr));
-                block.and(Operand::Consume(operand))
+                block.and(Operand::Consume(Lvalue::Local(operand)))
             }
         }
     }
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index cac1535b9fe..c83283ee38e 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -96,23 +96,23 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
             ExprKind::Box { value } => {
                 let value = this.hir.mirror(value);
-                let result = this.temp(expr.ty, expr_span);
+                let result = this.local_decls.push(LocalDecl::new_temp(expr.ty, expr_span));
                 this.cfg.push(block, Statement {
                     source_info,
-                    kind: StatementKind::StorageLive(result.clone())
+                    kind: StatementKind::StorageLive(result)
                 });
                 if let Some(scope) = scope {
                     // schedule a shallow free of that memory, lest we unwind:
-                    this.schedule_drop(expr_span, scope, &result, value.ty);
+                    this.schedule_drop(expr_span, scope, &Lvalue::Local(result), value.ty);
                 }
 
                 // malloc some memory of suitable type (thus far, uninitialized):
                 let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
-                this.cfg.push_assign(block, source_info, &result, box_);
+                this.cfg.push_assign(block, source_info, &Lvalue::Local(result), box_);
 
                 // initialize the box contents:
-                unpack!(block = this.into(&result.clone().deref(), block, value));
-                block.and(Rvalue::Use(Operand::Consume(result)))
+                unpack!(block = this.into(&Lvalue::Local(result).deref(), block, value));
+                block.and(Rvalue::Use(Operand::Consume(Lvalue::Local(result))))
             }
             ExprKind::Cast { source } => {
                 let source = this.hir.mirror(source);
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index ed259867a48..7826769600b 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -23,7 +23,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                       block: BasicBlock,
                       temp_lifetime: Option<region::Scope>,
                       expr: M)
-                      -> BlockAnd<Lvalue<'tcx>>
+                      -> BlockAnd<Local>
         where M: Mirror<'tcx, Output = Expr<'tcx>>
     {
         let expr = self.hir.mirror(expr);
@@ -34,7 +34,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     mut block: BasicBlock,
                     temp_lifetime: Option<region::Scope>,
                     expr: Expr<'tcx>)
-                    -> BlockAnd<Lvalue<'tcx>> {
+                    -> BlockAnd<Local> {
         debug!("expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?})",
                block, temp_lifetime, expr);
         let this = self;
@@ -47,13 +47,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             });
         }
 
-        let expr_ty = expr.ty.clone();
-        let temp = this.temp(expr_ty.clone(), expr_span);
+        let expr_ty = expr.ty;
+        let temp = this.local_decls.push(LocalDecl::new_temp(expr_ty, expr_span));
 
         if !expr_ty.is_never() {
             this.cfg.push(block, Statement {
                 source_info,
-                kind: StatementKind::StorageLive(temp.clone())
+                kind: StatementKind::StorageLive(temp)
             });
         }
 
@@ -68,10 +68,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             Category::Lvalue => {
                 let lvalue = unpack!(block = this.as_lvalue(block, expr));
                 let rvalue = Rvalue::Use(Operand::Consume(lvalue));
-                this.cfg.push_assign(block, source_info, &temp, rvalue);
+                this.cfg.push_assign(block, source_info, &Lvalue::Local(temp), rvalue);
             }
             _ => {
-                unpack!(block = this.into(&temp, block, expr));
+                unpack!(block = this.into(&Lvalue::Local(temp), block, expr));
             }
         }
 
@@ -79,7 +79,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // anything because no values with a destructor can be created in
         // a constant at this time, even if the type may need dropping.
         if let Some(temp_lifetime) = temp_lifetime {
-            this.schedule_drop(expr_span, temp_lifetime, &temp, expr_ty);
+            this.schedule_drop(expr_span, temp_lifetime, &Lvalue::Local(temp), expr_ty);
         }
 
         block.and(temp)
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 6d7c2132665..80a126dc425 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -229,7 +229,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
                     let topmost_scope = this.topmost_scope();
                     let ptr = unpack!(block = this.as_temp(block, Some(topmost_scope), ptr));
-                    this.into(&ptr.deref(), block, val)
+                    this.into(&Lvalue::Local(ptr).deref(), block, val)
                 } else {
                     let args: Vec<_> =
                         args.into_iter()
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index a2b376336b8..ec2e487b4e7 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -194,7 +194,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let source_info = self.source_info(span);
         self.cfg.push(block, Statement {
             source_info,
-            kind: StatementKind::StorageLive(Lvalue::Local(local_id))
+            kind: StatementKind::StorageLive(local_id)
         });
         Lvalue::Local(local_id)
     }
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index f527c4f0388..ed598c876f3 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -822,7 +822,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
             Lvalue::Local(index) if index.index() > arg_count => {
                 cfg.push(block, Statement {
                     source_info,
-                    kind: StatementKind::StorageDead(drop_data.location.clone())
+                    kind: StatementKind::StorageDead(index)
                 });
             }
             _ => continue
diff --git a/src/librustc_mir/dataflow/move_paths/abs_domain.rs b/src/librustc_mir/dataflow/move_paths/abs_domain.rs
index 173396f2245..00825c7a880 100644
--- a/src/librustc_mir/dataflow/move_paths/abs_domain.rs
+++ b/src/librustc_mir/dataflow/move_paths/abs_domain.rs
@@ -21,8 +21,7 @@
 //! `a[x]` would still overlap them both. But that is not this
 //! representation does today.)
 
-use rustc::mir::LvalueElem;
-use rustc::mir::{Operand, ProjectionElem};
+use rustc::mir::{Local, LvalueElem, Operand, ProjectionElem};
 use rustc::ty::Ty;
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -40,6 +39,10 @@ impl<'tcx> Lift for Operand<'tcx> {
     type Abstract = AbstractOperand;
     fn lift(&self) -> Self::Abstract { AbstractOperand }
 }
+impl Lift for Local {
+    type Abstract = AbstractOperand;
+    fn lift(&self) -> Self::Abstract { AbstractOperand }
+}
 impl<'tcx> Lift for Ty<'tcx> {
     type Abstract = AbstractType;
     fn lift(&self) -> Self::Abstract { AbstractType }
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 1e0858d6864..d3c886dab4e 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -479,9 +479,10 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
 
     fn array_shim(&mut self, ty: ty::Ty<'tcx>, len: usize) {
         let tcx = self.tcx;
+        let span = self.span;
         let rcvr = Lvalue::Local(Local::new(1+0)).deref();
 
-        let beg = self.make_lvalue(Mutability::Mut, tcx.types.usize);
+        let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
         let end = self.make_lvalue(Mutability::Not, tcx.types.usize);
         let ret = self.make_lvalue(Mutability::Mut, tcx.mk_array(ty, len));
 
@@ -492,7 +493,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
         let inits = vec![
             self.make_statement(
                 StatementKind::Assign(
-                    beg.clone(),
+                    Lvalue::Local(beg),
                     Rvalue::Use(Operand::Constant(self.make_usize(0)))
                 )
             ),
@@ -510,19 +511,19 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
         //     BB #3;
         // }
         // BB #4;
-        self.loop_header(beg.clone(), end, BasicBlock::new(2), BasicBlock::new(4), false);
+        self.loop_header(Lvalue::Local(beg), end, BasicBlock::new(2), BasicBlock::new(4), false);
 
         // BB #2
         // `let cloned = Clone::clone(rcvr[beg])`;
         // Goto #3 if ok, #5 if unwinding happens.
-        let rcvr_field = rcvr.clone().index(Operand::Consume(beg.clone()));
+        let rcvr_field = rcvr.clone().index(beg);
         let cloned = self.make_clone_call(ty, rcvr_field, BasicBlock::new(3), BasicBlock::new(5));
 
         // BB #3
         // `ret[beg] = cloned;`
         // `beg = beg + 1;`
         // `goto #1`;
-        let ret_field = ret.clone().index(Operand::Consume(beg.clone()));
+        let ret_field = ret.clone().index(beg);
         let statements = vec![
             self.make_statement(
                 StatementKind::Assign(
@@ -532,10 +533,10 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
             ),
             self.make_statement(
                 StatementKind::Assign(
-                    beg.clone(),
+                    Lvalue::Local(beg),
                     Rvalue::BinaryOp(
                         BinOp::Add,
-                        Operand::Consume(beg.clone()),
+                        Operand::Consume(Lvalue::Local(beg)),
                         Operand::Constant(self.make_usize(1))
                     )
                 )
@@ -558,10 +559,10 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
         // `let mut beg = 0;`
         // goto #6;
         let end = beg;
-        let beg = self.make_lvalue(Mutability::Mut, tcx.types.usize);
+        let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
         let init = self.make_statement(
             StatementKind::Assign(
-                beg.clone(),
+                Lvalue::Local(beg),
                 Rvalue::Use(Operand::Constant(self.make_usize(0)))
             )
         );
@@ -572,12 +573,13 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
         //     BB #8;
         // }
         // BB #9;
-        self.loop_header(beg.clone(), end, BasicBlock::new(7), BasicBlock::new(9), true);
+        self.loop_header(Lvalue::Local(beg), Lvalue::Local(end),
+                         BasicBlock::new(7), BasicBlock::new(9), true);
 
         // BB #7 (cleanup)
         // `drop(ret[beg])`;
         self.block(vec![], TerminatorKind::Drop {
-            location: ret.index(Operand::Consume(beg.clone())),
+            location: ret.index(beg),
             target: BasicBlock::new(8),
             unwind: None,
         }, true);
@@ -587,10 +589,10 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
         // `goto #6;`
         let statement = self.make_statement(
             StatementKind::Assign(
-                beg.clone(),
+                Lvalue::Local(beg),
                 Rvalue::BinaryOp(
                     BinOp::Add,
-                    Operand::Consume(beg.clone()),
+                    Operand::Consume(Lvalue::Local(beg)),
                     Operand::Constant(self.make_usize(1))
                 )
             )
diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs
index 186c465f601..ac8ebd306d3 100644
--- a/src/librustc_mir/transform/copy_prop.rs
+++ b/src/librustc_mir/transform/copy_prop.rs
@@ -236,8 +236,7 @@ impl<'tcx> Action<'tcx> {
                 }
 
                 // Replace all uses of the destination local with the source local.
-                let src_lvalue = Lvalue::Local(src_local);
-                def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue);
+                def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_local);
 
                 // Finally, zap the now-useless assignment instruction.
                 debug!("  Deleting assignment");
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 9bc572c66b6..d1e0465f555 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -88,7 +88,9 @@ struct RenameLocalVisitor {
 
 impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
     fn visit_local(&mut self,
-                        local: &mut Local) {
+                   local: &mut Local,
+                   _: LvalueContext<'tcx>,
+                   _: Location) {
         if *local == self.from {
             *local = self.to;
         }
@@ -98,6 +100,13 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
 struct DerefArgVisitor;
 
 impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
+    fn visit_local(&mut self,
+                   local: &mut Local,
+                   _: LvalueContext<'tcx>,
+                   _: Location) {
+        assert_ne!(*local, self_arg());
+    }
+
     fn visit_lvalue(&mut self,
                     lvalue: &mut Lvalue<'tcx>,
                     context: LvalueContext<'tcx>,
@@ -177,6 +186,13 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
+    fn visit_local(&mut self,
+                   local: &mut Local,
+                   _: LvalueContext<'tcx>,
+                   _: Location) {
+        assert_eq!(self.remap.get(local), None);
+    }
+
     fn visit_lvalue(&mut self,
                     lvalue: &mut Lvalue<'tcx>,
                     context: LvalueContext<'tcx>,
@@ -197,12 +213,8 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
         // Remove StorageLive and StorageDead statements for remapped locals
         data.retain_statements(|s| {
             match s.kind {
-                StatementKind::StorageLive(ref l) | StatementKind::StorageDead(ref l) => {
-                    if let Lvalue::Local(l) = *l {
-                        !self.remap.contains_key(&l)
-                    } else {
-                        true
-                    }
+                StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => {
+                    !self.remap.contains_key(&l)
                 }
                 _ => true
             }
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 124a1ef946e..3f8070fb3aa 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -589,16 +589,6 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
         new
     }
 
-    fn update_local(&self, local: Local) -> Option<Local> {
-        let idx = local.index();
-        if idx < (self.args.len() + 1) {
-            return None;
-        }
-        let idx = idx - (self.args.len() + 1);
-        let local = Local::new(idx);
-        self.local_map.get(local).cloned()
-    }
-
     fn arg_index(&self, arg: Local) -> Option<usize> {
         let idx = arg.index();
         if idx > 0 && idx <= self.args.len() {
@@ -610,32 +600,35 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
+    fn visit_local(&mut self,
+                   local: &mut Local,
+                   _ctxt: LvalueContext<'tcx>,
+                   _location: Location) {
+        if *local == RETURN_POINTER {
+            match self.destination {
+                Lvalue::Local(l) => *local = l,
+                ref lval => bug!("Return lvalue is {:?}, not local", lval)
+            }
+        }
+        let idx = local.index() - 1;
+        if idx < self.args.len() {
+            match self.args[idx] {
+                Operand::Consume(Lvalue::Local(l)) => *local = l,
+                ref op => bug!("Arg operand `{:?}` is {:?}, not local", idx, op)
+            }
+        }
+        *local = self.local_map[Local::new(idx - self.args.len())];
+    }
+
     fn visit_lvalue(&mut self,
                     lvalue: &mut Lvalue<'tcx>,
                     _ctxt: LvalueContext<'tcx>,
                     _location: Location) {
-        if let Lvalue::Local(ref mut local) = *lvalue {
-            if let Some(l) = self.update_local(*local) {
-                // Temp or Var; update the local reference
-                *local = l;
-                return;
-            }
-        }
-        if let Lvalue::Local(local) = *lvalue {
-            if local == RETURN_POINTER {
-                // Return pointer; update the lvalue itself
-                *lvalue = self.destination.clone();
-            } else if local.index() < (self.args.len() + 1) {
-                // Argument, once again update the the lvalue itself
-                let idx = local.index() - 1;
-                if let Operand::Consume(ref lval) = self.args[idx] {
-                    *lvalue = lval.clone();
-                } else {
-                    bug!("Arg operand `{:?}` is not an Lvalue use.", idx)
-                }
-            }
+        if let Lvalue::Local(RETURN_POINTER) = *lvalue {
+            // Return pointer; update the lvalue itself
+            *lvalue = self.destination.clone();
         } else {
-            self.super_lvalue(lvalue, _ctxt, _location)
+            self.super_lvalue(lvalue, _ctxt, _location);
         }
     }
 
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 3e136fb9e9c..ca6eda5c2d7 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -83,52 +83,49 @@ struct TempCollector<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> {
-    fn visit_lvalue(&mut self,
-                    lvalue: &Lvalue<'tcx>,
-                    context: LvalueContext<'tcx>,
-                    location: Location) {
-        self.super_lvalue(lvalue, context, location);
-        if let Lvalue::Local(index) = *lvalue {
-            // We're only interested in temporaries
-            if self.mir.local_kind(index) != LocalKind::Temp {
-                return;
-            }
+    fn visit_local(&mut self,
+                   &index: &Local,
+                   context: LvalueContext<'tcx>,
+                   location: Location) {
+        // We're only interested in temporaries
+        if self.mir.local_kind(index) != LocalKind::Temp {
+            return;
+        }
 
-            // Ignore drops, if the temp gets promoted,
-            // then it's constant and thus drop is noop.
-            // Storage live ranges are also irrelevant.
-            if context.is_drop() || context.is_storage_marker() {
-                return;
-            }
+        // Ignore drops, if the temp gets promoted,
+        // then it's constant and thus drop is noop.
+        // Storage live ranges are also irrelevant.
+        if context.is_drop() || context.is_storage_marker() {
+            return;
+        }
 
-            let temp = &mut self.temps[index];
-            if *temp == TempState::Undefined {
-                match context {
-                    LvalueContext::Store |
-                    LvalueContext::Call => {
-                        *temp = TempState::Defined {
-                            location,
-                            uses: 0
-                        };
-                        return;
-                    }
-                    _ => { /* mark as unpromotable below */ }
-                }
-            } else if let TempState::Defined { ref mut uses, .. } = *temp {
-                // We always allow borrows, even mutable ones, as we need
-                // to promote mutable borrows of some ZSTs e.g. `&mut []`.
-                let allowed_use = match context {
-                    LvalueContext::Borrow {..} => true,
-                    _ => context.is_nonmutating_use()
-                };
-                if allowed_use {
-                    *uses += 1;
+        let temp = &mut self.temps[index];
+        if *temp == TempState::Undefined {
+            match context {
+                LvalueContext::Store |
+                LvalueContext::Call => {
+                    *temp = TempState::Defined {
+                        location,
+                        uses: 0
+                    };
                     return;
                 }
-                /* mark as unpromotable below */
+                _ => { /* mark as unpromotable below */ }
             }
-            *temp = TempState::Unpromotable;
+        } else if let TempState::Defined { ref mut uses, .. } = *temp {
+            // We always allow borrows, even mutable ones, as we need
+            // to promote mutable borrows of some ZSTs e.g. `&mut []`.
+            let allowed_use = match context {
+                LvalueContext::Borrow {..} => true,
+                _ => context.is_nonmutating_use()
+            };
+            if allowed_use {
+                *uses += 1;
+                return;
+            }
+            /* mark as unpromotable below */
         }
+        *temp = TempState::Unpromotable;
     }
 
     fn visit_source_info(&mut self, source_info: &SourceInfo) {
@@ -326,16 +323,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
 
 /// Replaces all temporaries with their promoted counterparts.
 impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
-    fn visit_lvalue(&mut self,
-                    lvalue: &mut Lvalue<'tcx>,
-                    context: LvalueContext<'tcx>,
-                    location: Location) {
-        if let Lvalue::Local(ref mut temp) = *lvalue {
-            if self.source.local_kind(*temp) == LocalKind::Temp {
-                *temp = self.promote_temp(*temp);
-            }
+    fn visit_local(&mut self,
+                   local: &mut Local,
+                   _: LvalueContext<'tcx>,
+                   _: Location) {
+        if self.source.local_kind(*local) == LocalKind::Temp {
+            *local = self.promote_temp(*local);
         }
-        self.super_lvalue(lvalue, context, location);
     }
 }
 
@@ -412,8 +406,8 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
         block.statements.retain(|statement| {
             match statement.kind {
                 StatementKind::Assign(Lvalue::Local(index), _) |
-                StatementKind::StorageLive(Lvalue::Local(index)) |
-                StatementKind::StorageDead(Lvalue::Local(index)) => {
+                StatementKind::StorageLive(index) |
+                StatementKind::StorageDead(index) => {
                     !promoted(index)
                 }
                 _ => true
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 9e64b0f9c77..415421757c5 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -499,33 +499,40 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
 /// For functions (constant or not), it also records
 /// candidates for promotion in promotion_candidates.
 impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
+    fn visit_local(&mut self,
+                   &local: &Local,
+                   _: LvalueContext<'tcx>,
+                   _: Location) {
+        match self.mir.local_kind(local) {
+            LocalKind::ReturnPointer => {
+                self.not_const();
+            }
+            LocalKind::Arg => {
+                self.add(Qualif::FN_ARGUMENT);
+            }
+            LocalKind::Var => {
+                self.add(Qualif::NOT_CONST);
+            }
+            LocalKind::Temp => {
+                if !self.temp_promotion_state[local].is_promotable() {
+                    self.add(Qualif::NOT_PROMOTABLE);
+                }
+
+                if let Some(qualif) = self.temp_qualif[local] {
+                    self.add(qualif);
+                } else {
+                    self.not_const();
+                }
+            }
+        }
+    }
+
     fn visit_lvalue(&mut self,
                     lvalue: &Lvalue<'tcx>,
                     context: LvalueContext<'tcx>,
                     location: Location) {
         match *lvalue {
-            Lvalue::Local(local) => match self.mir.local_kind(local) {
-                LocalKind::ReturnPointer => {
-                    self.not_const();
-                }
-                LocalKind::Arg => {
-                    self.add(Qualif::FN_ARGUMENT);
-                }
-                LocalKind::Var => {
-                    self.add(Qualif::NOT_CONST);
-                }
-                LocalKind::Temp => {
-                    if !self.temp_promotion_state[local].is_promotable() {
-                        self.add(Qualif::NOT_PROMOTABLE);
-                    }
-
-                    if let Some(qualif) = self.temp_qualif[local] {
-                        self.add(qualif);
-                    } else {
-                        self.not_const();
-                    }
-                }
-            },
+            Lvalue::Local(ref local) => self.visit_local(local, context, location),
             Lvalue::Static(ref global) => {
                 self.add(Qualif::STATIC);
 
@@ -1101,7 +1108,7 @@ impl MirPass for QualifyAndPromoteConstants {
             for block in mir.basic_blocks_mut() {
                 block.statements.retain(|statement| {
                     match statement.kind {
-                        StatementKind::StorageDead(Lvalue::Local(index)) => {
+                        StatementKind::StorageDead(index) => {
                             !promoted_temps.contains(&index)
                         }
                         _ => true
diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs
index 070250cda4d..89828cf375a 100644
--- a/src/librustc_mir/transform/simplify.rs
+++ b/src/librustc_mir/transform/simplify.rs
@@ -352,15 +352,11 @@ struct DeclMarker {
 }
 
 impl<'tcx> Visitor<'tcx> for DeclMarker {
-    fn visit_lvalue(&mut self, lval: &Lvalue<'tcx>, ctx: LvalueContext<'tcx>, loc: Location) {
-        if ctx == LvalueContext::StorageLive || ctx == LvalueContext::StorageDead {
-            // ignore these altogether, they get removed along with their otherwise unused decls.
-            return;
+    fn visit_local(&mut self, local: &Local, ctx: LvalueContext<'tcx>, _: Location) {
+        // ignore these altogether, they get removed along with their otherwise unused decls.
+        if ctx != LvalueContext::StorageLive && ctx != LvalueContext::StorageDead {
+            self.locals.insert(local.index());
         }
-        if let Lvalue::Local(ref v) = *lval {
-            self.locals.insert(v.index());
-        }
-        self.super_lvalue(lval, ctx, loc);
     }
 }
 
@@ -373,22 +369,15 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
         // Remove unnecessary StorageLive and StorageDead annotations.
         data.statements.retain(|stmt| {
             match stmt.kind {
-                StatementKind::StorageLive(ref lval) | StatementKind::StorageDead(ref lval) => {
-                    match *lval {
-                        Lvalue::Local(l) => self.map[l.index()] != !0,
-                        _ => true
-                    }
+                StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => {
+                    self.map[l.index()] != !0
                 }
                 _ => true
             }
         });
         self.super_basic_block_data(block, data);
     }
-    fn visit_lvalue(&mut self, lval: &mut Lvalue<'tcx>, ctx: LvalueContext<'tcx>, loc: Location) {
-        match *lval {
-            Lvalue::Local(ref mut l) => *l = Local::new(self.map[l.index()]),
-            _ => (),
-        };
-        self.super_lvalue(lval, ctx, loc);
+    fn visit_local(&mut self, l: &mut Local, _: LvalueContext<'tcx>, _: Location) {
+        *l = Local::new(self.map[l.index()]);
     }
 }
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 59cf5903aa9..d4da14ea96e 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -165,7 +165,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                            base: LvalueTy<'tcx>,
                            pi: &LvalueElem<'tcx>,
                            lvalue: &Lvalue<'tcx>,
-                           location: Location)
+                           _: Location)
                            -> LvalueTy<'tcx> {
         debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, lvalue);
         let tcx = self.tcx();
@@ -181,9 +181,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                     })
                 }
             }
-            ProjectionElem::Index(ref i) => {
-                self.visit_operand(i, location);
-                let index_ty = i.ty(self.mir, tcx);
+            ProjectionElem::Index(i) => {
+                let index_ty = Lvalue::Local(i).ty(self.mir, tcx).to_ty(tcx);
                 if index_ty != tcx.types.usize {
                     LvalueTy::Ty {
                         ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i)
@@ -421,15 +420,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                                variant_index);
                 };
             }
-            StatementKind::StorageLive(ref lv) |
-            StatementKind::StorageDead(ref lv) => {
-                match *lv {
-                    Lvalue::Local(_) => {}
-                    _ => {
-                        span_mirbug!(self, stmt, "bad lvalue: expected local");
-                    }
-                }
-            }
+            StatementKind::StorageLive(_) |
+            StatementKind::StorageDead(_) |
             StatementKind::InlineAsm { .. } |
             StatementKind::EndRegion(_) |
             StatementKind::Validate(..) |
diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs
index 8263e149d84..bd9fb4bc3cc 100644
--- a/src/librustc_mir/util/def_use.rs
+++ b/src/librustc_mir/util/def_use.rs
@@ -10,7 +10,7 @@
 
 //! Def-use analysis.
 
-use rustc::mir::{Local, Location, Lvalue, Mir};
+use rustc::mir::{Local, Location, Mir};
 use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::marker::PhantomData;
@@ -51,7 +51,7 @@ impl<'tcx> DefUseAnalysis<'tcx> {
     }
 
     fn mutate_defs_and_uses<F>(&self, local: Local, mir: &mut Mir<'tcx>, mut callback: F)
-                               where F: for<'a> FnMut(&'a mut Lvalue<'tcx>,
+                               where F: for<'a> FnMut(&'a mut Local,
                                                       LvalueContext<'tcx>,
                                                       Location) {
         for lvalue_use in &self.info[local].defs_and_uses {
@@ -65,8 +65,8 @@ impl<'tcx> DefUseAnalysis<'tcx> {
     pub fn replace_all_defs_and_uses_with(&self,
                                           local: Local,
                                           mir: &mut Mir<'tcx>,
-                                          new_lvalue: Lvalue<'tcx>) {
-        self.mutate_defs_and_uses(local, mir, |lvalue, _, _| *lvalue = new_lvalue.clone())
+                                          new_local: Local) {
+        self.mutate_defs_and_uses(local, mir, |local, _, _| *local = new_local)
     }
 }
 
@@ -74,30 +74,15 @@ struct DefUseFinder<'tcx> {
     info: IndexVec<Local, Info<'tcx>>,
 }
 
-impl<'tcx> DefUseFinder<'tcx> {
-    fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> {
-        let info = &mut self.info;
-
-        if let Lvalue::Local(local) = *lvalue {
-            Some(&mut info[local])
-        } else {
-            None
-        }
-    }
-}
-
 impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> {
-    fn visit_lvalue(&mut self,
-                    lvalue: &Lvalue<'tcx>,
-                    context: LvalueContext<'tcx>,
-                    location: Location) {
-        if let Some(ref mut info) = self.lvalue_mut_info(lvalue) {
-            info.defs_and_uses.push(Use {
-                context,
-                location,
-            })
-        }
-        self.super_lvalue(lvalue, context, location)
+    fn visit_local(&mut self,
+                   &local: &Local,
+                   context: LvalueContext<'tcx>,
+                   location: Location) {
+        self.info[local].defs_and_uses.push(Use {
+            context,
+            location,
+        });
     }
 }
 
@@ -134,7 +119,7 @@ struct MutateUseVisitor<'tcx, F> {
 impl<'tcx, F> MutateUseVisitor<'tcx, F> {
     fn new(query: Local, callback: F, _: &Mir<'tcx>)
            -> MutateUseVisitor<'tcx, F>
-           where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
+           where F: for<'a> FnMut(&'a mut Local, LvalueContext<'tcx>, Location) {
         MutateUseVisitor {
             query,
             callback,
@@ -144,16 +129,13 @@ impl<'tcx, F> MutateUseVisitor<'tcx, F> {
 }
 
 impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F>
-              where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
-    fn visit_lvalue(&mut self,
-                    lvalue: &mut Lvalue<'tcx>,
+              where F: for<'a> FnMut(&'a mut Local, LvalueContext<'tcx>, Location) {
+    fn visit_local(&mut self,
+                    local: &mut Local,
                     context: LvalueContext<'tcx>,
                     location: Location) {
-        if let Lvalue::Local(local) = *lvalue {
-            if local == self.query {
-                (self.callback)(lvalue, context, location)
-            }
+        if *local == self.query {
+            (self.callback)(local, context, location)
         }
-        self.super_lvalue(lvalue, context, location)
     }
 }
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index 41618960337..f3b121f2eed 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -565,7 +565,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
     ///    drop(ptr)
     fn drop_loop(&mut self,
                  succ: BasicBlock,
-                 cur: &Lvalue<'tcx>,
+                 cur: Local,
                  length_or_end: &Lvalue<'tcx>,
                  ety: Ty<'tcx>,
                  unwind: Unwind,
@@ -584,20 +584,20 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
 
         let one = self.constant_usize(1);
         let (ptr_next, cur_next) = if ptr_based {
-            (Rvalue::Use(use_(cur)),
-             Rvalue::BinaryOp(BinOp::Offset, use_(cur), one))
+            (Rvalue::Use(use_(&Lvalue::Local(cur))),
+             Rvalue::BinaryOp(BinOp::Offset, use_(&Lvalue::Local(cur)), one))
         } else {
             (Rvalue::Ref(
                  tcx.types.re_erased,
                  BorrowKind::Mut,
-                 self.lvalue.clone().index(use_(cur))),
-             Rvalue::BinaryOp(BinOp::Add, use_(cur), one))
+                 self.lvalue.clone().index(cur)),
+             Rvalue::BinaryOp(BinOp::Add, use_(&Lvalue::Local(cur)), one))
         };
 
         let drop_block = BasicBlockData {
             statements: vec![
                 self.assign(ptr, ptr_next),
-                self.assign(cur, cur_next)
+                self.assign(&Lvalue::Local(cur), cur_next)
             ],
             is_cleanup: unwind.is_cleanup(),
             terminator: Some(Terminator {
@@ -611,7 +611,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
         let loop_block = BasicBlockData {
             statements: vec![
                 self.assign(can_go, Rvalue::BinaryOp(BinOp::Eq,
-                                                     use_(cur),
+                                                     use_(&Lvalue::Local(cur)),
                                                      use_(length_or_end)))
             ],
             is_cleanup: unwind.is_cleanup(),
@@ -678,7 +678,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
             tcx.types.usize
         };
 
-        let cur = Lvalue::Local(self.new_temp(iter_ty));
+        let cur = self.new_temp(iter_ty);
         let length = Lvalue::Local(self.new_temp(tcx.types.usize));
         let length_or_end = if ptr_based {
             Lvalue::Local(self.new_temp(iter_ty))
@@ -688,7 +688,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
 
         let unwind = self.unwind.map(|unwind| {
             self.drop_loop(unwind,
-                           &cur,
+                           cur,
                            &length_or_end,
                            ety,
                            Unwind::InCleanup,
@@ -698,12 +698,13 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
         let succ = self.succ; // FIXME(#6393)
         let loop_block = self.drop_loop(
             succ,
-            &cur,
+            cur,
             &length_or_end,
             ety,
             unwind,
             ptr_based);
 
+        let cur = Lvalue::Local(cur);
         let zero = self.constant_usize(0);
         let mut drop_block_stmts = vec![];
         drop_block_stmts.push(self.assign(&length, Rvalue::Len(self.lvalue.clone())));
diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs
index fd15c90dc90..e6d3a82ff9b 100644
--- a/src/librustc_mir/util/liveness.rs
+++ b/src/librustc_mir/util/liveness.rs
@@ -60,49 +60,45 @@ struct BlockInfoVisitor {
 }
 
 impl<'tcx> Visitor<'tcx> for BlockInfoVisitor {
-    fn visit_lvalue(&mut self,
-                    lvalue: &Lvalue<'tcx>,
-                    context: LvalueContext<'tcx>,
-                    location: Location) {
-        if let Lvalue::Local(local) = *lvalue {
-            match context {
-                LvalueContext::Store |
-
-                // We let Call defined the result in both the success and unwind cases.
-                // This may not be right.
-                LvalueContext::Call |
-
-                // Storage live and storage dead aren't proper defines, but we can ignore
-                // values that come before them.
-                LvalueContext::StorageLive |
-                LvalueContext::StorageDead => {
-                    self.defs.add(&local);
-                }
-                LvalueContext::Projection(..) |
-
-                // Borrows only consider their local used at the point of the borrow.
-                // This won't affect the results since we use this analysis for generators
-                // and we only care about the result at suspension points. Borrows cannot
-                // cross suspension points so this behavior is unproblematic.
-                LvalueContext::Borrow { .. } |
-
-                LvalueContext::Inspect |
-                LvalueContext::Consume |
-                LvalueContext::Validate |
-
-                // We consider drops to always be uses of locals.
-                // Drop eloboration should be run before this analysis otherwise
-                // the results might be too pessimistic.
-                LvalueContext::Drop => {
-                    // Ignore uses which are already defined in this block
-                    if !self.pre_defs.contains(&local) {
-                        self.uses.add(&local);
-                    }
+    fn visit_local(&mut self,
+                   &local: &Local,
+                   context: LvalueContext<'tcx>,
+                   _: Location) {
+        match context {
+            LvalueContext::Store |
+
+            // We let Call defined the result in both the success and unwind cases.
+            // This may not be right.
+            LvalueContext::Call |
+
+            // Storage live and storage dead aren't proper defines, but we can ignore
+            // values that come before them.
+            LvalueContext::StorageLive |
+            LvalueContext::StorageDead => {
+                self.defs.add(&local);
+            }
+            LvalueContext::Projection(..) |
+
+            // Borrows only consider their local used at the point of the borrow.
+            // This won't affect the results since we use this analysis for generators
+            // and we only care about the result at suspension points. Borrows cannot
+            // cross suspension points so this behavior is unproblematic.
+            LvalueContext::Borrow { .. } |
+
+            LvalueContext::Inspect |
+            LvalueContext::Consume |
+            LvalueContext::Validate |
+
+            // We consider drops to always be uses of locals.
+            // Drop eloboration should be run before this analysis otherwise
+            // the results might be too pessimistic.
+            LvalueContext::Drop => {
+                // Ignore uses which are already defined in this block
+                if !self.pre_defs.contains(&local) {
+                    self.uses.add(&local);
                 }
             }
         }
-
-        self.super_lvalue(lvalue, context, location)
     }
 }
 
diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs
index a17ddabb1a7..95b76d32bf8 100644
--- a/src/librustc_trans/mir/analyze.rs
+++ b/src/librustc_trans/mir/analyze.rs
@@ -134,60 +134,61 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
                     location: Location) {
         debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context);
 
-        // Allow uses of projections of immediate pair fields.
         if let mir::Lvalue::Projection(ref proj) = *lvalue {
-            if let mir::Lvalue::Local(_) = proj.base {
-                let ty = proj.base.ty(self.cx.mir, self.cx.ccx.tcx());
-
-                let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
-                if common::type_is_imm_pair(self.cx.ccx, ty) {
+            // Allow uses of projections of immediate pair fields.
+            if let LvalueContext::Consume = context {
+                if let mir::Lvalue::Local(_) = proj.base {
                     if let mir::ProjectionElem::Field(..) = proj.elem {
-                        if let LvalueContext::Consume = context {
+                        let ty = proj.base.ty(self.cx.mir, self.cx.ccx.tcx());
+
+                        let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
+                        if common::type_is_imm_pair(self.cx.ccx, ty) {
                             return;
                         }
                     }
                 }
             }
-        }
 
-        if let mir::Lvalue::Local(index) = *lvalue {
-            match context {
-                LvalueContext::Call => {
-                    self.mark_assigned(index);
-                }
+            // A deref projection only reads the pointer, never needs the lvalue.
+            if let mir::ProjectionElem::Deref = proj.elem {
+                return self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
+            }
+        }
 
-                LvalueContext::StorageLive |
-                LvalueContext::StorageDead |
-                LvalueContext::Validate |
-                LvalueContext::Inspect |
-                LvalueContext::Consume => {}
+        self.super_lvalue(lvalue, context, location);
+    }
 
-                LvalueContext::Store |
-                LvalueContext::Borrow { .. } |
-                LvalueContext::Projection(..) => {
-                    self.mark_as_lvalue(index);
-                }
+    fn visit_local(&mut self,
+                   &index: &mir::Local,
+                   context: LvalueContext<'tcx>,
+                   _: Location) {
+        match context {
+            LvalueContext::Call => {
+                self.mark_assigned(index);
+            }
 
-                LvalueContext::Drop => {
-                    let ty = lvalue.ty(self.cx.mir, self.cx.ccx.tcx());
-                    let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
+            LvalueContext::StorageLive |
+            LvalueContext::StorageDead |
+            LvalueContext::Validate |
+            LvalueContext::Inspect |
+            LvalueContext::Consume => {}
 
-                    // Only need the lvalue if we're actually dropping it.
-                    if self.cx.ccx.shared().type_needs_drop(ty) {
-                        self.mark_as_lvalue(index);
-                    }
-                }
+            LvalueContext::Store |
+            LvalueContext::Borrow { .. } |
+            LvalueContext::Projection(..) => {
+                self.mark_as_lvalue(index);
             }
-        }
 
-        // A deref projection only reads the pointer, never needs the lvalue.
-        if let mir::Lvalue::Projection(ref proj) = *lvalue {
-            if let mir::ProjectionElem::Deref = proj.elem {
-                return self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
+            LvalueContext::Drop => {
+                let ty = mir::Lvalue::Local(index).ty(self.cx.mir, self.cx.ccx.tcx());
+                let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
+
+                // Only need the lvalue if we're actually dropping it.
+                if self.cx.ccx.shared().type_needs_drop(ty) {
+                    self.mark_as_lvalue(index);
+                }
             }
         }
-
-        self.super_lvalue(lvalue, context, location);
     }
 }
 
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 65b9fec7eff..9987c9c3310 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -471,7 +471,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                         };
                         (Base::Value(llprojected), llextra)
                     }
-                    mir::ProjectionElem::Index(ref index) => {
+                    mir::ProjectionElem::Index(index) => {
+                        let index = &mir::Operand::Consume(mir::Lvalue::Local(index));
                         let llindex = self.const_operand(index, span)?.llval;
 
                         let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) {
diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs
index 89c76ccdd27..8155303b0d3 100644
--- a/src/librustc_trans/mir/lvalue.rs
+++ b/src/librustc_trans/mir/lvalue.rs
@@ -333,7 +333,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                         };
                         (tr_base.trans_field_ptr(bcx, field.index()), llextra)
                     }
-                    mir::ProjectionElem::Index(ref index) => {
+                    mir::ProjectionElem::Index(index) => {
+                        let index = &mir::Operand::Consume(mir::Lvalue::Local(index));
                         let index = self.trans_operand(bcx, index);
                         let llindex = self.prepare_index(bcx, index.immediate());
                         ((tr_base.project_index(bcx, llindex), align), ptr::null_mut())
diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs
index 52dfc8dc4de..bbf661ae9a7 100644
--- a/src/librustc_trans/mir/statement.rs
+++ b/src/librustc_trans/mir/statement.rs
@@ -67,11 +67,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                     variant_index as u64);
                 bcx
             }
-            mir::StatementKind::StorageLive(ref lvalue) => {
-                self.trans_storage_liveness(bcx, lvalue, base::Lifetime::Start)
+            mir::StatementKind::StorageLive(local) => {
+                self.trans_storage_liveness(bcx, local, base::Lifetime::Start)
             }
-            mir::StatementKind::StorageDead(ref lvalue) => {
-                self.trans_storage_liveness(bcx, lvalue, base::Lifetime::End)
+            mir::StatementKind::StorageDead(local) => {
+                self.trans_storage_liveness(bcx, local, base::Lifetime::End)
             }
             mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
                 let outputs = outputs.iter().map(|output| {
@@ -94,13 +94,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
 
     fn trans_storage_liveness(&self,
                               bcx: Builder<'a, 'tcx>,
-                              lvalue: &mir::Lvalue<'tcx>,
+                              index: mir::Local,
                               intrinsic: base::Lifetime)
                               -> Builder<'a, 'tcx> {
-        if let mir::Lvalue::Local(index) = *lvalue {
-            if let LocalRef::Lvalue(tr_lval) = self.locals[index] {
-                intrinsic.call(&bcx, tr_lval.llval);
-            }
+        if let LocalRef::Lvalue(tr_lval) = self.locals[index] {
+            intrinsic.call(&bcx, tr_lval.llval);
         }
         bcx
     }