about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-05-03 00:26:41 +0300
committerEduard Burtescu <edy.burt@gmail.com>2016-05-07 07:19:10 +0300
commit14efbf148109888f939f671fbd5b60650c5f4744 (patch)
tree773051d52ccbe7f629ee2f0c61cc782de3191f2e /src
parente1eca0a1103afa6ba87ee3e23a921ed8faf4c130 (diff)
downloadrust-14efbf148109888f939f671fbd5b60650c5f4744.tar.gz
rust-14efbf148109888f939f671fbd5b60650c5f4744.zip
mir: prepare for rvalue promotion support.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/dep_graph/dep_node.rs2
-rw-r--r--src/librustc/mir/repr.rs12
-rw-r--r--src/librustc/mir/transform.rs77
-rw-r--r--src/librustc/mir/visit.rs4
-rw-r--r--src/librustc_metadata/decoder.rs3
-rw-r--r--src/librustc_mir/build/mod.rs1
-rw-r--r--src/librustc_mir/mir_map.rs35
-rw-r--r--src/librustc_mir/pretty.rs61
-rw-r--r--src/librustc_mir/transform/break_critical_edges.rs5
-rw-r--r--src/librustc_mir/transform/erase_regions.rs5
-rw-r--r--src/librustc_mir/transform/no_landing_pads.rs5
-rw-r--r--src/librustc_mir/transform/remove_dead_blocks.rs5
-rw-r--r--src/librustc_mir/transform/simplify_cfg.rs9
-rw-r--r--src/librustc_mir/transform/type_check.rs16
-rw-r--r--src/librustc_trans/collector.rs3
-rw-r--r--src/librustc_trans/mir/constant.rs82
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs6
17 files changed, 236 insertions, 95 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 85b4b4f59c4..8378495599c 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -64,6 +64,7 @@ pub enum DepNode<D: Clone + Debug> {
     IntrinsicCheck(D),
     MatchCheck(D),
     MirMapConstruction(D),
+    MirPass(D),
     MirTypeck(D),
     BorrowCheck(D),
     RvalueCheck(D),
@@ -186,6 +187,7 @@ impl<D: Clone + Debug> DepNode<D> {
             IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck),
             MatchCheck(ref d) => op(d).map(MatchCheck),
             MirMapConstruction(ref d) => op(d).map(MirMapConstruction),
+            MirPass(ref d) => op(d).map(MirPass),
             MirTypeck(ref d) => op(d).map(MirTypeck),
             BorrowCheck(ref d) => op(d).map(BorrowCheck),
             RvalueCheck(ref d) => op(d).map(RvalueCheck),
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index 9ec05a9b292..9f8a3dbfa8f 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -36,6 +36,11 @@ pub struct Mir<'tcx> {
     /// used (eventually) for debuginfo. Indexed by a `ScopeId`.
     pub scopes: Vec<ScopeData>,
 
+    /// Rvalues promoted from this function, such as borrows of constants.
+    /// Each of them is the Mir of a constant with the fn's type parameters
+    /// in scope, but no vars or args and a separate set of temps.
+    pub promoted: Vec<Mir<'tcx>>,
+
     /// Return type of the function.
     pub return_ty: FnOutput<'tcx>,
 
@@ -987,6 +992,10 @@ pub enum Literal<'tcx> {
     Value {
         value: ConstVal,
     },
+    Promoted {
+        // Index into the `promoted` vector of `Mir`.
+        index: usize
+    },
 }
 
 impl<'tcx> Debug for Constant<'tcx> {
@@ -1007,6 +1016,9 @@ impl<'tcx> Debug for Literal<'tcx> {
                 write!(fmt, "const ")?;
                 fmt_const_val(fmt, value)
             }
+            Promoted { index } => {
+                write!(fmt, "promoted{}", index)
+            }
         }
     }
 }
diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs
index 410e3f9d066..520bfbddf9f 100644
--- a/src/librustc/mir/transform.rs
+++ b/src/librustc/mir/transform.rs
@@ -8,31 +8,102 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use dep_graph::DepNode;
+use hir;
+use hir::map::DefPathData;
+use hir::def_id::DefId;
 use mir::mir_map::MirMap;
 use mir::repr::Mir;
 use ty::TyCtxt;
 use syntax::ast::NodeId;
 
