about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-12-11 00:59:48 +0000
committerbors <bors@rust-lang.org>2015-12-11 00:59:48 +0000
commit7ce713961cb7c36bb66db70a276973eb78cf9e6e (patch)
treeb7379aa50ccc114e34709bc1f6d041d4905f7be5
parent0d3684063bab26117a8a5c26684470396446fe88 (diff)
parent5addc31adb558da1613c8f9748ee05688f6eaf91 (diff)
downloadrust-7ce713961cb7c36bb66db70a276973eb78cf9e6e.tar.gz
rust-7ce713961cb7c36bb66db70a276973eb78cf9e6e.zip
Auto merge of #30301 - michaelwoerister:mir-to-metadata2, r=nikomatsakis
This PR makes `Mir` `RustcEncodable` and `RustcDecodable` and stores it in crate metadata for inlinable items.

Some other things in here:
- `mir::visit::Visitor` is extended to also visit `Literals`, `Spans` and `DefIds`.
- It also adds `mir::visit::MutVisitor` which allows to mutate the visited `Mir` structure in place.
- Some numbers on how big MIR is in metadata (total metadata size in bytes):

|                | w/ MIR     | w/o MIR     | Rel. Size |
|----------------|-----------:|------------:|:---------:|
| libcore        | 17,695,473 |  14,263,377 |  124%     |
| liblibc        | 411,440   |  404,382    | 102%      |
| libcollections |  4,537,975 |   3,526,933 |   129%    |
| libserialize   |  2,574,769 |   2,060,798 |   125%    |
| libsyntax      | 15,262,894 |  12,075,574 |  126%     |
| librustc       | 16,984,537 |  13,692,168 |  124%     |

So, adding MIR to metadata makes it about 25% bigger. It could be worse, considering that it still uses the inefficient RBML encoding. Still, the question is whether we should put MIR emission behind a `-Z` flag.
-rw-r--r--src/librustc/middle/const_eval.rs2
-rw-r--r--src/librustc/middle/cstore.rs9
-rw-r--r--src/librustc/middle/ty/sty.rs28
-rw-r--r--src/librustc/mir/repr.rs59
-rw-r--r--src/librustc/mir/visit.rs316
-rw-r--r--src/librustc_data_structures/lib.rs1
-rw-r--r--src/librustc_data_structures/tuple_slice.rs60
-rw-r--r--src/librustc_metadata/common.rs3
-rw-r--r--src/librustc_metadata/csearch.rs11
-rw-r--r--src/librustc_metadata/decoder.rs58
-rw-r--r--src/librustc_metadata/encoder.rs24
-rw-r--r--src/librustc_mir/build/expr/as_lvalue.rs2
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs2
-rw-r--r--src/librustc_mir/build/expr/into.rs12
-rw-r--r--src/librustc_mir/build/matches/mod.rs2
-rw-r--r--src/librustc_mir/build/matches/test.rs8
-rw-r--r--src/librustc_mir/transform/simplify_cfg.rs11
-rw-r--r--src/librustc_trans/trans/base.rs18
-rw-r--r--src/librustc_trans/trans/mir/block.rs2
-rw-r--r--src/librustc_trans/trans/mir/rvalue.rs2
20 files changed, 567 insertions, 63 deletions
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index d6932c7ca3c..9f75f9ebb9a 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -242,7 +242,7 @@ pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId)
     }
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub enum ConstVal {
     Float(f64),
     Int(i64),
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 4efa7bfac18..22a4ddd2f68 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -28,6 +28,7 @@ use middle::def;
 use middle::lang_items;
 use middle::ty::{self, Ty};
 use middle::def_id::{DefId, DefIndex};
+use mir::repr::Mir;
 use session::Session;
 use session::search_paths::PathKind;
 use util::nodemap::{FnvHashMap, NodeMap, NodeSet};
@@ -100,6 +101,7 @@ pub enum InlinedItem {
 }
 
 /// A borrowed version of `hir::InlinedItem`.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 pub enum InlinedItemRef<'a> {
     Item(&'a hir::Item),
     TraitItem(DefId, &'a hir::TraitItem),
@@ -216,6 +218,8 @@ pub trait CrateStore<'tcx> : Any {
     // misc. metadata
     fn maybe_get_item_ast(&'tcx self, tcx: &ty::ctxt<'tcx>, def: DefId)
                           -> FoundAst<'tcx>;
+    fn maybe_get_item_mir(&self, tcx: &ty::ctxt<'tcx>, def: DefId)
+                          -> Option<Mir<'tcx>>;
     // This is basically a 1-based range of ints, which is a little
     // silly - I may fix that.
     fn crates(&self) -> Vec<ast::CrateNum>;
@@ -235,6 +239,7 @@ pub trait CrateStore<'tcx> : Any {
                        item_symbols: &RefCell<NodeMap<String>>,
                        link_meta: &LinkMeta,
                        reachable: &NodeSet,
+                       mir_map: &NodeMap<Mir<'tcx>>,
                        krate: &hir::Crate) -> Vec<u8>;
     fn metadata_encoding_version(&self) -> &[u8];
 }
@@ -383,6 +388,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     // misc. metadata
     fn maybe_get_item_ast(&'tcx self, tcx: &ty::ctxt<'tcx>, def: DefId)
                           -> FoundAst<'tcx> { unimplemented!() }
+    fn maybe_get_item_mir(&self, tcx: &ty::ctxt<'tcx>, def: DefId)
+                          -> Option<Mir<'tcx>> { unimplemented!() }
+
     // This is basically a 1-based range of ints, which is a little
     // silly - I may fix that.
     fn crates(&self) -> Vec<ast::CrateNum> { vec![] }
@@ -404,6 +412,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
                        item_symbols: &RefCell<NodeMap<String>>,
                        link_meta: &LinkMeta,
                        reachable: &NodeSet,
+                       mir_map: &NodeMap<Mir<'tcx>>,
                        krate: &hir::Crate) -> Vec<u8> { vec![] }
     fn metadata_encoding_version(&self) -> &[u8] { unimplemented!() }
 }
diff --git a/src/librustc/middle/ty/sty.rs b/src/librustc/middle/ty/sty.rs
index 425a324c7e0..66b2a9d3ad0 100644
--- a/src/librustc/middle/ty/sty.rs
+++ b/src/librustc/middle/ty/sty.rs
@@ -10,6 +10,7 @@
 
 //! This module contains TypeVariants and its major components
 
+use middle::cstore;
 use middle::def_id::DefId;
 use middle::region;
 use middle::subst::{self, Substs};
@@ -26,6 +27,8 @@ use syntax::abi;
 use syntax::ast::{self, Name};
 use syntax::parse::token::special_idents;
 
+use serialize::{Decodable, Decoder};
+
 use rustc_front::hir;
 
 use self::FnOutput::*;
@@ -233,7 +236,7 @@ pub enum TypeVariants<'tcx> {
 /// closure C wind up influencing the decisions we ought to make for
 /// closure C (which would then require fixed point iteration to
 /// handle). Plus it fixes an ICE. :P
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct ClosureSubsts<'tcx> {
     /// Lifetime and type parameters from the enclosing function.
     /// These are separated out because trans wants to pass them around
@@ -246,6 +249,23 @@ pub struct ClosureSubsts<'tcx> {
     pub upvar_tys: Vec<Ty<'tcx>>
 }
 
