diff --git a/.gitignore b/.gitignore
index 67e0dd8e795bb..d34ed114972c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,7 +12,7 @@ __pycache__/
 .project
 .settings/
 .valgrindrc
-.vscode/
+.vscode
 .favorites.json
 /*-*-*-*/
 /*-*-*/
diff --git a/Cargo.lock b/Cargo.lock
index 982070a243ee5..4417c25abcb4e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1481,7 +1481,7 @@ dependencies = [
 
 [[package]]
 name = "measureme"
-version = "0.2.1"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2346,7 +2346,7 @@ dependencies = [
  "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "measureme 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "measureme 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "polonius-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -4174,7 +4174,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
 "checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f"
 "checksum mdbook 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0ba0d44cb4089c741b9a91f3e5218298a40699c2f3a070a85014eed290c60819"
-"checksum measureme 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "36bb2b263a6795d352035024d6b30ce465bb79a5e5280d74c3b5f8464c657bcc"
+"checksum measureme 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09de7dafa3aa334bc806447c7e4de69419723312f4b88b80b561dea66601ce8"
 "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
 "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
 "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 5777331b9bfd5..da2e03a1a0848 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -317,6 +317,10 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
 fn configure_cmake(builder: &Builder<'_>,
                    target: Interned<String>,
                    cfg: &mut cmake::Config) {
+    // Do not print installation messages for up-to-date files.
+    // LLVM and LLD builds can produce a lot of those and hit CI limits on log size.
+    cfg.define("CMAKE_INSTALL_MESSAGE", "LAZY");
+
     if builder.config.ninja {
         cfg.generator("Ninja");
     }
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index 2468de99d60a8..4d50e80d4cf67 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -36,7 +36,7 @@ byteorder = { version = "1.1", features = ["i128"]}
 chalk-engine = { version = "0.9.0", default-features=false }
 rustc_fs_util = { path = "../librustc_fs_util" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
-measureme = "0.2.1"
+measureme = "0.3"
 
 # Note that these dependencies are a lie, they're just here to get linkage to
 # work.
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 2e54165be1f1b..ef0d4be268eaf 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -419,7 +419,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
         for arm in arms {
             // Add an exit node for when we've visited all the
             // patterns and the guard (if there is one) in the arm.
-            let arm_exit = self.add_dummy_node(&[]);
+            let bindings_exit = self.add_dummy_node(&[]);
 
             for pat in &arm.pats {
                 // Visit the pattern, coming from the discriminant exit
@@ -453,14 +453,16 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
 
                 // Add an edge from the exit of this pattern to the
                 // exit of the arm
-                self.add_contained_edge(pat_exit, arm_exit);
+                self.add_contained_edge(pat_exit, bindings_exit);
             }
 
             // Visit the body of this arm
-            let body_exit = self.expr(&arm.body, arm_exit);
+            let body_exit = self.expr(&arm.body, bindings_exit);
+
+            let arm_exit = self.add_ast_node(arm.hir_id.local_id, &[body_exit]);
 
             // Link the body to the exit of the expression
-            self.add_contained_edge(body_exit, expr_exit);
+            self.add_contained_edge(arm_exit, expr_exit);
         }
 
         expr_exit
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 38d6d710868c0..517c99f99efea 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -1102,6 +1102,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
 }
 
 pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
+    visitor.visit_id(arm.hir_id);
     walk_list!(visitor, visit_pat, &arm.pats);
     if let Some(ref g) = arm.guard {
         match g {
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index dd0d13d8f5a6a..05aa7690663e1 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1313,6 +1313,7 @@ impl<'a> LoweringContext<'a> {
 
     fn lower_arm(&mut self, arm: &Arm) -> hir::Arm {
         hir::Arm {
+            hir_id: self.next_id(),
             attrs: self.lower_attrs(&arm.attrs),
             pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(),
             guard: match arm.guard {
@@ -1320,6 +1321,7 @@ impl<'a> LoweringContext<'a> {
                 _ => None,
             },
             body: P(self.lower_expr(&arm.body)),
+            span: arm.span,
         }
     }
 
@@ -5023,9 +5025,11 @@ impl<'a> LoweringContext<'a> {
 
     fn arm(&mut self, pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
         hir::Arm {
+            hir_id: self.next_id(),
             attrs: hir_vec![],
             pats,
             guard: None,
+            span: expr.span,
             body: expr,
         }
     }
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index a1cf338bf12ea..accf8adcf9bdb 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -430,6 +430,16 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         });
     }
 
+    fn visit_arm(&mut self, arm: &'hir Arm) {
+        let node = Node::Arm(arm);
+
+        self.insert(arm.span, arm.hir_id, node);
+
+        self.with_parent(arm.hir_id, |this| {
+            intravisit::walk_arm(this, arm);
+        });
+    }
+
     fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
         self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant));
 
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index b8ee98551a20e..1da23dd8919d4 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -373,6 +373,7 @@ impl<'hir> Map<'hir> {
             Node::Pat(_) |
             Node::Binding(_) |
             Node::Local(_) |
+            Node::Arm(_) |
             Node::Lifetime(_) |
             Node::Visibility(_) |
             Node::Block(_) |
@@ -1000,6 +1001,7 @@ impl<'hir> Map<'hir> {
             Some(Node::Field(ref f)) => Some(&f.attrs[..]),
             Some(Node::Expr(ref e)) => Some(&*e.attrs),
             Some(Node::Stmt(ref s)) => Some(s.node.attrs()),
+            Some(Node::Arm(ref a)) => Some(&*a.attrs),
             Some(Node::GenericParam(param)) => Some(&param.attrs[..]),
             // Unit/tuple structs/variants take the attributes straight from
             // the struct/variant definition.
@@ -1073,6 +1075,7 @@ impl<'hir> Map<'hir> {
             Some(Node::TraitRef(tr)) => tr.path.span,
             Some(Node::Binding(pat)) => pat.span,
             Some(Node::Pat(pat)) => pat.span,
+            Some(Node::Arm(arm)) => arm.span,
             Some(Node::Block(block)) => block.span,
             Some(Node::Ctor(..)) => match self.find_by_hir_id(
                 self.get_parent_node_by_hir_id(hir_id))
@@ -1288,6 +1291,7 @@ impl<'a> print::State<'a> {
             Node::TraitRef(a)     => self.print_trait_ref(&a),
             Node::Binding(a)      |
             Node::Pat(a)          => self.print_pat(&a),
+            Node::Arm(a)          => self.print_arm(&a),
             Node::Block(a)        => {
                 use syntax::print::pprust::PrintState;
 
@@ -1417,6 +1421,9 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String {
         Some(Node::Pat(_)) => {
             format!("pat {}{}", map.hir_to_pretty_string(id), id_str)
         }
+        Some(Node::Arm(_)) => {
+            format!("arm {}{}", map.hir_to_pretty_string(id), id_str)
+        }
         Some(Node::Block(_)) => {
             format!("block {}{}", map.hir_to_pretty_string(id), id_str)
         }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index f407be4e87b82..43b9487dac582 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1228,6 +1228,9 @@ pub struct Local {
 /// `<pats> (if <guard>) => <body>`.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub struct Arm {
+    #[stable_hasher(ignore)]
+    pub hir_id: HirId,
+    pub span: Span,
     pub attrs: HirVec<Attribute>,
     /// Multiple patterns can be combined with `|`
     pub pats: HirVec<P<Pat>>,
@@ -2656,6 +2659,7 @@ pub enum Node<'hir> {
     TraitRef(&'hir TraitRef),
     Binding(&'hir Pat),
     Pat(&'hir Pat),
+    Arm(&'hir Arm),
     Block(&'hir Block),
     Local(&'hir Local),
     MacroDef(&'hir MacroDef),
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 8a9028e544391..ef9fee5cab694 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1862,7 +1862,7 @@ impl<'a> State<'a> {
         self.ann.post(self, AnnNode::Pat(pat))
     }
 
-    fn print_arm(&mut self, arm: &hir::Arm) -> io::Result<()> {
+    pub fn print_arm(&mut self, arm: &hir::Arm) -> io::Result<()> {
         // I have no idea why this check is necessary, but here it
         // is :(
         if arm.attrs.is_empty() {
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 4b6e7da333081..a2c8558be4643 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -462,6 +462,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             type Region = !;
             type Type = !;
             type DynExistential = !;
+            type Const = !;
 
             fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx> {
                 self.tcx
@@ -488,6 +489,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 Err(NonTrivialPath)
             }
 
+            fn print_const(
+                self,
+                _ct: &'tcx ty::Const<'tcx>,
+            ) -> Result<Self::Const, Self::Error> {
+                Err(NonTrivialPath)
+            }
+
             fn path_crate(
                 self,
                 cnum: CrateNum,
diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs
index 679635bef13e5..8f52ef7a3f3a4 100644
--- a/src/librustc/infer/freshen.rs
+++ b/src/librustc/infer/freshen.rs
@@ -260,7 +260,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
 
             ConstValue::Param(_) |
             ConstValue::Scalar(_) |
-            ConstValue::Slice(..) |
+            ConstValue::Slice { .. } |
             ConstValue::ByRef(..) |
             ConstValue::Unevaluated(..) => {}
         }
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index e713cf8d80553..03acfa4c229cf 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -791,6 +791,7 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
             type Region = ();
             type Type = ();
             type DynExistential = ();
+            type Const = ();
 
             fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
                 self.tcx
@@ -807,7 +808,14 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
             fn print_dyn_existential(
                 self,
                 _predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
-                ) -> Result<Self::DynExistential, Self::Error> {
+            ) -> Result<Self::DynExistential, Self::Error> {
+                Ok(())
+            }
+
+            fn print_const(
+                self,
+                _ct: &'tcx ty::Const<'tcx>,
+            ) -> Result<Self::Const, Self::Error> {
                 Ok(())
             }
 
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index 68b65f9b4a1cc..3682552d22d75 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -849,6 +849,12 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'a, 'tcx> {
         })
     }
 
+    fn visit_arm(&mut self, a: &'tcx hir::Arm) {
+        self.with_lint_attrs(a.hir_id, &a.attrs, |builder| {
+            intravisit::walk_arm(builder, a);
+        })
+    }
+
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
         self.with_lint_attrs(trait_item.hir_id, &trait_item.attrs, |builder| {
             intravisit::walk_trait_item(builder, trait_item);
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 8ef4e9ac8f45f..4f70d72cbffa8 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -119,18 +119,18 @@ impl fmt::Debug for Scope {
 pub enum ScopeData {
     Node,
 
-    // Scope of the call-site for a function or closure
-    // (outlives the arguments as well as the body).
+    /// Scope of the call-site for a function or closure
+    /// (outlives the arguments as well as the body).
     CallSite,
 
-    // Scope of arguments passed to a function or closure
-    // (they outlive its body).
+    /// Scope of arguments passed to a function or closure
+    /// (they outlive its body).
     Arguments,
 
-    // Scope of destructors for temporaries of node-id.
+    /// Scope of destructors for temporaries of node-id.
     Destruction,
 
-    // Scope following a `let id = expr;` binding in a block.
+    /// Scope following a `let id = expr;` binding in a block.
     Remainder(FirstStatementIndex)
 }
 
@@ -152,11 +152,11 @@ newtype_index! {
     ///
     /// * The subscope with `first_statement_index == 1` is scope of `c`,
     ///   and thus does not include EXPR_2, but covers the `...`.
-    pub struct FirstStatementIndex { .. }
+    pub struct FirstStatementIndex {
+        derive [HashStable]
+    }
 }
 
-impl_stable_hash_for!(struct crate::middle::region::FirstStatementIndex { private });
-
 // compilation error if size of `ScopeData` is not the same as a `u32`
 static_assert!(ASSERT_SCOPE_DATA: mem::size_of::<ScopeData>() == 4);
 
@@ -814,6 +814,16 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
 }
 
 fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &'tcx hir::Arm) {
+    let prev_cx = visitor.cx;
+
+    visitor.enter_scope(
+        Scope {
+            id: arm.hir_id.local_id,
+            data: ScopeData::Node,
+        }
+    );
+    visitor.cx.var_parent = visitor.cx.parent;
+
     visitor.terminating_scopes.insert(arm.body.hir_id.local_id);
 
     if let Some(hir::Guard::If(ref expr)) = arm.guard {
@@ -821,6 +831,8 @@ fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &
     }
 
     intravisit::walk_arm(visitor, arm);
+
+    visitor.cx = prev_cx;
 }
 
 fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &'tcx hir::Pat) {
@@ -893,10 +905,6 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
                 terminating(body.hir_id.local_id);
             }
 
-            hir::ExprKind::Match(..) => {
-                visitor.cx.var_parent = visitor.cx.parent;
-            }
-
             hir::ExprKind::DropTemps(ref expr) => {
                 // `DropTemps(expr)` does not denote a conditional scope.
                 // Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`.
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 5c6fc6f49f0f0..9c2fd399ee029 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -38,7 +38,7 @@ impl ErrorHandled {
 }
 
 pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
-pub type ConstEvalResult<'tcx> = Result<ty::Const<'tcx>, ErrorHandled>;
+pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
 
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct ConstEvalErr<'tcx> {
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index 7e45568725f35..d99485f7af632 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -35,14 +35,12 @@ pub enum ConstValue<'tcx> {
     /// Not using the enum `Value` to encode that this must not be `Undef`.
     Scalar(Scalar),
 
-    /// Used only for slices and strings (`&[T]`, `&str`, `*const [T]`, `*mut str`, `Box<str>`,
-    /// etc.).
-    ///
-    /// Empty slices don't necessarily have an address backed by an `AllocId`, thus we also need to
-    /// enable integer pointers. The `Scalar` type covers exactly those two cases. While we could
-    /// create dummy-`AllocId`s, the additional code effort for the conversions doesn't seem worth
-    /// it.
-    Slice(Scalar, u64),
+    /// Used only for `&[u8]` and `&str`
+    Slice {
+        data: &'tcx Allocation,
+        start: usize,
+        end: usize,
+    },
 
     /// An allocation together with a pointer into the allocation.
     /// Invariant: the pointer's `AllocId` resolves to the allocation.
@@ -54,7 +52,7 @@ pub enum ConstValue<'tcx> {
 }
 
 #[cfg(target_arch = "x86_64")]
-static_assert!(CONST_SIZE: ::std::mem::size_of::<ConstValue<'static>>() == 40);
+static_assert!(CONST_SIZE: ::std::mem::size_of::<ConstValue<'static>>() == 32);
 
 impl<'tcx> ConstValue<'tcx> {
     #[inline]
@@ -65,7 +63,7 @@ impl<'tcx> ConstValue<'tcx> {
             ConstValue::Placeholder(_) |
             ConstValue::ByRef(..) |
             ConstValue::Unevaluated(..) |
-            ConstValue::Slice(..) => None,
+            ConstValue::Slice { .. } => None,
             ConstValue::Scalar(val) => Some(val),
         }
     }
@@ -79,14 +77,6 @@ impl<'tcx> ConstValue<'tcx> {
     pub fn try_to_ptr(&self) -> Option<Pointer> {
         self.try_to_scalar()?.to_ptr().ok()
     }
-
-    #[inline]
-    pub fn new_slice(
-        val: Scalar,
-        len: u64,
-    ) -> Self {
-        ConstValue::Slice(val, len)
-    }
 }
 
 /// A `Scalar` represents an immediate, primitive value existing outside of a
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index bd67aabfe8e5f..94a37341baa23 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -9,8 +9,6 @@ use crate::hir::def_id::DefId;
 use crate::hir::{self, InlineAsm as HirInlineAsm};
 use crate::mir::interpret::{ConstValue, InterpError, Scalar};
 use crate::mir::visit::MirVisitable;
-use rustc_apfloat::ieee::{Double, Single};
-use rustc_apfloat::Float;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::dominators::{dominators, Dominators};
 use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
@@ -21,13 +19,13 @@ use rustc_macros::HashStable;
 use crate::rustc_serialize::{self as serialize};
 use smallvec::SmallVec;
 use std::borrow::Cow;
-use std::fmt::{self, Debug, Formatter, Write};
+use std::fmt::{self, Debug, Formatter, Write, Display};
 use std::iter::FusedIterator;
 use std::ops::{Index, IndexMut};
 use std::slice;
 use std::vec::IntoIter;
 use std::{iter, mem, option, u32};
-use syntax::ast::{self, Name};
+use syntax::ast::Name;
 use syntax::symbol::{InternedString, Symbol};
 use syntax_pos::{Span, DUMMY_SP};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
@@ -1655,28 +1653,25 @@ impl<'tcx> TerminatorKind<'tcx> {
                 switch_ty,
                 ..
             } => {
-                let size = ty::tls::with(|tcx| {
+                ty::tls::with(|tcx| {
                     let param_env = ty::ParamEnv::empty();
                     let switch_ty = tcx.lift_to_global(&switch_ty).unwrap();
-                    tcx.layout_of(param_env.and(switch_ty)).unwrap().size
-                });
-                values
-                    .iter()
-                    .map(|&u| {
-                        let mut s = String::new();
-                        let c = ty::Const {
-                            val: ConstValue::Scalar(
-                                Scalar::Bits {
-                                    bits: u,
-                                    size: size.bytes() as u8,
-                                }.into(),
-                            ),
-                            ty: switch_ty,
-                        };
-                        fmt_const_val(&mut s, c).unwrap();
-                        s.into()
-                    }).chain(iter::once("otherwise".into()))
-                    .collect()
+                    let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
+                    values
+                        .iter()
+                        .map(|&u| {
+                            tcx.mk_const(ty::Const {
+                                val: ConstValue::Scalar(
+                                    Scalar::Bits {
+                                        bits: u,
+                                        size: size.bytes() as u8,
+                                    }.into(),
+                                ),
+                                ty: switch_ty,
+                            }).to_string().into()
+                        }).chain(iter::once("otherwise".into()))
+                        .collect()
+                })
             }
             Call {
                 destination: Some(_),
@@ -2332,9 +2327,7 @@ impl<'tcx> Operand<'tcx> {
             span,
             ty,
             user_ty: None,
-            literal: tcx.mk_const(
-                ty::Const::zero_sized(ty),
-            ),
+            literal: ty::Const::zero_sized(tcx, ty),
         })
     }
 
@@ -2828,67 +2821,15 @@ newtype_index! {
 
 impl<'tcx> Debug for Constant<'tcx> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        write!(fmt, "const ")?;
-        fmt_const_val(fmt, *self.literal)
-    }
-}
-/// Write a `ConstValue` in a way closer to the original source code than the `Debug` output.
-pub fn fmt_const_val(f: &mut impl Write, const_val: ty::Const<'_>) -> fmt::Result {
-    use crate::ty::TyKind::*;
-    let value = const_val.val;
-    let ty = const_val.ty;
-    // print some primitives
-    if let ConstValue::Scalar(Scalar::Bits { bits, .. }) = value {
-        match ty.sty {
-            Bool if bits == 0 => return write!(f, "false"),
-            Bool if bits == 1 => return write!(f, "true"),
-            Float(ast::FloatTy::F32) => return write!(f, "{}f32", Single::from_bits(bits)),
-            Float(ast::FloatTy::F64) => return write!(f, "{}f64", Double::from_bits(bits)),
-            Uint(ui) => return write!(f, "{:?}{}", bits, ui),
-            Int(i) => {
-                let bit_width = ty::tls::with(|tcx| {
-                    let ty = tcx.lift_to_global(&ty).unwrap();
-                    tcx.layout_of(ty::ParamEnv::empty().and(ty))
-                        .unwrap()
-                        .size
-                        .bits()
-                });
-                let shift = 128 - bit_width;
-                return write!(f, "{:?}{}", ((bits as i128) << shift) >> shift, i);
-            }
-            Char => return write!(f, "{:?}", ::std::char::from_u32(bits as u32).unwrap()),
-            _ => {}
-        }
+        write!(fmt, "{}", self)
     }
-    // print function definitions
-    if let FnDef(did, _) = ty.sty {
-        return write!(f, "{}", def_path_str(did));
-    }
-    // print string literals
-    if let ConstValue::Slice(ptr, len) = value {
-        if let Scalar::Ptr(ptr) = ptr {
-            if let Ref(_, &ty::TyS { sty: Str, .. }, _) = ty.sty {
-                return ty::tls::with(|tcx| {
-                    let alloc = tcx.alloc_map.lock().get(ptr.alloc_id);
-                    if let Some(interpret::AllocKind::Memory(alloc)) = alloc {
-                        assert_eq!(len as usize as u64, len);
-                        let slice =
-                            &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];
-                        let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
-                        write!(f, "{:?}", s)
-                    } else {
-                        write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len)
-                    }
-                });
-            }
-        }
-    }
-    // just raw dump everything else
-    write!(f, "{:?} : {}", value, ty)
 }
 
-fn def_path_str(def_id: DefId) -> String {
-    ty::tls::with(|tcx| tcx.def_path_str(def_id))
+impl<'tcx> Display for Constant<'tcx> {
+    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+        write!(fmt, "const ")?;
+        write!(fmt, "{}", self.literal)
+    }
 }
 
 impl<'tcx> graph::DirectedGraph for Mir<'tcx> {
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index f05a19372918e..2fbf1ae6198de 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -412,7 +412,6 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
                         };
                         if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
                             let substs = tcx.lift_to_global(&substs).unwrap();
-                            let evaluated = tcx.mk_const(evaluated);
                             let evaluated = evaluated.subst(tcx, substs);
                             return evaluated;
                         }
@@ -426,7 +425,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
                                 promoted: None
                             };
                             if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
-                                return tcx.mk_const(evaluated);
+                                return evaluated;
                             }
                         }
                     }
diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs
index 9940249da8ba9..d09a9c107869b 100644
--- a/src/librustc/traits/query/normalize.rs
+++ b/src/librustc/traits/query/normalize.rs
@@ -202,7 +202,6 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx
                         };
                         if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
                             let substs = tcx.lift_to_global(&substs).unwrap();
-                            let evaluated = tcx.mk_const(evaluated);
                             let evaluated = evaluated.subst(tcx, substs);
                             return evaluated;
                         }
@@ -216,7 +215,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx
                                 promoted: None,
                             };
                             if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
-                                return tcx.mk_const(evaluated);
+                                return evaluated;
                             }
                         }
                     }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index c9fee02f66bbd..8fa1aa015fa0c 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -24,7 +24,7 @@ use crate::middle::lang_items;
 use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault};
 use crate::middle::stability;
 use crate::mir::{self, Mir, interpret, ProjectionKind};
-use crate::mir::interpret::{ConstValue, Allocation};
+use crate::mir::interpret::{ConstValue, Allocation, Scalar};
 use crate::ty::subst::{Kind, InternalSubsts, SubstsRef, Subst};
 use crate::ty::ReprOptions;
 use crate::traits;
@@ -996,7 +996,10 @@ impl<'tcx> CommonConsts<'tcx> {
         };
 
         CommonConsts {
-            err: mk_const(ty::Const::zero_sized(types.err)),
+            err: mk_const(ty::Const {
+                val: ConstValue::Scalar(Scalar::Bits { bits: 0, size: 0 }),
+                ty: types.err,
+            }),
         }
     }
 }
@@ -1810,14 +1813,6 @@ nop_list_lift!{ProjectionKind => ProjectionKind}
 // this is the impl for `&'a InternalSubsts<'a>`
 nop_list_lift!{Kind<'a> => Kind<'tcx>}
 
-impl<'a, 'tcx> Lift<'tcx> for &'a mir::interpret::Allocation {
-    type Lifted = &'tcx mir::interpret::Allocation;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
-        assert!(tcx.global_arenas.const_allocs.in_arena(*self as *const _));
-        Some(unsafe { mem::transmute(*self) })
-    }
-}
-
 pub mod tls {
     use super::{GlobalCtxt, TyCtxt, ptr_eq};
 
@@ -2582,9 +2577,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     #[inline]
     pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
-        self.mk_ty(Array(ty, self.mk_const(
-            ty::Const::from_usize(self.global_tcx(), n)
-        )))
+        self.mk_ty(Array(ty, ty::Const::from_usize(self.global_tcx(), n)))
     }
 
     #[inline]
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index dbf9047f775bf..dae28d51efc2e 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -939,7 +939,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
     fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
         let flags = FlagComputation::for_const(c);
         debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags);