+/// Where a specific Mir comes from.
+#[derive(Copy, Clone)]
+pub enum MirSource {
+    /// Functions and methods.
+    Fn(NodeId),
+
+    /// Constants and associated constants.
+    Const(NodeId),
+
+    /// Initializer of a `static` item.
+    Static(NodeId, hir::Mutability),
+
+    /// Promoted rvalues within a function.
+    Promoted(NodeId, usize)
+}
+
+impl MirSource {
+    pub fn from_node(tcx: &TyCtxt, id: NodeId) -> MirSource {
+        use hir::*;
+
+        // Handle constants in enum discriminants, types, and repeat expressions.
+        let def_id = tcx.map.local_def_id(id);
+        let def_key = tcx.def_key(def_id);
+        if def_key.disambiguated_data.data == DefPathData::Initializer {
+            return MirSource::Const(id);
+        }
+
+        match tcx.map.get(id) {
+            map::NodeItem(&Item { node: ItemConst(..), .. }) |
+            map::NodeTraitItem(&TraitItem { node: ConstTraitItem(..), .. }) |
+            map::NodeImplItem(&ImplItem { node: ImplItemKind::Const(..), .. }) => {
+                MirSource::Const(id)
+            }
+            map::NodeItem(&Item { node: ItemStatic(_, m, _), .. }) => {
+                MirSource::Static(id, m)
+            }
+            // Default to function if it's not a constant or static.
+            _ => MirSource::Fn(id)
+        }
+    }
+
+    pub fn item_id(&self) -> NodeId {
+        match *self {
+            MirSource::Fn(id) |
+            MirSource::Const(id) |
+            MirSource::Static(id, _) |
+            MirSource::Promoted(id, _) => id
+        }
+    }
+}
+
 /// Various information about pass.
 pub trait Pass {
     // fn name() for printouts of various sorts?
     // fn should_run(Session) to check if pass should run?
+    fn dep_node(&self, def_id: DefId) -> DepNode<DefId> {
+        DepNode::MirPass(def_id)
+    }
 }
 
 /// A pass which inspects the whole MirMap.
 pub trait MirMapPass<'tcx>: Pass {
-    fn run_pass(&mut self, cx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>);
+    fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>);
 }
 
 /// A pass which inspects Mir of functions in isolation.
 pub trait MirPass<'tcx>: Pass {
-    fn run_pass(&mut self, cx: &TyCtxt<'tcx>, id: NodeId, mir: &mut Mir<'tcx>);
+    fn run_pass_on_promoted(&mut self, tcx: &TyCtxt<'tcx>,
+                            item_id: NodeId, index: usize,
+                            mir: &mut Mir<'tcx>) {
+        self.run_pass(tcx, MirSource::Promoted(item_id, index), mir);
+    }
+    fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, src: MirSource, mir: &mut Mir<'tcx>);
 }
 
 impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T {
     fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>) {
         for (&id, mir) in &mut map.map {
-            MirPass::run_pass(self, tcx, id, mir);
+            let def_id = tcx.map.local_def_id(id);
+            let _task = tcx.dep_graph.in_task(self.dep_node(def_id));
+
+            let src = MirSource::from_node(tcx, id);
+            MirPass::run_pass(self, tcx, src, mir);
+
+            for (i, mir) in mir.promoted.iter_mut().enumerate() {
+                self.run_pass_on_promoted(tcx, id, i, mir);
+            }
         }
     }
 }
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 10afd3dd953..f6a241004b3 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -244,6 +244,7 @@ macro_rules! make_mir_visitor {
                 let Mir {
                     ref $($mutability)* basic_blocks,
                     ref $($mutability)* scopes,
+                    promoted: _, // Visited by passes separately.
                     ref $($mutability)* return_ty,
                     ref $($mutability)* var_decls,
                     ref $($mutability)* arg_decls,
@@ -649,10 +650,11 @@ macro_rules! make_mir_visitor {
                                     ref $($mutability)* substs } => {
                         self.visit_def_id(def_id);
                         self.visit_substs(substs);
-                    },
+                    }
                     Literal::Value { ref $($mutability)* value } => {
                         self.visit_const_val(value);
                     }
+                    Literal::Promoted { index: _ } => {}
                 }
             }
 
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index b5b27586a7f..c911b20c2ab 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -855,6 +855,9 @@ pub fn maybe_get_item_mir<'tcx>(cdata: Cmd,
         };
 
         def_id_and_span_translator.visit_mir(&mut mir);
