about summary refs log tree commit diff
path: root/src/librustc_mir/transform
diff options
context:
space:
mode:
authorJonas Schievink <jonasschievink@gmail.com>2016-09-25 01:38:27 +0200
committerJonas Schievink <jonasschievink@gmail.com>2016-09-26 20:41:54 +0200
commit393db2d83089b3940fa2fe77f1241ca4625fe883 (patch)
tree49bcbec475b6668847f8af1d007f8f28e10102b2 /src/librustc_mir/transform
parent205dac935531aaf0a5b70898db28e1f1e5f86176 (diff)
downloadrust-393db2d83089b3940fa2fe77f1241ca4625fe883.tar.gz
rust-393db2d83089b3940fa2fe77f1241ca4625fe883.zip
[WIP] Move MIR towards a single kind of local
Diffstat (limited to 'src/librustc_mir/transform')
-rw-r--r--src/librustc_mir/transform/copy_prop.rs67
-rw-r--r--src/librustc_mir/transform/instcombine.rs7
-rw-r--r--src/librustc_mir/transform/promote_consts.rs74
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs98
-rw-r--r--src/librustc_mir/transform/type_check.rs23
5 files changed, 141 insertions, 128 deletions
diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs
index 79fd16012d9..783162cd558 100644
--- a/src/librustc_mir/transform/copy_prop.rs
+++ b/src/librustc_mir/transform/copy_prop.rs
@@ -29,12 +29,11 @@
 //! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the
 //! future.
 
-use def_use::{DefUseAnalysis, MirSummary};
+use def_use::DefUseAnalysis;
 use rustc::mir::repr::{Constant, Local, Location, Lvalue, Mir, Operand, Rvalue, StatementKind};
 use rustc::mir::transform::{MirPass, MirSource, Pass};
 use rustc::mir::visit::MutVisitor;
 use rustc::ty::TyCtxt;
-use rustc_data_structures::indexed_vec::Idx;
 use transform::qualify_consts;
 
 pub struct CopyPropagation;
@@ -78,9 +77,8 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
             def_use_analysis.analyze(mir);
 
             let mut changed = false;