-        flags.intersects(self.flags) || c.super_visit_with(self)
+        flags.intersects(self.flags)
     }
 }
 
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index d1a8a9a34e155..6d7b0926c7ae2 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -19,6 +19,12 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
                                            StableHasherResult};
 
 pub use rustc_target::abi::*;
+use rustc_target::spec::{HasTargetSpec, abi::Abi as SpecAbi};
+use rustc_target::abi::call::{
+    ArgAttribute, ArgAttributes, ArgType, Conv, FnType, IgnoreMode, PassMode, Reg, RegKind
+};
+
+
 
 pub trait IntegerExt {
     fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, signed: bool) -> Ty<'tcx>;
@@ -2259,3 +2265,380 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for LayoutError<'gcx>
         }
     }
 }
+
+pub trait FnTypeExt<'tcx, C>
+where
+    C: LayoutOf<Ty = Ty<'tcx>, TyLayout = TyLayout<'tcx>>
+        + HasDataLayout
+        + HasTargetSpec
+        + HasTyCtxt<'tcx>
+        + HasParamEnv<'tcx>,
+{
+    fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self;
+    fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
+    fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
+    fn new_internal(
+        cx: &C,
+        sig: ty::FnSig<'tcx>,
+        extra_args: &[Ty<'tcx>],
+        mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
+    ) -> Self;
+    fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
+}
+
+impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>>
+where
+    C: LayoutOf<Ty = Ty<'tcx>, TyLayout = TyLayout<'tcx>>
+        + HasDataLayout
+        + HasTargetSpec
+        + HasTyCtxt<'tcx>
+        + HasParamEnv<'tcx>,
+{
+    fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self {
+        let sig = instance.fn_sig(cx.tcx());
+        let sig = cx
+            .tcx()
+            .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+        call::FnType::new(cx, sig, &[])
+    }
+
+    fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
+        call::FnType::new_internal(cx, sig, extra_args, |ty, _| ArgType::new(cx.layout_of(ty)))
+    }
+
+    fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
+        FnTypeExt::new_internal(cx, sig, extra_args, |ty, arg_idx| {
+            let mut layout = cx.layout_of(ty);
+            // Don't pass the vtable, it's not an argument of the virtual fn.
+            // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
+            // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
+            if arg_idx == Some(0) {
+                let fat_pointer_ty = if layout.is_unsized() {
+                    // unsized `self` is passed as a pointer to `self`
+                    // FIXME (mikeyhew) change this to use &own if it is ever added to the language
+                    cx.tcx().mk_mut_ptr(layout.ty)
+                } else {
+                    match layout.abi {
+                        Abi::ScalarPair(..) => (),
+                        _ => bug!("receiver type has unsupported layout: {:?}", layout),
+                    }
+
+                    // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
+                    // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
+                    // elsewhere in the compiler as a method on a `dyn Trait`.
+                    // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
+                    // get a built-in pointer type
+                    let mut fat_pointer_layout = layout;
+                    'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
+                        && !fat_pointer_layout.ty.is_region_ptr()
+                    {
+                        'iter_fields: for i in 0..fat_pointer_layout.fields.count() {
+                            let field_layout = fat_pointer_layout.field(cx, i);
+
+                            if !field_layout.is_zst() {
+                                fat_pointer_layout = field_layout;
+                                continue 'descend_newtypes;
+                            }
+                        }
+
+                        bug!(
+                            "receiver has no non-zero-sized fields {:?}",
+                            fat_pointer_layout
+                        );
+                    }
+
+                    fat_pointer_layout.ty
+                };
+
+                // we now have a type like `*mut RcBox<dyn Trait>`
+                // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
+                // this is understood as a special case elsewhere in the compiler
+                let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit());
+                layout = cx.layout_of(unit_pointer_ty);
+                layout.ty = fat_pointer_ty;
+            }
+            ArgType::new(layout)
+        })
+    }
+
+    fn new_internal(
+        cx: &C,
+        sig: ty::FnSig<'tcx>,
+        extra_args: &[Ty<'tcx>],
+        mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
+    ) -> Self {
+        debug!("FnType::new_internal({:?}, {:?})", sig, extra_args);
+
+        use rustc_target::spec::abi::Abi::*;
+        let conv = match cx.tcx().sess.target.target.adjust_abi(sig.abi) {
+            RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::C,
+
+            // It's the ABI's job to select this, not ours.
+            System => bug!("system abi should be selected elsewhere"),
+
+            Stdcall => Conv::X86Stdcall,
+            Fastcall => Conv::X86Fastcall,
+            Vectorcall => Conv::X86VectorCall,
+            Thiscall => Conv::X86ThisCall,
+            C => Conv::C,
+            Unadjusted => Conv::C,
+            Win64 => Conv::X86_64Win64,
+            SysV64 => Conv::X86_64SysV,
+            Aapcs => Conv::ArmAapcs,
+            PtxKernel => Conv::PtxKernel,
+            Msp430Interrupt => Conv::Msp430Intr,
+            X86Interrupt => Conv::X86Intr,
+            AmdGpuKernel => Conv::AmdGpuKernel,
+
+            // These API constants ought to be more specific...
+            Cdecl => Conv::C,
+        };
+
+        let mut inputs = sig.inputs();
+        let extra_args = if sig.abi == RustCall {
+            assert!(!sig.c_variadic && extra_args.is_empty());
+
+            match sig.inputs().last().unwrap().sty {
+                ty::Tuple(tupled_arguments) => {
+                    inputs = &sig.inputs()[0..sig.inputs().len() - 1];
+                    tupled_arguments.iter().map(|k| k.expect_ty()).collect()
+                }
+                _ => {
+                    bug!(
+                        "argument to function with \"rust-call\" ABI \
+                         is not a tuple"
+                    );
+                }
+            }
+        } else {
+            assert!(sig.c_variadic || extra_args.is_empty());
+            extra_args.to_vec()
+        };
+
+        let target = &cx.tcx().sess.target.target;
+        let win_x64_gnu =
+            target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu";
+        let linux_s390x =
+            target.target_os == "linux" && target.arch == "s390x" && target.target_env == "gnu";
+        let linux_sparc64 =
+            target.target_os == "linux" && target.arch == "sparc64" && target.target_env == "gnu";
+        let rust_abi = match sig.abi {
+            RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
+            _ => false,
+        };
+
+        // Handle safe Rust thin and fat pointers.
+        let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
+                                      scalar: &Scalar,
+                                      layout: TyLayout<'tcx>,
+                                      offset: Size,
+                                      is_return: bool| {
+            // Booleans are always an i1 that needs to be zero-extended.
+            if scalar.is_bool() {
+                attrs.set(ArgAttribute::ZExt);
+                return;
+            }
+
+            // Only pointer types handled below.
+            if scalar.value != Pointer {
+                return;
+            }
+
+            if scalar.valid_range.start() < scalar.valid_range.end() {
+                if *scalar.valid_range.start() > 0 {
+                    attrs.set(ArgAttribute::NonNull);
+                }
+            }
+
+            if let Some(pointee) = layout.pointee_info_at(cx, offset) {
+                if let Some(kind) = pointee.safe {
+                    attrs.pointee_size = pointee.size;
+                    attrs.pointee_align = Some(pointee.align);
+
+                    // `Box` pointer parameters never alias because ownership is transferred
+                    // `&mut` pointer parameters never alias other parameters,
+                    // or mutable global data
+                    //
+                    // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
+                    // and can be marked as both `readonly` and `noalias`, as
+                    // LLVM's definition of `noalias` is based solely on memory
+                    // dependencies rather than pointer equality
+                    let no_alias = match kind {
+                        PointerKind::Shared => false,
+                        PointerKind::UniqueOwned => true,
+                        PointerKind::Frozen | PointerKind::UniqueBorrowed => !is_return,
+                    };
+                    if no_alias {
+                        attrs.set(ArgAttribute::NoAlias);
+                    }
+
+                    if kind == PointerKind::Frozen && !is_return {
+                        attrs.set(ArgAttribute::ReadOnly);
+                    }
+                }
+            }
+        };
+
+        // Store the index of the last argument. This is useful for working with
+        // C-compatible variadic arguments.
+        let last_arg_idx = if sig.inputs().is_empty() {
+            None
+        } else {
+            Some(sig.inputs().len() - 1)
+        };
+
+        let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
+            let is_return = arg_idx.is_none();
+            let mut arg = mk_arg_type(ty, arg_idx);
+            if arg.layout.is_zst() {
+                // For some forsaken reason, x86_64-pc-windows-gnu
+                // doesn't ignore zero-sized struct arguments.
+                // The same is true for s390x-unknown-linux-gnu
+                // and sparc64-unknown-linux-gnu.
+                if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) {
+                    arg.mode = PassMode::Ignore(IgnoreMode::Zst);
+                }
+            }
+
+            // If this is a C-variadic function, this is not the return value,
+            // and there is one or more fixed arguments; ensure that the `VaList`
+            // is ignored as an argument.
+            if sig.c_variadic {
+                match (last_arg_idx, arg_idx) {
+                    (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => {
+                        let va_list_did = match cx.tcx().lang_items().va_list() {
+                            Some(did) => did,
+                            None => bug!("`va_list` lang item required for C-variadic functions"),
+                        };
+                        match ty.sty {
+                            ty::Adt(def, _) if def.did == va_list_did => {
+                                // This is the "spoofed" `VaList`. Set the arguments mode
+                                // so that it will be ignored.
+                                arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs);
+                            }
+                            _ => (),
+                        }
+                    }
+                    _ => {}
+                }
+            }
+
+            // FIXME(eddyb) other ABIs don't have logic for scalar pairs.
+            if !is_return && rust_abi {
+                if let Abi::ScalarPair(ref a, ref b) = arg.layout.abi {
+                    let mut a_attrs = ArgAttributes::new();
+                    let mut b_attrs = ArgAttributes::new();
+                    adjust_for_rust_scalar(&mut a_attrs, a, arg.layout, Size::ZERO, false);
+                    adjust_for_rust_scalar(
+                        &mut b_attrs,
+                        b,
+                        arg.layout,
+                        a.value.size(cx).align_to(b.value.align(cx).abi),
+                        false,
+                    );
+                    arg.mode = PassMode::Pair(a_attrs, b_attrs);
+                    return arg;
+                }
+            }
+
+            if let Abi::Scalar(ref scalar) = arg.layout.abi {
+                if let PassMode::Direct(ref mut attrs) = arg.mode {
+                    adjust_for_rust_scalar(attrs, scalar, arg.layout, Size::ZERO, is_return);
+                }
+            }
+
+            arg
+        };
+
+        let mut fn_ty = FnType {
+            ret: arg_of(sig.output(), None),
+            args: inputs
+                .iter()
+                .cloned()
+                .chain(extra_args)
+                .enumerate()
+                .map(|(i, ty)| arg_of(ty, Some(i)))
+                .collect(),
+            c_variadic: sig.c_variadic,
+            conv,
+        };
+        fn_ty.adjust_for_abi(cx, sig.abi);
+        fn_ty
+    }
+
+    fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) {
+        if abi == SpecAbi::Unadjusted {
+            return;
+        }
+
+        if abi == SpecAbi::Rust
+            || abi == SpecAbi::RustCall
+            || abi == SpecAbi::RustIntrinsic
+            || abi == SpecAbi::PlatformIntrinsic
+        {
+            let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| {
+                if arg.is_ignore() {
+                    return;
+                }
+
+                match arg.layout.abi {
+                    Abi::Aggregate { .. } => {}
+
+                    // This is a fun case! The gist of what this is doing is
+                    // that we want callers and callees to always agree on the
+                    // ABI of how they pass SIMD arguments. If we were to *not*
+                    // make these arguments indirect then they'd be immediates
+                    // in LLVM, which means that they'd used whatever the
+                    // appropriate ABI is for the callee and the caller. That
+                    // means, for example, if the caller doesn't have AVX
+                    // enabled but the callee does, then passing an AVX argument
+                    // across this boundary would cause corrupt data to show up.
+                    //
+                    // This problem is fixed by unconditionally passing SIMD
+                    // arguments through memory between callers and callees
+                    // which should get them all to agree on ABI regardless of
+                    // target feature sets. Some more information about this
+                    // issue can be found in #44367.
+                    //
+                    // Note that the platform intrinsic ABI is exempt here as
+                    // that's how we connect up to LLVM and it's unstable
+                    // anyway, we control all calls to it in libstd.
+                    Abi::Vector { .. }
+                        if abi != SpecAbi::PlatformIntrinsic
+                            && cx.tcx().sess.target.target.options.simd_types_indirect =>
+                    {
+                        arg.make_indirect();
+                        return;
+                    }
+
+                    _ => return,
+                }
+
+                let size = arg.layout.size;
+                if arg.layout.is_unsized() || size > Pointer.size(cx) {
+                    arg.make_indirect();
+                } else {
+                    // We want to pass small aggregates as immediates, but using
+                    // a LLVM aggregate type for this leads to bad optimizations,
+                    // so we pick an appropriately sized integer type instead.
+                    arg.cast_to(Reg {
+                        kind: RegKind::Integer,
+                        size,
+                    });
+                }
+            };
+            fixup(&mut self.ret);
+            for arg in &mut self.args {
+                fixup(arg);
+            }
+            if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
+                attrs.set(ArgAttribute::StructRet);
+            }
+            return;
+        }
+
+        if let Err(msg) = self.adjust_for_cabi(cx, abi) {
+            cx.tcx().sess.fatal(&msg);
+        }
+    }
+}
diff --git a/src/librustc/ty/print/mod.rs b/src/librustc/ty/print/mod.rs
index d5d4f64844463..53d4466cfef68 100644
--- a/src/librustc/ty/print/mod.rs
+++ b/src/librustc/ty/print/mod.rs
@@ -31,6 +31,7 @@ pub trait Printer<'gcx: 'tcx, 'tcx>: Sized {
     type Region;
     type Type;
     type DynExistential;
+    type Const;
 
     fn tcx(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
 
@@ -66,6 +67,11 @@ pub trait Printer<'gcx: 'tcx, 'tcx>: Sized {
         predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
     ) -> Result<Self::DynExistential, Self::Error>;
 
+    fn print_const(
+        self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<Self::Const, Self::Error>;
+
     fn path_crate(
         self,
         cnum: CrateNum,
@@ -325,3 +331,11 @@ impl<'gcx: 'tcx, 'tcx, P: Printer<'gcx, 'tcx>> Print<'gcx, 'tcx, P>
         cx.print_dyn_existential(self)
     }
 }
+
+impl<'gcx: 'tcx, 'tcx, P: Printer<'gcx, 'tcx>> Print<'gcx, 'tcx, P> for &'tcx ty::Const<'tcx> {
+    type Output = P::Const;
+    type Error = P::Error;
+    fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
+        cx.print_const(self)
+    }
+}
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 8e98d4d85b9cc..6e3f283a44338 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1,13 +1,17 @@
 use crate::hir;
-use crate::hir::def::Namespace;
+use crate::hir::def::{Namespace, DefKind};
 use crate::hir::map::{DefPathData, DisambiguatedDefPathData};
 use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
 use crate::middle::region;
 use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
 use crate::ty::subst::{Kind, Subst, UnpackedKind};
-use crate::mir::interpret::ConstValue;
+use crate::ty::layout::Size;
+use crate::mir::interpret::{ConstValue, sign_extend, Scalar};
 use syntax::symbol::{keywords, Symbol};
+use syntax::ast;
+use rustc_apfloat::ieee::{Double, Single};
+use rustc_apfloat::Float;
 
 use rustc_target::spec::abi::Abi;
 use syntax::symbol::InternedString;
@@ -171,6 +175,7 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
         Region = Self,
         Type = Self,
         DynExistential = Self,
+        Const = Self,
     > +
     fmt::Write
 {
@@ -663,12 +668,10 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
             },
             ty::Array(ty, sz) => {
                 p!(write("["), print(ty), write("; "));
-                match sz.val {
-                    ConstValue::Unevaluated(..) |
-                    ConstValue::Infer(..) => p!(write("_")),
-                    ConstValue::Param(ParamConst { name, .. }) =>
-                        p!(write("{}", name)),
-                    _ => p!(write("{}", sz.unwrap_usize(self.tcx()))),
+                if let Some(n) = sz.assert_usize(self.tcx()) {
+                    p!(write("{}", n));
+                } else {
+                    p!(write("_"));
                 }
                 p!(write("]"))
             }
@@ -806,6 +809,113 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
 
         Ok(self)
     }
+
+    fn pretty_print_const(
+        mut self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<Self::Const, Self::Error> {
+        define_scoped_cx!(self);
+
+        let u8 = self.tcx().types.u8;
+        if let ty::FnDef(did, substs) = ct.ty.sty {
+            p!(print_value_path(did, substs));
+            return Ok(self);
+        }
+        if let ConstValue::Unevaluated(did, substs) = ct.val {
+            match self.tcx().def_kind(did) {
+                | Some(DefKind::Static)
+                | Some(DefKind::Const)
+                | Some(DefKind::AssociatedConst) => p!(print_value_path(did, substs)),
+                _ => if did.is_local() {
+                    let span = self.tcx().def_span(did);
+                    if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
+                        p!(write("{}", snip))
+                    } else {
+                        p!(write("_: "), print(ct.ty))
+                    }
+                } else {
+                    p!(write("_: "), print(ct.ty))
+                },
+            }
+            return Ok(self);
+        }
+        if let ConstValue::Infer(..) = ct.val {
+            p!(write("_: "), print(ct.ty));
+            return Ok(self);
+        }
+        if let ConstValue::Param(ParamConst { name, .. }) = ct.val {
+            p!(write("{}", name));
+            return Ok(self);
+        }
+        if let ConstValue::Scalar(Scalar::Bits { bits, .. }) = ct.val {
+            match ct.ty.sty {
+                ty::Bool => {
+                    p!(write("{}", if bits == 0 { "false" } else { "true" }));
+                    return Ok(self);
+                },
+                ty::Float(ast::FloatTy::F32) => {
+                    p!(write("{}f32", Single::from_bits(bits)));
+                    return Ok(self);
+                },
+                ty::Float(ast::FloatTy::F64) => {
+                    p!(write("{}f64", Double::from_bits(bits)));
+                    return Ok(self);
+                },
+                ty::Uint(ui) => {
+                    p!(write("{}{}", bits, ui));
+                    return Ok(self);
+                },
+                ty::Int(i) =>{
+                    let ty = self.tcx().lift_to_global(&ct.ty).unwrap();
+                    let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty))
+                        .unwrap()
+                        .size;
+                    p!(write("{}{}", sign_extend(bits, size) as i128, i));
+                    return Ok(self);
+                },
+                ty::Char => {
+                    p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap()));
+                    return Ok(self);
+                }
+                _ => {},
+            }
+        }
+        if let ty::Ref(_, ref_ty, _) = ct.ty.sty {
+            let byte_str = match (ct.val, &ref_ty.sty) {
+                (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => {
+                    let n = n.unwrap_usize(self.tcx());
+                    Some(self.tcx()
+                        .alloc_map.lock()
+                        .unwrap_memory(ptr.alloc_id)
+                        .get_bytes(&self.tcx(), ptr, Size::from_bytes(n)).unwrap())
+                },
+                (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => {
+                    Some(&data.bytes[start..end])
+                },
+                (ConstValue::Slice { data, start, end }, ty::Str) => {
+                    let slice = &data.bytes[start..end];
+                    let s = ::std::str::from_utf8(slice)
+                        .expect("non utf8 str from miri");
+                    p!(write("{:?}", s));
+                    return Ok(self);
+                },
+                _ => None,
+            };
+            if let Some(byte_str) = byte_str {
+                p!(write("b\""));
+                for &c in byte_str {
+                    for e in std::ascii::escape_default(c) {
+                        self.write_char(e as char)?;
+                    }
+                }
+                p!(write("\""));
+                return Ok(self);
+            }
+        }
+        p!(write("{:?} : ", ct.val), print(ct.ty));
+
+        Ok(self)
+    }
 }
 
 // HACK(eddyb) boxed to avoid moving around a large struct by-value.
@@ -898,6 +1008,7 @@ impl<F: fmt::Write> Printer<'gcx, 'tcx> for FmtPrinter<'_, 'gcx, 'tcx, F> {
     type Region = Self;
     type Type = Self;
     type DynExistential = Self;