+        for promoted in &mut mir.promoted {
+            def_id_and_span_translator.visit_mir(promoted);
+        }
 
         mir
     });
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 89c89e6e2e3..4ce77d162e0 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -296,6 +296,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
         (Mir {
             basic_blocks: self.cfg.basic_blocks,
             scopes: self.scope_datas,
+            promoted: vec![],
             var_decls: self.var_decls,
             arg_decls: arg_decls,
             temp_decls: self.temp_decls,
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index e6b795531d9..8f22f491455 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -19,6 +19,7 @@
 use build;
 use rustc::dep_graph::DepNode;
 use rustc::mir::repr::Mir;
+use rustc::mir::transform::MirSource;
 use pretty;
 use hair::cx::Cx;
 
@@ -55,10 +56,10 @@ struct BuildMir<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> BuildMir<'a, 'tcx> {
-    fn build<F>(&mut self, id: ast::NodeId, f: F)
+    fn build<F>(&mut self, src: MirSource, f: F)
         where F: for<'b> FnOnce(Cx<'b, 'tcx>) -> (Mir<'tcx>, build::ScopeAuxiliaryVec)
     {
-        let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
+        let param_env = ty::ParameterEnvironment::for_item(self.tcx, src.item_id());
         let infcx = infer::new_infer_ctxt(self.tcx,
                                           &self.tcx.tables,
                                           Some(param_env),
@@ -66,9 +67,9 @@ impl<'a, 'tcx> BuildMir<'a, 'tcx> {
 
         let (mir, scope_auxiliary) = f(Cx::new(&infcx));
 
-        pretty::dump_mir(self.tcx, "mir_map", &0, id, &mir, Some(&scope_auxiliary));
+        pretty::dump_mir(self.tcx, "mir_map", &0, src, &mir, Some(&scope_auxiliary));
 
-        assert!(self.map.map.insert(id, mir).is_none())
+        assert!(self.map.map.insert(src.item_id(), mir).is_none())
     }
 
     fn build_const_integer(&mut self, expr: &'tcx hir::Expr) {
@@ -79,7 +80,9 @@ impl<'a, 'tcx> BuildMir<'a, 'tcx> {
         if let hir::ExprClosure(..) = expr.node {
             return;
         }
-        self.build(expr.id, |cx| build::construct_const(cx, expr.id, expr));
+        self.build(MirSource::Const(expr.id), |cx| {
+            build::construct_const(cx, expr.id, expr)
+        });
     }
 }
 
@@ -87,9 +90,15 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     // Const and static items.
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
-            hir::ItemConst(_, ref expr) |
-            hir::ItemStatic(_, _, ref expr) => {
-                self.build(item.id, |cx| build::construct_const(cx, item.id, expr));
+            hir::ItemConst(_, ref expr) => {
+                self.build(MirSource::Const(item.id), |cx| {
+                    build::construct_const(cx, item.id, expr)
+                });
+            }
+            hir::ItemStatic(_, m, ref expr) => {
+                self.build(MirSource::Static(item.id, m), |cx| {
+                    build::construct_const(cx, item.id, expr)
+                });
             }
             _ => {}
         }
@@ -99,7 +108,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     // Trait associated const defaults.
     fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
         if let hir::ConstTraitItem(_, Some(ref expr)) = item.node {
-            self.build(item.id, |cx| build::construct_const(cx, item.id, expr));
+            self.build(MirSource::Const(item.id), |cx| {
+                build::construct_const(cx, item.id, expr)
+            });
         }
         intravisit::walk_trait_item(self, item);
     }
@@ -107,7 +118,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     // Impl associated const.
     fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
         if let hir::ImplItemKind::Const(_, ref expr) = item.node {
-            self.build(item.id, |cx| build::construct_const(cx, item.id, expr));
+            self.build(MirSource::Const(item.id), |cx| {
+                build::construct_const(cx, item.id, expr)
+            });
         }
         intravisit::walk_impl_item(self, item);
     }
@@ -166,7 +179,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
                     (fn_sig.inputs[index], Some(&*arg.pat))
                 });
 