-            for dest_local_index in 0..mir.count_locals() {
-                let dest_local = Local::new(dest_local_index);
-                debug!("Considering destination local: {}", mir.format_local(dest_local));
+            for dest_local in mir.local_decls.indices() {
+                debug!("Considering destination local: {:?}", dest_local);
 
                 let action;
                 let location;
@@ -89,19 +87,19 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
                     let dest_use_info = def_use_analysis.local_info(dest_local);
                     let dest_def_count = dest_use_info.def_count_not_including_drop();
                     if dest_def_count == 0 {
-                        debug!("  Can't copy-propagate local: dest {} undefined",
-                               mir.format_local(dest_local));
+                        debug!("  Can't copy-propagate local: dest {:?} undefined",
+                               dest_local);
                         continue
                     }
                     if dest_def_count > 1 {
-                        debug!("  Can't copy-propagate local: dest {} defined {} times",
-                               mir.format_local(dest_local),
+                        debug!("  Can't copy-propagate local: dest {:?} defined {} times",
+                               dest_local,
                                dest_use_info.def_count());
                         continue
                     }
                     if dest_use_info.use_count() == 0 {
-                        debug!("  Can't copy-propagate local: dest {} unused",
-                               mir.format_local(dest_local));
+                        debug!("  Can't copy-propagate local: dest {:?} unused",
+                               dest_local);
                         continue
                     }
                     let dest_lvalue_def = dest_use_info.defs_and_uses.iter().filter(|lvalue_def| {
@@ -121,11 +119,11 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
 
                     // That use of the source must be an assignment.
                     match statement.kind {
-                        StatementKind::Assign(ref dest_lvalue, Rvalue::Use(ref operand)) if
-                                Some(dest_local) == mir.local_index(dest_lvalue) => {
+                        StatementKind::Assign(Lvalue::Local(local), Rvalue::Use(ref operand)) if
+                                local == dest_local => {
                             let maybe_action = match *operand {
                                 Operand::Consume(ref src_lvalue) => {
-                                    Action::local_copy(mir, &def_use_analysis, src_lvalue)
+                                    Action::local_copy(&def_use_analysis, src_lvalue)
                                 }
                                 Operand::Constant(ref src_constant) => {
                                     Action::constant(src_constant)
@@ -162,15 +160,14 @@ enum Action<'tcx> {
 }
 
 impl<'tcx> Action<'tcx> {
-    fn local_copy(mir: &Mir<'tcx>, def_use_analysis: &DefUseAnalysis, src_lvalue: &Lvalue<'tcx>)
+    fn local_copy(def_use_analysis: &DefUseAnalysis, src_lvalue: &Lvalue<'tcx>)
                   -> Option<Action<'tcx>> {
         // The source must be a local.
-        let src_local = match mir.local_index(src_lvalue) {
-            Some(src_local) => src_local,
-            None => {
-                debug!("  Can't copy-propagate local: source is not a local");
-                return None
-            }
+        let src_local = if let Lvalue::Local(local) = *src_lvalue {
+            local
+        } else {
+            debug!("  Can't copy-propagate local: source is not a local");
+            return None;
         };
 
         // We're trying to copy propagate a local.
@@ -225,9 +222,9 @@ impl<'tcx> Action<'tcx> {
                 // First, remove all markers.
                 //
                 // FIXME(pcwalton): Don't do this. Merge live ranges instead.
-                debug!("  Replacing all uses of {} with {} (local)",
-                       mir.format_local(dest_local),
-                       mir.format_local(src_local));
+                debug!("  Replacing all uses of {:?} with {:?} (local)",
+                       dest_local,
+                       src_local);
                 for lvalue_use in &def_use_analysis.local_info(dest_local).defs_and_uses {
                     if lvalue_use.context.is_storage_marker() {
                         mir.make_statement_nop(lvalue_use.location)
@@ -240,7 +237,7 @@ impl<'tcx> Action<'tcx> {
                 }
 
                 // Replace all uses of the destination local with the source local.
-                let src_lvalue = Lvalue::from_local(mir, src_local);
+                let src_lvalue = Lvalue::Local(src_local);
                 def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue);
 
                 // Finally, zap the now-useless assignment instruction.
@@ -253,8 +250,8 @@ impl<'tcx> Action<'tcx> {
                 // First, remove all markers.
                 //
                 // FIXME(pcwalton): Don't do this. Merge live ranges instead.
-                debug!("  Replacing all uses of {} with {:?} (constant)",
-                       mir.format_local(dest_local),
+                debug!("  Replacing all uses of {:?} with {:?} (constant)",
+                       dest_local,
                        src_constant);
                 let dest_local_info = def_use_analysis.local_info(dest_local);
                 for lvalue_use in &dest_local_info.defs_and_uses {
@@ -264,8 +261,7 @@ impl<'tcx> Action<'tcx> {
                 }
 
                 // Replace all uses of the destination local with the constant.
-                let mut visitor = ConstantPropagationVisitor::new(MirSummary::new(mir),
-                                                                  dest_local,
+                let mut visitor = ConstantPropagationVisitor::new(dest_local,
                                                                   src_constant);
                 for dest_lvalue_use in &dest_local_info.defs_and_uses {
                     visitor.visit_location(mir, dest_lvalue_use.location)
@@ -298,17 +294,15 @@ impl<'tcx> Action<'tcx> {
 struct ConstantPropagationVisitor<'tcx> {
     dest_local: Local,
     constant: Constant<'tcx>,
-    mir_summary: MirSummary,
     uses_replaced: usize,
 }
 
 impl<'tcx> ConstantPropagationVisitor<'tcx> {
-    fn new(mir_summary: MirSummary, dest_local: Local, constant: Constant<'tcx>)
+    fn new(dest_local: Local, constant: Constant<'tcx>)
            -> ConstantPropagationVisitor<'tcx> {
         ConstantPropagationVisitor {
             dest_local: dest_local,
             constant: constant,
-            mir_summary: mir_summary,
             uses_replaced: 0,
         }
     }
@@ -319,16 +313,11 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> {
         self.super_operand(operand, location);
 
         match *operand {
-            Operand::Consume(ref lvalue) => {
-                if self.mir_summary.local_index(lvalue) != Some(self.dest_local) {
-                    return
-                }
-            }
-            Operand::Constant(_) => return,
+            Operand::Consume(Lvalue::Local(local)) if local == self.dest_local => {}
+            _ => return,
         }
 
         *operand = Operand::Constant(self.constant.clone());
         self.uses_replaced += 1
     }
 }
-
diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs
index a0331f03b01..b4159af6f07 100644
--- a/src/librustc_mir/transform/instcombine.rs
+++ b/src/librustc_mir/transform/instcombine.rs
@@ -10,11 +10,12 @@
 
 //! Performs various peephole optimizations.
 
-use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue};
+use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue, Local};
 use rustc::mir::transform::{MirPass, MirSource, Pass};
 use rustc::mir::visit::{MutVisitor, Visitor};
 use rustc::ty::TyCtxt;
 use rustc::util::nodemap::FnvHashSet;
+use rustc_data_structures::indexed_vec::Idx;
 use std::mem;
 
 pub struct InstCombine {
@@ -61,7 +62,8 @@ impl<'tcx> MutVisitor<'tcx> for InstCombine {
             debug!("Replacing `&*`: {:?}", rvalue);
             let new_lvalue = match *rvalue {
                 Rvalue::Ref(_, _, Lvalue::Projection(ref mut projection)) => {
-                    mem::replace(&mut projection.base, Lvalue::ReturnPointer)
+                    // Replace with dummy
+                    mem::replace(&mut projection.base, Lvalue::Local(Local::new(0)))
                 }
                 _ => bug!("Detected `&*` but didn't find `&*`!"),
             };
@@ -107,4 +109,3 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> {
 struct OptimizationList {
     and_stars: FnvHashSet<Location>,
 }
-
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 57de68fce1d..939531a16bc 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -30,6 +30,7 @@ use syntax_pos::Span;
 
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
+use std::iter;
 use std::mem;
 use std::usize;
 
@@ -74,15 +75,21 @@ pub enum Candidate {
     ShuffleIndices(BasicBlock)
 }
 
-struct TempCollector {
-    temps: IndexVec<Temp, TempState>,
-    span: Span
+struct TempCollector<'tcx> {
+    temps: IndexVec<Local, TempState>,
+    span: Span,
+    mir: &'tcx Mir<'tcx>,
 }
 
-impl<'tcx> Visitor<'tcx> for TempCollector {
-    fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) {
+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::Temp(index) = *lvalue {
+        if let Lvalue::Local(index) = *lvalue {
+            // 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.
@@ -126,10 +133,11 @@ impl<'tcx> Visitor<'tcx> for TempCollector {
     }
 }
 
-pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Temp, TempState> {
+pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Local, TempState> {
     let mut collector = TempCollector {
-        temps: IndexVec::from_elem(TempState::Undefined, &mir.temp_decls),
-        span: mir.span
+        temps: IndexVec::from_elem(TempState::Undefined, &mir.local_decls),
+        span: mir.span,
+        mir: mir,
     };
     for (bb, data) in rpo {
         collector.visit_basic_block_data(bb, data);
@@ -140,7 +148,7 @@ pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Temp, Te
 struct Promoter<'a, 'tcx: 'a> {
     source: &'a mut Mir<'tcx>,
     promoted: Mir<'tcx>,
-    temps: &'a mut IndexVec<Temp, TempState>,
+    temps: &'a mut IndexVec<Local, TempState>,
 
     /// If true, all nested temps are also kept in the
     /// source MIR, not moved to the promoted MIR.
@@ -177,7 +185,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
 
     /// Copy the initialization of this temp to the
     /// promoted MIR, recursing through temps.
-    fn promote_temp(&mut self, temp: Temp) -> Temp {
+    fn promote_temp(&mut self, temp: Local) -> Local {
         let old_keep_original = self.keep_original;
         let (bb, stmt_idx) = match self.temps[temp] {
             TempState::Defined {
@@ -259,20 +267,19 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
             });
         }
 
-        let new_temp = self.promoted.temp_decls.push(TempDecl {
-            ty: self.source.temp_decls[temp].ty
-        });
+        let new_temp = self.promoted.local_decls.push(
+            LocalDecl::new_temp(self.source.local_decls[temp].ty));
 
         // Inject the Rvalue or Call into the promoted MIR.
         if stmt_idx < no_stmts {
-            self.assign(Lvalue::Temp(new_temp), rvalue.unwrap(), source_info.span);
+            self.assign(Lvalue::Local(new_temp), rvalue.unwrap(), source_info.span);
         } else {
             let last = self.promoted.basic_blocks().last().unwrap();
             let new_target = self.new_block();
             let mut call = call.unwrap();
             match call {
                 TerminatorKind::Call { ref mut destination, ..}  => {
-                    *destination = Some((Lvalue::Temp(new_temp), new_target));
+                    *destination = Some((Lvalue::Local(new_temp), new_target));
                 }
                 _ => bug!()
             }
@@ -315,11 +322,12 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                 }
             }
         };
-        self.visit_rvalue(&mut rvalue, Location{
+        self.visit_rvalue(&mut rvalue, Location {
             block: BasicBlock::new(0),
             statement_index: usize::MAX
         });
-        self.assign(Lvalue::ReturnPointer, rvalue, span);
+
+        self.assign(Lvalue::Local(RETURN_POINTER), rvalue, span);
         self.source.promoted.push(self.promoted);
     }
 }
@@ -330,8 +338,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
                     lvalue: &mut Lvalue<'tcx>,
                     context: LvalueContext<'tcx>,
                     location: Location) {
-        if let Lvalue::Temp(ref mut temp) = *lvalue {
-            *temp = self.promote_temp(*temp);
+        if let Lvalue::Local(ref mut temp) = *lvalue {
+            if self.source.local_kind(*temp) == LocalKind::Temp {
+                *temp = self.promote_temp(*temp);
+            }
         }
         self.super_lvalue(lvalue, context, location);
     }
@@ -339,7 +349,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
 
 pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                    mut temps: IndexVec<Temp, TempState>,
+                                    mut temps: IndexVec<Local, TempState>,
                                     candidates: Vec<Candidate>) {
     // Visit candidates in reverse, in case they're nested.
     for candidate in candidates.into_iter().rev() {
@@ -353,7 +363,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                                   "expected assignment to promote");
                     }
                 };
-                if let Lvalue::Temp(index) = *dest {
+                if let Lvalue::Local(index) = *dest {
                     if temps[index] == TempState::PromotedOut {
                         // Already promoted.
                         continue;
@@ -376,8 +386,10 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
             }
         };
 
+        // Declare return pointer local
+        let initial_locals = iter::once(LocalDecl::new_return_pointer(ty)).collect();
+
         let mut promoter = Promoter {
-            source: mir,
             promoted: Mir::new(
                 IndexVec::new(),
                 Some(VisibilityScopeData {
@@ -386,12 +398,12 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                 }).into_iter().collect(),
                 IndexVec::new(),
                 ty,
-                IndexVec::new(),
-                IndexVec::new(),
-                IndexVec::new(),
+                initial_locals,
+                0,
                 vec![],
                 span
             ),
+            source: mir,
             temps: &mut temps,
             keep_original: false
         };
@@ -400,13 +412,13 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
     }
 
     // Eliminate assignments to, and drops of promoted temps.
-    let promoted = |index: Temp| temps[index] == TempState::PromotedOut;
+    let promoted = |index: Local| temps[index] == TempState::PromotedOut;
     for block in mir.basic_blocks_mut() {
         block.statements.retain(|statement| {
             match statement.kind {
-                StatementKind::Assign(Lvalue::Temp(index), _) |
-                StatementKind::StorageLive(Lvalue::Temp(index)) |
-                StatementKind::StorageDead(Lvalue::Temp(index)) => {
+                StatementKind::Assign(Lvalue::Local(index), _) |
+                StatementKind::StorageLive(Lvalue::Local(index)) |
+                StatementKind::StorageDead(Lvalue::Local(index)) => {
                     !promoted(index)
                 }
                 _ => true
@@ -414,7 +426,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
         });
         let terminator = block.terminator_mut();
         match terminator.kind {
-            TerminatorKind::Drop { location: Lvalue::Temp(index), target, .. } => {
+            TerminatorKind::Drop { location: Lvalue::Local(index), target, .. } => {
                 if promoted(index) {
                     terminator.kind = TerminatorKind::Goto {
                         target: target
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 2c03af2c8e9..acc3084c906 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -143,11 +143,11 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     param_env: ty::ParameterEnvironment<'tcx>,
     qualif_map: &'a mut DefIdMap<Qualif>,
     mir_map: Option<&'a MirMap<'tcx>>,
-    temp_qualif: IndexVec<Temp, Option<Qualif>>,
+    temp_qualif: IndexVec<Local, Option<Qualif>>,
     return_qualif: Option<Qualif>,
     qualif: Qualif,
     const_fn_arg_vars: BitVector,
-    temp_promotion_state: IndexVec<Temp, TempState>,
+    temp_promotion_state: IndexVec<Local, TempState>,
     promotion_candidates: Vec<Candidate>
 }
 
@@ -173,10 +173,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
             param_env: param_env,
             qualif_map: qualif_map,
             mir_map: mir_map,
-            temp_qualif: IndexVec::from_elem(None, &mir.temp_decls),
+            temp_qualif: IndexVec::from_elem(None, &mir.local_decls),
             return_qualif: None,
             qualif: Qualif::empty(),
-            const_fn_arg_vars: BitVector::new(mir.var_decls.len()),
+            const_fn_arg_vars: BitVector::new(mir.local_decls.len()),
             temp_promotion_state: temps,
             promotion_candidates: vec![]
         }
@@ -332,8 +332,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
 
         // Only handle promotable temps in non-const functions.
         if self.mode == Mode::Fn {
-            if let Lvalue::Temp(index) = *dest {
-                if self.temp_promotion_state[index].is_promotable() {
+            if let Lvalue::Local(index) = *dest {
+                if self.mir.local_kind(index) == LocalKind::Temp
+                && self.temp_promotion_state[index].is_promotable() {
+                    debug!("store to promotable temp {:?}", index);
                     store(&mut self.temp_qualif[index]);
                 }
             }
@@ -341,13 +343,20 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
         }
 
         match *dest {
-            Lvalue::Temp(index) => store(&mut self.temp_qualif[index]),
-            Lvalue::ReturnPointer => store(&mut self.return_qualif),
+            Lvalue::Local(index) if self.mir.local_kind(index) == LocalKind::Temp => {
+                debug!("store to temp {:?}", index);
+                store(&mut self.temp_qualif[index])
+            }
+            Lvalue::Local(index) if self.mir.local_kind(index) == LocalKind::ReturnPointer => {
+                debug!("store to return pointer {:?}", index);
+                store(&mut self.return_qualif)
+            }
 
             Lvalue::Projection(box Projection {
-                base: Lvalue::Temp(index),
+                base: Lvalue::Local(index),
                 elem: ProjectionElem::Deref
-            }) if self.mir.temp_decls[index].ty.is_unique()
+            }) if self.mir.local_kind(index) == LocalKind::Temp
+               && self.mir.local_decls[index].ty.is_unique()
                && self.temp_qualif[index].map_or(false, |qualif| {
                     qualif.intersects(Qualif::NOT_CONST)
                }) => {
@@ -366,6 +375,8 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
 
     /// Qualify a whole const, static initializer or const fn.
     fn qualify_const(&mut self) -> Qualif {
+        debug!("qualifying {} {}", self.mode, self.tcx.item_path_str(self.def_id));
+
         let mir = self.mir;
 
         let mut seen_blocks = BitVector::new(mir.basic_blocks().len());
@@ -399,7 +410,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
                 TerminatorKind::Return => {
                     // Check for unused values. This usually means
                     // there are extra statements in the AST.
-                    for temp in mir.temp_decls.indices() {
+                    for temp in mir.temp_iter() {
                         if self.temp_qualif[temp].is_none() {
                             continue;
                         }
@@ -424,9 +435,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
 
                     // Make sure there are no extra unassigned variables.
                     self.qualif = Qualif::NOT_CONST;
-                    for index in 0..mir.var_decls.len() {
-                        if !self.const_fn_arg_vars.contains(index) {
-                            self.assign(&Lvalue::Var(Var::new(index)), Location {
+                    for index in mir.var_iter() {
+                        if !self.const_fn_arg_vars.contains(index.index()) {
+                            debug!("unassigned variable {:?}", index);
+                            self.assign(&Lvalue::Local(index), Location {
                                 block: bb,
                                 statement_index: usize::MAX,
                             });
@@ -480,23 +492,28 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                     context: LvalueContext<'tcx>,
                     location: Location) {
         match *lvalue {
-            Lvalue::Arg(_) => {
-                self.add(Qualif::FN_ARGUMENT);
-            }
-            Lvalue::Var(_) => {
-                self.add(Qualif::NOT_CONST);
-            }
-            Lvalue::Temp(index) => {
-                if !self.temp_promotion_state[index].is_promotable() {
-                    self.add(Qualif::NOT_PROMOTABLE);
+            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[index] {
-                    self.add(qualif);
-                } else {
-                    self.not_const();
+                    if let Some(qualif) = self.temp_qualif[local] {
+                        self.add(qualif);
+                    } else {
+                        self.not_const();
+                    }
                 }
-            }
+            },
             Lvalue::Static(_) => {
                 self.add(Qualif::STATIC);
                 if self.mode == Mode::Const || self.mode == Mode::ConstFn {
@@ -505,9 +522,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                                a constant instead", self.mode);
                 }
             }
-            Lvalue::ReturnPointer => {
-                self.not_const();
-            }
             Lvalue::Projection(ref proj) => {
                 self.nest(|this| {
                     this.super_lvalue(lvalue, context, location);
@@ -685,8 +699,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                 if self.mode == Mode::Fn || self.mode == Mode::ConstFn {
                     if !self.qualif.intersects(Qualif::NEVER_PROMOTE) {
                         // We can only promote direct borrows of temps.
-                        if let Lvalue::Temp(_) = *lvalue {
-                            self.promotion_candidates.push(candidate);
+                        if let Lvalue::Local(local) = *lvalue {
+                            if self.mir.local_kind(local) == LocalKind::Temp {
+                                self.promotion_candidates.push(candidate);
+                            }
                         }
                     }
                 }
@@ -879,17 +895,21 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
         self.visit_rvalue(rvalue, location);
 
         // Check the allowed const fn argument forms.
-        if let (Mode::ConstFn, &Lvalue::Var(index)) = (self.mode, dest) {
-            if self.const_fn_arg_vars.insert(index.index()) {
+        if let (Mode::ConstFn, &Lvalue::Local(index)) = (self.mode, dest) {
+            if self.mir.local_kind(index) == LocalKind::Var &&
+               self.const_fn_arg_vars.insert(index.index()) {
+
                 // Direct use of an argument is permitted.
-                if let Rvalue::Use(Operand::Consume(Lvalue::Arg(_))) = *rvalue {
-                    return;
+                if let Rvalue::Use(Operand::Consume(Lvalue::Local(local))) = *rvalue {
+                    if self.mir.local_kind(local) == LocalKind::Arg {
+                        return;
+                    }
                 }
 
                 // Avoid a generic error for other uses of arguments.
                 if self.qualif.intersects(Qualif::FN_ARGUMENT) {
-                    let decl = &self.mir.var_decls[index];
-                    span_err!(self.tcx.sess, decl.source_info.span, E0022,
+                    let decl = &self.mir.local_decls[index];
+                    span_err!(self.tcx.sess, decl.source_info.unwrap().span, E0022,
                               "arguments of constant functions can only \
                                be immutable by-value bindings");
                     return;
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 7b6a2f55808..7a682292429 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -90,14 +90,8 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
 
     fn visit_mir(&mut self, mir: &Mir<'tcx>) {
         self.sanitize_type(&"return type", mir.return_ty);
-        for var_decl in &mir.var_decls {
-            self.sanitize_type(var_decl, var_decl.ty);
-        }
-        for (n, arg_decl) in mir.arg_decls.iter().enumerate() {
-            self.sanitize_type(&(n, arg_decl), arg_decl.ty);
-        }
-        for (n, tmp_decl) in mir.temp_decls.iter().enumerate() {
-            self.sanitize_type(&(n, tmp_decl), tmp_decl.ty);
+        for local_decl in &mir.local_decls {
+            self.sanitize_type(local_decl, local_decl.ty);
         }
         if self.errors_reported {
             return;
@@ -131,14 +125,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
     fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> {
         debug!("sanitize_lvalue: {:?}", lvalue);
         match *lvalue {
-            Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index].ty },
-            Lvalue::Temp(index) => LvalueTy::Ty { ty: self.mir.temp_decls[index].ty },
-            Lvalue::Arg(index) => LvalueTy::Ty { ty: self.mir.arg_decls[index].ty },
+            Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty },
             Lvalue::Static(def_id) =>
                 LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty },
-            Lvalue::ReturnPointer => {
-                LvalueTy::Ty { ty: self.mir.return_ty }
-            }
             Lvalue::Projection(ref proj) => {
                 let base_ty = self.sanitize_lvalue(&proj.base, location);
                 if let LvalueTy::Ty { ty } = base_ty {
@@ -380,9 +369,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             StatementKind::StorageLive(ref lv) |
             StatementKind::StorageDead(ref lv) => {
                 match *lv {
-                    Lvalue::Temp(_) | Lvalue::Var(_) => {}
+                    Lvalue::Local(_) => {}
                     _ => {
-                        span_mirbug!(self, stmt, "bad lvalue: expected temp or var");
+                        span_mirbug!(self, stmt, "bad lvalue: expected local");
                     }
                 }
             }
@@ -711,6 +700,8 @@ impl TypeckMir {
 impl<'tcx> MirPass<'tcx> for TypeckMir {
     fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     src: MirSource, mir: &mut Mir<'tcx>) {
+        debug!("run_pass: {}", tcx.node_path_str(src.item_id()));
+
         if tcx.sess.err_count() > 0 {
             // compiling a broken program can obviously result in a
             // broken MIR, so try not to report duplicate errors.