+    type Const = Self;
 
     fn tcx(&'a self) -> TyCtxt<'a, 'gcx, 'tcx> {
         self.tcx
@@ -973,6 +1084,13 @@ impl<F: fmt::Write> Printer<'gcx, 'tcx> for FmtPrinter<'_, 'gcx, 'tcx, F> {
         self.pretty_print_dyn_existential(predicates)
     }
 
+    fn print_const(
+        self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<Self::Const, Self::Error> {
+        self.pretty_print_const(ct)
+    }
+
     fn path_crate(
         mut self,
         cnum: CrateNum,
@@ -1443,6 +1561,7 @@ impl fmt::Display for ty::RegionKind {
 forward_display_to_print! {
     Ty<'tcx>,
     &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
+    &'tcx ty::Const<'tcx>,
 
     // HACK(eddyb) these are exhaustive instead of generic,
     // because `for<'gcx: 'tcx, 'tcx>` isn't possible yet.
@@ -1532,15 +1651,6 @@ define_print_and_forward_display! {
         p!(print_def_path(self.def_id, self.substs));
     }
 
-    &'tcx ty::Const<'tcx> {
-        match self.val {
-            ConstValue::Unevaluated(..) |
-            ConstValue::Infer(..) => p!(write("_")),
-            ConstValue::Param(ParamConst { name, .. }) => p!(write("{}", name)),
-            _ => p!(write("{:?}", self)),
-        }
-    }
-
     ty::ParamTy {
         p!(write("{}", self.name))
     }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index cf04d6eac3ae0..0daa567052d56 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -6,7 +6,7 @@
 use crate::hir::def::Namespace;
 use crate::mir::ProjectionKind;
 use crate::mir::interpret::ConstValue;
-use crate::ty::{self, Lift, Ty, TyCtxt, ConstVid, InferConst};
+use crate::ty::{self, Lift, Ty, TyCtxt, InferConst};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use crate::ty::print::{FmtPrinter, Printer};
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@@ -14,7 +14,6 @@ use smallvec::SmallVec;
 use crate::mir::interpret;
 
 use std::fmt;
-use std::marker::PhantomData;
 use std::rc::Rc;
 
 impl fmt::Debug for ty::GenericParamDef {
@@ -788,16 +787,6 @@ BraceStructLiftImpl! {
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for ConstVid<'a> {
-    type Lifted = ConstVid<'tcx>;
-    fn lift_to_tcx<'b, 'gcx>(&self, _: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
-        Some(ConstVid {
-            index: self.index,
-            phantom: PhantomData,
-        })
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // TypeFoldable implementations.
 //
@@ -1356,7 +1345,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
             ConstValue::Param(p) => ConstValue::Param(p.fold_with(folder)),
             ConstValue::Placeholder(p) => ConstValue::Placeholder(p),
             ConstValue::Scalar(a) => ConstValue::Scalar(a),
-            ConstValue::Slice(a, b) => ConstValue::Slice(a, b),
+            ConstValue::Slice { data, start, end } => ConstValue::Slice { data, start, end },
             ConstValue::Unevaluated(did, substs)
                 => ConstValue::Unevaluated(did, substs.fold_with(folder)),
         }
@@ -1369,7 +1358,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
             ConstValue::Param(p) => p.visit_with(visitor),
             ConstValue::Placeholder(_) => false,
             ConstValue::Scalar(_) => false,
-            ConstValue::Slice(..) => false,
+            ConstValue::Slice { .. } => false,
             ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor),
         }
     }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 760f3d60d0571..75bb60674e7c5 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -2207,18 +2207,19 @@ pub struct Const<'tcx> {
 }
 
 #[cfg(target_arch = "x86_64")]
-static_assert!(CONST_SIZE: ::std::mem::size_of::<Const<'static>>() == 48);
+static_assert!(CONST_SIZE: ::std::mem::size_of::<Const<'static>>() == 40);
 
 impl<'tcx> Const<'tcx> {
     #[inline]
     pub fn from_scalar(
+        tcx: TyCtxt<'_, '_, 'tcx>,
         val: Scalar,
         ty: Ty<'tcx>,
-    ) -> Self {
-        Self {
+    ) -> &'tcx Self {
+        tcx.mk_const(Self {
             val: ConstValue::Scalar(val),
             ty,
-        }
+        })
     }
 
     #[inline]
@@ -2226,28 +2227,28 @@ impl<'tcx> Const<'tcx> {
         tcx: TyCtxt<'_, '_, 'tcx>,
         bits: u128,
         ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
-    ) -> Self {
+    ) -> &'tcx Self {
         let ty = tcx.lift_to_global(&ty).unwrap();
         let size = tcx.layout_of(ty).unwrap_or_else(|e| {
             panic!("could not compute layout for {:?}: {:?}", ty, e)
         }).size;
         let truncated = truncate(bits, size);
         assert_eq!(truncated, bits, "from_bits called with untruncated value");
-        Self::from_scalar(Scalar::Bits { bits, size: size.bytes() as u8 }, ty.value)
+        Self::from_scalar(tcx, Scalar::Bits { bits, size: size.bytes() as u8 }, ty.value)
     }
 
     #[inline]
-    pub fn zero_sized(ty: Ty<'tcx>) -> Self {
-        Self::from_scalar(Scalar::Bits { bits: 0, size: 0 }, ty)
+    pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
+        Self::from_scalar(tcx, Scalar::Bits { bits: 0, size: 0 }, ty)
     }
 
     #[inline]
-    pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> Self {
+    pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> &'tcx Self {
         Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool))
     }
 
     #[inline]
-    pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> Self {
+    pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self {
         Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
     }
 
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index 70d184240fccd..38d4b7e3f9d85 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -11,9 +11,9 @@ use rustc_target::abi::call::ArgType;
 
 use rustc_codegen_ssa::traits::*;
 
-use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayout, Abi as LayoutAbi};
-use rustc::ty::{self, Ty, Instance};
-use rustc::ty::layout::{self, PointerKind};
+use rustc_target::abi::{HasDataLayout, LayoutOf};
+use rustc::ty::{Ty};
+use rustc::ty::layout::{self};
 
 use libc::c_uint;
 
@@ -294,23 +294,7 @@ impl ArgTypeMethods<'tcx> for Builder<'a, 'll, 'tcx> {
     }
 }
 
-pub trait FnTypeExt<'tcx> {
-    fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self;
-    fn new(cx: &CodegenCx<'ll, 'tcx>,
-           sig: ty::FnSig<'tcx>,
-           extra_args: &[Ty<'tcx>]) -> Self;
-    fn new_vtable(cx: &CodegenCx<'ll, 'tcx>,
-                  sig: ty::FnSig<'tcx>,
-                  extra_args: &[Ty<'tcx>]) -> Self;
-    fn new_internal(
-        cx: &CodegenCx<'ll, 'tcx>,
-        sig: ty::FnSig<'tcx>,
-        extra_args: &[Ty<'tcx>],
-        mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
-    ) -> Self;
-    fn adjust_for_abi(&mut self,
-                      cx: &CodegenCx<'ll, 'tcx>,
-                      abi: Abi);
+pub trait FnTypeLlvmExt<'tcx> {
     fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
     fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
     fn llvm_cconv(&self) -> llvm::CallConv;
@@ -318,356 +302,7 @@ pub trait FnTypeExt<'tcx> {
     fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
 }
 
-impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
-    fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self {
-        let sig = instance.fn_sig(cx.tcx);
-        let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
-        FnType::new(cx, sig, &[])
-    }
-
-    fn new(cx: &CodegenCx<'ll, 'tcx>,
-           sig: ty::FnSig<'tcx>,
-           extra_args: &[Ty<'tcx>]) -> Self {
-        FnType::new_internal(cx, sig, extra_args, |ty, _| {
-            ArgType::new(cx.layout_of(ty))
-        })
-    }
-
-    fn new_vtable(cx: &CodegenCx<'ll, 'tcx>,
-                  sig: ty::FnSig<'tcx>,
-                  extra_args: &[Ty<'tcx>]) -> Self {
-        FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| {
-            let mut layout = cx.layout_of(ty);
-            // Don't pass the vtable, it's not an argument of the virtual fn.
-            // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
-            // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
-            if arg_idx == Some(0) {
-                let fat_pointer_ty = if layout.is_unsized() {
-                    // unsized `self` is passed as a pointer to `self`
-                    // FIXME (mikeyhew) change this to use &own if it is ever added to the language
-                    cx.tcx.mk_mut_ptr(layout.ty)
-                } else {
-                    match layout.abi {
-                        LayoutAbi::ScalarPair(..) => (),
-                        _ => bug!("receiver type has unsupported layout: {:?}", layout)
-                    }
-
-                    // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
-                    // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
-                    // elsewhere in the compiler as a method on a `dyn Trait`.
-                    // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
-                    // get a built-in pointer type
-                    let mut fat_pointer_layout = layout;
-                    'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
-                        && !fat_pointer_layout.ty.is_region_ptr()
-                    {
-                        'iter_fields: for i in 0..fat_pointer_layout.fields.count() {
-                            let field_layout = fat_pointer_layout.field(cx, i);
-
-                            if !field_layout.is_zst() {
-                                fat_pointer_layout = field_layout;
-                                continue 'descend_newtypes
-                            }
-                        }
-
-                        bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
-                    }
-
-                    fat_pointer_layout.ty
-                };
-
-                // we now have a type like `*mut RcBox<dyn Trait>`
-                // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
-                // this is understood as a special case elsewhere in the compiler
-                let unit_pointer_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_unit());
-                layout = cx.layout_of(unit_pointer_ty);
-                layout.ty = fat_pointer_ty;
-            }
-            ArgType::new(layout)
-        })
-    }
-
-    fn new_internal(
-        cx: &CodegenCx<'ll, 'tcx>,
-        sig: ty::FnSig<'tcx>,
-        extra_args: &[Ty<'tcx>],
-        mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
-    ) -> Self {
-        debug!("FnType::new_internal({:?}, {:?})", sig, extra_args);
-
-        use self::Abi::*;
-        let conv = match cx.sess().target.target.adjust_abi(sig.abi) {
-            RustIntrinsic | PlatformIntrinsic |
-            Rust | RustCall => Conv::C,
-
-            // It's the ABI's job to select this, not ours.
-            System => bug!("system abi should be selected elsewhere"),
-
-            Stdcall => Conv::X86Stdcall,
-            Fastcall => Conv::X86Fastcall,
-            Vectorcall => Conv::X86VectorCall,
-            Thiscall => Conv::X86ThisCall,
-            C => Conv::C,
-            Unadjusted => Conv::C,
-            Win64 => Conv::X86_64Win64,
-            SysV64 => Conv::X86_64SysV,
-            Aapcs => Conv::ArmAapcs,
-            PtxKernel => Conv::PtxKernel,
-            Msp430Interrupt => Conv::Msp430Intr,
-            X86Interrupt => Conv::X86Intr,
-            AmdGpuKernel => Conv::AmdGpuKernel,
-
-            // These API constants ought to be more specific...
-            Cdecl => Conv::C,
-        };
-
-        let mut inputs = sig.inputs();
-        let extra_args = if sig.abi == RustCall {
-            assert!(!sig.c_variadic && extra_args.is_empty());
-
-            match sig.inputs().last().unwrap().sty {
-                ty::Tuple(tupled_arguments) => {
-                    inputs = &sig.inputs()[0..sig.inputs().len() - 1];
-                    tupled_arguments.iter().map(|k| k.expect_ty()).collect()
-                }
-                _ => {
-                    bug!("argument to function with \"rust-call\" ABI \
-                          is not a tuple");
-                }
-            }
-        } else {
-            assert!(sig.c_variadic || extra_args.is_empty());
-            extra_args.to_vec()
-        };
-
-        let target = &cx.sess().target.target;
-        let win_x64_gnu = target.target_os == "windows"
-                       && target.arch == "x86_64"
-                       && target.target_env == "gnu";
-        let linux_s390x = target.target_os == "linux"
-                       && target.arch == "s390x"
-                       && target.target_env == "gnu";
-        let linux_sparc64 = target.target_os == "linux"
-                       && target.arch == "sparc64"
-                       && target.target_env == "gnu";
-        let rust_abi = match sig.abi {
-            RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
-            _ => false
-        };
-
-        // Handle safe Rust thin and fat pointers.
-        let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
-                                      scalar: &layout::Scalar,
-                                      layout: TyLayout<'tcx, Ty<'tcx>>,
-                                      offset: Size,
-                                      is_return: bool| {
-            // Booleans are always an i1 that needs to be zero-extended.
-            if scalar.is_bool() {
-                attrs.set(ArgAttribute::ZExt);
-                return;
-            }
-
-            // Only pointer types handled below.
-            if scalar.value != layout::Pointer {
-                return;
-            }
-
-            if scalar.valid_range.start() < scalar.valid_range.end() {
-                if *scalar.valid_range.start() > 0 {
-                    attrs.set(ArgAttribute::NonNull);
-                }
-            }
-
-            if let Some(pointee) = layout.pointee_info_at(cx, offset) {
-                if let Some(kind) = pointee.safe {
-                    attrs.pointee_size = pointee.size;
-                    attrs.pointee_align = Some(pointee.align);
-
-                    // `Box` pointer parameters never alias because ownership is transferred
-                    // `&mut` pointer parameters never alias other parameters,
-                    // or mutable global data
-                    //
-                    // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
-                    // and can be marked as both `readonly` and `noalias`, as
-                    // LLVM's definition of `noalias` is based solely on memory
-                    // dependencies rather than pointer equality
-                    let no_alias = match kind {
-                        PointerKind::Shared => false,
-                        PointerKind::UniqueOwned => true,
-                        PointerKind::Frozen |
-                        PointerKind::UniqueBorrowed => !is_return
-                    };
-                    if no_alias {
-                        attrs.set(ArgAttribute::NoAlias);
-                    }
-
-                    if kind == PointerKind::Frozen && !is_return {
-                        attrs.set(ArgAttribute::ReadOnly);
-                    }
-                }
-            }
-        };
-
-        // Store the index of the last argument. This is useful for working with
-        // C-compatible variadic arguments.
-        let last_arg_idx = if sig.inputs().is_empty() {
-            None
-        } else {
-            Some(sig.inputs().len() - 1)
-        };
-
-        let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
-            let is_return = arg_idx.is_none();
-            let mut arg = mk_arg_type(ty, arg_idx);
-            if arg.layout.is_zst() {
-                // For some forsaken reason, x86_64-pc-windows-gnu
-                // doesn't ignore zero-sized struct arguments.
-                // The same is true for s390x-unknown-linux-gnu
-                // and sparc64-unknown-linux-gnu.
-                if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) {
-                    arg.mode = PassMode::Ignore(IgnoreMode::Zst);
-                }
-            }
-
-            // If this is a C-variadic function, this is not the return value,
-            // and there is one or more fixed arguments; ensure that the `VaList`
-            // is ignored as an argument.
-            if sig.c_variadic {
-                match (last_arg_idx, arg_idx) {
-                    (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => {
-                        let va_list_did = match cx.tcx.lang_items().va_list() {
-                            Some(did) => did,
-                            None => bug!("`va_list` lang item required for C-variadic functions"),
-                        };
-                        match ty.sty {
-                            ty::Adt(def, _) if def.did == va_list_did => {
-                                // This is the "spoofed" `VaList`. Set the arguments mode
-                                // so that it will be ignored.
-                                arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs);
-                            },
-                            _ => (),
-                        }
-                    }
-                    _ => {}
-                }
-            }
-
-            // FIXME(eddyb) other ABIs don't have logic for scalar pairs.
-            if !is_return && rust_abi {
-                if let layout::Abi::ScalarPair(ref a, ref b) = arg.layout.abi {
-                    let mut a_attrs = ArgAttributes::new();
-                    let mut b_attrs = ArgAttributes::new();
-                    adjust_for_rust_scalar(&mut a_attrs,
-                                           a,
-                                           arg.layout,
-                                           Size::ZERO,
-                                           false);
-                    adjust_for_rust_scalar(&mut b_attrs,
-                                           b,
-                                           arg.layout,
-                                           a.value.size(cx).align_to(b.value.align(cx).abi),
-                                           false);
-                    arg.mode = PassMode::Pair(a_attrs, b_attrs);
-                    return arg;
-                }
-            }
-
-            if let layout::Abi::Scalar(ref scalar) = arg.layout.abi {
-                if let PassMode::Direct(ref mut attrs) = arg.mode {
-                    adjust_for_rust_scalar(attrs,
-                                           scalar,
-                                           arg.layout,
-                                           Size::ZERO,
-                                           is_return);
-                }
-            }
-
-            arg
-        };
-
-        let mut fn_ty = FnType {
-            ret: arg_of(sig.output(), None),
-            args: inputs.iter().cloned().chain(extra_args).enumerate().map(|(i, ty)| {
-                arg_of(ty, Some(i))
-            }).collect(),
-            c_variadic: sig.c_variadic,
-            conv,
-        };
-        fn_ty.adjust_for_abi(cx, sig.abi);
-        fn_ty
-    }
-
-    fn adjust_for_abi(&mut self,
-                      cx: &CodegenCx<'ll, 'tcx>,
-                      abi: Abi) {
-        if abi == Abi::Unadjusted { return }
-
-        if abi == Abi::Rust || abi == Abi::RustCall ||
-           abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
-            let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| {
-                if arg.is_ignore() { return; }
-
-                match arg.layout.abi {
-                    layout::Abi::Aggregate { .. } => {}
-
-                    // This is a fun case! The gist of what this is doing is
-                    // that we want callers and callees to always agree on the
-                    // ABI of how they pass SIMD arguments. If we were to *not*
-                    // make these arguments indirect then they'd be immediates
-                    // in LLVM, which means that they'd used whatever the
-                    // appropriate ABI is for the callee and the caller. That
-                    // means, for example, if the caller doesn't have AVX
-                    // enabled but the callee does, then passing an AVX argument
-                    // across this boundary would cause corrupt data to show up.
-                    //
-                    // This problem is fixed by unconditionally passing SIMD
-                    // arguments through memory between callers and callees
-                    // which should get them all to agree on ABI regardless of
-                    // target feature sets. Some more information about this
-                    // issue can be found in #44367.
-                    //
-                    // Note that the platform intrinsic ABI is exempt here as
-                    // that's how we connect up to LLVM and it's unstable
-                    // anyway, we control all calls to it in libstd.
-                    layout::Abi::Vector { .. }
-                        if abi != Abi::PlatformIntrinsic &&
-                            cx.sess().target.target.options.simd_types_indirect =>
-                    {
-                        arg.make_indirect();
-                        return
-                    }
-
-                    _ => return
-                }
-
-                let size = arg.layout.size;
-                if arg.layout.is_unsized() || size > layout::Pointer.size(cx) {
-                    arg.make_indirect();
-                } else {
-                    // We want to pass small aggregates as immediates, but using
-                    // a LLVM aggregate type for this leads to bad optimizations,
-                    // so we pick an appropriately sized integer type instead.
-                    arg.cast_to(Reg {
-                        kind: RegKind::Integer,
-                        size
-                    });
-                }
-            };
-            fixup(&mut self.ret);
-            for arg in &mut self.args {
-                fixup(arg);
-            }
-            if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
-                attrs.set(ArgAttribute::StructRet);
-            }
-            return;
-        }
-
-        if let Err(msg) = self.adjust_for_cabi(cx, abi) {
-            cx.sess().fatal(&msg);
-        }
-    }
-
+impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
     fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
         let args_capacity: usize = self.args.iter().map(|arg|
             if arg.pad.is_some() { 1 } else { 0 } +
@@ -836,22 +471,6 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
     }
 }
 
-impl AbiMethods<'tcx> for CodegenCx<'ll, 'tcx> {
-    fn new_fn_type(&self, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>> {
-        FnType::new(&self, sig, extra_args)
-    }
-    fn new_vtable(
-        &self,
-        sig: ty::FnSig<'tcx>,
-        extra_args: &[Ty<'tcx>]
-    ) -> FnType<'tcx, Ty<'tcx>> {
-        FnType::new_vtable(&self, sig, extra_args)
-    }
-    fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>> {
-        FnType::of_instance(&self, instance)
-    }
-}
-
 impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
     fn apply_attrs_callsite(
         &mut self,
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index bc2bb97a19e54..48808eea3045e 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -18,6 +18,7 @@ use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::base::to_immediate;
 use rustc_codegen_ssa::mir::operand::{OperandValue, OperandRef};
 use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_target::spec::{HasTargetSpec, Target};
 use std::borrow::Cow;
 use std::ops::{Deref, Range};
 use std::ptr;
@@ -72,6 +73,12 @@ impl ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> {
     }
 }
 
+impl HasTargetSpec for Builder<'_, '_, 'tcx> {
+    fn target_spec(&self) -> &Target {
+        &self.cx.target_spec()
+    }
+}
+
 impl ty::layout::LayoutOf for Builder<'_, '_, 'tcx> {
     type Ty = Ty<'tcx>;
     type TyLayout = TyLayout<'tcx>;
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index 3febcb019ce29..bcb14b8899ec2 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -13,13 +13,13 @@
 
 use crate::llvm;
 use crate::llvm::AttributePlace::Function;
-use crate::abi::{FnType, FnTypeExt};
+use crate::abi::{FnType, FnTypeLlvmExt};
 use crate::attributes;
 use crate::context::CodegenCx;
 use crate::type_::Type;
 use crate::value::Value;
 use rustc::ty::{self, PolyFnSig};
-use rustc::ty::layout::LayoutOf;
+use rustc::ty::layout::{FnTypeExt, LayoutOf};
 use rustc::session::config::Sanitizer;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_codegen_ssa::traits::*;
diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs
index a5ed64a66a39d..a3d3f0756a5f3 100644
--- a/src/librustc_codegen_llvm/type_.rs
+++ b/src/librustc_codegen_llvm/type_.rs
@@ -10,7 +10,7 @@ use rustc_codegen_ssa::traits::*;
 
 use crate::common;
 use crate::type_of::LayoutLlvmExt;
-use crate::abi::{LlvmType, FnTypeExt};
+use crate::abi::{LlvmType, FnTypeLlvmExt};
 use syntax::ast;
 use rustc::ty::Ty;
 use rustc::ty::layout::{self, Align, Size, TyLayout};
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index ff25ed9256613..800bf505125d6 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -1,8 +1,8 @@
-use crate::abi::{FnType, FnTypeExt};
+use crate::abi::{FnType};
 use crate::common::*;
 use crate::type_::Type;
 use rustc::ty::{self, Ty, TypeFoldable};
-use rustc::ty::layout::{self, Align, LayoutOf, PointeeInfo, Size, TyLayout};
+use rustc::ty::layout::{self, Align, LayoutOf, FnTypeExt, PointeeInfo, Size, TyLayout};
 use rustc_target::abi::{FloatTy, TyLayoutMethods};
 use rustc_mir::monomorphize::item::DefPathBasedNames;
 use rustc_codegen_ssa::traits::*;
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index e64c847db651b..96b8558c1d2c4 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -1,6 +1,6 @@
 use rustc::middle::lang_items;
 use rustc::ty::{self, Ty, TypeFoldable};
-use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
+use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt};
 use rustc::mir::{self, Place, PlaceBase, Static, StaticKind};
 use rustc::mir::interpret::InterpError;
 use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode};
@@ -334,14 +334,14 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     ty::ParamEnv::reveal_all(),
                     &sig,
                 );
-                let fn_ty = bx.new_vtable(sig, &[]);
+                let fn_ty = FnType::new_vtable(&bx, sig, &[]);
                 let vtable = args[1];
                 args = &args[..1];
                 (meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_ty), fn_ty)
             }
             _ => {
                 (bx.get_fn(drop_fn),
-                 bx.fn_type_of_instance(&drop_fn))
+                 FnType::of_instance(&bx, &drop_fn))
             }
         };
         helper.do_call(self, &mut bx, fn_ty, drop_fn, args,
@@ -439,7 +439,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // Obtain the panic entry point.
         let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item);
         let instance = ty::Instance::mono(bx.tcx(), def_id);
-        let fn_ty = bx.fn_type_of_instance(&instance);
+        let fn_ty = FnType::of_instance(&bx, &instance);
         let llfn = bx.get_fn(instance);
 
         // Codegen the actual panic invoke/call.
@@ -518,7 +518,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         let fn_ty = match def {
             Some(ty::InstanceDef::Virtual(..)) => {
-                bx.new_vtable(sig, &extra_args)
+                FnType::new_vtable(&bx, sig, &extra_args)
             }
             Some(ty::InstanceDef::DropGlue(_, None)) => {
                 // Empty drop glue; a no-op.
@@ -526,7 +526,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 helper.funclet_br(self, &mut bx, target);
                 return;
             }
-            _ => bx.new_fn_type(sig, &extra_args)
+            _ => FnType::new(&bx, sig, &extra_args)
         };
 
         // Emit a panic or a no-op for `panic_if_uninhabited`.
@@ -556,7 +556,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let def_id =
                     common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
                 let instance = ty::Instance::mono(bx.tcx(), def_id);
-                let fn_ty = bx.fn_type_of_instance(&instance);
+                let fn_ty = FnType::of_instance(&bx, &instance);
                 let llfn = bx.get_fn(instance);
 
                 // Codegen the actual panic invoke/call.
diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs
index 3f8dc420cf402..eaa1dd186a536 100644
--- a/src/librustc_codegen_ssa/mir/constant.rs
+++ b/src/librustc_codegen_ssa/mir/constant.rs
@@ -13,7 +13,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn eval_mir_constant(
         &mut self,
         constant: &mir::Constant<'tcx>,
-    ) -> Result<ty::Const<'tcx>, ErrorHandled> {
+    ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
         match constant.literal.val {
             mir::interpret::ConstValue::Unevaluated(def_id, ref substs) => {
                 let substs = self.monomorphize(substs);
@@ -26,7 +26,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 };
                 self.cx.tcx().const_eval(ty::ParamEnv::reveal_all().and(cid))
             },
-            _ => Ok(*self.monomorphize(&constant.literal)),
+            _ => Ok(self.monomorphize(&constant.literal)),
         }
     }
 
@@ -36,7 +36,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         bx: &Bx,
         span: Span,
         ty: Ty<'tcx>,
-        constant: Result<ty::Const<'tcx>, ErrorHandled>,
+        constant: Result<&'tcx ty::Const<'tcx>, ErrorHandled>,
     ) -> (Bx::Value, Ty<'tcx>) {
         constant
             .map(|c| {
diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs
index fcf099235aa14..060d7d18625fc 100644
--- a/src/librustc_codegen_ssa/mir/mod.rs
+++ b/src/librustc_codegen_ssa/mir/mod.rs
@@ -1,5 +1,5 @@
 use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts};
-use rustc::ty::layout::{TyLayout, HasTyCtxt};
+use rustc::ty::layout::{TyLayout, HasTyCtxt, FnTypeExt};
 use rustc::mir::{self, Mir};
 use rustc::session::config::DebugInfo;
 use rustc_mir::monomorphize::Instance;
@@ -202,7 +202,7 @@ pub fn codegen_mir<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
 ) {
     assert!(!instance.substs.needs_infer());
 
-    let fn_ty = cx.new_fn_type(sig, &[]);
+    let fn_ty = FnType::new(cx, sig, &[]);
     debug!("fn_ty: {:?}", fn_ty);
     let mut debug_context =
         cx.create_function_debug_context(instance, sig, llfn, mir);
diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs
index 3b8e5b4495383..96b149dcf231e 100644
--- a/src/librustc_codegen_ssa/mir/operand.rs
+++ b/src/librustc_codegen_ssa/mir/operand.rs
@@ -1,7 +1,7 @@
-use rustc::mir::interpret::{ConstValue, ErrorHandled};
+use rustc::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar};
 use rustc::mir;
 use rustc::ty;
-use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
+use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, Size};
 
 use crate::base;
 use crate::MemFlags;