-        self.build(id, |cx| {
+        self.build(MirSource::Fn(id), |cx| {
             let arguments = implicit_argument.into_iter().chain(explicit_arguments);
             build::construct_fn(cx, id, arguments, fn_sig.output, body)
         });
diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs
index 77e8e37ef74..0e082ac262e 100644
--- a/src/librustc_mir/pretty.rs
+++ b/src/librustc_mir/pretty.rs
@@ -9,7 +9,9 @@
 // except according to those terms.
 
 use build::{Location, ScopeAuxiliaryVec};
+use rustc::hir;
 use rustc::mir::repr::*;
+use rustc::mir::transform::MirSource;
 use rustc::ty::{self, TyCtxt};
 use rustc_data_structures::fnv::FnvHashMap;
 use std::fmt::Display;
@@ -37,13 +39,14 @@ const INDENT: &'static str = "    ";
 pub fn dump_mir<'a, 'tcx>(tcx: &TyCtxt<'tcx>,
                           pass_name: &str,
                           disambiguator: &Display,
-                          node_id: NodeId,
+                          src: MirSource,
                           mir: &Mir<'tcx>,
                           auxiliary: Option<&ScopeAuxiliaryVec>) {
     let filters = match tcx.sess.opts.debugging_opts.dump_mir {
         None => return,
         Some(ref filters) => filters,
     };
+    let node_id = src.item_id();
     let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id));
     let is_matched =
         filters.split("&")
@@ -64,7 +67,7 @@ pub fn dump_mir<'a, 'tcx>(tcx: &TyCtxt<'tcx>,
         try!(writeln!(file, "// pass_name = {}", pass_name));
         try!(writeln!(file, "// disambiguator = {}", disambiguator));
         try!(writeln!(file, ""));
-        try!(write_mir_fn(tcx, node_id, mir, &mut file, auxiliary));
+        try!(write_mir_fn(tcx, src, mir, &mut file, auxiliary));
         Ok(())
     });
 }
@@ -76,8 +79,13 @@ pub fn write_mir_pretty<'a, 'tcx, I>(tcx: &TyCtxt<'tcx>,
                                      -> io::Result<()>
     where I: Iterator<Item=(&'a NodeId, &'a Mir<'tcx>)>, 'tcx: 'a
 {
-    for (&node_id, mir) in iter {
-        write_mir_fn(tcx, node_id, mir, w, None)?;
+    for (&id, mir) in iter {
+        let src = MirSource::from_node(tcx, id);
+        write_mir_fn(tcx, src, mir, w, None)?;
+
+        for (i, mir) in mir.promoted.iter().enumerate() {
+            write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w, None)?;
+        }
     }
     Ok(())
 }
@@ -88,7 +96,7 @@ enum Annotation {
 }
 
 pub fn write_mir_fn<'tcx>(tcx: &TyCtxt<'tcx>,
-                          node_id: NodeId,
+                          src: MirSource,
                           mir: &Mir<'tcx>,
                           w: &mut Write,
                           auxiliary: Option<&ScopeAuxiliaryVec>)
@@ -111,7 +119,7 @@ pub fn write_mir_fn<'tcx>(tcx: &TyCtxt<'tcx>,
         }
     }
 
-    write_mir_intro(tcx, node_id, mir, w)?;
+    write_mir_intro(tcx, src, mir, w)?;
     for block in mir.all_basic_blocks() {
         write_basic_block(tcx, block, mir, w, &annotations)?;
     }