+impl<'tcx> Decodable for &'tcx ClosureSubsts<'tcx> {
+    fn decode<S: Decoder>(s: &mut S) -> Result<&'tcx ClosureSubsts<'tcx>, S::Error> {
+        let closure_substs = try! { Decodable::decode(s) };
+        let dummy_def_id: DefId = unsafe { mem::zeroed() };
+
+        cstore::tls::with_decoding_context(s, |dcx, _| {
+            // Intern the value
+            let ty = dcx.tcx().mk_closure_from_closure_substs(dummy_def_id,
+                                                              Box::new(closure_substs));
+            match ty.sty {
+                TyClosure(_, ref closure_substs) => Ok(&**closure_substs),
+                _ => unreachable!()
+            }
+        })
+    }
+}
+
 #[derive(Clone, PartialEq, Eq, Hash)]
 pub struct TraitTy<'tcx> {
     pub principal: ty::PolyTraitRef<'tcx>,
@@ -434,7 +454,7 @@ pub struct ClosureTy<'tcx> {
     pub sig: PolyFnSig<'tcx>,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub enum FnOutput<'tcx> {
     FnConverging(Ty<'tcx>),
     FnDiverging
@@ -632,7 +652,7 @@ pub struct DebruijnIndex {
 ///
 /// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
 /// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
-#[derive(Clone, PartialEq, Eq, Hash, Copy)]
+#[derive(Clone, PartialEq, Eq, Hash, Copy, RustcEncodable, RustcDecodable)]
 pub enum Region {
     // Region bound in a type or fn declaration which will be
     // substituted 'early' -- that is, at the same time when type
@@ -701,7 +721,7 @@ pub struct RegionVid {
     pub index: u32
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct SkolemizedRegionVid {
     pub index: u32
 }
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index d5d8da248e0..049063f73a5 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -13,6 +13,7 @@ use middle::def_id::DefId;
 use middle::subst::Substs;
 use middle::ty::{AdtDef, ClosureSubsts, FnOutput, Region, Ty};
 use rustc_back::slice;
+use rustc_data_structures::tuple_slice::TupleSlice;
 use rustc_front::hir::InlineAsm;
 use syntax::ast::Name;
 use syntax::codemap::Span;
@@ -20,6 +21,7 @@ use std::fmt::{Debug, Formatter, Error};
 use std::u32;
 
 /// Lowered representation of a single function.
+#[derive(RustcEncodable, RustcDecodable)]
 pub struct Mir<'tcx> {
     /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock`
     /// that indexes into this vector.
@@ -70,13 +72,13 @@ impl<'tcx> Mir<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Mutability and borrow kinds
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum Mutability {
     Mut,
     Not,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum BorrowKind {
     /// Data must be immutable and is aliasable.
     Shared,
@@ -127,6 +129,7 @@ pub enum BorrowKind {
 
 // A "variable" is a binding declared by the user as part of the fn
 // decl, a let, etc.
+#[derive(RustcEncodable, RustcDecodable)]
 pub struct VarDecl<'tcx> {
     pub mutability: Mutability,
     pub name: Name,
@@ -135,6 +138,7 @@ pub struct VarDecl<'tcx> {
 
 // A "temp" is a temporary that we place on the stack. They are
 // anonymous, always mutable, and have only a type.
+#[derive(RustcEncodable, RustcDecodable)]
 pub struct TempDecl<'tcx> {
     pub ty: Ty<'tcx>,
 }
@@ -150,6 +154,7 @@ pub struct TempDecl<'tcx> {
 //
 // there is only one argument, of type `(i32, u32)`, but two bindings
 // (`x` and `y`).
+#[derive(RustcEncodable, RustcDecodable)]
 pub struct ArgDecl<'tcx> {
     pub ty: Ty<'tcx>,
 }
@@ -161,7 +166,7 @@ pub struct ArgDecl<'tcx> {
 /// list of the `Mir`.
 ///
 /// (We use a `u32` internally just to save memory.)
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub struct BasicBlock(u32);
 
 impl BasicBlock {
@@ -185,12 +190,13 @@ impl Debug for BasicBlock {
 ///////////////////////////////////////////////////////////////////////////
 // BasicBlock and Terminator
 
-#[derive(Debug)]
+#[derive(Debug, RustcEncodable, RustcDecodable)]
 pub struct BasicBlockData<'tcx> {
     pub statements: Vec<Statement<'tcx>>,
     pub terminator: Terminator<'tcx>,
 }
 
+#[derive(RustcEncodable, RustcDecodable)]
 pub enum Terminator<'tcx> {
     /// block should have one successor in the graph; we jump there
     Goto {
@@ -206,7 +212,7 @@ pub enum Terminator<'tcx> {
     /// jump to branch 0 if this lvalue evaluates to true
     If {
         cond: Operand<'tcx>,
-        targets: [BasicBlock; 2],
+        targets: (BasicBlock, BasicBlock),
     },
 
     /// lvalue evaluates to some enum; jump depending on the branch
@@ -254,7 +260,7 @@ pub enum Terminator<'tcx> {
     /// unwinding.
     Call {
         data: CallData<'tcx>,
-        targets: [BasicBlock; 2],
+        targets: (BasicBlock, BasicBlock),
     },
 }
 
@@ -264,12 +270,12 @@ impl<'tcx> Terminator<'tcx> {
         match *self {
             Goto { target: ref b } => slice::ref_slice(b),
             Panic { target: ref b } => slice::ref_slice(b),
-            If { cond: _, targets: ref b } => b,
+            If { cond: _, targets: ref b } => b.as_slice(),
             Switch { targets: ref b, .. } => b,
             SwitchInt { targets: ref b, .. } => b,
             Diverge => &[],
             Return => &[],
-            Call { data: _, targets: ref b } => b,
+            Call { data: _, targets: ref b } => b.as_slice(),
         }
     }
 
@@ -278,17 +284,17 @@ impl<'tcx> Terminator<'tcx> {
         match *self {
             Goto { target: ref mut b } => slice::mut_ref_slice(b),
             Panic { target: ref mut b } => slice::mut_ref_slice(b),
-            If { cond: _, targets: ref mut b } => b,
+            If { cond: _, targets: ref mut b } => b.as_mut_slice(),
             Switch { targets: ref mut b, .. } => b,
             SwitchInt { targets: ref mut b, .. } => b,
             Diverge => &mut [],
             Return => &mut [],
-            Call { data: _, targets: ref mut b } => b,
+            Call { data: _, targets: ref mut b } => b.as_mut_slice(),
         }
     }
 }
 
-#[derive(Debug)]
+#[derive(Debug, RustcEncodable, RustcDecodable)]
 pub struct CallData<'tcx> {
     /// where the return value is written to
     pub destination: Lvalue<'tcx>,
@@ -345,18 +351,19 @@ impl<'tcx> Debug for Terminator<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Statements
 
+#[derive(RustcEncodable, RustcDecodable)]
 pub struct Statement<'tcx> {
     pub span: Span,
     pub kind: StatementKind<'tcx>,
 }
 
-#[derive(Debug)]
+#[derive(Debug, RustcEncodable, RustcDecodable)]
 pub enum StatementKind<'tcx> {
     Assign(Lvalue<'tcx>, Rvalue<'tcx>),
     Drop(DropKind, Lvalue<'tcx>),
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum DropKind {
     Free, // free a partially constructed box, should go away eventually
     Deep
@@ -377,7 +384,7 @@ impl<'tcx> Debug for Statement<'tcx> {
 
 /// A path to a value; something that can be evaluated without
 /// changing or disturbing program state.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum Lvalue<'tcx> {
     /// local variable declared by the user
     Var(u32),
@@ -403,13 +410,13 @@ pub enum Lvalue<'tcx> {
 /// or `*B` or `B[index]`. Note that it is parameterized because it is
 /// shared between `Constant` and `Lvalue`. See the aliases
 /// `LvalueProjection` etc below.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
 pub struct Projection<'tcx, B, V> {
     pub base: B,
     pub elem: ProjectionElem<'tcx, V>,
 }
 
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum ProjectionElem<'tcx, V> {
     Deref,
     Field(Field),
@@ -447,7 +454,7 @@ pub type LvalueElem<'tcx> =
     ProjectionElem<'tcx,Operand<'tcx>>;
 
 /// Index into the list of fields found in a `VariantDef`
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct Field(u32);
 
 impl Field {
@@ -523,7 +530,7 @@ impl<'tcx> Debug for Lvalue<'tcx> {
 // lvalue). They are intentionally limited to prevent rvalues from
 // being nested in one another.
 
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum Operand<'tcx> {
     Consume(Lvalue<'tcx>),
     Constant(Constant<'tcx>),
@@ -542,7 +549,7 @@ impl<'tcx> Debug for Operand<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Rvalues
 
-#[derive(Clone)]
+#[derive(Clone, RustcEncodable, RustcDecodable)]
 pub enum Rvalue<'tcx> {
     // x (either a move or copy, depending on type of x)
     Use(Operand<'tcx>),
@@ -583,10 +590,10 @@ pub enum Rvalue<'tcx> {
         from_end: usize,
     },
 
-    InlineAsm(&'tcx InlineAsm),
+    InlineAsm(InlineAsm),
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum CastKind {
     Misc,
 
@@ -604,7 +611,7 @@ pub enum CastKind {
     Unsize,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum AggregateKind<'tcx> {
     Vec,
     Tuple,
@@ -612,7 +619,7 @@ pub enum AggregateKind<'tcx> {
     Closure(DefId, &'tcx ClosureSubsts<'tcx>),
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum BinOp {
     /// The `+` operator (addition)
     Add,
@@ -648,7 +655,7 @@ pub enum BinOp {
     Gt,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum UnOp {
     /// The `!` operator for logical inversion
     Not,
@@ -684,14 +691,14 @@ impl<'tcx> Debug for Rvalue<'tcx> {
 // this does not necessarily mean that they are "==" in Rust -- in
 // particular one must be wary of `NaN`!
 
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
 pub struct Constant<'tcx> {
     pub span: Span,
     pub ty: Ty<'tcx>,
     pub literal: Literal<'tcx>,
 }
 
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum Literal<'tcx> {
     Item {
         def_id: DefId,
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index ac4f54b4b49..00d21d3c16e 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -8,8 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use middle::def_id::DefId;
 use middle::ty::Region;
 use mir::repr::*;
+use rustc_data_structures::tuple_slice::TupleSlice;
+use syntax::codemap::Span;
 
 pub trait Visitor<'tcx> {
     // Override these, and call `self.super_xxx` to revert back to the
@@ -55,6 +58,18 @@ pub trait Visitor<'tcx> {
         self.super_constant(constant);
     }
 
+    fn visit_literal(&mut self, literal: &Literal<'tcx>) {
+        self.super_literal(literal);
+    }
+
+    fn visit_def_id(&mut self, def_id: DefId) {
+        self.super_def_id(def_id);
+    }
+
+    fn visit_span(&mut self, span: Span) {
+        self.super_span(span);
+    }
+
     // The `super_xxx` methods comprise the default behavior and are
     // not meant to be overidden.
 
@@ -73,6 +88,8 @@ pub trait Visitor<'tcx> {
     }
 
     fn super_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
+        self.visit_span(statement.span);
+
         match statement.kind {
             StatementKind::Assign(ref lvalue, ref rvalue) => {
                 self.visit_assign(block, lvalue, rvalue);
@@ -97,7 +114,7 @@ pub trait Visitor<'tcx> {
 
             Terminator::If { ref cond, ref targets } => {
                 self.visit_operand(cond);
-                for &target in &targets[..] {
+                for &target in targets.as_slice() {
                     self.visit_branch(block, target);
                 }
             }
@@ -126,7 +143,7 @@ pub trait Visitor<'tcx> {
                 for arg in &data.args {
                     self.visit_operand(arg);
                 }
-                for &target in &targets[..] {
+                for &target in targets.as_slice() {
                     self.visit_branch(block, target);
                 }
             }
@@ -217,7 +234,26 @@ pub trait Visitor<'tcx> {
     fn super_branch(&mut self, _source: BasicBlock, _target: BasicBlock) {
     }
 
-    fn super_constant(&mut self, _constant: &Constant<'tcx>) {
+    fn super_constant(&mut self, constant: &Constant<'tcx>) {
+        self.visit_span(constant.span);
+        self.visit_literal(&constant.literal);
+    }
+
+    fn super_literal(&mut self, literal: &Literal<'tcx>) {
+        match *literal {
+            Literal::Item { def_id, .. } => {
+                self.visit_def_id(def_id);
+            },
+            Literal::Value { .. } => {
+                // Nothing to do
+            }
+        }
+    }
+
+    fn super_def_id(&mut self, _def_id: DefId) {
+    }
+
+    fn super_span(&mut self, _span: Span) {
     }
 }
 
@@ -244,3 +280,277 @@ pub enum LvalueContext {
     // Consumed as part of an operand
     Consume,
 }
+
+pub trait MutVisitor<'tcx> {
+    // Override these, and call `self.super_xxx` to revert back to the
+    // default behavior.
+
+    fn visit_mir(&mut self, mir: &mut Mir<'tcx>) {
+        self.super_mir(mir);
+    }
+
+    fn visit_basic_block_data(&mut self,
+                              block: BasicBlock,
+                              data: &mut BasicBlockData<'tcx>) {
+        self.super_basic_block_data(block, data);
+    }
+
+    fn visit_statement(&mut self,
+                       block: BasicBlock,
+                       statement: &mut Statement<'tcx>) {
+        self.super_statement(block, statement);
+    }
+
+    fn visit_assign(&mut self,
+                    block: BasicBlock,
+                    lvalue: &mut Lvalue<'tcx>,
+                    rvalue: &mut Rvalue<'tcx>) {
+        self.super_assign(block, lvalue, rvalue);
+    }
+
+    fn visit_terminator(&mut self,
+                        block: BasicBlock,
+                        terminator: &mut Terminator<'tcx>) {
+        self.super_terminator(block, terminator);
+    }
+
+    fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>) {
+        self.super_rvalue(rvalue);
+    }
+
+    fn visit_operand(&mut self, operand: &mut Operand<'tcx>) {
+        self.super_operand(operand);
+    }
+
+    fn visit_lvalue(&mut self,
+                    lvalue: &mut Lvalue<'tcx>,
+                    context: LvalueContext) {
+        self.super_lvalue(lvalue, context);
+    }
+
+    fn visit_branch(&mut self, source: BasicBlock, target: BasicBlock) {
+        self.super_branch(source, target);
+    }
+
+    fn visit_constant(&mut self, constant: &mut Constant<'tcx>) {
+        self.super_constant(constant);
+    }
+
+    fn visit_literal(&mut self, literal: &mut Literal<'tcx>) {
+        self.super_literal(literal);
+    }
+
+    fn visit_def_id(&mut self, def_id: &mut DefId) {
+        self.super_def_id(def_id);
+    }
+
+    fn visit_span(&mut self, span: &mut Span) {
+        self.super_span(span);
+    }
+
+    // The `super_xxx` methods comprise the default behavior and are
+    // not meant to be overidden.
+
+    fn super_mir(&mut self, mir: &mut Mir<'tcx>) {
+        for block in mir.all_basic_blocks() {
+            let data = mir.basic_block_data_mut(block);
+            self.visit_basic_block_data(block, data);
+        }
+    }
+
+    fn super_basic_block_data(&mut self,
+                              block: BasicBlock,
+                              data: &mut BasicBlockData<'tcx>) {
+        for statement in &mut data.statements {
+            self.visit_statement(block, statement);
+        }
+        self.visit_terminator(block, &mut data.terminator);
+    }
+
+    fn super_statement(&mut self,
+                       block: BasicBlock,
+                       statement: &mut Statement<'tcx>) {
+        self.visit_span(&mut statement.span);
+
+        match statement.kind {
+            StatementKind::Assign(ref mut lvalue, ref mut rvalue) => {
+                self.visit_assign(block, lvalue, rvalue);
+            }
+            StatementKind::Drop(_, ref mut lvalue) => {
+                self.visit_lvalue(lvalue, LvalueContext::Drop);
+            }
+        }
+    }
+
+    fn super_assign(&mut self,
+                    _block: BasicBlock,
+                    lvalue: &mut Lvalue<'tcx>,
+                    rvalue: &mut Rvalue<'tcx>) {
+        self.visit_lvalue(lvalue, LvalueContext::Store);
+        self.visit_rvalue(rvalue);
+    }
+
+    fn super_terminator(&mut self,
+                        block: BasicBlock,
+                        terminator: &mut Terminator<'tcx>) {
+        match *terminator {
+            Terminator::Goto { target } |
+            Terminator::Panic { target } => {
+                self.visit_branch(block, target);
+            }
+
+            Terminator::If { ref mut cond, ref mut targets } => {
+                self.visit_operand(cond);
+                for &target in targets.as_slice() {
+                    self.visit_branch(block, target);
+                }
+            }
+
+            Terminator::Switch { ref mut discr, adt_def: _, ref targets } => {
+                self.visit_lvalue(discr, LvalueContext::Inspect);
+                for &target in targets {
+                    self.visit_branch(block, target);
+                }
+            }
+
+            Terminator::SwitchInt { ref mut discr, switch_ty: _, values: _, ref targets } => {
+                self.visit_lvalue(discr, LvalueContext::Inspect);
+                for &target in targets {
+                    self.visit_branch(block, target);
+                }
+            }
+
+            Terminator::Diverge |
+            Terminator::Return => {
+            }
+
+            Terminator::Call { ref mut data, ref mut targets } => {
+                self.visit_lvalue(&mut data.destination, LvalueContext::Store);
+                self.visit_operand(&mut data.func);
+                for arg in &mut data.args {
+                    self.visit_operand(arg);
+                }
+                for &target in targets.as_slice() {
+                    self.visit_branch(block, target);
+                }
+            }
+        }
+    }
+
+    fn super_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>) {
+        match *rvalue {
+            Rvalue::Use(ref mut operand) => {
+                self.visit_operand(operand);
+            }
+
+            Rvalue::Repeat(ref mut value, ref mut len) => {
+                self.visit_operand(value);
+                self.visit_constant(len);
+            }
+
+            Rvalue::Ref(r, bk, ref mut path) => {
+                self.visit_lvalue(path, LvalueContext::Borrow {
+                    region: r,
+                    kind: bk
+                });
+            }
+
+            Rvalue::Len(ref mut path) => {
+                self.visit_lvalue(path, LvalueContext::Inspect);
+            }
+
+            Rvalue::Cast(_, ref mut operand, _) => {
+                self.visit_operand(operand);
+            }
+
+            Rvalue::BinaryOp(_, ref mut lhs, ref mut rhs) => {
+                self.visit_operand(lhs);
+                self.visit_operand(rhs);
+            }
+
+            Rvalue::UnaryOp(_, ref mut op) => {
+                self.visit_operand(op);
+            }
+
+            Rvalue::Box(_) => {
+            }
+
+            Rvalue::Aggregate(ref mut kind, ref mut operands) => {
+                match *kind {
+                    AggregateKind::Closure(ref mut def_id, _) => {
+                        self.visit_def_id(def_id);
+                    }
+                    _ => { /* nothing to do */ }
+                }
+
+                for operand in &mut operands[..] {
+                    self.visit_operand(operand);
+                }
+            }
+
+            Rvalue::Slice { ref mut input, from_start, from_end } => {
+                self.visit_lvalue(input, LvalueContext::Slice {
+                    from_start: from_start,
+                    from_end: from_end,
+                });
+            }
+
+            Rvalue::InlineAsm(_) => {
+            }
+        }
+    }
+
+    fn super_operand(&mut self, operand: &mut Operand<'tcx>) {
+        match *operand {
+            Operand::Consume(ref mut lvalue) => {
+                self.visit_lvalue(lvalue, LvalueContext::Consume);
+            }
+            Operand::Constant(ref mut constant) => {
+                self.visit_constant(constant);
+            }
+        }
+    }
+
+    fn super_lvalue(&mut self,
+                    lvalue: &mut Lvalue<'tcx>,
+                    _context: LvalueContext) {
+        match *lvalue {
+            Lvalue::Var(_) |
+            Lvalue::Temp(_) |
+            Lvalue::Arg(_) |
+            Lvalue::ReturnPointer => {
+            }
+            Lvalue::Static(ref mut def_id) => {
+                self.visit_def_id(def_id);
+            }
+            Lvalue::Projection(ref mut proj) => {
+                self.visit_lvalue(&mut proj.base, LvalueContext::Projection);
+            }
+        }
+    }
+
+    fn super_branch(&mut self, _source: BasicBlock, _target: BasicBlock) {
+    }
+
+    fn super_constant(&mut self, constant: &mut Constant<'tcx>) {
+        self.visit_span(&mut constant.span);
+        self.visit_literal(&mut constant.literal);
+    }
+
+    fn super_literal(&mut self, literal: &mut Literal<'tcx>) {
+        match *literal {
+            Literal::Item { ref mut def_id, .. } => {
+                self.visit_def_id(def_id);
+            },
+            Literal::Value { .. } => {
+                // Nothing to do
+            }
+        }
+    }
+
+    fn super_def_id(&mut self, _def_id: &mut DefId) {
+    }
+
+    fn super_span(&mut self, _span: &mut Span) {
+    }
+}
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 39b3842791f..0ea7cfa3902 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -42,6 +42,7 @@ pub mod snapshot_vec;
 pub mod transitive_relation;
 pub mod unify;
 pub mod fnv;
+pub mod tuple_slice;
 
 // See comments in src/librustc/lib.rs
 #[doc(hidden)]
diff --git a/src/librustc_data_structures/tuple_slice.rs b/src/librustc_data_structures/tuple_slice.rs
new file mode 100644
index 00000000000..f157d82eda1
--- /dev/null
+++ b/src/librustc_data_structures/tuple_slice.rs
@@ -0,0 +1,60 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::slice;
+
+/// Allows to view uniform tuples as slices
+pub trait TupleSlice<T> {
+    fn as_slice(&self) -> &[T];
+    fn as_mut_slice(&mut self) -> &mut [T];
+}
+
+macro_rules! impl_tuple_slice {
+    ($tuple_type:ty, $size:expr) => {
+        impl<T> TupleSlice<T> for $tuple_type {
+            fn as_slice(&self) -> &[T] {
+                unsafe {
+                    let ptr = &self.0 as *const T;
+                    slice::from_raw_parts(ptr, $size)
+                }
+            }
+
+            fn as_mut_slice(&mut self) -> &mut [T] {
+                unsafe {
+                    let ptr = &mut self.0 as *mut T;
+                    slice::from_raw_parts_mut(ptr, $size)
+                }
+            }
+        }
+    }
+}
+
+impl_tuple_slice!((T,T), 2);
+impl_tuple_slice!((T,T,T), 3);
+impl_tuple_slice!((T,T,T,T), 4);
+impl_tuple_slice!((T,T,T,T,T), 5);
+impl_tuple_slice!((T,T,T,T,T,T), 6);
+impl_tuple_slice!((T,T,T,T,T,T,T), 7);
+impl_tuple_slice!((T,T,T,T,T,T,T,T), 8);
+
+#[test]
+fn test_sliced_tuples() {
+    let t2 = (100i32, 101i32);
+    assert_eq!(t2.as_slice(), &[100i32, 101i32]);
+
+    let t3 = (102i32, 103i32, 104i32);
+    assert_eq!(t3.as_slice(), &[102i32, 103i32, 104i32]);
+
+    let t4 = (105i32, 106i32, 107i32, 108i32);
+    assert_eq!(t4.as_slice(), &[105i32, 106i32, 107i32, 108i32]);
+
+    let t5 = (109i32, 110i32, 111i32, 112i32, 113i32);
+    assert_eq!(t5.as_slice(), &[109i32, 110i32, 111i32, 112i32, 113i32]);
+}
diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs
index b6454a4c81a..5186c969133 100644
--- a/src/librustc_metadata/common.rs
+++ b/src/librustc_metadata/common.rs
@@ -120,7 +120,8 @@ enum_from_u32! {
 
         tag_tree = 0x51,
 
-        // GAP 0x52
+        tag_mir = 0x52,
+
         tag_table = 0x53,
         // GAP 0x54, 0x55
         tag_table_def = 0x56,
diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs
index aae3a762c19..ad00ef29e5f 100644
--- a/src/librustc_metadata/csearch.rs
+++ b/src/librustc_metadata/csearch.rs
@@ -22,6 +22,7 @@ use middle::ty::{self, Ty};
 use middle::def_id::{DefId, DefIndex};
 
 use rustc::front::map as hir_map;
+use rustc::mir::repr::Mir;
 use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet};
 
 use std::cell::RefCell;
@@ -421,6 +422,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         decoder::maybe_get_item_ast(&*cdata, tcx, def.index, decode_inlined_item)
     }
 
+    fn maybe_get_item_mir(&self, tcx: &ty::ctxt<'tcx>, def: DefId)
+                          -> Option<Mir<'tcx>> {
+        let cdata = self.get_crate_data(def.krate);
+        decoder::maybe_get_item_mir(&*cdata, tcx, def.index)
+    }
+
     fn crates(&self) -> Vec<ast::CrateNum>
     {
         let mut result = vec![];
@@ -473,6 +480,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
                        item_symbols: &RefCell<NodeMap<String>>,
                        link_meta: &LinkMeta,
                        reachable: &NodeSet,
+                       mir_map: &NodeMap<Mir<'tcx>>,
                        krate: &hir::Crate) -> Vec<u8>
     {
         let encode_inlined_item: encoder::EncodeInlinedItem =
@@ -486,7 +494,8 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
             link_meta: link_meta,
             cstore: self,
             encode_inlined_item: encode_inlined_item,
-            reachable: reachable
+            reachable: reachable,
+            mir_map: mir_map,
         };
         encoder::encode_metadata(encode_params, krate)
 
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index c139ec4f62a..d1917b29b9f 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -18,6 +18,7 @@ use cstore::{self, crate_metadata};
 use common::*;
 use encoder::def_to_u64;
 use index;
+use tls_context;
 use tydecode::TyDecoder;
 
 use rustc::back::svh::Svh;
@@ -26,7 +27,7 @@ use rustc::util::nodemap::FnvHashMap;
 use rustc_front::hir;
 
 use middle::cstore::{LOCAL_CRATE, FoundAst, InlinedItem, LinkagePreference};
-use middle::cstore::{DefLike, DlDef, DlField, DlImpl};
+use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls};
 use middle::def;
 use middle::def_id::{DefId, DefIndex};
 use middle::lang_items;
@@ -34,6 +35,9 @@ use middle::subst;
 use middle::ty::{ImplContainer, TraitContainer};
 use middle::ty::{self, RegionEscape, Ty};
 
+use rustc::mir;
+use rustc::mir::visit::MutVisitor;
+
 use std::cell::{Cell, RefCell};
 use std::io::prelude::*;
 use std::io;
@@ -48,7 +52,7 @@ use syntax::parse::token::{IdentInterner, special_idents};
 use syntax::parse::token;
 use syntax::ast;
 use syntax::abi;
-use syntax::codemap;
+use syntax::codemap::{self, Span};
 use syntax::print::pprust;
 use syntax::ptr::P;
 
@@ -783,6 +787,56 @@ pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: DefIndex,
     }
 }
 
+pub fn maybe_get_item_mir<'tcx>(cdata: Cmd,
+                                tcx: &ty::ctxt<'tcx>,
+                                id: DefIndex)
+                                -> Option<mir::repr::Mir<'tcx>> {
+    let item_doc = cdata.lookup_item(id);
+
+    return reader::maybe_get_doc(item_doc, tag_mir as usize).map(|mir_doc| {
+        let dcx = tls_context::DecodingContext {
+            crate_metadata: cdata,
+            tcx: tcx,
+        };
+        let mut decoder = reader::Decoder::new(mir_doc);
+
+        let mut mir = tls::enter_decoding_context(&dcx, &mut decoder, |_, decoder| {
+            Decodable::decode(decoder).unwrap()
+        });
+
+        let mut def_id_and_span_translator = MirDefIdAndSpanTranslator {
+            crate_metadata: cdata,
+            codemap: tcx.sess.codemap(),
+            last_filemap_index_hint: Cell::new(0),
+        };
+
+        def_id_and_span_translator.visit_mir(&mut mir);
+
+        mir
+    });
+
+    struct MirDefIdAndSpanTranslator<'cdata, 'codemap> {
+        crate_metadata: Cmd<'cdata>,
+        codemap: &'codemap codemap::CodeMap,
+        last_filemap_index_hint: Cell<usize>
+    }
+
+    impl<'v, 'cdata, 'codemap> mir::visit::MutVisitor<'v>
+        for MirDefIdAndSpanTranslator<'cdata, 'codemap>
+    {
+        fn visit_def_id(&mut self, def_id: &mut DefId) {
+            *def_id = translate_def_id(self.crate_metadata, *def_id);
+        }
+
+        fn visit_span(&mut self, span: &mut Span) {
+            *span = translate_span(self.crate_metadata,
+                                   self.codemap,
+                                   &self.last_filemap_index_hint,
+                                   *span);
+        }
+    }
+}
+
 fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory {
     fn get_mutability(ch: u8) -> hir::Mutability {
         match ch as char {
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 448a64c93c1..a627eeb6880 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -30,6 +30,7 @@ use middle::ty::{self, Ty};
 use rustc::back::svh::Svh;
 use rustc::front::map::{LinkedPath, PathElem, PathElems};
 use rustc::front::map as ast_map;
+use rustc::mir::repr::Mir;
 use rustc::session::config;
 use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet};
 
@@ -64,6 +65,7 @@ pub struct EncodeParams<'a, 'tcx: 'a> {
     pub cstore: &'a cstore::CStore,
     pub encode_inlined_item: EncodeInlinedItem<'a>,
     pub reachable: &'a NodeSet,
+    pub mir_map: &'a NodeMap<Mir<'tcx>>,
 }
 
 pub struct EncodeContext<'a, 'tcx: 'a> {
@@ -76,6 +78,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> {
     pub encode_inlined_item: RefCell<EncodeInlinedItem<'a>>,
     pub type_abbrevs: tyencode::abbrev_map<'tcx>,
     pub reachable: &'a NodeSet,
+    pub mir_map: &'a NodeMap<Mir<'tcx>>,
 }
 
 impl<'a, 'tcx> EncodeContext<'a,'tcx> {
@@ -840,7 +843,24 @@ fn encode_inlined_item(ecx: &EncodeContext,
                        ii: InlinedItemRef) {
     let mut eii = ecx.encode_inlined_item.borrow_mut();
     let eii: &mut EncodeInlinedItem = &mut *eii;
-    eii(ecx, rbml_w, ii)
+    eii(ecx, rbml_w, ii);
+
+    encode_mir(ecx, rbml_w, ii);
+}
+
+fn encode_mir(ecx: &EncodeContext, rbml_w: &mut Encoder, ii: InlinedItemRef) {
+    let id = match ii {
+        InlinedItemRef::Item(item) => item.id,
+        InlinedItemRef::TraitItem(_, trait_item) => trait_item.id,
+        InlinedItemRef::ImplItem(_, impl_item) => impl_item.id,
+        InlinedItemRef::Foreign(foreign_item) => foreign_item.id
+    };
+
+    if let Some(mir) = ecx.mir_map.get(&id) {
+        rbml_w.start_tag(tag_mir as usize);
+        Encodable::encode(mir, rbml_w).unwrap();
+        rbml_w.end_tag();
+    }
 }
 
 const FN_FAMILY: char = 'f';
@@ -1884,6 +1904,7 @@ pub fn encode_metadata(parms: EncodeParams, krate: &hir::Crate) -> Vec<u8> {
         encode_inlined_item,
         link_meta,
         reachable,
+        mir_map,
         ..
     } = parms;
     let ecx = EncodeContext {
@@ -1896,6 +1917,7 @@ pub fn encode_metadata(parms: EncodeParams, krate: &hir::Crate) -> Vec<u8> {
         encode_inlined_item: RefCell::new(encode_inlined_item),
         type_abbrevs: RefCell::new(FnvHashMap()),
         reachable: reachable,
+        mir_map: mir_map,
     };
 
     let mut wr = Cursor::new(Vec::new());
diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs
index 697799efd14..1c96addcea0 100644
--- a/src/librustc_mir/build/expr/as_lvalue.rs
+++ b/src/librustc_mir/build/expr/as_lvalue.rs
@@ -69,7 +69,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                 this.cfg.terminate(block,
                                    Terminator::If {
                                        cond: Operand::Consume(lt),
-                                       targets: [success, failure],
+                                       targets: (success, failure),
                                    });
                 this.panic(failure);
                 success.and(slice.index(idx))
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 7f69b9a521f..2f57dd22454 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -40,7 +40,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                 this.in_scope(extent, block, |this| this.as_rvalue(block, value))
             }
             ExprKind::InlineAsm { asm } => {
-                block.and(Rvalue::InlineAsm(asm))
+                block.and(Rvalue::InlineAsm(asm.clone()))
             }
             ExprKind::Repeat { value, count } => {
                 let value_operand = unpack!(block = this.as_operand(block, value));
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index ac3e87e6b62..802c55ce764 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -53,7 +53,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                 let mut else_block = this.cfg.start_new_block();
                 this.cfg.terminate(block, Terminator::If {
                     cond: operand,
-                    targets: [then_block, else_block]
+                    targets: (then_block, else_block)
                 });
 
                 unpack!(then_block = this.into(destination, then_block, then_expr));
@@ -84,15 +84,15 @@ impl<'a,'tcx> Builder<'a,'tcx> {
 
                 let lhs = unpack!(block = this.as_operand(block, lhs));
                 let blocks = match op {
-                    LogicalOp::And => [else_block, false_block],
-                    LogicalOp::Or => [true_block, else_block],
+                    LogicalOp::And => (else_block, false_block),
+                    LogicalOp::Or => (true_block, else_block),
                 };
                 this.cfg.terminate(block, Terminator::If { cond: lhs, targets: blocks });
 
                 let rhs = unpack!(else_block = this.as_operand(else_block, rhs));
                 this.cfg.terminate(else_block, Terminator::If {
                     cond: rhs,
-                    targets: [true_block, false_block]
+                    targets: (true_block, false_block)
                 });
 
                 this.cfg.push_assign_constant(
@@ -149,7 +149,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                         this.cfg.terminate(loop_block_end,
                                            Terminator::If {
                                                cond: cond,
-                                               targets: [body_block, exit_block]
+                                               targets: (body_block, exit_block)
                                            });
                     } else {
                         body_block = loop_block;
@@ -225,7 +225,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                                            func: fun,
                                            args: args,
                                        },
-                                       targets: [success, panic],
+                                       targets: (success, panic),
                                    });
                 success.unit()
             }
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 0248f2fc49a..f8385d58170 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -555,7 +555,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
             let cond = unpack!(block = self.as_operand(block, guard));
             let otherwise = self.cfg.start_new_block();
             self.cfg.terminate(block, Terminator::If { cond: cond,
-                                                       targets: [arm_block, otherwise]});
+                                                       targets: (arm_block, otherwise)});
             Some(otherwise)
         } else {
             self.cfg.terminate(block, Terminator::Goto { target: arm_block });
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 968514cd05c..7b329fc4d52 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -232,7 +232,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                                                  self.cfg.start_new_block()];
                 self.cfg.terminate(block, Terminator::If {
                     cond: Operand::Consume(result),
-                    targets: [target_blocks[0], target_blocks[1]]
+                    targets: (target_blocks[0], target_blocks[1])
                 });
 
                 target_blocks
@@ -252,7 +252,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
         let bool_ty = self.hir.bool_ty();
         let eq_result = self.temp(bool_ty);
         let func = self.item_ref_operand(span, item_ref);
-        let call_blocks = [self.cfg.start_new_block(), self.diverge_cleanup()];
+        let call_blocks = (self.cfg.start_new_block(), self.diverge_cleanup());
         self.cfg.terminate(block,
                            Terminator::Call {
                                data: CallData {
@@ -264,10 +264,10 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                            });
 
         // check the result
-        self.cfg.terminate(call_blocks[0],
+        self.cfg.terminate(call_blocks.0,
                            Terminator::If {
                                cond: Operand::Consume(eq_result),
-                               targets: [target_blocks[0], target_blocks[1]],
+                               targets: (target_blocks[0], target_blocks[1]),
                            });
 
         target_blocks
diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs
index 558276a13a8..d0c0afc80a6 100644
--- a/src/librustc_mir/transform/simplify_cfg.rs
+++ b/src/librustc_mir/transform/simplify_cfg.rs
@@ -96,9 +96,9 @@ impl SimplifyCfg {
             mem::swap(&mut terminator, &mut mir.basic_block_data_mut(bb).terminator);
 
             mir.basic_block_data_mut(bb).terminator = match terminator {
-                Terminator::If { ref targets, .. } if targets[0] == targets[1] => {
+                Terminator::If { ref targets, .. } if targets.0 == targets.1 => {
                     changed = true;
-                    Terminator::Goto { target: targets[0] }
+                    Terminator::Goto { target: targets.0 }
                 }
                 Terminator::If { ref targets, cond: Operand::Constant(Constant {
                     literal: Literal::Value {
@@ -106,8 +106,11 @@ impl SimplifyCfg {
                     }, ..
                 }) } => {
                     changed = true;
-                    let target_idx = if cond { 0 } else { 1 };
-                    Terminator::Goto { target: targets[target_idx] }
+                    if cond {
+                        Terminator::Goto { target: targets.0 }
+                    } else {
+                        Terminator::Goto { target: targets.1 }
+                    }
                 }
                 Terminator::SwitchInt { ref targets, .. }  if targets.len() == 1 => {
                     Terminator::Goto { target: targets[0] }
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index dde6e3935b2..838a5435d4f 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -2760,7 +2760,11 @@ fn register_method(ccx: &CrateContext,
     }
 }
 
-pub fn write_metadata(cx: &SharedCrateContext, krate: &hir::Crate, reachable: &NodeSet) -> Vec<u8> {
+pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>,
+                                krate: &hir::Crate,
+                                reachable: &NodeSet,
+                                mir_map: &MirMap<'tcx>)
+                                -> Vec<u8> {
     use flate;
 
     let any_library = cx.sess()
@@ -2773,9 +2777,13 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &hir::Crate, reachable: &N
     }
 
     let cstore = &cx.tcx().sess.cstore;
-    let metadata = cstore.encode_metadata(
-        cx.tcx(), cx.export_map(), cx.item_symbols(), cx.link_meta(), reachable,
-        krate);
+    let metadata = cstore.encode_metadata(cx.tcx(),
+                                          cx.export_map(),
+                                          cx.item_symbols(),
+                                          cx.link_meta(),
+                                          reachable,
+                                          mir_map,
+                                          krate);
     let mut compressed = cstore.metadata_encoding_version().to_vec();
     compressed.extend_from_slice(&flate::deflate_bytes(&metadata));
 
@@ -3045,7 +3053,7 @@ pub fn trans_crate<'tcx>(tcx: &ty::ctxt<'tcx>,
     let reachable_symbol_ids = filter_reachable_ids(&shared_ccx);
 
     // Translate the metadata.
-    let metadata = write_metadata(&shared_ccx, krate, &reachable_symbol_ids);
+    let metadata = write_metadata(&shared_ccx, krate, &reachable_symbol_ids, mir_map);
 
     if shared_ccx.sess().trans_stats() {
         let stats = shared_ccx.stats();
diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs
index 3ce08fb2f60..b58b51f5a2b 100644
--- a/src/librustc_trans/trans/mir/block.rs
+++ b/src/librustc_trans/trans/mir/block.rs
@@ -39,7 +39,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 unimplemented!()
             }
 
-            mir::Terminator::If { ref cond, targets: [true_bb, false_bb] } => {
+            mir::Terminator::If { ref cond, targets: (true_bb, false_bb) } => {
                 let cond = self.trans_operand(bcx, cond);
                 let lltrue = self.llblock(true_bb);
                 let llfalse = self.llblock(false_bb);
diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs
index 17e4ec8e827..529e65dace0 100644
--- a/src/librustc_trans/trans/mir/rvalue.rs
+++ b/src/librustc_trans/trans/mir/rvalue.rs
@@ -120,7 +120,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 bcx
             }
 
-            mir::Rvalue::InlineAsm(inline_asm) => {
+            mir::Rvalue::InlineAsm(ref inline_asm) => {
                 asm::trans_inline_asm(bcx, inline_asm)
             }