@@ -67,7 +67,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
 
     pub fn from_const<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         bx: &mut Bx,
-        val: ty::Const<'tcx>
+        val: &'tcx ty::Const<'tcx>
     ) -> Result<Self, ErrorHandled> {
         let layout = bx.layout_of(val.ty);
 
@@ -92,17 +92,21 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
                 );
                 OperandValue::Immediate(llval)
             },
-            ConstValue::Slice(a, b) => {
+            ConstValue::Slice { data, start, end } => {
                 let a_scalar = match layout.abi {
                     layout::Abi::ScalarPair(ref a, _) => a,
                     _ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout)
                 };
+                let a = Scalar::from(Pointer::new(
+                    bx.tcx().alloc_map.lock().allocate(data),
+                    Size::from_bytes(start as u64),
+                )).into();
                 let a_llval = bx.scalar_to_backend(
                     a,
                     a_scalar,
                     bx.scalar_pair_element_backend_type(layout, 0, true),
                 );
-                let b_llval = bx.const_usize(b);
+                let b_llval = bx.const_usize((end - start) as u64);
                 OperandValue::Pair(a_llval, b_llval)
             },
             ConstValue::ByRef(ptr, alloc) => {
diff --git a/src/librustc_codegen_ssa/traits/abi.rs b/src/librustc_codegen_ssa/traits/abi.rs
index a8fd4e1d2c7c7..509255c37be70 100644
--- a/src/librustc_codegen_ssa/traits/abi.rs
+++ b/src/librustc_codegen_ssa/traits/abi.rs
@@ -1,13 +1,7 @@
 use super::BackendTypes;
-use rustc::ty::{FnSig, Instance, Ty};
+use rustc::ty::{Ty};
 use rustc_target::abi::call::FnType;
 
-pub trait AbiMethods<'tcx> {
-    fn new_fn_type(&self, sig: FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>>;
-    fn new_vtable(&self, sig: FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>>;
-    fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>>;
-}
-
 pub trait AbiBuilderMethods<'tcx>: BackendTypes {
     fn apply_attrs_callsite(&mut self, ty: &FnType<'tcx, Ty<'tcx>>, callsite: Self::Value);
     fn get_param(&self, index: usize) -> Self::Value;
diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/src/librustc_codegen_ssa/traits/builder.rs
index a3f99cd869e28..0c4c4547a7955 100644
--- a/src/librustc_codegen_ssa/traits/builder.rs
+++ b/src/librustc_codegen_ssa/traits/builder.rs
@@ -11,6 +11,7 @@ use crate::mir::place::PlaceRef;
 use crate::MemFlags;
 use rustc::ty::Ty;
 use rustc::ty::layout::{Align, Size, HasParamEnv};
+use rustc_target::spec::{HasTargetSpec};
 use std::ops::Range;
 use std::iter::TrustedLen;
 
@@ -30,6 +31,7 @@ pub trait BuilderMethods<'a, 'tcx: 'a>:
     + AsmBuilderMethods<'tcx>
     + StaticBuilderMethods<'tcx>
     + HasParamEnv<'tcx>
+    + HasTargetSpec
 
 {
     fn new_block<'b>(cx: &'a Self::CodegenCx, llfn: Self::Value, name: &'b str) -> Self;
diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/src/librustc_codegen_ssa/traits/mod.rs
index c237cd8bd2645..2bb619e79f5e0 100644
--- a/src/librustc_codegen_ssa/traits/mod.rs
+++ b/src/librustc_codegen_ssa/traits/mod.rs
@@ -27,7 +27,7 @@ mod statics;
 mod type_;
 mod write;
 
-pub use self::abi::{AbiBuilderMethods, AbiMethods};
+pub use self::abi::{AbiBuilderMethods};
 pub use self::asm::{AsmBuilderMethods, AsmMethods};
 pub use self::backend::{Backend, BackendTypes, ExtraBackendMethods};
 pub use self::builder::{BuilderMethods, OverflowOp};
@@ -41,7 +41,8 @@ pub use self::type_::{
     ArgTypeMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods,
 };
 pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
-use rustc::ty::layout::{HasParamEnv};
+use rustc::ty::layout::{HasParamEnv, HasTyCtxt};
+use rustc_target::spec::{HasTargetSpec};
 
 
 use std::fmt;
@@ -56,11 +57,12 @@ pub trait CodegenMethods<'tcx>:
     + ConstMethods<'tcx>
     + StaticMethods
     + DebugInfoMethods<'tcx>
-    + AbiMethods<'tcx>
     + DeclareMethods<'tcx>
     + AsmMethods<'tcx>
     + PreDefineMethods<'tcx>
     + HasParamEnv<'tcx>
+    + HasTyCtxt<'tcx>
+    + HasTargetSpec
 {
 }
 
@@ -71,11 +73,12 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where
         + ConstMethods<'tcx>
         + StaticMethods
         + DebugInfoMethods<'tcx>
-        + AbiMethods<'tcx>
         + DeclareMethods<'tcx>
         + AsmMethods<'tcx>
         + PreDefineMethods<'tcx>
         + HasParamEnv<'tcx>
+        + HasTyCtxt<'tcx>
+        + HasTargetSpec
 {
 }
 
diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs
index d50a9a1607b24..33ed0bfe1e451 100644
--- a/src/librustc_codegen_utils/symbol_names.rs
+++ b/src/librustc_codegen_utils/symbol_names.rs
@@ -96,6 +96,7 @@ use rustc::ty::print::{PrettyPrinter, Printer, Print};
 use rustc::ty::query::Providers;
 use rustc::ty::subst::{Kind, SubstsRef, UnpackedKind};
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::mir::interpret::{ConstValue, Scalar};
 use rustc::util::common::record_time;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_mir::monomorphize::item::{InstantiationMode, MonoItem, MonoItemExt};
@@ -391,6 +392,7 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> {
     type Region = Self;
     type Type = Self;
     type DynExistential = Self;
+    type Const = Self;
 
     fn tcx(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
         self.tcx
@@ -436,6 +438,20 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> {
         Ok(self)
     }
 
+    fn print_const(
+        mut self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<Self::Const, Self::Error> {
+        // only print integers
+        if let ConstValue::Scalar(Scalar::Bits { .. }) = ct.val {
+            if ct.ty.is_integral() {
+                return self.pretty_print_const(ct);
+            }
+        }
+        self.write_str("_")?;
+        Ok(self)
+    }
+
     fn path_crate(
         mut self,
         cnum: CrateNum,
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index 7469aceee3a9e..b5bab1585342a 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -23,8 +23,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             safety_mode
         } =
             self.hir.mirror(ast_block);
-        self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), block, move |this| {
-            this.in_scope((region_scope, source_info), LintLevel::Inherited, block, move |this| {
+        self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), move |this| {
+            this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
                 if targeted_by_break {
                     // This is a `break`-able block
                     let exit_block = this.cfg.start_new_block();
@@ -83,9 +83,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 StmtKind::Expr { scope, expr } => {
                     this.block_context.push(BlockFrame::Statement { ignores_expr_result: true });
                     unpack!(block = this.in_opt_scope(
-                        opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
+                        opt_destruction_scope.map(|de|(de, source_info)), |this| {
                             let si = (scope, source_info);
-                            this.in_scope(si, LintLevel::Inherited, block, |this| {
+                            this.in_scope(si, LintLevel::Inherited, |this| {
                                 let expr = this.hir.mirror(expr);
                                 this.stmt_expr(block, expr, Some(stmt_span))
                             })
@@ -113,31 +113,39 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let remainder_span = remainder_scope.span(this.hir.tcx(),
                                                               &this.hir.region_scope_tree);
 
-                    let scope;
+                    let visibility_scope =
+                        Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
 
                     // Evaluate the initializer, if present.
                     if let Some(init) = initializer {
                         let initializer_span = init.span();
 
-                        scope = this.declare_bindings(
-                            None,
-                            remainder_span,
-                            lint_level,
-                            &pattern,
-                            ArmHasGuard(false),
-                            Some((None, initializer_span)),
-                        );
                         unpack!(block = this.in_opt_scope(
-                            opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
+                            opt_destruction_scope.map(|de|(de, source_info)), |this| {
                                 let scope = (init_scope, source_info);
-                                this.in_scope(scope, lint_level, block, |this| {
+                                this.in_scope(scope, lint_level, |this| {
+                                    this.declare_bindings(
+                                        visibility_scope,
+                                        remainder_span,
+                                        &pattern,
+                                        ArmHasGuard(false),
+                                        Some((None, initializer_span)),
+                                    );
                                     this.expr_into_pattern(block, pattern, init)
                                 })
                             }));
                     } else {
-                        scope = this.declare_bindings(
-                            None, remainder_span, lint_level, &pattern,
-                            ArmHasGuard(false), None);
+                        let scope = (init_scope, source_info);
+                        unpack!(this.in_scope(scope, lint_level, |this| {
+                            this.declare_bindings(
+                                visibility_scope,
+                                remainder_span,
+                                &pattern,
+                                ArmHasGuard(false),
+                                None,
+                            );
+                            block.unit()
+                        }));
 
                         debug!("ast_block_stmts: pattern={:?}", pattern);
                         this.visit_bindings(
@@ -149,8 +157,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             })
                     }
 
-                    // Enter the source scope, after evaluating the initializer.
-                    if let Some(source_scope) = scope {
+                    // Enter the visibility scope, after evaluating the initializer.
+                    if let Some(source_scope) = visibility_scope {
                         this.source_scope = source_scope;
                     }
                 }
diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs
index e354a2ee8160b..ed80cb1a16369 100644
--- a/src/librustc_mir/build/expr/as_operand.rs
+++ b/src/librustc_mir/build/expr/as_operand.rs
@@ -57,7 +57,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         {
             let source_info = this.source_info(expr.span);
             let region_scope = (region_scope, source_info);
-            return this.in_scope(region_scope, lint_level, block, |this| {
+            return this.in_scope(region_scope, lint_level, |this| {
                 this.as_operand(block, scope, value)
             });
         }
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index 5f444d4ceeb88..a956eacb0699f 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -52,7 +52,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 region_scope,
                 lint_level,
                 value,
-            } => this.in_scope((region_scope, source_info), lint_level, block, |this| {
+            } => this.in_scope((region_scope, source_info), lint_level, |this| {
                 if mutability == Mutability::Not {
                     this.as_read_only_place(block, value)
                 } else {
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index fbc4835a6557b..a0b504a99de9a 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -58,7 +58,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 value,
             } => {
                 let region_scope = (region_scope, source_info);
-                this.in_scope(region_scope, lint_level, block, |this| {
+                this.in_scope(region_scope, lint_level, |this| {
                     this.as_rvalue(block, scope, value)
                 })
             }
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index cba771f27065d..cffd8fb2892f5 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -1,6 +1,7 @@
 //! See docs in build/expr/mod.rs
 
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
+use crate::build::scope::{CachedBlock, DropKind};
 use crate::hair::*;
 use rustc::middle::region;
 use rustc::mir::*;
@@ -43,7 +44,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             value,
         } = expr.kind
         {
-            return this.in_scope((region_scope, source_info), lint_level, block, |this| {
+            return this.in_scope((region_scope, source_info), lint_level, |this| {
                 this.as_temp(block, temp_lifetime, value, mutability)
             });
         }
@@ -63,6 +64,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
             this.local_decls.push(local_decl)
         };
+        let temp_place = &Place::Base(PlaceBase::Local(temp));
+
         if !expr_ty.is_never() {
             this.cfg.push(
                 block,
@@ -71,25 +74,38 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     kind: StatementKind::StorageLive(temp),
                 },
             );
+
+            // In constants, `temp_lifetime` is `None` for temporaries that live for the
+            // `'static` lifetime. Thus we do not drop these temporaries and simply leak them.
+            // This is equivalent to what `let x = &foo();` does in functions. The temporary
+            // is lifted to their surrounding scope. In a function that means the temporary lives
+            // until just before the function returns. In constants that means it outlives the
+            // constant's initialization value computation. Anything outliving a constant
+            // must have the `'static` lifetime and live forever.
+            // Anything with a shorter lifetime (e.g the `&foo()` in `bar(&foo())` or anything
+            // within a block will keep the regular drops just like runtime code.
+            if let Some(temp_lifetime) = temp_lifetime {
+                this.schedule_drop(
+                    expr_span,
+                    temp_lifetime,
+                    temp_place,
+                    expr_ty,
+                    DropKind::Storage,
+                );
+            }
         }
 
-        unpack!(block = this.into(&Place::Base(PlaceBase::Local(temp)), block, expr));
+        unpack!(block = this.into(temp_place, block, expr));
 
-        // In constants, temp_lifetime is None for temporaries that live for the
-        // 'static lifetime. Thus we do not drop these temporaries and simply leak them.
-        // This is equivalent to what `let x = &foo();` does in functions. The temporary
-        // is lifted to their surrounding scope. In a function that means the temporary lives
-        // until just before the function returns. In constants that means it outlives the
-        // constant's initialization value computation. Anything outliving a constant
-        // must have the `'static` lifetime and live forever.
-        // Anything with a shorter lifetime (e.g the `&foo()` in `bar(&foo())` or anything
-        // within a block will keep the regular drops just like runtime code.
         if let Some(temp_lifetime) = temp_lifetime {
-            this.schedule_drop_storage_and_value(
+            this.schedule_drop(
                 expr_span,
                 temp_lifetime,
-                &Place::Base(PlaceBase::Local(temp)),
+                temp_place,
                 expr_ty,
+                DropKind::Value {
+                    cached_block: CachedBlock::default(),
+                },
             );
         }
 
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 15795a64e3b7d..7bdfdf0b0895f 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -46,7 +46,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 value,
             } => {
                 let region_scope = (region_scope, source_info);
-                this.in_scope(region_scope, lint_level, block, |this| {
+                this.in_scope(region_scope, lint_level, |this| {
                     this.into(destination, block, value)
                 })
             }
diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs
index b58914b017fd4..ac690f89264bf 100644
--- a/src/librustc_mir/build/expr/stmt.rs
+++ b/src/librustc_mir/build/expr/stmt.rs
@@ -29,7 +29,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 value,
             } => {
                 let value = this.hir.mirror(value);
-                this.in_scope((region_scope, source_info), lint_level, block, |this| {
+                this.in_scope((region_scope, source_info), lint_level, |this| {
                     this.stmt_expr(block, value, opt_stmt_span)
                 })
             }
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 51d5c96083d8f..8c2ef082c339f 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -12,6 +12,7 @@ use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
 use crate::hair::{self, *};
 use rustc::hir::HirId;
 use rustc::mir::*;
+use rustc::middle::region;
 use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty};
 use rustc::ty::layout::VariantIdx;
 use rustc_data_structures::bit_set::BitSet;
@@ -251,37 +252,39 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         // Step 5. Create everything else: the guards and the arms.
 
-        let outer_source_info = self.source_info(span);
         let arm_end_blocks: Vec<_> = arm_candidates.into_iter().map(|(arm, candidates)| {
-            let mut arm_block = self.cfg.start_new_block();
-
-            let body = self.hir.mirror(arm.body.clone());
-            let scope = self.declare_bindings(
-                None,
-                body.span,
-                LintLevel::Inherited,
-                &arm.patterns[0],
-                ArmHasGuard(arm.guard.is_some()),
-                Some((Some(&scrutinee_place), scrutinee_span)),
-            );
-
-            for candidate in candidates {
-                self.bind_and_guard_matched_candidate(
-                    candidate,
-                    arm.guard.clone(),
-                    arm_block,
-                    &fake_borrow_temps,
-                    scrutinee_span,
+            let arm_source_info = self.source_info(arm.span);
+            let region_scope = (arm.scope, arm_source_info);
+            self.in_scope(region_scope, arm.lint_level, |this| {
+                let arm_block = this.cfg.start_new_block();
+
+                let body = this.hir.mirror(arm.body.clone());
+                let scope = this.declare_bindings(
+                    None,
+                    arm.span,
+                    &arm.patterns[0],
+                    ArmHasGuard(arm.guard.is_some()),
+                    Some((Some(&scrutinee_place), scrutinee_span)),
                 );
-            }
 
-            if let Some(source_scope) = scope {
-                self.source_scope = source_scope;
-            }
+                if let Some(source_scope) = scope {
+                    this.source_scope = source_scope;
+                }
 
-            unpack!(arm_block = self.into(destination, arm_block, body));
+                for candidate in candidates {
+                    this.clear_top_scope(arm.scope);
+                    this.bind_and_guard_matched_candidate(
+                        candidate,
+                        arm.guard.clone(),
+                        arm_block,
+                        &fake_borrow_temps,
+                        scrutinee_span,
+                        region_scope,
+                    );
+                }
 
-            arm_block
+                this.into(destination, arm_block, body)
+            })
         }).collect();
 
         // all the arm blocks will rejoin here
@@ -289,7 +292,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         for arm_block in arm_end_blocks {
             self.cfg.terminate(
-                arm_block,
+                unpack!(arm_block),
                 outer_source_info,
                 TerminatorKind::Goto { target: end_block },
             );
@@ -489,33 +492,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         &mut self,
         mut visibility_scope: Option<SourceScope>,
         scope_span: Span,
-        lint_level: LintLevel,
         pattern: &Pattern<'tcx>,
         has_guard: ArmHasGuard,
         opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
     ) -> Option<SourceScope> {
-        assert!(
-            !(visibility_scope.is_some() && lint_level.is_explicit()),
-            "can't have both a visibility and a lint scope at the same time"
-        );
-        let mut scope = self.source_scope;
         debug!("declare_bindings: pattern={:?}", pattern);
         self.visit_bindings(
             &pattern,
             UserTypeProjections::none(),
             &mut |this, mutability, name, mode, var, span, ty, user_ty| {
                 if visibility_scope.is_none() {
-                    // If we have lints, create a new source scope
-                    // that marks the lints for the locals. See the comment
-                    // on the `source_info` field for why this is needed.
-                    if lint_level.is_explicit() {
-                        scope = this.new_source_scope(scope_span, lint_level, None);
-                    }
-                visibility_scope = Some(this.new_source_scope(scope_span,
-                                                           LintLevel::Inherited,
-                                                           None));
+                    visibility_scope =
+                        Some(this.new_source_scope(scope_span, LintLevel::Inherited, None));
                 }
-                let source_info = SourceInfo { span, scope };
+                let source_info = SourceInfo { span, scope: this.source_scope };
                 let visibility_scope = visibility_scope.unwrap();
                 this.declare_binding(
                     source_info,
@@ -747,12 +737,12 @@ enum TestKind<'tcx> {
     SwitchInt {
         switch_ty: Ty<'tcx>,
         options: Vec<u128>,
-        indices: FxHashMap<ty::Const<'tcx>, usize>,
+        indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
     },
 
     // test for equality
     Eq {
-        value: ty::Const<'tcx>,
+        value: &'tcx ty::Const<'tcx>,
         ty: Ty<'tcx>,
     },
 
@@ -880,7 +870,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             span,
             untested_candidates,
             join_block,
-            &mut None,
+            fake_borrows,
         )
     }
 
@@ -1328,6 +1318,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         arm_block: BasicBlock,
         fake_borrows: &Vec<(&Place<'tcx>, Local)>,
         scrutinee_span: Span,
+        region_scope: (region::Scope, SourceInfo),
     ) {
         debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
 
@@ -1510,17 +1501,40 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             //
             // and that is clearly not correct.
             let post_guard_block = self.cfg.start_new_block();
+            let otherwise_post_guard_block = self.cfg.start_new_block();
             self.cfg.terminate(
                 block,
                 source_info,
                 TerminatorKind::if_(
                     self.hir.tcx(),
-                    cond,
+                    cond.clone(),
                     post_guard_block,
-                    candidate.otherwise_block.unwrap()
+                    otherwise_post_guard_block,
                 ),
             );
 
+            self.exit_scope(
+                source_info.span,
+                region_scope,
+                otherwise_post_guard_block,
+                candidate.otherwise_block.unwrap(),
+            );
+
+            if let Operand::Copy(cond_place) | Operand::Move(cond_place) = cond {
+                if let Place::Base(PlaceBase::Local(cond_temp)) = cond_place {
+                    // We will call `clear_top_scope` if there's another guard. So
+                    // we have to drop this variable now or it will be "storage
+                    // leaked".
+                    self.pop_variable(
+                        post_guard_block,
+                        region_scope.0,
+                        cond_temp
+                    );
+                } else {
+                    bug!("Expected as_local_operand to produce a temporary");
+                }
+            }
+
             let by_value_bindings = candidate.bindings.iter().filter(|binding| {
                 if let BindingMode::ByValue = binding.binding_mode { true } else { false }
             });
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index a5834b02ffc82..0995a2f7fdf49 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -98,7 +98,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                      candidate: &Candidate<'pat, 'tcx>,
                                      switch_ty: Ty<'tcx>,
                                      options: &mut Vec<u128>,
-                                     indices: &mut FxHashMap<ty::Const<'tcx>, usize>)
+                                     indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>)
                                      -> bool
     {
         let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
@@ -305,7 +305,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     }
                     let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap();
                     let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty.into()]);
-                    let method = self.hir.tcx().mk_const(method);
 
                     let re_erased = self.hir.tcx().lifetimes.re_erased;
                     // take the argument by reference
@@ -371,8 +370,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
             TestKind::Range(PatternRange { ref lo, ref hi, ty, ref end }) => {
                 // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
-                let lo = self.literal_operand(test.span, ty.clone(), lo.clone());
-                let hi = self.literal_operand(test.span, ty.clone(), hi.clone());
+                let lo = self.literal_operand(test.span, ty, lo);
+                let hi = self.literal_operand(test.span, ty, hi);
                 let val = Operand::Copy(place.clone());
 
                 let fail = self.cfg.start_new_block();
@@ -724,7 +723,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     fn const_range_contains(
         &self,
         range: PatternRange<'tcx>,
-        value: ty::Const<'tcx>,
+        value: &'tcx ty::Const<'tcx>,
     ) -> Option<bool> {
         use std::cmp::Ordering::*;
 
@@ -744,7 +743,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     fn values_not_contained_in_range(
         &self,
         range: PatternRange<'tcx>,
-        indices: &FxHashMap<ty::Const<'tcx>, usize>,
+        indices: &FxHashMap<&'tcx ty::Const<'tcx>, usize>,
     ) -> Option<bool> {
         for &val in indices.keys() {
             if self.const_range_contains(range, val)? {
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index d71a13dec5a2f..daf59d7a1353c 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -27,13 +27,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn literal_operand(&mut self,
                            span: Span,
                            ty: Ty<'tcx>,
-                           literal: ty::Const<'tcx>)
+                           literal: &'tcx ty::Const<'tcx>)
                            -> Operand<'tcx> {
         let constant = box Constant {
             span,
             ty,
             user_ty: None,
-            literal: self.hir.tcx().mk_const(literal),
+            literal,
         };
         Operand::Constant(constant)
     }
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 16ab233bd2e36..8cd4ac0ad3ade 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -702,13 +702,13 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
     let mut block = START_BLOCK;
     let source_info = builder.source_info(span);
     let call_site_s = (call_site_scope, source_info);
-    unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, block, |builder| {
+    unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
         if should_abort_on_panic(tcx, fn_def_id, abi) {
             builder.schedule_abort();
         }
 
         let arg_scope_s = (arg_scope, source_info);
-        unpack!(block = builder.in_scope(arg_scope_s, LintLevel::Inherited, block, |builder| {
+        unpack!(block = builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
             builder.args_and_body(block, &arguments, arg_scope, &body.value)
         }));
         // Attribute epilogue to function's closing brace
@@ -945,10 +945,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         self.var_indices.insert(var, LocalsForNode::One(local));
                     }
                     _ => {
-                        scope = self.declare_bindings(scope, ast_body.span,
-                                                      LintLevel::Inherited, &pattern,
-                                                      matches::ArmHasGuard(false),
-                                                      Some((Some(&place), span)));
+                        scope = self.declare_bindings(
+                            scope,
+                            ast_body.span,
+                            &pattern,
+                            matches::ArmHasGuard(false),
+                            Some((Some(&place), span)),
+                        );
                         unpack!(block = self.place_into_pattern(block, pattern, &place, false));
                     }
                 }
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 4aa463b37ab77..34df40ae180af 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -19,13 +19,18 @@ paragraph). This is because region scopes are tied to
 them. Eventually, when we shift to non-lexical lifetimes, there should
 be no need to remember this mapping.
 
-There is one additional wrinkle, actually, that I wanted to hide from
-you but duty compels me to mention. In the course of building
-matches, it sometimes happen that certain code (namely guards) gets
-executed multiple times. This means that the scope lexical scope may
-in fact correspond to multiple, disjoint SEME regions. So in fact our
+### Not so SEME Regions
+
+In the course of building matches, it sometimes happens that certain code
+(namely guards) gets executed multiple times. This means that the scope lexical
+scope may in fact correspond to multiple, disjoint SEME regions. So in fact our
 mapping is from one scope to a vector of SEME regions.
 
+Also in matches, the scopes assigned to arms are not even SEME regions! Each
+arm has a single region with one entry for each pattern. We manually
+manipulate the scheduled drops in this scope to avoid dropping things multiple
+times, although drop elaboration would clean this up for value drops.
+
 ### Drops
 
 The primary purpose for scopes is to insert drops: while building
@@ -279,13 +284,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     pub fn in_opt_scope<F, R>(&mut self,
                               opt_scope: Option<(region::Scope, SourceInfo)>,
-                              mut block: BasicBlock,
                               f: F)
                               -> BlockAnd<R>
         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd<R>
     {
-        debug!("in_opt_scope(opt_scope={:?}, block={:?})", opt_scope, block);
+        debug!("in_opt_scope(opt_scope={:?})", opt_scope);
         if let Some(region_scope) = opt_scope { self.push_scope(region_scope); }
+        let mut block;
         let rv = unpack!(block = f(self));
         if let Some(region_scope) = opt_scope {
             unpack!(block = self.pop_scope(region_scope, block));
@@ -299,12 +304,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn in_scope<F, R>(&mut self,
                           region_scope: (region::Scope, SourceInfo),
                           lint_level: LintLevel,
-                          mut block: BasicBlock,
                           f: F)
                           -> BlockAnd<R>
         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd<R>
     {
-        debug!("in_scope(region_scope={:?}, block={:?})", region_scope, block);
+        debug!("in_scope(region_scope={:?})", region_scope);
         let source_scope = self.source_scope;
         let tcx = self.hir.tcx();
         if let LintLevel::Explicit(current_hir_id) = lint_level {
@@ -330,6 +334,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
         }
         self.push_scope(region_scope);
+        let mut block;
         let rv = unpack!(block = f(self));
         unpack!(block = self.pop_scope(region_scope, block));
         self.source_scope = source_scope;
@@ -731,7 +736,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             // Note that this code iterates scopes from the inner-most to the outer-most,
             // invalidating caches of each scope visited. This way bare minimum of the
             // caches gets invalidated. i.e., if a new drop is added into the middle scope, the
-            // cache of outer scpoe stays intact.
+            // cache of outer scope stays intact.
             scope.invalidate_cache(!needs_drop, this_scope);
             if this_scope {
                 if let DropKind::Value { .. } = drop_kind {
@@ -873,6 +878,73 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         success_block
     }
+
+    // `match` arm scopes
+    // ==================
+    /// Unschedules any drops in the top scope.
+    ///
+    /// This is only needed for `match` arm scopes, because they have one
+    /// entrance per pattern, but only one exit.
+    pub fn clear_top_scope(&mut self, region_scope: region::Scope) {
+        let top_scope = self.scopes.last_mut().unwrap();
+
+        assert_eq!(top_scope.region_scope, region_scope);
+
+        top_scope.drops.clear();
+        top_scope.invalidate_cache(false, true);
+    }
+
+    /// Drops the single variable provided
+    ///
+    /// * The scope must be the top scope.
+    /// * The variable must be in that scope.
+    /// * The variable must be at the top of that scope: it's the next thing
+    ///   scheduled to drop.
+    /// * The drop must be of `DropKind::Storage`.
+    ///
+    /// This is used for the boolean holding the result of the match guard. We
+    /// do this because:
+    ///
+    /// * The boolean is different for each pattern
+    /// * There is only one exit for the arm scope
+    /// * The guard expression scope is too short, it ends just before the
+    ///   boolean is tested.
+    pub fn pop_variable(
+        &mut self,
+        block: BasicBlock,
+        region_scope: region::Scope,
+        variable: Local,
+    ) {
+        let top_scope = self.scopes.last_mut().unwrap();
+
+        assert_eq!(top_scope.region_scope, region_scope);
+
+        let top_drop_data = top_scope.drops.pop().unwrap();
+
+        match top_drop_data.kind {
+            DropKind::Value { .. } => {
+                bug!("Should not be calling pop_top_variable on non-copy type!")
+            }
+            DropKind::Storage => {
+                // Drop the storage for both value and storage drops.
+                // Only temps and vars need their storage dead.
+                match top_drop_data.location {
+                    Place::Base(PlaceBase::Local(index)) => {
+                        let source_info = top_scope.source_info(top_drop_data.span);
+                        assert_eq!(index, variable);
+                        self.cfg.push(block, Statement {
+                            source_info,
+                            kind: StatementKind::StorageDead(index)
+                        });
+                    }
+                    _ => unreachable!(),
+                }
+            }
+        }
+
+        top_scope.invalidate_cache(true, true);
+    }
+
 }
 
 /// Builds drops for pop_scope and exit_scope.
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 866b6492d10bc..776d4c242415a 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -5,6 +5,7 @@ use std::error::Error;
 use std::borrow::{Borrow, Cow};
 use std::hash::Hash;
 use std::collections::hash_map::Entry;
+use std::convert::TryInto;
 
 use rustc::hir::def::DefKind;
 use rustc::hir::def_id::DefId;
@@ -65,7 +66,7 @@ pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(
 fn mplace_to_const<'tcx>(
     ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
     mplace: MPlaceTy<'tcx>,
-) -> ty::Const<'tcx> {
+) -> &'tcx ty::Const<'tcx> {
     let MemPlace { ptr, align, meta } = *mplace;
     // extract alloc-offset pair
     assert!(meta.is_none());
@@ -79,17 +80,24 @@ fn mplace_to_const<'tcx>(
     // interned this?  I thought that is the entire point of that `FinishStatic` stuff?
     let alloc = ecx.tcx.intern_const_alloc(alloc);
     let val = ConstValue::ByRef(ptr, alloc);
-    ty::Const { val, ty: mplace.layout.ty }
+    ecx.tcx.mk_const(ty::Const { val, ty: mplace.layout.ty })
 }
 
 fn op_to_const<'tcx>(
     ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
     op: OpTy<'tcx>,
-) -> ty::Const<'tcx> {
+) -> &'tcx ty::Const<'tcx> {
     // We do not normalize just any data.  Only non-union scalars and slices.
     let normalize = match op.layout.abi {
         layout::Abi::Scalar(..) => op.layout.ty.ty_adt_def().map_or(true, |adt| !adt.is_union()),
-        layout::Abi::ScalarPair(..) => op.layout.ty.is_slice(),
+        layout::Abi::ScalarPair(..) => match op.layout.ty.sty {
+            ty::Ref(_, inner, _) => match inner.sty {
+                ty::Slice(elem) => elem == ecx.tcx.types.u8,
+                ty::Str => true,
+                _ => false,
+            },
+            _ => false,
+        },
         _ => false,
     };
     let normalized_op = if normalize {
@@ -101,10 +109,28 @@ fn op_to_const<'tcx>(
         Ok(mplace) => return mplace_to_const(ecx, mplace),
         Err(Immediate::Scalar(x)) =>
             ConstValue::Scalar(x.not_undef().unwrap()),
-        Err(Immediate::ScalarPair(a, b)) =>
-            ConstValue::Slice(a.not_undef().unwrap(), b.to_usize(ecx).unwrap()),
+        Err(Immediate::ScalarPair(a, b)) => {
+            let (data, start) = match a.not_undef().unwrap() {
+                Scalar::Ptr(ptr) => (
+                    ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
+                    ptr.offset.bytes(),
+                ),
+                Scalar::Bits { .. } => (
+                    ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(b"", ())),
+                    0,
+                ),
+            };
+            let len = b.to_usize(&ecx.tcx.tcx).unwrap();
+            let start = start.try_into().unwrap();
+            let len: usize = len.try_into().unwrap();
+            ConstValue::Slice {
+                data,
+                start,
+                end: start + len,
+            }
+        },
     };
-    ty::Const { val, ty: op.layout.ty }
+    ecx.tcx.mk_const(ty::Const { val, ty: op.layout.ty })
 }
 
 // Returns a pointer to where the result lives
@@ -450,8 +476,8 @@ pub fn const_field<'a, 'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     variant: Option<VariantIdx>,
     field: mir::Field,
-    value: ty::Const<'tcx>,
-) -> ty::Const<'tcx> {
+    value: &'tcx ty::Const<'tcx>,
+) -> &'tcx ty::Const<'tcx> {
     trace!("const_field: {:?}, {:?}", field, value);
     let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
     // get the operand again
@@ -473,7 +499,7 @@ pub fn const_field<'a, 'tcx>(
 pub fn const_variant_index<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    val: ty::Const<'tcx>,
+    val: &'tcx ty::Const<'tcx>,
 ) -> VariantIdx {
     trace!("const_variant_index: {:?}", val);
     let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs
index 4dcfb3f1a7fc3..03d55b84f32e2 100644
--- a/src/librustc_mir/dataflow/impls/mod.rs
+++ b/src/librustc_mir/dataflow/impls/mod.rs
@@ -11,8 +11,7 @@ use super::MoveDataParamEnv;
 
 use crate::util::elaborate_drops::DropFlagState;
 
-use super::move_paths::{HasMoveData, MoveData, MovePathIndex, InitIndex};
-use super::move_paths::{LookupResult, InitKind};
+use super::move_paths::{HasMoveData, MoveData, MovePathIndex, InitIndex, InitKind};
 use super::{BitDenotation, BlockSets, InitialFlow};
 
 use super::drop_flag_effects_for_function_entry;
@@ -470,35 +469,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'gcx, 'tc
         sets.gen_all(&init_loc_map[location]);
 
         match stmt.kind {
-            mir::StatementKind::StorageDead(local) |
-            mir::StatementKind::StorageLive(local) => {
-                // End inits for StorageDead and StorageLive, so that an immutable
-                // variable can be reinitialized on the next iteration of the loop.
-                //
-                // FIXME(#46525): We *need* to do this for StorageLive as well as
-                // StorageDead, because lifetimes of match bindings with guards are
-                // weird - i.e., this code
-                //
-                // ```
-                //     fn main() {
-                //         match 0 {
-                //             a | a
-                //             if { println!("a={}", a); false } => {}
-                //             _ => {}
-                //         }
-                //     }
-                // ```
-                //
-                // runs the guard twice, using the same binding for `a`, and only
-                // storagedeads after everything ends, so if we don't regard the
-                // storagelive as killing storage, we would have a multiple assignment
-                // to immutable data error.
-                if let LookupResult::Exact(mpi) =
-                    rev_lookup.find(&mir::Place::Base(mir::PlaceBase::Local(local))) {
-                    debug!("stmt {:?} at loc {:?} clears the ever initialized status of {:?}",
-                           stmt, location, &init_path_map[mpi]);
-                    sets.kill_all(&init_path_map[mpi]);
-                }
+            mir::StatementKind::StorageDead(local) => {
+                // End inits for StorageDead, so that an immutable variable can
+                // be reinitialized on the next iteration of the loop.
+                let move_path_index = rev_lookup.find_local(local);
+                debug!("stmt {:?} at loc {:?} clears the ever initialized status of {:?}",
+                        stmt, location, &init_path_map[move_path_index]);
+                sets.kill_all(&init_path_map[move_path_index]);
             }
             _ => {}
         }
diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs
index caadc6055b5c6..d2c86d36238e1 100644
--- a/src/librustc_mir/hair/constant.rs
+++ b/src/librustc_mir/hair/constant.rs
@@ -14,7 +14,7 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>(
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     ty: Ty<'tcx>,
     neg: bool,
-) -> Result<ty::Const<'tcx>, LitToConstError> {
+) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
     use syntax::ast::*;
 
     let trunc = |n| {
@@ -33,16 +33,18 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>(
     let lit = match *lit {
         LitKind::Str(ref s, _) => {
             let s = s.as_str();
-            let id = tcx.allocate_bytes(s.as_bytes());
-            ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64)
+            let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes(), ());
+            let allocation = tcx.intern_const_alloc(allocation);
+            ConstValue::Slice { data: allocation, start: 0, end: s.len() }
         },
         LitKind::Err(ref s) => {
             let s = s.as_str();
-            let id = tcx.allocate_bytes(s.as_bytes());
-            return Ok(ty::Const {
-                val: ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64),
+            let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes(), ());
+            let allocation = tcx.intern_const_alloc(allocation);
+            return Ok(tcx.mk_const(ty::Const {
+                val: ConstValue::Slice{ data: allocation, start: 0, end: s.len() },
                 ty: tcx.types.err,
-            });
+            }));
         },
         LitKind::ByteStr(ref data) => {
             let id = tcx.allocate_bytes(data);
@@ -71,7 +73,7 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>(
         LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)),
         LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)),
     };
-    Ok(ty::Const { val: lit, ty })
+    Ok(tcx.mk_const(ty::Const { val: lit, ty }))
 }
 
 fn parse_float<'tcx>(
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 50140880a368d..ca457b0ac7c72 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -329,9 +329,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprKind::Lit(ref lit) => ExprKind::Literal {
-            literal: cx.tcx.mk_const(
-                cx.const_eval_literal(&lit.node, expr_ty, lit.span, false)
-            ),
+            literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false),
             user_ty: None,
         },
 
@@ -429,9 +427,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             } else {
                 if let hir::ExprKind::Lit(ref lit) = arg.node {
                     ExprKind::Literal {
-                        literal: cx.tcx.mk_const(
-                            cx.const_eval_literal(&lit.node, expr_ty, lit.span, true)
-                        ),
+                        literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true),
                         user_ty: None,
                     }
                 } else {
@@ -680,7 +676,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         ty: var_ty,
                         span: expr.span,
                         kind: ExprKind::Literal {
-                            literal: cx.tcx.mk_const(literal),
+                            literal,
                             user_ty: None
                         },
                     }.to_ref();
@@ -694,10 +690,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                             // in case we are offsetting from a computed discriminant
                             // and not the beginning of discriminants (which is always `0`)
                             let substs = InternalSubsts::identity_for_item(cx.tcx(), did);
-                            let lhs = mk_const(ty::Const {
+                            let lhs = mk_const(cx.tcx().mk_const(ty::Const {
                                 val: ConstValue::Unevaluated(did, substs),
                                 ty: var_ty,
-                            });
+                            }));
                             let bin = ExprKind::Binary {
                                 op: BinOp::Add,
                                 lhs,
@@ -837,9 +833,7 @@ fn method_callee<'a, 'gcx, 'tcx>(
         ty,
         span,
         kind: ExprKind::Literal {
-            literal: cx.tcx().mk_const(
-                ty::Const::zero_sized(ty)
-            ),
+            literal: ty::Const::zero_sized(cx.tcx(), ty),
             user_ty,
         },
     }
@@ -879,8 +873,12 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm)
                 _ => None,
             },
         body: arm.body.to_ref(),
-        // BUG: fix this
-        lint_level: LintLevel::Inherited,
+        lint_level: LintLevel::Explicit(arm.hir_id),
+        scope: region::Scope {
+            id: arm.hir_id.local_id,
+            data: region::ScopeData::Node
+        },
+        span: arm.span,
     }
 }
 
@@ -898,9 +896,10 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res);
             debug!("convert_path_expr: user_ty={:?}", user_ty);
             ExprKind::Literal {
-                literal: cx.tcx.mk_const(ty::Const::zero_sized(
+                literal: ty::Const::zero_sized(
+                    cx.tcx,
                     cx.tables().node_type(expr.hir_id),
-                )),
+                ),
                 user_ty,
             }
         }
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index e8070b21bb8c7..c993a02a6decc 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -106,7 +106,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     }
 
     pub fn usize_literal(&mut self, value: u64) -> &'tcx ty::Const<'tcx> {
-        self.tcx.mk_const(ty::Const::from_usize(self.tcx, value))
+        ty::Const::from_usize(self.tcx, value)
     }
 
     pub fn bool_ty(&mut self) -> Ty<'tcx> {
@@ -118,11 +118,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     }
 
     pub fn true_literal(&mut self) -> &'tcx ty::Const<'tcx> {
-        self.tcx.mk_const(ty::Const::from_bool(self.tcx, true))
+        ty::Const::from_bool(self.tcx, true)
     }
 
     pub fn false_literal(&mut self) -> &'tcx ty::Const<'tcx> {
-        self.tcx.mk_const(ty::Const::from_bool(self.tcx, false))
+        ty::Const::from_bool(self.tcx, false)
     }
 
     pub fn const_eval_literal(
@@ -131,7 +131,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         ty: Ty<'tcx>,
         sp: Span,
         neg: bool,
-    ) -> ty::Const<'tcx> {
+    ) -> &'tcx ty::Const<'tcx> {
         trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
 
         match lit_to_const(lit, self.tcx, ty, neg) {
@@ -166,14 +166,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                         method_name: &str,
                         self_ty: Ty<'tcx>,
                         params: &[Kind<'tcx>])
-                        -> (Ty<'tcx>, ty::Const<'tcx>) {
+                        -> (Ty<'tcx>, &'tcx ty::Const<'tcx>) {
         let method_name = Symbol::intern(method_name);
         let substs = self.tcx.mk_substs_trait(self_ty, params);
         for item in self.tcx.associated_items(trait_def_id) {
             if item.kind == ty::AssociatedKind::Method && item.ident.name == method_name {
                 let method_ty = self.tcx.type_of(item.def_id);
                 let method_ty = method_ty.subst(self.tcx, substs);
-                return (method_ty, ty::Const::zero_sized(method_ty));
+                return (method_ty, ty::Const::zero_sized(self.tcx, method_ty));
             }
         }
 
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index d4f139e103a64..8e19913f4df26 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -31,15 +31,6 @@ pub enum LintLevel {
     Explicit(hir::HirId)
 }
 
-impl LintLevel {
-    pub fn is_explicit(self) -> bool {
-        match self {
-            LintLevel::Inherited => false,
-            LintLevel::Explicit(_) => true
-        }
-    }
-}
-
 #[derive(Clone, Debug)]
 pub struct Block<'tcx> {
     pub targeted_by_break: bool,
@@ -311,6 +302,8 @@ pub struct Arm<'tcx> {
     pub guard: Option<Guard<'tcx>>,
     pub body: ExprRef<'tcx>,
     pub lint_level: LintLevel,
+    pub scope: region::Scope,
+    pub span: Span,
 }
 
 #[derive(Clone, Debug)]
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index fd4416fc2b763..29e9c425685e8 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -172,7 +172,7 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const};
 use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size};
 
 use rustc::mir::Field;
-use rustc::mir::interpret::{ConstValue, Scalar, truncate};
+use rustc::mir::interpret::{ConstValue, Scalar, truncate, AllocId, Pointer};
 use rustc::util::common::ErrorReported;
 
 use syntax::attr::{SignedInt, UnsignedInt};
@@ -186,6 +186,7 @@ use std::fmt;
 use std::iter::{FromIterator, IntoIterator};
 use std::ops::RangeInclusive;
 use std::u128;
+use std::convert::TryInto;
 
 pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>)
                                 -> &'a Pattern<'tcx>
@@ -221,16 +222,17 @@ impl<'a, 'tcx> LiteralExpander<'a, 'tcx> {
             // unsize array to slice if pattern is array but match value or other patterns are slice
             (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
                 assert_eq!(t, u);
-                ConstValue::Slice(
-                    Scalar::Ptr(p),
-                    n.val.try_to_scalar()
-                        .unwrap()
-                        .to_usize(&self.tcx)
-                        .unwrap(),
-                )
+                ConstValue::Slice {
+                    data: self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id),
+                    start: p.offset.bytes().try_into().unwrap(),
+                    end: n.unwrap_usize(self.tcx).try_into().unwrap(),
+                }
             },
             // fat pointers stay the same
-            (ConstValue::Slice(..), _, _) => val,
+            | (ConstValue::Slice { .. }, _, _)
+            | (_, ty::Slice(_), ty::Slice(_))
+            | (_, ty::Str, ty::Str)
+            => val,
             // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
             _ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
         }
@@ -255,10 +257,10 @@ impl<'a, 'tcx> PatternFolder<'tcx> for LiteralExpander<'a, 'tcx> {
                         subpattern: Pattern {
                             ty: rty,
                             span: pat.span,
-                            kind: box PatternKind::Constant { value: Const {
-                                val: self.fold_const_value_deref(val, rty, crty),
+                            kind: box PatternKind::Constant { value: self.tcx.mk_const(Const {
+                                val: self.fold_const_value_deref(*val, rty, crty),
                                 ty: rty,
-                            } },
+                            }) },
                         }
                     }
                 }
@@ -423,7 +425,7 @@ enum Constructor<'tcx> {
     /// Enum variants.
     Variant(DefId),
     /// Literal values.
-    ConstantValue(ty::Const<'tcx>),
+    ConstantValue(&'tcx ty::Const<'tcx>),
     /// Ranges of literal values (`2...5` and `2..5`).
     ConstantRange(u128, u128, Ty<'tcx>, RangeEnd),
     /// Array patterns of length n.
@@ -786,9 +788,9 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
                         max_fixed_len,
                         n.unwrap_usize(cx.tcx),
                     ),
-                    (ConstValue::Slice(_, n), ty::Slice(_)) => max_fixed_len = cmp::max(
+                    (ConstValue::Slice{ start, end, .. }, ty::Slice(_)) => max_fixed_len = cmp::max(
                         max_fixed_len,
-                        n,
+                        (end - start) as u64,
                     ),
                     _ => {},
                 }
@@ -1424,49 +1426,24 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
 fn slice_pat_covered_by_const<'tcx>(
     tcx: TyCtxt<'_, 'tcx, '_>,
     _span: Span,
-    const_val: ty::Const<'tcx>,
+    const_val: &'tcx ty::Const<'tcx>,
     prefix: &[Pattern<'tcx>],
     slice: &Option<Pattern<'tcx>>,
     suffix: &[Pattern<'tcx>]
 ) -> Result<bool, ErrorReported> {
     let data: &[u8] = match (const_val.val, &const_val.ty.sty) {
         (ConstValue::ByRef(ptr, alloc), ty::Array(t, n)) => {
-            if *t != tcx.types.u8 {
-                // FIXME(oli-obk): can't mix const patterns with slice patterns and get
-                // any sort of exhaustiveness/unreachable check yet
-                // This solely means that we don't lint about unreachable patterns, even if some
-                // are definitely unreachable.
-                return Ok(false);
-            }
+            assert_eq!(*t, tcx.types.u8);
             let n = n.assert_usize(tcx).unwrap();
             alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
         },
-        // a slice fat pointer to a zero length slice
-        (ConstValue::Slice(Scalar::Bits { .. }, 0), ty::Slice(t)) => {
-            if *t != tcx.types.u8 {
-                // FIXME(oli-obk): can't mix const patterns with slice patterns and get
-                // any sort of exhaustiveness/unreachable check yet
-                // This solely means that we don't lint about unreachable patterns, even if some
-                // are definitely unreachable.
-                return Ok(false);
-            }
-            &[]
-        },
-        //
-        (ConstValue::Slice(Scalar::Ptr(ptr), n), ty::Slice(t)) => {
-            if *t != tcx.types.u8 {
-                // FIXME(oli-obk): can't mix const patterns with slice patterns and get
-                // any sort of exhaustiveness/unreachable check yet
-                // This solely means that we don't lint about unreachable patterns, even if some
-                // are definitely unreachable.
-                return Ok(false);
-            }
-            tcx.alloc_map
-                .lock()
-                .unwrap_memory(ptr.alloc_id)
-                .get_bytes(&tcx, ptr, Size::from_bytes(n))
-                .unwrap()
+        (ConstValue::Slice { data, start, end }, ty::Slice(t)) => {
+            assert_eq!(*t, tcx.types.u8);
+            let ptr = Pointer::new(AllocId(0), Size::from_bytes(start as u64));
+            data.get_bytes(&tcx, ptr, Size::from_bytes((end - start) as u64)).unwrap()
         },
+        // FIXME(oli-obk): create a way to extract fat pointers from ByRef
+        (_, ty::Slice(_)) => return Ok(false),
         _ => bug!(
             "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
             const_val, prefix, slice, suffix,
@@ -1774,11 +1751,12 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
                     // necessarily point to memory, they are usually just integers. The only time
                     // they should be pointing to memory is when they are subslices of nonzero
                     // slices
-                    let (opt_ptr, n, ty) = match value.ty.sty {
+                    let (alloc, offset, n, ty) = match value.ty.sty {
                         ty::Array(t, n) => {
                             match value.val {
                                 ConstValue::ByRef(ptr, alloc) => (
-                                    Some((ptr, alloc)),
+                                    alloc,
+                                    ptr.offset,
                                     n.unwrap_usize(cx.tcx),
                                     t,
                                 ),
@@ -1790,14 +1768,16 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
                         },
                         ty::Slice(t) => {
                             match value.val {
-                                ConstValue::Slice(ptr, n) => (
-                                    ptr.to_ptr().ok().map(|ptr| (
-                                        ptr,
-                                        cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
-                                    )),
-                                    n,
+                                ConstValue::Slice { data, start, end } => (
+                                    data,
+                                    Size::from_bytes(start as u64),
+                                    (end - start) as u64,
                                     t,
                                 ),
+                                ConstValue::ByRef(..) => {
+                                    // FIXME(oli-obk): implement `deref` for `ConstValue`
+                                    return None;
+                                },
                                 _ => span_bug!(
                                     pat.span,
                                     "slice pattern constant must be scalar pair but is {:?}",
@@ -1814,31 +1794,22 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
                     };
                     if wild_patterns.len() as u64 == n {
                         // convert a constant slice/array pattern to a list of patterns.
-                        match (n, opt_ptr) {
-                            (0, _) => Some(SmallVec::new()),
-                            (_, Some((ptr, alloc))) => {
-                                let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
-                                (0..n).map(|i| {
-                                    let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
-                                    let scalar = alloc.read_scalar(
-                                        &cx.tcx, ptr, layout.size,
-                                    ).ok()?;
-                                    let scalar = scalar.not_undef().ok()?;
-                                    let value = ty::Const::from_scalar(scalar, ty);
-                                    let pattern = Pattern {
-                                        ty,
-                                        span: pat.span,
-                                        kind: box PatternKind::Constant { value },
-                                    };
-                                    Some(&*cx.pattern_arena.alloc(pattern))
-                                }).collect()
-                            },
-                            (_, None) => span_bug!(
-                                pat.span,
-                                "non zero length slice with const-val {:?}",
-                                value,
-                            ),
-                        }
+                        let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
+                        let ptr = Pointer::new(AllocId(0), offset);
+                        (0..n).map(|i| {
+                            let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
+                            let scalar = alloc.read_scalar(
+                                &cx.tcx, ptr, layout.size,
+                            ).ok()?;
+                            let scalar = scalar.not_undef().ok()?;
+                            let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
+                            let pattern = Pattern {
+                                ty,
+                                span: pat.span,
+                                kind: box PatternKind::Constant { value },
+                            };
+                            Some(&*cx.pattern_arena.alloc(pattern))
+                        }).collect()
                     } else {
                         None
                     }
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 0576bb53d8f42..1c47f850ddb75 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -10,13 +10,13 @@ use crate::const_eval::{const_field, const_variant_index};
 use crate::hair::util::UserAnnotatedTyHelpers;
 use crate::hair::constant::*;
 
-use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
+use rustc::mir::{Field, BorrowKind, Mutability};
 use rustc::mir::{UserTypeProjection};
-use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
+use rustc::mir::interpret::{GlobalId, ConstValue, sign_extend, AllocId, Pointer};
 use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, UserType, DefIdTree};
 use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations};
 use rustc::ty::subst::{SubstsRef, Kind};
-use rustc::ty::layout::VariantIdx;
+use rustc::ty::layout::{VariantIdx, Size};
 use rustc::hir::{self, PatKind, RangeEnd};
 use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind};
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
@@ -152,7 +152,7 @@ pub enum PatternKind<'tcx> {
     },
 
     Constant {
-        value: ty::Const<'tcx>,
+        value: &'tcx ty::Const<'tcx>,
     },
 
     Range(PatternRange<'tcx>),
@@ -176,8 +176,8 @@ pub enum PatternKind<'tcx> {
 
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub struct PatternRange<'tcx> {
-    pub lo: ty::Const<'tcx>,
-    pub hi: ty::Const<'tcx>,
+    pub lo: &'tcx ty::Const<'tcx>,
+    pub hi: &'tcx ty::Const<'tcx>,
     pub ty: Ty<'tcx>,
     pub end: RangeEnd,
 }
@@ -291,15 +291,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
                 write!(f, "{}", subpattern)
             }
             PatternKind::Constant { value } => {
-                fmt_const_val(f, value)
+                write!(f, "{}", value)
             }
             PatternKind::Range(PatternRange { lo, hi, ty: _, end }) => {
-                fmt_const_val(f, lo)?;
+                write!(f, "{}", lo)?;
                 match end {
                     RangeEnd::Included => write!(f, "..=")?,
                     RangeEnd::Excluded => write!(f, "..")?,
                 }
-                fmt_const_val(f, hi)
+                write!(f, "{}", hi)
             }
             PatternKind::Slice { ref prefix, ref slice, ref suffix } |
             PatternKind::Array { ref prefix, ref slice, ref suffix } => {
@@ -942,7 +942,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
     fn const_to_pat(
         &self,
         instance: ty::Instance<'tcx>,
-        cv: ty::Const<'tcx>,
+        cv: &'tcx ty::Const<'tcx>,
         id: hir::HirId,
         span: Span,
     ) -> Pattern<'tcx> {
@@ -1205,7 +1205,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
             PatternKind::Constant {
                 value
             } => PatternKind::Constant {
-                value: value.fold_with(folder)
+                value,
             },
             PatternKind::Range(PatternRange {
                 lo,
@@ -1213,8 +1213,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
                 ty,
                 end,
             }) => PatternKind::Range(PatternRange {
-                lo: lo.fold_with(folder),
-                hi: hi.fold_with(folder),
+                lo,
+                hi,
                 ty: ty.fold_with(folder),
                 end,
             }),
@@ -1242,8 +1242,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
 
 pub fn compare_const_vals<'a, 'gcx, 'tcx>(
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    a: ty::Const<'tcx>,
-    b: ty::Const<'tcx>,
+    a: &'tcx ty::Const<'tcx>,
+    b: &'tcx ty::Const<'tcx>,
     ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
 ) -> Option<Ordering> {
     trace!("compare_const_vals: {:?}, {:?}", a, b);
@@ -1293,22 +1293,25 @@ pub fn compare_const_vals<'a, 'gcx, 'tcx>(
     if let ty::Str = ty.value.sty {
         match (a.val, b.val) {
             (
-                ConstValue::Slice(
-                    Scalar::Ptr(ptr_a),
-                    len_a,
-                ),
-                ConstValue::Slice(
-                    Scalar::Ptr(ptr_b),
-                    len_b,
-                ),
-            ) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => {
-                if len_a == len_b {
-                    let map = tcx.alloc_map.lock();
-                    let alloc_a = map.unwrap_memory(ptr_a.alloc_id);
-                    let alloc_b = map.unwrap_memory(ptr_b.alloc_id);
-                    if alloc_a.bytes.len() as u64 == len_a {
-                        return from_bool(alloc_a == alloc_b);
-                    }
+                ConstValue::Slice { data: alloc_a, start: offset_a, end: end_a },
+                ConstValue::Slice { data: alloc_b, start: offset_b, end: end_b },
+            ) => {
+                let len_a = end_a - offset_a;
+                let len_b = end_b - offset_b;
+                let a = alloc_a.get_bytes(
+                    &tcx,
+                    // invent a pointer, only the offset is relevant anyway
+                    Pointer::new(AllocId(0), Size::from_bytes(offset_a as u64)),
+                    Size::from_bytes(len_a as u64),
+                );
+                let b = alloc_b.get_bytes(
+                    &tcx,
+                    // invent a pointer, only the offset is relevant anyway
+                    Pointer::new(AllocId(0), Size::from_bytes(offset_b as u64)),
+                    Size::from_bytes(len_b as u64),
+                );
+                if let (Ok(a), Ok(b)) = (a, b) {
+                    return from_bool(a == b);
                 }
             }
             _ => (),
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 9c2b491925f47..407622dc2599b 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -500,7 +500,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
             Move(ref place) =>
                 self.eval_place_to_op(place, layout)?,
 
-            Constant(ref constant) => self.eval_const_to_op(*constant.literal, layout)?,
+            Constant(ref constant) => self.eval_const_to_op(constant.literal, layout)?,
         };
         trace!("{:?}: {:?}", mir_op, *op);
         Ok(op)
@@ -520,7 +520,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
     // in patterns via the `const_eval` module
     crate fn eval_const_to_op(
         &self,
-        val: ty::Const<'tcx>,
+        val: &'tcx ty::Const<'tcx>,
         layout: Option<TyLayout<'tcx>>,
     ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         let op = match val.val {
@@ -533,11 +533,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
                     MemPlace::from_ptr(ptr.with_default_tag(), alloc.align)
                 )
             },
-            ConstValue::Slice(a, b) =>
+            ConstValue::Slice { data, start, end } =>
                 Operand::Immediate(Immediate::ScalarPair(
-                    a.with_default_tag().into(),
-                    Scalar::from_uint(b, self.tcx.data_layout.pointer_size)
-                        .with_default_tag().into(),
+                    Scalar::from(Pointer::new(
+                        self.tcx.alloc_map.lock().allocate(data),
+                        Size::from_bytes(start as u64),
+                    )).with_default_tag().into(),
+                    Scalar::from_uint(
+                        (end - start) as u64,
+                        self.tcx.data_layout.pointer_size,
+                    ).with_default_tag().into(),
                 )),
             ConstValue::Scalar(x) =>
                 Operand::Immediate(Immediate::Scalar(x.with_default_tag().into())),
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 91cf0fbb9b44f..b90db7646d492 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -609,7 +609,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
     fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) {
         debug!("visiting const {:?} @ {:?}", *constant, location);
 
-        collect_const(self.tcx, **constant, self.param_substs, self.output);
+        collect_const(self.tcx, *constant, self.param_substs, self.output);
 
         self.super_const(constant);
     }
@@ -1248,17 +1248,17 @@ fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
 fn collect_const<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    constant: ty::Const<'tcx>,
+    constant: &'tcx ty::Const<'tcx>,
     param_substs: SubstsRef<'tcx>,
     output: &mut Vec<MonoItem<'tcx>>,
 ) {
     debug!("visiting const {:?}", constant);
 
     match constant.val {
-        ConstValue::Slice(Scalar::Ptr(ptr), _) |
         ConstValue::Scalar(Scalar::Ptr(ptr)) =>
             collect_miri(tcx, ptr.alloc_id, output),
-        ConstValue::ByRef(_ptr, alloc) => {
+        ConstValue::Slice { data: alloc, start: _, end: _ } |
+        ConstValue::ByRef(_, alloc) => {
             for &((), id) in alloc.relocations.values() {
                 collect_miri(tcx, id, output);
             }
diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs
index 999e7402afd93..f46c5ff9a2b8e 100644
--- a/src/librustc_mir/monomorphize/item.rs
+++ b/src/librustc_mir/monomorphize/item.rs
@@ -401,7 +401,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
     // as well as the unprintable types of constants (see `push_type_name` for more details).
     pub fn push_const_name(&self, c: &Const<'tcx>, output: &mut String, debug: bool) {
         match c.val {
-            ConstValue::Scalar(..) | ConstValue::Slice(..) | ConstValue::ByRef(..) => {
+            ConstValue::Scalar(..) | ConstValue::Slice { .. } | ConstValue::ByRef(..) => {
                 // FIXME(const_generics): we could probably do a better job here.
                 write!(output, "{:?}", c).unwrap()
             }
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 5bd3a1714887d..6a03ec83d232e 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -458,9 +458,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
             span: self.span,
             ty: func_ty,
             user_ty: None,
-            literal: tcx.mk_const(
-                ty::Const::zero_sized(func_ty),
-            ),
+            literal: ty::Const::zero_sized(tcx, func_ty),
         });
 
         let ref_loc = self.make_place(
@@ -520,9 +518,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
             span: self.span,
             ty: self.tcx.types.usize,
             user_ty: None,
-            literal: self.tcx.mk_const(
-                ty::Const::from_usize(self.tcx, value),
-            ),
+            literal: ty::Const::from_usize(self.tcx, value),
         }
     }
 
@@ -762,9 +758,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 span,
                 ty,
                 user_ty: None,
-                literal: tcx.mk_const(
-                    ty::Const::zero_sized(ty)
-                ),
+                literal: ty::Const::zero_sized(tcx, ty),
              }),
              vec![rcvr])
         }
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 72af027820106..9ec48a3aec060 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -280,7 +280,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
         c: &Constant<'tcx>,
     ) -> Option<Const<'tcx>> {
         self.ecx.tcx.span = c.span;
-        match self.ecx.eval_const_to_op(*c.literal, None) {
+        match self.ecx.eval_const_to_op(c.literal, None) {
             Ok(op) => {
                 Some(op)
             },
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index 023a61588c42e..6320cb4424814 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -533,9 +533,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
             span,
             ty: self.tcx.types.bool,
             user_ty: None,
-            literal: self.tcx.mk_const(
-                ty::Const::from_bool(self.tcx, val),
-            ),
+            literal: ty::Const::from_bool(self.tcx, val),
         })))
     }
 
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index d2da1e6e3ac9d..8e38ae6dde9b4 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -757,9 +757,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             span: mir.span,
             ty: tcx.types.bool,
             user_ty: None,
-            literal: tcx.mk_const(
-                ty::Const::from_bool(tcx, false),
-            ),
+            literal: ty::Const::from_bool(tcx, false),
         }),
         expected: true,
         msg: message,
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index 98ca7c32675c8..ac5ebc5e2512a 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -975,9 +975,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
             span: self.source_info.span,
             ty: self.tcx().types.usize,
             user_ty: None,
-            literal: self.tcx().mk_const(
-                ty::Const::from_usize(self.tcx(), val.into())
-            ),
+            literal: ty::Const::from_usize(self.tcx(), val.into()),
         })
     }
 
diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs
index c74314ce0c4b5..0088c97679c66 100644
--- a/src/librustc_passes/hir_stats.rs
+++ b/src/librustc_passes/hir_stats.rs
@@ -149,7 +149,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
     }
 
     fn visit_arm(&mut self, a: &'v hir::Arm) {
-        self.record("Arm", Id::None, a);
+        self.record("Arm", Id::Node(a.hir_id), a);
         hir_visit::walk_arm(self, a)
     }
 
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index a69f639e8941f..e4b431e6e68f1 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -540,7 +540,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         err.help(&format!("did you mean `{}: &{}`?", snippet, expected));
                     }
                 }
-                hir::Node::Expr(hir::Expr { node: hir::ExprKind::Match(..), .. }) |
+                hir::Node::Arm(_) |
                 hir::Node::Pat(_) => {
                     // rely on match ergonomics or it might be nested `&&pat`
                     if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) {
@@ -781,14 +781,17 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
     fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, span: Span) -> Option<(Span, String)> {
         use hir::Node::{Block, Item, Local};
 
-        let node = self.tcx.hir().get_by_hir_id(self.tcx.hir().get_parent_node_by_hir_id(
-            self.tcx.hir().get_parent_node_by_hir_id(hir_id),
-        ));
+        let hir = self.tcx.hir();
+        let arm_id = hir.get_parent_node_by_hir_id(hir_id);
+        let match_id = hir.get_parent_node_by_hir_id(arm_id);
+        let containing_id = hir.get_parent_node_by_hir_id(match_id);
+
+        let node = hir.get_by_hir_id(containing_id);
         if let Block(block) = node {
             // check that the body's parent is an fn
-            let parent = self.tcx.hir().get_by_hir_id(
-                self.tcx.hir().get_parent_node_by_hir_id(
-                    self.tcx.hir().get_parent_node_by_hir_id(block.hir_id),
+            let parent = hir.get_by_hir_id(
+                hir.get_parent_node_by_hir_id(
+                    hir.get_parent_node_by_hir_id(block.hir_id),
                 ),
             );
             if let (Some(expr), Item(hir::Item {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 362b6f0504d99..97d08938d0ba9 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4442,7 +4442,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 if element_ty.references_error() {
                     tcx.types.err
                 } else if let Ok(count) = count {
-                    tcx.mk_ty(ty::Array(t, tcx.mk_const(count)))
+                    tcx.mk_ty(ty::Array(t, count))
                 } else {
                     tcx.types.err
                 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f9a43ccfbace1..a325737e8fa6e 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2959,7 +2959,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
             ty::Str => Primitive(PrimitiveType::Str),
             ty::Slice(ty) => Slice(box ty.clean(cx)),
             ty::Array(ty, n) => {
-                let mut n = *cx.tcx.lift(&n).expect("array lift failed");
+                let mut n = cx.tcx.lift(&n).expect("array lift failed");
                 if let ConstValue::Unevaluated(def_id, substs) = n.val {
                     let param_env = cx.tcx.param_env(def_id);
                     let cid = GlobalId {
@@ -4119,7 +4119,7 @@ fn name_from_pat(p: &hir::Pat) -> String {
     }
 }
 
-fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
+fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String {
     match n.val {
         ConstValue::Unevaluated(def_id, _) => {
             if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
@@ -4129,12 +4129,15 @@ fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
             }
         },
         _ => {
-            let mut s = String::new();
-            ::rustc::mir::fmt_const_val(&mut s, n).expect("fmt_const_val failed");
+            let mut s = n.to_string();
             // array lengths are obviously usize
             if s.ends_with("usize") {
                 let n = s.len() - "usize".len();
                 s.truncate(n);
+                if s.ends_with(": ") {
+                    let n = s.len() - ": ".len();
+                    s.truncate(n);
+                }
             }
             s
         },
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index d12240655e628..14c77e589a6a1 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -912,6 +912,7 @@ pub struct Arm {
     pub pats: Vec<P<Pat>>,
     pub guard: Option<Guard>,
     pub body: P<Expr>,
+    pub span: Span,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index d24106f697e19..cb967a76822c9 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -890,12 +890,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.pat_tuple_struct(span, path, vec![pat])
     }
 
-    fn arm(&self, _span: Span, pats: Vec<P<ast::Pat>>, expr: P<ast::Expr>) -> ast::Arm {
+    fn arm(&self, span: Span, pats: Vec<P<ast::Pat>>, expr: P<ast::Expr>) -> ast::Arm {
         ast::Arm {
             attrs: vec![],
             pats,
             guard: None,
             body: expr,
+            span,
         }
     }
 
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index f587e63e12b94..cb21014ec7646 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -392,11 +392,15 @@ pub fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) {
     vis.visit_span(span);
 }
 
-pub fn noop_visit_arm<T: MutVisitor>(Arm { attrs, pats, guard, body }: &mut Arm, vis: &mut T) {
+pub fn noop_visit_arm<T: MutVisitor>(
+    Arm { attrs, pats, guard, body, span }: &mut Arm,
+    vis: &mut T,
+) {
     visit_attrs(attrs, vis);
     visit_vec(pats, |pat| vis.visit_pat(pat));
     visit_opt(guard, |guard| vis.visit_guard(guard));
     vis.visit_expr(body);
+    vis.visit_span(span);
 }
 
 pub fn noop_visit_guard<T: MutVisitor>(g: &mut Guard, vis: &mut T) {
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index e76605cde32ab..47da3ee6a6c78 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -62,19 +62,7 @@ pub struct StringReader<'a> {
     // cache a direct reference to the source text, so that we don't have to
     // retrieve it via `self.source_file.src.as_ref().unwrap()` all the time.
     src: Lrc<String>,
-    token: token::Token,
-    span: Span,
-    /// The raw source span which *does not* take `override_span` into account
-    span_src_raw: Span,
-    /// Stack of open delimiters and their spans. Used for error message.
-    open_braces: Vec<(token::DelimToken, Span)>,
-    crate unmatched_braces: Vec<UnmatchedBrace>,
-    /// The type and spans for all braces
-    ///
-    /// Used only for error recovery when arriving to EOF with mismatched braces.
-    matching_delim_spans: Vec<(token::DelimToken, Span, Span)>,
-    crate override_span: Option<Span>,
-    last_unclosed_found_span: Option<Span>,
+    override_span: Option<Span>,
 }
 
 impl<'a> StringReader<'a> {
@@ -121,8 +109,6 @@ impl<'a> StringReader<'a> {
             sp: self.peek_span,
         };
         self.advance_token()?;
-        self.span_src_raw = self.peek_span_src_raw;
-
         Ok(ret_val)
     }
 
@@ -159,9 +145,6 @@ impl<'a> StringReader<'a> {
             }
         }
 
-        self.token = t.tok.clone();
-        self.span = t.sp;
-
         Ok(t)
     }
 
@@ -251,14 +234,7 @@ impl<'a> StringReader<'a> {
             peek_span_src_raw: syntax_pos::DUMMY_SP,
             src,
             fatal_errs: Vec::new(),
-            token: token::Eof,
-            span: syntax_pos::DUMMY_SP,
-            span_src_raw: syntax_pos::DUMMY_SP,
-            open_braces: Vec::new(),
-            unmatched_braces: Vec::new(),
-            matching_delim_spans: Vec::new(),
             override_span,
-            last_unclosed_found_span: None,
         }
     }
 
diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs
index 0db36c84cdfeb..4bfc5bb16c0bb 100644
--- a/src/libsyntax/parse/lexer/tokentrees.rs
+++ b/src/libsyntax/parse/lexer/tokentrees.rs
@@ -1,13 +1,46 @@
+use syntax_pos::Span;
+
 use crate::print::pprust::token_to_string;
 use crate::parse::lexer::{StringReader, UnmatchedBrace};
 use crate::parse::{token, PResult};
 use crate::tokenstream::{DelimSpan, IsJoint::*, TokenStream, TokenTree, TreeAndJoint};
 
 impl<'a> StringReader<'a> {
+    crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
+        let mut tt_reader = TokenTreesReader {
+            string_reader: self,
+            token: token::Eof,
+            span: syntax_pos::DUMMY_SP,
+            open_braces: Vec::new(),
+            unmatched_braces: Vec::new(),
+            matching_delim_spans: Vec::new(),
+            last_unclosed_found_span: None,
+        };
+        let res = tt_reader.parse_all_token_trees();
+        (res, tt_reader.unmatched_braces)
+    }
+}
+
+struct TokenTreesReader<'a> {
+    string_reader: StringReader<'a>,
+    token: token::Token,
+    span: Span,
+    /// Stack of open delimiters and their spans. Used for error message.
+    open_braces: Vec<(token::DelimToken, Span)>,
+    unmatched_braces: Vec<UnmatchedBrace>,
+    /// The type and spans for all braces
+    ///
+    /// Used only for error recovery when arriving to EOF with mismatched braces.
+    matching_delim_spans: Vec<(token::DelimToken, Span, Span)>,
+    last_unclosed_found_span: Option<Span>,
+}
+
+impl<'a> TokenTreesReader<'a> {
     // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`.
-    crate fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
+    fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
         let mut tts = Vec::new();
 
+        self.real_token();
         while self.token != token::Eof {
             tts.push(self.parse_token_tree()?);
         }
@@ -34,11 +67,12 @@ impl<'a> StringReader<'a> {
     }
 
     fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> {
-        let sm = self.sess.source_map();
+        let sm = self.string_reader.sess.source_map();
         match self.token {
             token::Eof => {
                 let msg = "this file contains an un-closed delimiter";
-                let mut err = self.sess.span_diagnostic.struct_span_err(self.span, msg);
+                let mut err = self.string_reader.sess.span_diagnostic
+                    .struct_span_err(self.span, msg);
                 for &(_, sp) in &self.open_braces {
                     err.span_label(sp, "un-closed delimiter");
                 }
@@ -46,13 +80,12 @@ impl<'a> StringReader<'a> {
                 if let Some((delim, _)) = self.open_braces.last() {
                     if let Some((_, open_sp, close_sp)) = self.matching_delim_spans.iter()
                         .filter(|(d, open_sp, close_sp)| {
-
-                        if let Some(close_padding) = sm.span_to_margin(*close_sp) {
-                            if let Some(open_padding) = sm.span_to_margin(*open_sp) {
-                                return delim == d && close_padding != open_padding;
+                            if let Some(close_padding) = sm.span_to_margin(*close_sp) {
+                                if let Some(open_padding) = sm.span_to_margin(*open_sp) {
+                                    return delim == d && close_padding != open_padding;
+                                }
                             }
-                        }
-                        false
+                            false
                         }).next()  // these are in reverse order as they get inserted on close, but
                     {              // we want the last open/first close
                         err.span_label(
@@ -164,7 +197,8 @@ impl<'a> StringReader<'a> {
                 // matching opening delimiter).
                 let token_str = token_to_string(&self.token);
                 let msg = format!("unexpected close delimiter: `{}`", token_str);
-                let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &msg);
+                let mut err = self.string_reader.sess.span_diagnostic
+                    .struct_span_err(self.span, &msg);
                 err.span_label(self.span, "unexpected close delimiter");
                 Err(err)
             },
@@ -173,11 +207,20 @@ impl<'a> StringReader<'a> {
                 // Note that testing for joint-ness here is done via the raw
                 // source span as the joint-ness is a property of the raw source
                 // rather than wanting to take `override_span` into account.
-                let raw = self.span_src_raw;
+                // Additionally, we actually check if the *next* pair of tokens
+                // is joint, but this is equivalent to checking the current pair.
+                let raw = self.string_reader.peek_span_src_raw;
                 self.real_token();
-                let is_joint = raw.hi() == self.span_src_raw.lo() && token::is_op(&self.token);
+                let is_joint = raw.hi() == self.string_reader.peek_span_src_raw.lo()
+                    && token::is_op(&self.token);
                 Ok((tt, if is_joint { Joint } else { NonJoint }))
             }
         }
     }
+
+    fn real_token(&mut self) {
+        let t = self.string_reader.real_token();
+        self.token = t.tok;
+        self.span = t.sp;
+    }
 }
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 655baafcd2d5d..0611c1d9b42a5 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -290,22 +290,22 @@ pub fn source_file_to_stream(
 }
 
 /// Given a source file, produces a sequence of token trees. Returns any buffered errors from
-/// parsing the token tream.
+/// parsing the token stream.
 pub fn maybe_file_to_stream(
     sess: &ParseSess,
     source_file: Lrc<SourceFile>,
     override_span: Option<Span>,
 ) -> Result<(TokenStream, Vec<lexer::UnmatchedBrace>), Vec<Diagnostic>> {
-    let mut srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?;
-    srdr.real_token();
+    let srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?;
+    let (token_trees, unmatched_braces) = srdr.into_token_trees();
 
-    match srdr.parse_all_token_trees() {
-        Ok(stream) => Ok((stream, srdr.unmatched_braces)),
+    match token_trees {
+        Ok(stream) => Ok((stream, unmatched_braces)),
         Err(err) => {
             let mut buffer = Vec::with_capacity(1);
             err.buffer(&mut buffer);
             // Not using `emit_unclosed_delims` to use `db.buffer`
-            for unmatched in srdr.unmatched_braces {
+            for unmatched in unmatched_braces {
                 let mut db = sess.span_diagnostic.struct_span_err(unmatched.found_span, &format!(
                     "incorrect close delimiter: `{}`",
                     token_to_string(&token::Token::CloseDelim(unmatched.found_delim)),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 2d6c8c5407583..1c897f1bda944 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -4041,6 +4041,7 @@ impl<'a> Parser<'a> {
 
     crate fn parse_arm(&mut self) -> PResult<'a, Arm> {
         let attrs = self.parse_outer_attributes()?;
+        let lo = self.span;
         let pats = self.parse_pats()?;
         let guard = if self.eat_keyword(keywords::If) {
             Some(Guard::If(self.parse_expr()?))
@@ -4060,6 +4061,8 @@ impl<'a> Parser<'a> {
         let require_comma = classify::expr_requires_semi_to_be_stmt(&expr)
             && self.token != token::CloseDelim(token::Brace);
 
+        let hi = self.span;
+
         if require_comma {
             let cm = self.sess.source_map();
             self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)])
@@ -4103,6 +4106,7 @@ impl<'a> Parser<'a> {
             pats,
             guard,
             body: expr,
+            span: lo.to(hi),
         })
     }
 
diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs
index d4852db6d475e..9f55d84964405 100644
--- a/src/test/mir-opt/box_expr.rs
+++ b/src/test/mir-opt/box_expr.rs
@@ -22,13 +22,11 @@ impl Drop for S {
 // END RUST SOURCE
 // START rustc.main.ElaborateDrops.before.mir
 //     let mut _0: ();
+//     let _1: std::boxed::Box<S>;
 //     let mut _2: std::boxed::Box<S>;
 //     let mut _3: ();
 //     let mut _4: std::boxed::Box<S>;
 //     scope 1 {
-//         let _1: std::boxed::Box<S>;
-//     }
-//     scope 2 {
 //     }
 //     bb0: {
 //         StorageLive(_1);
@@ -54,7 +52,7 @@ impl Drop for S {
 //         StorageDead(_2);
 //         StorageLive(_4);
 //         _4 = move _1;
-//         _3 = const std::mem::drop(move _4) -> [return: bb5, unwind: bb7];
+//         _3 = const std::mem::drop::<std::boxed::Box<S>>(move _4) -> [return: bb5, unwind: bb7];
 //     }
 //
 //     bb5: {
diff --git a/src/test/mir-opt/byte_slice.rs b/src/test/mir-opt/byte_slice.rs
new file mode 100644
index 0000000000000..7edfa3e1124db
--- /dev/null
+++ b/src/test/mir-opt/byte_slice.rs
@@ -0,0 +1,15 @@
+// compile-flags: -Z mir-opt-level=0
+
+fn main() {
+    let x = b"foo";
+    let y = [5u8, b'x'];
+}
+
+// END RUST SOURCE
+// START rustc.main.EraseRegions.after.mir
+// ...
+// _1 = const b"foo";
+// ...
+// _2 = [const 5u8, const 120u8];
+// ...
+// END rustc.main.EraseRegions.after.mir
diff --git a/src/test/mir-opt/inline-trait-method.rs b/src/test/mir-opt/inline-trait-method.rs
index 0f79f43ee2df0..a2c5fb920cd30 100644
--- a/src/test/mir-opt/inline-trait-method.rs
+++ b/src/test/mir-opt/inline-trait-method.rs
@@ -25,7 +25,7 @@ impl X for () {
 // ...
 // bb0: {
 // ...
-//     _0 = const X::y(move _2) -> bb1;
+//     _0 = const <dyn X as X>::y(move _2) -> bb1;
 // }
 // ...
 // END rustc.test.Inline.after.mir
diff --git a/src/test/mir-opt/inline-trait-method_2.rs b/src/test/mir-opt/inline-trait-method_2.rs
index 8f9f2535aa5f8..4ad4311113a3a 100644
--- a/src/test/mir-opt/inline-trait-method_2.rs
+++ b/src/test/mir-opt/inline-trait-method_2.rs
@@ -30,7 +30,7 @@ fn main() {
 // ...
 // bb0: {
 // ...
-//     _0 = const X::y(move _2) -> bb1;
+//     _0 = const <dyn X as X>::y(move _2) -> bb1;
 // }
 // ...
 // END rustc.test2.Inline.after.mir
diff --git a/src/test/mir-opt/issue-41110.rs b/src/test/mir-opt/issue-41110.rs
index 023440af0eb10..0b678be2ab319 100644
--- a/src/test/mir-opt/issue-41110.rs
+++ b/src/test/mir-opt/issue-41110.rs
@@ -29,27 +29,24 @@ impl S {
 // END RUST SOURCE
 // START rustc.main.ElaborateDrops.after.mir
 //    let mut _0: ();
+//    let _1: ();
 //    let mut _2: S;
 //    let mut _3: S;
 //    let mut _4: S;
 //    let mut _5: bool;
 //    scope 1 {
-//        let _1: ();
-//    }
-//    scope 2 {
 //    }
 //    ...
 //    bb0: {
 // END rustc.main.ElaborateDrops.after.mir
 // START rustc.test.ElaborateDrops.after.mir
 //    let mut _0: ();
+//    let _1: S;
 //    let mut _3: ();
 //    let mut _4: S;
 //    let mut _5: S;
 //    let mut _6: bool;
 //    ...
-//    let _1: S;
-//    ...
 //    let mut _2: S;
 //    ...
 //    bb0: {
diff --git a/src/test/mir-opt/issue-49232.rs b/src/test/mir-opt/issue-49232.rs
index 29446d2ecc23e..447f3a07a6a98 100644
--- a/src/test/mir-opt/issue-49232.rs
+++ b/src/test/mir-opt/issue-49232.rs
@@ -18,14 +18,12 @@ fn main() {
 // fn main() -> (){
 //     let mut _0: ();
 //     let mut _1: ();
+//     let _2: i32;
 //     let mut _3: bool;
 //     let mut _4: !;
 //     let mut _5: ();
 //     let mut _6: &i32;
 //     scope 1 {
-//         let _2: i32;
-//     }
-//     scope 2 {
 //     }
 //     bb0: {
 //         goto -> bb1;
@@ -88,7 +86,6 @@ fn main() {
 //         unreachable;
 //     }
 //     bb17: {
-//         StorageDead(_4);
 //         goto -> bb18;
 //     }
 //     bb18: {
@@ -96,7 +93,7 @@ fn main() {
 //         StorageDead(_3);
 //         StorageLive(_6);
 //         _6 = &_2;
-//         _5 = const std::mem::drop(move _6) -> [return: bb19, unwind: bb4];
+//         _5 = const std::mem::drop::<&i32>(move _6) -> [return: bb19, unwind: bb4];
 //     }
 //     bb19: {
 //         StorageDead(_6);
diff --git a/src/test/mir-opt/match-arm-scopes.rs b/src/test/mir-opt/match-arm-scopes.rs
new file mode 100644
index 0000000000000..0f026b8a08dfa
--- /dev/null
+++ b/src/test/mir-opt/match-arm-scopes.rs
@@ -0,0 +1,245 @@
+// Test that StorageDead and Drops are generated properly for bindings in
+// matches:
+// * The MIR should only contain a single drop of `s` and `t`: at the end
+//   of their respective arms.
+// * StorageDead and StorageLive statements are correctly matched up on
+//   non-unwind paths.
+// * The visibility scopes of the match arms should be disjoint, and contain.
+//   all of the bindings for that scope.
+// * No drop flags are used.
+
+#![feature(nll, bind_by_move_pattern_guards)]
+
+fn complicated_match(cond: bool, items: (bool, bool, String)) -> i32 {
+    match items {
+        (false, a, s) | (a, false, s) if if cond { return 3 } else { a } => 1,
+        (true, b, t) | (false, b, t) => 2,
+    }
+}
+
+const CASES: &[(bool, bool, bool, i32)] = &[
+    (false, false, false, 2),
+    (false, false, true, 1),
+    (false, true, false, 1),
+    (false, true, true, 2),
+    (true, false, false, 3),
+    (true, false, true, 3),
+    (true, true, false, 3),
+    (true, true, true, 2),
+];
+
+fn main() {
+    for &(cond, items_1, items_2, result) in CASES {
+        assert_eq!(
+            complicated_match(cond, (items_1, items_2, String::new())),
+            result,
+        );
+    }
+}
+
+// END RUST SOURCE
+// START rustc.complicated_match.SimplifyCfg-initial.after.mir
+// let mut _0: i32;
+// let mut _3: &bool;                   // Temp for fake borrow of `items.0`
+// let mut _4: &bool;                   // Temp for fake borrow of `items.1`
+// let _5: bool;                    // `a` in arm
+// let _6: &bool;                   // `a` in guard
+// let _7: std::string::String;     // `s` in arm
+// let _8: &std::string::String;    // `s` in guard
+// let mut _9: bool;                    // `if cond { return 3 } else { a }`
+// let mut _10: bool;                   // `cond`
+// let mut _11: !;                      // `return 3`
+// let mut _12: bool;                   // `if cond { return 3 } else { a }`
+// let mut _13: bool;                   // `cond`
+// let mut _14: !;                      // `return 3`
+// let _15: bool;                   // `b`
+// let _16: std::string::String;    // `t`
+// scope 1 {
+// }
+// scope 2 {
+// }
+// bb0: {
+//     FakeRead(ForMatchedPlace, _2);
+//     switchInt((_2.0: bool)) -> [false: bb2, otherwise: bb7];
+// }
+// bb1 (cleanup): {
+//     resume;
+// }
+// bb2: {
+//     falseEdges -> [real: bb10, imaginary: bb3];
+// }
+// bb3: {
+//     falseEdges -> [real: bb21, imaginary: bb4];
+// }
+// bb4: {
+//     falseEdges -> [real: bb31, imaginary: bb5];
+// }
+// bb5: {
+//     falseEdges -> [real: bb32, imaginary: bb6];
+// }
+// bb6: {
+//     unreachable;
+// }
+// bb7: {
+//     switchInt((_2.1: bool)) -> [false: bb3, otherwise: bb8];
+// }
+// bb8: {
+//     switchInt((_2.0: bool)) -> [false: bb5, otherwise: bb4];
+// }
+// bb9: {                               // arm 1
+//     _0 = const 1i32;
+//     drop(_7) -> [return: bb29, unwind: bb16];
+// }
+// bb10: {                              // guard - first time
+//     StorageLive(_6);
+//     _6 = &(_2.1: bool);
+//     StorageLive(_8);
+//     _8 = &(_2.2: std::string::String);
+//     _3 = &shallow (_2.0: bool);
+//     _4 = &shallow (_2.1: bool);
+//     StorageLive(_9);
+//     StorageLive(_10);
+//     _10 = _1;
+//     FakeRead(ForMatchedPlace, _10);
+//     switchInt(_10) -> [false: bb12, otherwise: bb11];
+// }
+// bb11: {
+//     falseEdges -> [real: bb14, imaginary: bb12];
+// }
+// bb12: {
+//     falseEdges -> [real: bb18, imaginary: bb13];
+// }
+// bb13: {
+//     unreachable;
+// }
+// bb14: {                              // `return 3` - first time
+//     _0 = const 3i32;
+//     StorageDead(_10);
+//     StorageDead(_9);
+//     StorageDead(_8);
+//     StorageDead(_6);
+//     goto -> bb17;
+// }
+// bb15: {
+//     return;
+// }
+// bb16 (cleanup): {
+//     drop(_2) -> bb1;
+// }
+// bb17: {
+//     drop(_2) -> [return: bb15, unwind: bb1];
+// }
+// bb18: {                              // `else` block - first time
+//     _9 = (*_6);
+//     StorageDead(_10);
+//     FakeRead(ForMatchGuard, _3);
+//     FakeRead(ForMatchGuard, _4);
+//     FakeRead(ForGuardBinding, _6);
+//     FakeRead(ForGuardBinding, _8);
+//     switchInt(move _9) -> [false: bb20, otherwise: bb19];
+// }
+// bb19: {
+//     StorageDead(_9);
+//     StorageLive(_5);
+//     _5 = (_2.1: bool);
+//     StorageLive(_7);
+//     _7 = move (_2.2: std::string::String);
+//     goto -> bb9;
+// }
+// bb20: {                              // guard otherwise case - first time
+//     StorageDead(_9);
+//     StorageDead(_8);
+//     StorageDead(_6);
+//     falseEdges -> [real: bb7, imaginary: bb3];
+// }
+// bb21: {                              // guard - second time
+//     StorageLive(_6);
+//     _6 = &(_2.0: bool);
+//     StorageLive(_8);
+//     _8 = &(_2.2: std::string::String);
+//     _3 = &shallow (_2.0: bool);
+//     _4 = &shallow (_2.1: bool);
+//     StorageLive(_12);
+//     StorageLive(_13);
+//     _13 = _1;
+//     FakeRead(ForMatchedPlace, _13);
+//     switchInt(_13) -> [false: bb23, otherwise: bb22];
+// }
+// bb22: {
+//     falseEdges -> [real: bb25, imaginary: bb23];
+// }
+// bb23: {
+//     falseEdges -> [real: bb26, imaginary: bb24];
+// }
+// bb24: {
+//     unreachable;
+// }
+// bb25: {                              // `return 3` - second time
+//     _0 = const 3i32;
+//     StorageDead(_13);
+//     StorageDead(_12);
+//     StorageDead(_8);
+//     StorageDead(_6);
+//     goto -> bb17;
+// }
+// bb26: {                              // `else` block - second time
+//     _12 = (*_6);
+//     StorageDead(_13);
+//     FakeRead(ForMatchGuard, _3);
+//     FakeRead(ForMatchGuard, _4);
+//     FakeRead(ForGuardBinding, _6);
+//     FakeRead(ForGuardBinding, _8);
+//     switchInt(move _12) -> [false: bb28, otherwise: bb27];
+// }
+// bb27: {                              // Guard otherwise case - second time
+//     StorageDead(_12);
+//     StorageLive(_5);
+//     _5 = (_2.0: bool);
+//     StorageLive(_7);
+//     _7 = move (_2.2: std::string::String);
+//     goto -> bb9;
+// }
+// bb28: {                              // rest of arm 1
+//     StorageDead(_12);
+//     StorageDead(_8);
+//     StorageDead(_6);
+//     falseEdges -> [real: bb8, imaginary: bb4];
+// }
+// bb29: {
+//     StorageDead(_7);
+//     StorageDead(_5);
+//     StorageDead(_8);
+//     StorageDead(_6);
+//     goto -> bb34;
+// }
+// bb30: {                              // arm 2
+//     _0 = const 2i32;
+//     drop(_16) -> [return: bb33, unwind: bb16];
+// }
+// bb31: {                              // bindings for arm 2 - first pattern
+//     StorageLive(_15);
+//     _15 = (_2.1: bool);
+//     StorageLive(_16);
+//     _16 = move (_2.2: std::string::String);
+//     goto -> bb30;
+// }
+// bb32: {                              // bindings for arm 2 - first pattern
+//     StorageLive(_15);
+//     _15 = (_2.1: bool);
+//     StorageLive(_16);
+//     _16 = move (_2.2: std::string::String);
+//     goto -> bb30;
+// }
+// bb33: {                              // rest of arm 2
+//     StorageDead(_16);
+//     StorageDead(_15);
+//     goto -> bb34;
+// }
+// bb34: {                              // end of match
+//     drop(_2) -> [return: bb15, unwind: bb1];
+// }
+// END rustc.complicated_match.SimplifyCfg-initial.after.mir
+// START rustc.complicated_match.ElaborateDrops.after.mir
+// let _16: std::string::String;      // No drop flags, which would come after this.
+// scope 1 {
+// END rustc.complicated_match.ElaborateDrops.after.mir
diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs
index 7ac36a22274f3..6979924c8cd90 100644
--- a/src/test/mir-opt/match_false_edges.rs
+++ b/src/test/mir-opt/match_false_edges.rs
@@ -45,13 +45,13 @@ fn main() {
 //      _2 = std::option::Option::<i32>::Some(const 42i32,);
 //      FakeRead(ForMatchedPlace, _2);
 //      _3 = discriminant(_2);
-//      switchInt(move _3) -> [0isize: bb4, 1isize: bb2, otherwise: bb7];
+//      switchInt(move _3) -> [0isize: bb4, 1isize: bb2, otherwise: bb6];
 //  }
 //  bb1 (cleanup): {
 //      resume;
 //  }
 //  bb2: {
-//      falseEdges -> [real: bb8, imaginary: bb3]; //pre_binding1
+//      falseEdges -> [real: bb7, imaginary: bb3]; //pre_binding1
 //  }
 //  bb3: {
 //      falseEdges -> [real: bb11, imaginary: bb4]; //pre_binding2
@@ -62,48 +62,56 @@ fn main() {
 //  bb5: {
 //      unreachable;
 //  }
-//  bb6: { // to pre_binding2
-//      falseEdges -> [real: bb3, imaginary: bb3];
-//  }
-//  bb7: {
+//  bb6: {
 //      unreachable;
 //  }
-//  bb8: { // binding1 and guard
+//  bb7: { // binding1 and guard
 //      StorageLive(_6);
 //      _6 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32);
 //      _4 = &shallow _2;
 //      StorageLive(_7);
-//      _7 = const guard() -> [return: bb9, unwind: bb1];
+//      _7 = const guard() -> [return: bb8, unwind: bb1];
 //  }
-//  bb9: {
+//  bb8: { // end of guard
 //      FakeRead(ForMatchGuard, _4);
 //      FakeRead(ForGuardBinding, _6);
-//      switchInt(move _7) -> [false: bb6, otherwise: bb10];
+//      switchInt(move _7) -> [false: bb10, otherwise: bb9];
 //  }
-//  bb10: {
+//  bb9: { // arm1
+//      StorageDead(_7);
 //      StorageLive(_5);
 //      _5 = ((_2 as Some).0: i32);
 //      StorageLive(_8);
 //      _8 = _5;
 //      _1 = (const 1i32, move _8);
 //      StorageDead(_8);
+//      StorageDead(_5);
+//      StorageDead(_6);
 //      goto -> bb13;
 //  }
-//  bb11: {
+//  bb10: { // to pre_binding2
+//      StorageDead(_7);
+//      StorageDead(_6);
+//      falseEdges -> [real: bb3, imaginary: bb3];
+//  }
+//  bb11: { // arm2
 //      StorageLive(_9);
 //      _9 = ((_2 as Some).0: i32);
 //      StorageLive(_10);
 //      _10 = _9;
 //      _1 = (const 2i32, move _10);
 //      StorageDead(_10);
+//      StorageDead(_9);
 //      goto -> bb13;
 //  }
-//  bb12: {
+//  bb12: { // arm3
 //      _1 = (const 3i32, const 3i32);
 //      goto -> bb13;
 //  }
 //  bb13: {
-//      ...
+//      StorageDead(_2);
+//      StorageDead(_1);
+//      _0 = ();
 //      return;
 //  }
 // END rustc.full_tested_match.QualifyAndPromoteConstants.after.mir
@@ -114,13 +122,13 @@ fn main() {
 //      _2 = std::option::Option::<i32>::Some(const 42i32,);
 //      FakeRead(ForMatchedPlace, _2);
 //      _3 = discriminant(_2);
-//      switchInt(move _3) -> [0isize: bb3, 1isize: bb2, otherwise: bb7];
+//      switchInt(move _3) -> [0isize: bb3, 1isize: bb2, otherwise: bb6];
 //  }
 //  bb1 (cleanup): {
 //      resume;
 //  }
 //  bb2: {
-//      falseEdges -> [real: bb8, imaginary: bb3];
+//      falseEdges -> [real: bb7, imaginary: bb3];
 //  }
 //  bb3: {
 //      falseEdges -> [real: bb11, imaginary: bb4];
@@ -131,33 +139,38 @@ fn main() {
 //  bb5: {
 //      unreachable;
 //  }
-//  bb6: { // to pre_binding3 (can skip 2 since this is `Some`)
-//      falseEdges -> [real: bb4, imaginary: bb3];
-//  }
-//  bb7: {
+//  bb6: {
 //      unreachable;
 //  }
-//  bb8: { // binding1 and guard
+//  bb7: { // binding1 and guard
 //      StorageLive(_6);
 //      _6 = &((_2 as Some).0: i32);
 //      _4 = &shallow _2;
 //      StorageLive(_7);
-//      _7 = const guard() -> [return: bb9, unwind: bb1];
+//      _7 = const guard() -> [return: bb8, unwind: bb1];
 //  }
-//  bb9: { // end of guard
+//  bb8: { // end of guard
 //      FakeRead(ForMatchGuard, _4);
 //      FakeRead(ForGuardBinding, _6);
-//      switchInt(move _7) -> [false: bb6, otherwise: bb10];
+//      switchInt(move _7) -> [false: bb10, otherwise: bb9];
 //  }
-//  bb10: { // arm1
+//  bb9: { // arm1
+//      StorageDead(_7);
 //      StorageLive(_5);
 //      _5 = ((_2 as Some).0: i32);
 //      StorageLive(_8);
 //      _8 = _5;
 //      _1 = (const 1i32, move _8);
 //      StorageDead(_8);
+//      StorageDead(_5);
+//      StorageDead(_6);
 //      goto -> bb13;
 //  }
+//  bb10: { // to pre_binding3 (can skip 2 since this is `Some`)
+//      StorageDead(_7);
+//      StorageDead(_6);
+//      falseEdges -> [real: bb4, imaginary: bb3];
+//  }
 //  bb11: { // arm2
 //      _1 = (const 3i32, const 3i32);
 //      goto -> bb13;
@@ -169,16 +182,19 @@ fn main() {
 //      _10 = _9;
 //      _1 = (const 2i32, move _10);
 //      StorageDead(_10);
+//      StorageDead(_9);
 //      goto -> bb13;
 //  }
 //  bb13: {
-//      ...
+//      StorageDead(_2);
+//      StorageDead(_1);
+//      _0 = ();
 //      return;
 //  }
 // END rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir
 //
 // START rustc.main.QualifyAndPromoteConstants.before.mir
-// bb0: {
+//  bb0: {
 //     ...
 //      _2 = std::option::Option::<i32>::Some(const 1i32,);
 //      FakeRead(ForMatchedPlace, _2);
@@ -189,13 +205,13 @@ fn main() {
 //      resume;
 //  }
 //  bb2: {
-//      falseEdges -> [real: bb9, imaginary: bb3];
+//      falseEdges -> [real: bb7, imaginary: bb3];
 //  }
 //  bb3: {
-//      falseEdges -> [real: bb12, imaginary: bb4];
+//      falseEdges -> [real: bb11, imaginary: bb4];
 //  }
 //  bb4: {
-//      falseEdges -> [real: bb13, imaginary: bb5];
+//      falseEdges -> [real: bb12, imaginary: bb5];
 //  }
 //  bb5: {
 //      falseEdges -> [real: bb16, imaginary: bb6];
@@ -203,65 +219,79 @@ fn main() {
 //  bb6: {
 //      unreachable;
 //  }
-//  bb7: {
-//      falseEdges -> [real: bb3, imaginary: bb3];
-//  }
-//  bb8: {
-//      falseEdges -> [real: bb5, imaginary: bb5];
-//  }
-//  bb9: { // binding1: Some(w) if guard()
+//  bb7: { // binding1: Some(w) if guard()
 //      StorageLive(_7);
 //      _7 = &((_2 as Some).0: i32);
 //      _5 = &shallow _2;
 //      StorageLive(_8);
-//      _8 = const guard() -> [return: bb10, unwind: bb1];
+//      _8 = const guard() -> [return: bb8, unwind: bb1];
 //  }
-//  bb10: { //end of guard
+//  bb8: { //end of guard1
 //      FakeRead(ForMatchGuard, _5);
 //      FakeRead(ForGuardBinding, _7);
-//      switchInt(move _8) -> [false: bb7, otherwise: bb11];
+//      switchInt(move _8) -> [false: bb10, otherwise: bb9];
 //  }
-//  bb11: { // set up bindings for arm1
+//  bb9: {
+//      StorageDead(_8);
 //      StorageLive(_6);
 //      _6 = ((_2 as Some).0: i32);
 //      _1 = const 1i32;
+//      StorageDead(_6);
+//      StorageDead(_7);
 //      goto -> bb17;
 //  }
-//  bb12: { // binding2 & arm2
+//  bb10: {
+//      StorageDead(_8);
+//      StorageDead(_7);
+//      falseEdges -> [real: bb3, imaginary: bb3];
+//  }
+//  bb11: { // binding2 & arm2
 //      StorageLive(_9);
 //      _9 = _2;
 //      _1 = const 2i32;
+//      StorageDead(_9);
 //      goto -> bb17;
 //  }
-//  bb13: { // binding3: Some(y) if guard2(y)
+//  bb12: { // binding3: Some(y) if guard2(y)
 //      StorageLive(_11);
 //      _11 = &((_2 as Some).0: i32);
 //      _5 = &shallow _2;
 //      StorageLive(_12);
 //      StorageLive(_13);
 //      _13 = (*_11);
-//      _12 = const guard2(move _13) -> [return: bb14, unwind: bb1];
+//      _12 = const guard2(move _13) -> [return: bb13, unwind: bb1];
 //  }
-//  bb14: { // end of guard2
+//  bb13: { // end of guard2
 //      StorageDead(_13);
 //      FakeRead(ForMatchGuard, _5);
 //      FakeRead(ForGuardBinding, _11);
-//      switchInt(move _12) -> [false: bb8, otherwise: bb15];
+//      switchInt(move _12) -> [false: bb15, otherwise: bb14];
 //  }
-//  bb15: { // binding4 & arm4
+//  bb14: { // binding4 & arm4
+//      StorageDead(_12);
 //      StorageLive(_10);
 //      _10 = ((_2 as Some).0: i32);
 //      _1 = const 3i32;
+//      StorageDead(_10);
+//      StorageDead(_11);
 //      goto -> bb17;
 //  }
+//  bb15: {
+//      StorageDead(_12);
+//      StorageDead(_11);
+//      falseEdges -> [real: bb5, imaginary: bb5];
+//  }
 //  bb16: {
 //      StorageLive(_14);
 //      _14 = _2;
 //      _1 = const 4i32;
+//      StorageDead(_14);
 //      goto -> bb17;
 //  }
 //  bb17: {
-//      ...
+//      StorageDead(_2);
+//      StorageDead(_1);
+//      _0 = ();
 //      return;
 //  }
 // END rustc.main.QualifyAndPromoteConstants.before.mir
diff --git a/src/test/mir-opt/match_test.rs b/src/test/mir-opt/match_test.rs
index a5317f98ef188..2ef9520c12c63 100644
--- a/src/test/mir-opt/match_test.rs
+++ b/src/test/mir-opt/match_test.rs
@@ -20,10 +20,10 @@ fn main() {
 // START rustc.main.SimplifyCfg-initial.after.mir
 //    bb0: {
 //        ...
-//        switchInt(move _4) -> [false: bb7, otherwise: bb8];
+//        switchInt(move _4) -> [false: bb6, otherwise: bb7];
 //    }
 //    bb1: {
-//        falseEdges -> [real: bb12, imaginary: bb2];
+//        falseEdges -> [real: bb10, imaginary: bb2];
 //    }
 //    bb2: {
 //        falseEdges -> [real: bb13, imaginary: bb3];
@@ -38,33 +38,35 @@ fn main() {
 //        unreachable;
 //    }
 //    bb6: {
-//        falseEdges -> [real: bb4, imaginary: bb2];
+//        _6 = Le(const 10i32, _1);
+//        switchInt(move _6) -> [false: bb8, otherwise: bb9];
 //    }
 //    bb7: {
-//        _6 = Le(const 10i32, _1);
-//        switchInt(move _6) -> [false: bb9, otherwise: bb10];
+//        _5 = Lt(_1, const 10i32);
+//        switchInt(move _5) -> [false: bb6, otherwise: bb1];
 //    }
 //    bb8: {
-//        _5 = Lt(_1, const 10i32);
-//        switchInt(move _5) -> [false: bb7, otherwise: bb1];
+//        switchInt(_1) -> [-1i32: bb3, otherwise: bb4];
 //    }
 //    bb9: {
-//        switchInt(_1) -> [-1i32: bb3, otherwise: bb4];
+//        _7 = Le(_1, const 20i32);
+//        switchInt(move _7) -> [false: bb8, otherwise: bb2];
 //    }
 //    bb10: {
-//        _7 = Le(_1, const 20i32);
-//        switchInt(move _7) -> [false: bb9, otherwise: bb2];
+//        _8 = &shallow _1;
+//        StorageLive(_9);
+//        _9 = _2;
+//        FakeRead(ForMatchGuard, _8);
+//        switchInt(move _9) -> [false: bb12, otherwise: bb11];
 //    }
 //    bb11: {
+//        StorageDead(_9);
 //        _3 = const 0i32;
 //        goto -> bb16;
 //    }
 //    bb12: {
-//        _8 = &shallow _1;
-//        StorageLive(_9);
-//        _9 = _2;
-//        FakeRead(ForMatchGuard, _8);
-//        switchInt(move _9) -> [false: bb6, otherwise: bb11];
+//        StorageDead(_9);
+//        falseEdges -> [real: bb4, imaginary: bb2];
 //    }
 //    bb13: {
 //        _3 = const 1i32;
@@ -79,7 +81,6 @@ fn main() {
 //        goto -> bb16;
 //    }
 //    bb16: {
-//        StorageDead(_9);
 //        _0 = ();
 //        StorageDead(_2);
 //        StorageDead(_1);
diff --git a/src/test/mir-opt/packed-struct-drop-aligned.rs b/src/test/mir-opt/packed-struct-drop-aligned.rs
index 7e8c58e64c28d..da73cc96348f0 100644
--- a/src/test/mir-opt/packed-struct-drop-aligned.rs
+++ b/src/test/mir-opt/packed-struct-drop-aligned.rs
@@ -18,15 +18,13 @@ impl Drop for Droppy {
 // START rustc.main.EraseRegions.before.mir
 // fn main() -> () {
 //     let mut _0: ();
+//     let mut _1: Packed;
 //     let mut _2: Aligned;
 //     let mut _3: Droppy;
 //     let mut _4: Aligned;
 //     let mut _5: Droppy;
 //     let mut _6: Aligned;
 //     scope 1 {
-//         let mut _1: Packed;
-//     }
-//     scope 2 {
 //     }
 //
 //     bb0: {
diff --git a/src/test/mir-opt/remove_fake_borrows.rs b/src/test/mir-opt/remove_fake_borrows.rs
index 144348450a91b..12de1e8a51c4b 100644
--- a/src/test/mir-opt/remove_fake_borrows.rs
+++ b/src/test/mir-opt/remove_fake_borrows.rs
@@ -21,10 +21,10 @@ fn main() {
 // bb0: {
 //     FakeRead(ForMatchedPlace, _1);
 //     _3 = discriminant(_1);
-//     switchInt(move _3) -> [1isize: bb5, otherwise: bb2];
+//     switchInt(move _3) -> [1isize: bb4, otherwise: bb2];
 // }
 // bb1: {
-//     goto -> bb7;
+//     goto -> bb5;
 // }
 // bb2: {
 //     goto -> bb8;
@@ -33,16 +33,9 @@ fn main() {
 //     unreachable;
 // }
 // bb4: {
-//     goto -> bb2;
-// }
-// bb5: {
 //     switchInt((*(*((_1 as Some).0: &'<empty> &'<empty> i32)))) -> [0i32: bb1, otherwise: bb2];
 // }
-// bb6: {
-//     _0 = const 0i32;
-//     goto -> bb9;
-// }
-// bb7: {
+// bb5: {
 //     _4 = &shallow _1;
 //     _5 = &shallow ((_1 as Some).0: &'<empty> &'<empty> i32);
 //     _6 = &shallow (*((_1 as Some).0: &'<empty> &'<empty> i32));
@@ -53,14 +46,22 @@ fn main() {
 //     FakeRead(ForMatchGuard, _5);
 //     FakeRead(ForMatchGuard, _6);
 //     FakeRead(ForMatchGuard, _7);
-//     switchInt(move _8) -> [false: bb4, otherwise: bb6];
+//     switchInt(move _8) -> [false: bb7, otherwise: bb6];
+// }
+// bb6: {
+//     StorageDead(_8);
+//     _0 = const 0i32;
+//     goto -> bb9;
+// }
+// bb7: {
+//     StorageDead(_8);
+//     goto -> bb2;
 // }
 // bb8: {
 //     _0 = const 1i32;
 //     goto -> bb9;
 // }
 // bb9: {
-//     StorageDead(_8);
 //     return;
 // }
 // bb10 (cleanup): {
@@ -72,10 +73,10 @@ fn main() {
 // bb0: {
 //     nop;
 //     _3 = discriminant(_1);
-//     switchInt(move _3) -> [1isize: bb5, otherwise: bb2];
+//     switchInt(move _3) -> [1isize: bb4, otherwise: bb2];
 // }
 // bb1: {
-//     goto -> bb7;
+//     goto -> bb5;
 // }
 // bb2: {
 //     goto -> bb8;
@@ -84,16 +85,9 @@ fn main() {
 //     unreachable;
 // }
 // bb4: {
-//     goto -> bb2;
-// }
-// bb5: {
 //     switchInt((*(*((_1 as Some).0: &'<empty> &'<empty> i32)))) -> [0i32: bb1, otherwise: bb2];
 // }
-// bb6: {
-//     _0 = const 0i32;
-//     goto -> bb9;
-// }
-// bb7: {
+// bb5: {
 //     nop;
 //     nop;
 //     nop;
@@ -104,14 +98,22 @@ fn main() {
 //     nop;
 //     nop;
 //     nop;
-//     switchInt(move _8) -> [false: bb4, otherwise: bb6];
+//     switchInt(move _8) -> [false: bb7, otherwise: bb6];
+// }
+// bb6: {
+//     StorageDead(_8);
+//     _0 = const 0i32;
+//     goto -> bb9;
+// }
+// bb7: {
+//     StorageDead(_8);
+//     goto -> bb2;
 // }
 // bb8: {
 //     _0 = const 1i32;
 //     goto -> bb9;
 // }
 // bb9: {
-//     StorageDead(_8);
 //     return;
 // }
 // bb10 (cleanup): {
diff --git a/src/test/mir-opt/storage_live_dead_in_statics.rs b/src/test/mir-opt/storage_live_dead_in_statics.rs
index 10f00cf8b0c32..2ed34ecfad2c6 100644
--- a/src/test/mir-opt/storage_live_dead_in_statics.rs
+++ b/src/test/mir-opt/storage_live_dead_in_statics.rs
@@ -182,8 +182,8 @@ fn main() {
 //        _2 = Foo { tup: const "hi", data: move _3 };
 //        _1 = &_2;
 //        _0 = &(*_1);
-//        StorageDead(_1);
 //        StorageDead(_5);
+//        StorageDead(_1);
 //        return;
 //    }
 //}
diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs
index 606503151c985..67a55101d829f 100644
--- a/src/test/mir-opt/unusual-item-types.rs
+++ b/src/test/mir-opt/unusual-item-types.rs
@@ -1,5 +1,6 @@
 // Test that we don't ICE when trying to dump MIR for unusual item types and
 // that we don't create filenames containing `<` and `>`
+// ignore-tidy-linelength
 
 struct A;
 
@@ -68,7 +69,7 @@ fn main() {
 // }
 // bb7: {
 //     _2 = &mut (*_1);
-//     _3 = const std::ops::Drop::drop(move _2) -> [return: bb6, unwind: bb5];
+//     _3 = const <std::vec::Vec<i32> as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5];
 // }
 // END rustc.ptr-real_drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir
 
diff --git a/src/test/ui/const-generics/cannot-infer-const-args.stderr b/src/test/ui/const-generics/cannot-infer-const-args.stderr
index 5528c2fca6a3b..544cd05cdbebf 100644
--- a/src/test/ui/const-generics/cannot-infer-const-args.stderr
+++ b/src/test/ui/const-generics/cannot-infer-const-args.stderr
@@ -8,7 +8,7 @@ error[E0282]: type annotations needed
   --> $DIR/cannot-infer-const-args.rs:9:5
    |
 LL |     foo();
-   |     ^^^ cannot infer type for `fn() -> usize {foo::<_>}`
+   |     ^^^ cannot infer type for `fn() -> usize {foo::<_: usize>}`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const_let_refutable.stderr b/src/test/ui/consts/const_let_refutable.stderr
index 20433bbf8b5c7..917bd76d48302 100644
--- a/src/test/ui/consts/const_let_refutable.stderr
+++ b/src/test/ui/consts/const_let_refutable.stderr
@@ -4,7 +4,7 @@ error[E0005]: refutable pattern in function argument: `&[]` not covered
 LL | const fn slice([a, b]: &[i32]) -> i32 {
    |                ^^^^^^ pattern `&[]` not covered
 
-error[E0723]: can only call other `const fn` within a `const fn`, but `const std::ops::Add::add` is not stable as `const fn`
+error[E0723]: can only call other `const fn` within a `const fn`, but `const <&i32 as std::ops::Add>::add` is not stable as `const fn`
   --> $DIR/const_let_refutable.rs:4:5
    |
 LL |     a + b
diff --git a/src/test/ui/lint/lint-match-arms.rs b/src/test/ui/lint/lint-match-arms.rs
new file mode 100644
index 0000000000000..2c471a61054b2
--- /dev/null
+++ b/src/test/ui/lint/lint-match-arms.rs
@@ -0,0 +1,18 @@
+fn deny_on_arm() {
+    match 0 {
+        #[deny(unused_variables)]
+        //~^ NOTE lint level defined here
+        y => (),
+        //~^ ERROR unused variable
+    }
+}
+
+#[deny(unused_variables)]
+fn allow_on_arm() {
+    match 0 {
+        #[allow(unused_variables)]
+        y => (), // OK
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-match-arms.stderr b/src/test/ui/lint/lint-match-arms.stderr
new file mode 100644
index 0000000000000..e4e3adab0a9b2
--- /dev/null
+++ b/src/test/ui/lint/lint-match-arms.stderr
@@ -0,0 +1,14 @@
+error: unused variable: `y`
+  --> $DIR/lint-match-arms.rs:5:9
+   |
+LL |         y => (),
+   |         ^ help: consider prefixing with an underscore: `_y`
+   |
+note: lint level defined here
+  --> $DIR/lint-match-arms.rs:3:16
+   |
+LL |         #[deny(unused_variables)]
+   |                ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lint/lint-unused-mut-variables.rs b/src/test/ui/lint/lint-unused-mut-variables.rs
index da0236ac45070..78609a6e24b5e 100644
--- a/src/test/ui/lint/lint-unused-mut-variables.rs
+++ b/src/test/ui/lint/lint-unused-mut-variables.rs
@@ -105,6 +105,14 @@ fn main() {
       _ => {}
     }
 
+    // Attribute should be respected on match arms
+    match 0 {
+        #[allow(unused_mut)]
+        mut x => {
+            let mut y = 1;
+        },
+    }
+
     let x = |mut y: isize| y = 32;
     fn nothing(mut foo: isize) { foo = 37; }
 
diff --git a/src/test/ui/lint/lint-unused-mut-variables.stderr b/src/test/ui/lint/lint-unused-mut-variables.stderr
index e41d8f8ac7408..1a175c9683ec7 100644
--- a/src/test/ui/lint/lint-unused-mut-variables.stderr
+++ b/src/test/ui/lint/lint-unused-mut-variables.stderr
@@ -133,7 +133,7 @@ LL |     fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] {
    |                    help: remove this `mut`
 
 error: variable does not need to be mutable
-  --> $DIR/lint-unused-mut-variables.rs:130:9
+  --> $DIR/lint-unused-mut-variables.rs:138:9
    |
 LL |     let mut b = vec![2];
    |         ----^
@@ -141,7 +141,7 @@ LL |     let mut b = vec![2];
    |         help: remove this `mut`
    |
 note: lint level defined here
-  --> $DIR/lint-unused-mut-variables.rs:126:8
+  --> $DIR/lint-unused-mut-variables.rs:134:8
    |
 LL | #[deny(unused_mut)]
    |        ^^^^^^^^^^
diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr
index 260c2e04d74f7..fabaea0535f5b 100644
--- a/src/test/ui/pattern/const-pat-ice.stderr
+++ b/src/test/ui/pattern/const-pat-ice.stderr
@@ -1,4 +1,4 @@
-thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1083:5
+thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1085:5
 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
 
 error: internal compiler error: unexpected panic
diff --git a/src/test/ui/pattern/slice-pattern-const-2.rs b/src/test/ui/pattern/slice-pattern-const-2.rs
index 6cfef115d08dc..a36c550f530a9 100644
--- a/src/test/ui/pattern/slice-pattern-const-2.rs
+++ b/src/test/ui/pattern/slice-pattern-const-2.rs
@@ -6,13 +6,13 @@ fn main() {
     match s {
         MAGIC_TEST => (),
         [0x00, 0x00, 0x00, 0x00] => (),
-        [4, 5, 6, 7] => (), //~ ERROR unreachable pattern
+        [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not
         _ => (),
     }
     match s {
         [0x00, 0x00, 0x00, 0x00] => (),
         MAGIC_TEST => (),
-        [4, 5, 6, 7] => (), //~ ERROR unreachable pattern
+        [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not
         _ => (),
     }
     match s {
diff --git a/src/test/ui/pattern/slice-pattern-const-2.stderr b/src/test/ui/pattern/slice-pattern-const-2.stderr
index e2c408a90e4e1..0c7401269dfc7 100644
--- a/src/test/ui/pattern/slice-pattern-const-2.stderr
+++ b/src/test/ui/pattern/slice-pattern-const-2.stderr
@@ -1,8 +1,8 @@
 error: unreachable pattern
-  --> $DIR/slice-pattern-const-2.rs:9:9
+  --> $DIR/slice-pattern-const-2.rs:28:9
    |
-LL |         [4, 5, 6, 7] => (),
-   |         ^^^^^^^^^^^^
+LL |         FOO => (),
+   |         ^^^
    |
 note: lint level defined here
   --> $DIR/slice-pattern-const-2.rs:1:9
@@ -10,17 +10,5 @@ note: lint level defined here
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: unreachable pattern
-  --> $DIR/slice-pattern-const-2.rs:15:9
-   |
-LL |         [4, 5, 6, 7] => (),
-   |         ^^^^^^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/slice-pattern-const-2.rs:28:9
-   |
-LL |         FOO => (),
-   |         ^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/symbol-names/impl2.rs b/src/test/ui/symbol-names/impl2.rs
new file mode 100644
index 0000000000000..d48b182f2a200
--- /dev/null
+++ b/src/test/ui/symbol-names/impl2.rs
@@ -0,0 +1,14 @@
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+trait Foo {
+    fn baz();
+}
+
+impl Foo for [u8; 1 + 2] {
+    #[rustc_def_path] //~ ERROR def-path(<[u8; _] as Foo>::baz)
+    fn baz() { }
+}
+
+fn main() {
+}
diff --git a/src/test/ui/symbol-names/impl2.stderr b/src/test/ui/symbol-names/impl2.stderr
new file mode 100644
index 0000000000000..de26fed44139e
--- /dev/null
+++ b/src/test/ui/symbol-names/impl2.stderr
@@ -0,0 +1,8 @@
+error: def-path(<[u8; _] as Foo>::baz)
+  --> $DIR/impl2.rs:9:5
+   |
+LL |     #[rustc_def_path]
+   |     ^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+