@@ -214,24 +222,39 @@ fn write_scope_tree(tcx: &TyCtxt,
 
 /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
 /// local variables (both user-defined bindings and compiler temporaries).
-fn write_mir_intro(tcx: &TyCtxt, nid: NodeId, mir: &Mir, w: &mut Write)
+fn write_mir_intro(tcx: &TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
                    -> io::Result<()> {
-    write!(w, "fn {}(", tcx.node_path_str(nid))?;
+    match src {
+        MirSource::Fn(_) => write!(w, "fn")?,
+        MirSource::Const(_) => write!(w, "const")?,
+        MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
+        MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
+        MirSource::Promoted(_, i) => write!(w, "promoted{} in", i)?
+    }
+
+    write!(w, " {}", tcx.node_path_str(src.item_id()))?;
 
-    // fn argument types.
-    for (i, arg) in mir.arg_decls.iter().enumerate() {
-        if i > 0 {
-            write!(w, ", ")?;
+    if let MirSource::Fn(_) = src {
+        write!(w, "(")?;
+
+        // fn argument types.
+        for (i, arg) in mir.arg_decls.iter().enumerate() {
+            if i > 0 {
+                write!(w, ", ")?;
+            }
+            write!(w, "{:?}: {}", Lvalue::Arg(i as u32), arg.ty)?;
         }
-        write!(w, "{:?}: {}", Lvalue::Arg(i as u32), arg.ty)?;
-    }
 
-    write!(w, ") -> ")?;
+        write!(w, ") -> ")?;
 
-    // fn return type.
-    match mir.return_ty {
-        ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty)?,
-        ty::FnOutput::FnDiverging => write!(w, "!")?,
+        // fn return type.
+        match mir.return_ty {
+            ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty)?,
+            ty::FnOutput::FnDiverging => write!(w, "!")?,
+        }
+    } else {
+        assert!(mir.arg_decls.is_empty());
+        write!(w, ": {} =", mir.return_ty.unwrap())?;
     }
 
     writeln!(w, " {{")?;
diff --git a/src/librustc_mir/transform/break_critical_edges.rs b/src/librustc_mir/transform/break_critical_edges.rs
index e1fb5dfd437..ee7c9015baa 100644
--- a/src/librustc_mir/transform/break_critical_edges.rs
+++ b/src/librustc_mir/transform/break_critical_edges.rs
@@ -10,8 +10,7 @@
 
 use rustc::ty::TyCtxt;
 use rustc::mir::repr::*;
-use rustc::mir::transform::{MirPass, Pass};
-use syntax::ast::NodeId;
+use rustc::mir::transform::{MirPass, MirSource, Pass};
 
 use rustc_data_structures::bitvec::BitVector;
 
@@ -43,7 +42,7 @@ pub struct BreakCriticalEdges;
  */
 
 impl<'tcx> MirPass<'tcx> for BreakCriticalEdges {
-    fn run_pass(&mut self, _: &TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) {
+    fn run_pass(&mut self, _: &TyCtxt<'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {
         break_critical_edges(mir);
     }
 }
diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
index 12bfa3aebc2..678d2c4614d 100644
--- a/src/librustc_mir/transform/erase_regions.rs
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -16,8 +16,7 @@ use rustc::ty::subst::Substs;
 use rustc::ty::{Ty, TyCtxt};
 use rustc::mir::repr::*;
 use rustc::mir::visit::MutVisitor;
-use rustc::mir::transform::{MirPass, Pass};
-use syntax::ast::NodeId;
+use rustc::mir::transform::{MirPass, MirSource, Pass};
 
 struct EraseRegionsVisitor<'a, 'tcx: 'a> {
     tcx: &'a TyCtxt<'tcx>,
@@ -47,7 +46,7 @@ pub struct EraseRegions;
 impl Pass for EraseRegions {}
 
 impl<'tcx> MirPass<'tcx> for EraseRegions {
-    fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) {
+    fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {
         EraseRegionsVisitor::new(tcx).visit_mir(mir);
     }
 }
diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs
index edfe75b8430..9c9f95e2e63 100644
--- a/src/librustc_mir/transform/no_landing_pads.rs
+++ b/src/librustc_mir/transform/no_landing_pads.rs
@@ -14,8 +14,7 @@
 use rustc::ty::TyCtxt;
 use rustc::mir::repr::*;
 use rustc::mir::visit::MutVisitor;
-use rustc::mir::transform::{Pass, MirPass};
-use syntax::ast::NodeId;
+use rustc::mir::transform::{Pass, MirPass, MirSource};
 
 pub struct NoLandingPads;
 
@@ -42,7 +41,7 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
 }
 
 impl<'tcx> MirPass<'tcx> for NoLandingPads {
-    fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) {
+    fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {
         if tcx.sess.no_landing_pads() {
             self.visit_mir(mir);
         }
diff --git a/src/librustc_mir/transform/remove_dead_blocks.rs b/src/librustc_mir/transform/remove_dead_blocks.rs
index 2099e9a435a..e0d05a17d43 100644
--- a/src/librustc_mir/transform/remove_dead_blocks.rs
+++ b/src/librustc_mir/transform/remove_dead_blocks.rs
@@ -35,13 +35,12 @@
 use rustc_data_structures::bitvec::BitVector;
 use rustc::ty::TyCtxt;
 use rustc::mir::repr::*;
-use rustc::mir::transform::{Pass, MirPass};
-use syntax::ast::NodeId;
+use rustc::mir::transform::{Pass, MirPass, MirSource};
 
 pub struct RemoveDeadBlocks;
 
 impl<'tcx> MirPass<'tcx> for RemoveDeadBlocks {
-    fn run_pass(&mut self, _: &TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) {
+    fn run_pass(&mut self, _: &TyCtxt<'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {
         let mut seen = BitVector::new(mir.basic_blocks.len());
         // This block is always required.
         seen.insert(START_BLOCK.index());
diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs
index 00b8f5c0930..a137a812867 100644
--- a/src/librustc_mir/transform/simplify_cfg.rs
+++ b/src/librustc_mir/transform/simplify_cfg.rs
@@ -11,9 +11,8 @@
 use rustc::middle::const_val::ConstVal;
 use rustc::ty::TyCtxt;
 use rustc::mir::repr::*;
-use rustc::mir::transform::{MirPass, Pass};
+use rustc::mir::transform::{MirPass, MirSource, Pass};
 use pretty;
-use syntax::ast::NodeId;
 
 use super::remove_dead_blocks::RemoveDeadBlocks;
 
@@ -112,15 +111,15 @@ impl SimplifyCfg {
 }
 
 impl<'tcx> MirPass<'tcx> for SimplifyCfg {
-    fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, id: NodeId, mir: &mut Mir<'tcx>) {
+    fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, src: MirSource, mir: &mut Mir<'tcx>) {
         let mut counter = 0;
         let mut changed = true;
         while changed {
-            pretty::dump_mir(tcx, "simplify_cfg", &counter, id, mir, None);
+            pretty::dump_mir(tcx, "simplify_cfg", &counter, src, mir, None);
             counter += 1;
             changed = self.simplify_branches(mir);
             changed |= self.remove_goto_chains(mir);
-            RemoveDeadBlocks.run_pass(tcx, id, mir);
+            RemoveDeadBlocks.run_pass(tcx, src, mir);
         }
         // FIXME: Should probably be moved into some kind of pass manager
         mir.basic_blocks.shrink_to_fit();
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 11ac1fa8f82..18ebadf42d6 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -12,16 +12,16 @@
 #![allow(unreachable_code)]
 
 use rustc::dep_graph::DepNode;
+use rustc::hir::def_id::DefId;
 use rustc::infer::{self, InferCtxt, InferOk};
 use rustc::traits::{self, ProjectionMode};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::mir::repr::*;
 use rustc::mir::tcx::LvalueTy;
-use rustc::mir::transform::{MirPass, Pass};
+use rustc::mir::transform::{MirPass, MirSource, Pass};
 use rustc::mir::visit::{self, Visitor};
 use std::fmt;
-use syntax::ast::NodeId;
 use syntax::codemap::{Span, DUMMY_SP};
 
 macro_rules! span_mirbug {
@@ -578,15 +578,13 @@ impl TypeckMir {
 }
 
 impl<'tcx> MirPass<'tcx> for TypeckMir {
-    fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, id: NodeId, mir: &mut Mir<'tcx>) {
+    fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, src: MirSource, mir: &mut Mir<'tcx>) {
         if tcx.sess.err_count() > 0 {
             // compiling a broken program can obviously result in a
             // broken MIR, so try not to report duplicate errors.
             return;
         }
-        let def_id = tcx.map.local_def_id(id);
-        let _task = tcx.dep_graph.in_task(DepNode::MirTypeck(def_id));
-        let param_env = ty::ParameterEnvironment::for_item(tcx, id);
+        let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
         let infcx = infer::new_infer_ctxt(tcx,
                                           &tcx.tables,
                                           Some(param_env),
@@ -605,4 +603,8 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
     }
 }
 
-impl Pass for TypeckMir {}
+impl Pass for TypeckMir {
+    fn dep_node(&self, def_id: DefId) -> DepNode<DefId> {
+        DepNode::MirTypeck(def_id)
+    }
+}
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index e8181579911..a0311ec6066 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -414,6 +414,9 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
             };
 
             visitor.visit_mir(&mir);
+            for promoted in &mir.promoted {
+                visitor.visit_mir(promoted);
+            }
         }
     }
 
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 22e4ab1dd89..9c1dfb0fc8d 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -35,7 +35,7 @@ use syntax::codemap::{Span, DUMMY_SP};
 use std::ptr;
 
 use super::operand::{OperandRef, OperandValue};
-use super::{CachedMir, MirContext};
+use super::MirContext;
 
 /// A sized constant rvalue.
 /// The LLVM type might not be the same for a single Rust type,
@@ -179,7 +179,7 @@ impl<'tcx> ConstLvalue<'tcx> {
 /// FIXME(eddyb) use miri and lower its allocations to LLVM.
 struct MirConstContext<'a, 'tcx: 'a> {
     ccx: &'a CrateContext<'a, 'tcx>,
-    mir: CachedMir<'a, 'tcx>,
+    mir: &'a mir::Mir<'tcx>,
 
     /// Type parameters for const fn and associated constants.
     substs: &'tcx Substs<'tcx>,
@@ -200,10 +200,25 @@ struct MirConstContext<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
     fn new(ccx: &'a CrateContext<'a, 'tcx>,
-           mut instance: Instance<'tcx>,
+           mir: &'a mir::Mir<'tcx>,
+           substs: &'tcx Substs<'tcx>,
            args: Vec<Const<'tcx>>)
            -> MirConstContext<'a, 'tcx> {
+        MirConstContext {
+            ccx: ccx,
+            mir: mir,
+            substs: substs,
+            args: args,
+            vars: vec![None; mir.var_decls.len()],
+            temps: vec![None; mir.temp_decls.len()],
+            return_value: None
+        }
+    }
 
+    fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
+                 mut instance: Instance<'tcx>,
+                 args: Vec<Const<'tcx>>)
+                 -> Result<Const<'tcx>, ConstEvalFailure> {
         // Try to resolve associated constants.
         if instance.substs.self_ty().is_some() {
             // Only trait items can have a Self parameter.
@@ -226,15 +241,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
         let mir = ccx.get_mir(instance.def).unwrap_or_else(|| {
             bug!("missing constant MIR for {}", instance)
         });
-        MirConstContext {
-            ccx: ccx,
-            substs: instance.substs,
-            args: args,
-            vars: vec![None; mir.var_decls.len()],
-            temps: vec![None; mir.temp_decls.len()],
-            return_value: None,
-            mir: mir
-        }
+        MirConstContext::new(ccx, &mir, instance.substs, args).trans()
     }
 
     fn monomorphize<T>(&self, value: &T) -> T
@@ -247,10 +254,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
 
     fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalFailure> {
         let tcx = self.ccx.tcx();
-        let mir = self.mir.clone();
         let mut bb = mir::START_BLOCK;
         loop {
-            let data = mir.basic_block_data(bb);
+            let data = self.mir.basic_block_data(bb);
             for statement in &data.statements {
                 match statement.kind {
                     mir::StatementKind::Assign(ref dest, ref rvalue) => {
@@ -284,7 +290,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                 }
 
                 mir::TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
-                    let fn_ty = mir.operand_ty(tcx, func);
+                    let fn_ty = self.mir.operand_ty(tcx, func);
                     let fn_ty = self.monomorphize(&fn_ty);
                     let instance = match fn_ty.sty {
                         ty::TyFnDef(def_id, substs, _) => {
@@ -304,7 +310,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                     let args = args.iter().map(|arg| {
                         self.const_operand(arg, span)
                     }).collect::<Result<Vec<_>, _>>()?;
-                    let value = MirConstContext::new(self.ccx, instance, args).trans()?;
+                    let value = MirConstContext::trans_def(self.ccx, instance, args)?;
                     if let Some((ref dest, target)) = *destination {
                         self.store(dest, value, span);
                         target
@@ -432,7 +438,11 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
 
                         let substs = self.ccx.tcx().mk_substs(self.monomorphize(substs));
                         let instance = Instance::new(def_id, substs);
-                        MirConstContext::new(self.ccx, instance, vec![]).trans()
+                        MirConstContext::trans_def(self.ccx, instance, vec![])
+                    }
+                    mir::Literal::Promoted { index } => {
+                        let mir = &self.mir.promoted[index];
+                        MirConstContext::new(self.ccx, mir, self.substs, vec![]).trans()
                     }
                     mir::Literal::Value { value } => {
                         Ok(Const::from_constval(self.ccx, value, ty))
@@ -792,7 +802,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                           -> OperandRef<'tcx>
     {
         let ty = bcx.monomorphize(&constant.ty);
-        let val = match constant.literal.clone() {
+        let result = match constant.literal.clone() {
             mir::Literal::Item { def_id, substs } => {
                 // Shortcut for zero-sized types, including function item
                 // types, which would not work with MirConstContext.
@@ -806,22 +816,28 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
                 let substs = bcx.tcx().mk_substs(bcx.monomorphize(substs));
                 let instance = Instance::new(def_id, substs);
-                match MirConstContext::new(bcx.ccx(), instance, vec![]).trans() {
-                    Ok(v) => v,
-                    Err(ConstEvalFailure::Compiletime(_)) => {
-                        // We've errored, so we don't have to produce working code.
-                        let llty = type_of::type_of(bcx.ccx(), ty);
-                        Const::new(C_undef(llty), ty)
-                    }
-                    Err(ConstEvalFailure::Runtime(err)) => {
-                        span_bug!(constant.span,
-                                  "MIR constant {:?} results in runtime panic: {}",
-                                  constant, err.description())
-                    }
-                }
+                MirConstContext::trans_def(bcx.ccx(), instance, vec![])
+            }
+            mir::Literal::Promoted { index } => {
+                let mir = &self.mir.promoted[index];
+                MirConstContext::new(bcx.ccx(), mir, bcx.fcx().param_substs, vec![]).trans()
             }
             mir::Literal::Value { value } => {
-                Const::from_constval(bcx.ccx(), value, ty)
+                Ok(Const::from_constval(bcx.ccx(), value, ty))
+            }
+        };
+
+        let val = match result {
+            Ok(v) => v,
+            Err(ConstEvalFailure::Compiletime(_)) => {
+                // We've errored, so we don't have to produce working code.
+                let llty = type_of::type_of(bcx.ccx(), ty);
+                Const::new(C_undef(llty), ty)
+            }
+            Err(ConstEvalFailure::Runtime(err)) => {
+                span_bug!(constant.span,
+                          "MIR constant {:?} results in runtime panic: {}",
+                          constant, err.description())
             }
         };
 
@@ -839,5 +855,5 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
                                 -> Result<ValueRef, ConstEvalFailure> {
     let instance = Instance::mono(ccx.tcx(), def_id);
-    MirConstContext::new(ccx, instance, vec![]).trans().map(|c| c.llval)
+    MirConstContext::trans_def(ccx, instance, vec![]).map(|c| c.llval)
 }
diff --git a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs
index b5234af937b..600df1c778b 100644
--- a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs
@@ -18,7 +18,7 @@ extern crate rustc_plugin;
 extern crate rustc_const_math;
 extern crate syntax;
 
-use rustc::mir::transform::{self, MirPass};
+use rustc::mir::transform::{self, MirPass, MirSource};
 use rustc::mir::repr::{Mir, Literal};
 use rustc::mir::visit::MutVisitor;
 use rustc::ty;
@@ -26,13 +26,11 @@ use rustc::middle::const_val::ConstVal;
 use rustc_const_math::ConstInt;
 use rustc_plugin::Registry;
 
-use syntax::ast::NodeId;
-
 struct Pass;
 
 impl transform::Pass for Pass {}
 impl<'tcx> MirPass<'tcx> for Pass {
-    fn run_pass(&mut self, _: &ty::TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) {
+    fn run_pass(&mut self, _: &ty::TyCtxt<'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {
         Visitor.visit_mir(mir)
     }
 }