From 677161e0d94082e9aac1fd76dbe5849837160b58 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Mon, 18 Mar 2019 14:21:41 +0100
Subject: [PATCH 01/42] Remove unnecessary secondary recursion

---
 src/librustc/ty/fold.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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)
     }
 }
 

From 35cf77f0911449945ea3d70b1da29895541e9f5a Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 26 Mar 2019 17:57:13 +0100
Subject: [PATCH 02/42] Ignore .vscode even if it is a symlink

---
 .gitignore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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
 /*-*-*-*/
 /*-*-*/

From f223eec8228ae0acf9c45d5bdafdb449f6240944 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Fri, 29 Mar 2019 10:52:09 +0100
Subject: [PATCH 03/42] Reuse the pretty printing architecture for printing of
 constants

---
 src/librustc/mir/mod.rs              | 77 ++++------------------------
 src/librustc/ty/print/pretty.rs      | 59 ++++++++++++++++++---
 src/librustc/ty/structural_impls.rs  | 33 ++++++++++++
 src/librustc_mir/hair/pattern/mod.rs |  8 +--
 src/librustdoc/clean/mod.rs          |  3 +-
 5 files changed, 100 insertions(+), 80 deletions(-)

diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index bd67aabfe8e5f..aebe0be50a330 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};
@@ -1663,8 +1661,7 @@ impl<'tcx> TerminatorKind<'tcx> {
                 values
                     .iter()
                     .map(|&u| {
-                        let mut s = String::new();
-                        let c = ty::Const {
+                        (&ty::Const {
                             val: ConstValue::Scalar(
                                 Scalar::Bits {
                                     bits: u,
@@ -1672,9 +1669,7 @@ impl<'tcx> TerminatorKind<'tcx> {
                                 }.into(),
                             ),
                             ty: switch_ty,
-                        };
-                        fmt_const_val(&mut s, c).unwrap();
-                        s.into()
+                        }).to_string().into()
                     }).chain(iter::once("otherwise".into()))
                     .collect()
             }
@@ -2828,67 +2823,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/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 8e98d4d85b9cc..0129805474012 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -6,8 +6,11 @@ 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::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;
@@ -1532,12 +1535,54 @@ 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::Const<'tcx> {
+        match (self.val, &self.ty.sty) {
+            | (ConstValue::Unevaluated(..), _)
+            | (ConstValue::Infer(..), _)
+            => p!(write("_: "), print(self.ty)),
+            (ConstValue::Param(ParamConst { name, .. }), _) => p!(write("{}", name)),
+            (ConstValue::Scalar(Scalar::Bits { bits: 0, .. }), ty::Bool) => p!(write("false")),
+            (ConstValue::Scalar(Scalar::Bits { bits: 1, .. }), ty::Bool) => p!(write("true")),
+            (ConstValue::Scalar(Scalar::Bits { bits, .. }), ty::Float(ast::FloatTy::F32)) =>
+                p!(write(
+                    "{}f32",
+                    Single::from_bits(bits)
+                )),
+            (ConstValue::Scalar(Scalar::Bits { bits, .. }), ty::Float(ast::FloatTy::F64)) =>
+                p!(write(
+                    "{}f64",
+                    Double::from_bits(bits)
+                )),
+            (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Uint(ui)) =>
+                p!(write("{}{}", bits, ui)),
+            (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Int(i)) => {
+                let size = ty::tls::with(|tcx| {
+                    let ty = tcx.lift_to_global(&self.ty).unwrap();
+                    tcx.layout_of(ty::ParamEnv::empty().and(ty))
+                        .unwrap()
+                        .size
+                });
+                p!(write("{}{}", sign_extend(bits, size) as i128, i))
+            },
+            (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Char)
+                => p!(write("{}", ::std::char::from_u32(bits as u32).unwrap())),
+            (_, ty::FnDef(did, _)) => p!(write("{}", ty::tls::with(|tcx| tcx.def_path_str(*did)))),
+            (ConstValue::Slice(_, 0), ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _)) =>
+                p!(write("\"\"")),
+            (
+                ConstValue::Slice(Scalar::Ptr(ptr), len),
+                ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _),
+            ) => {
+                ty::tls::with(|tcx| {
+                    let alloc = tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
+                    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");
+                    Ok(p!(write("{:?}", s)))
+                })?;
+            },
+            _ => p!(write("{:?} : ", self.val), print(self.ty)),
         }
     }
 
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index cf04d6eac3ae0..35d0359dbcfd2 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -295,6 +295,9 @@ CloneTypeFoldableAndLiftImpls! {
     (),
     bool,
     usize,
+    u32,
+    crate::ty::BoundVar,
+    crate::ty::DebruijnIndex,
     crate::ty::layout::VariantIdx,
     u64,
     String,
@@ -311,6 +314,8 @@ CloneTypeFoldableAndLiftImpls! {
     ::rustc_target::spec::abi::Abi,
     crate::mir::Local,
     crate::mir::Promoted,
+    crate::mir::interpret::Scalar,
+    crate::mir::interpret::Pointer,
     crate::traits::Reveal,
     crate::ty::adjustment::AutoBorrowMutability,
     crate::ty::AdtKind,
@@ -788,6 +793,34 @@ BraceStructLiftImpl! {
     }
 }
 
+BraceStructLiftImpl! {
+    impl<'a, 'tcx> Lift<'tcx> for ty::Const<'a> {
+        type Lifted = ty::Const<'tcx>;
+        val, ty
+    }
+}
+
+EnumLiftImpl! {
+    impl<'a, 'tcx> Lift<'tcx> for interpret::ConstValue<'a> {
+        type Lifted = interpret::ConstValue<'tcx>;
+        (interpret::ConstValue::Unevaluated)(a, b),
+        (interpret::ConstValue::Param)(a),
+        (interpret::ConstValue::Infer)(a),
+        (interpret::ConstValue::Scalar)(a),
+        (interpret::ConstValue::Slice)(a, b),
+        (interpret::ConstValue::ByRef)(a, b),
+    }
+}
+
+EnumLiftImpl! {
+    impl<'a, 'tcx> Lift<'tcx> for ty::InferConst<'a> {
+        type Lifted = ty::InferConst<'tcx>;
+        (ty::InferConst::Var)(a),
+        (ty::InferConst::Fresh)(a),
+        (ty::InferConst::Canonical)(a, b),
+    }
+}
+
 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> {
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 01b1780a2054f..6a8ae47143591 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -10,7 +10,7 @@ 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::ty::{self, Region, TyCtxt, AdtDef, Ty, UserType, DefIdTree};
@@ -290,15 +290,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 } => {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 3a260db806520..3a0a15526b0f4 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -4128,8 +4128,7 @@ 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();

From 72087ec43b3f8f20040094f535a0bf686a35f015 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 2 Apr 2019 14:23:23 +0200
Subject: [PATCH 04/42] There's a tcx in scope, don't use the tls one

---
 src/librustc/ty/print/pretty.rs | 26 +++++++++++---------------
 1 file changed, 11 insertions(+), 15 deletions(-)

diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 0129805474012..7b72ffcb7b0d7 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1556,31 +1556,27 @@ define_print_and_forward_display! {
             (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Uint(ui)) =>
                 p!(write("{}{}", bits, ui)),
             (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Int(i)) => {
-                let size = ty::tls::with(|tcx| {
-                    let ty = tcx.lift_to_global(&self.ty).unwrap();
-                    tcx.layout_of(ty::ParamEnv::empty().and(ty))
-                        .unwrap()
-                        .size
-                });
+                let ty = cx.tcx().lift_to_global(&self.ty).unwrap();
+                let size = cx.tcx().layout_of(ty::ParamEnv::empty().and(ty))
+                    .unwrap()
+                    .size;
                 p!(write("{}{}", sign_extend(bits, size) as i128, i))
             },
             (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Char)
                 => p!(write("{}", ::std::char::from_u32(bits as u32).unwrap())),
-            (_, ty::FnDef(did, _)) => p!(write("{}", ty::tls::with(|tcx| tcx.def_path_str(*did)))),
+            (_, ty::FnDef(did, _)) => p!(write("{}", cx.tcx().def_path_str(*did))),
             (ConstValue::Slice(_, 0), ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _)) =>
                 p!(write("\"\"")),
             (
                 ConstValue::Slice(Scalar::Ptr(ptr), len),
                 ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _),
             ) => {
-                ty::tls::with(|tcx| {
-                    let alloc = tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
-                    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");
-                    Ok(p!(write("{:?}", s)))
-                })?;
+                let alloc = cx.tcx().alloc_map.lock().unwrap_memory(ptr.alloc_id);
+                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");
+                p!(write("{:?}", s))
             },
             _ => p!(write("{:?} : ", self.val), print(self.ty)),
         }

From 7e7cd9280932262ea5c6b347fc2e4d1ebbd9fec0 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 2 Apr 2019 14:26:28 +0200
Subject: [PATCH 05/42] Merge the string printing paths of ty::Const

---
 src/librustc/ty/print/pretty.rs | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 7b72ffcb7b0d7..e7de05a8bc874 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1565,17 +1565,21 @@ define_print_and_forward_display! {
             (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Char)
                 => p!(write("{}", ::std::char::from_u32(bits as u32).unwrap())),
             (_, ty::FnDef(did, _)) => p!(write("{}", cx.tcx().def_path_str(*did))),
-            (ConstValue::Slice(_, 0), ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _)) =>
-                p!(write("\"\"")),
             (
-                ConstValue::Slice(Scalar::Ptr(ptr), len),
+                ConstValue::Slice(place, len),
                 ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _),
             ) => {
-                let alloc = cx.tcx().alloc_map.lock().unwrap_memory(ptr.alloc_id);
-                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");
+                let s = match (place, len) {
+                    (_, 0) => "",
+                    (Scalar::Ptr(ptr), len) => {
+                        let alloc = cx.tcx().alloc_map.lock().unwrap_memory(ptr.alloc_id);
+                        assert_eq!(len as usize as u64, len);
+                        let slice =
+                            &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];
+                        ::std::str::from_utf8(slice).expect("non utf8 str from miri")
+                    },
+                    _ => bug!("invalid slice: {:#?}", self),
+                };
                 p!(write("{:?}", s))
             },
             _ => p!(write("{:?} : ", self.val), print(self.ty)),

From 17c6c8dc3da3d753a1c4198a7d199141ae094e0f Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 2 Apr 2019 14:26:56 +0200
Subject: [PATCH 06/42] Print const chars escaped with surrounding quotes

---
 src/librustc/ty/print/pretty.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index e7de05a8bc874..bcc3bba060688 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1563,7 +1563,7 @@ define_print_and_forward_display! {
                 p!(write("{}{}", sign_extend(bits, size) as i128, i))
             },
             (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Char)
-                => p!(write("{}", ::std::char::from_u32(bits as u32).unwrap())),
+                => p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap())),
             (_, ty::FnDef(did, _)) => p!(write("{}", cx.tcx().def_path_str(*did))),
             (
                 ConstValue::Slice(place, len),

From 04ad22cf40b083d0b9dfe00434b5ab230139e0c8 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Wed, 3 Apr 2019 15:29:31 +0200
Subject: [PATCH 07/42] Don't use `ty::Const` without immediately interning

---
 src/librustc/mir/interpret/error.rs           |  2 +-
 src/librustc/mir/mod.rs                       | 38 ++++++++-------
 src/librustc/traits/project.rs                |  3 +-
 src/librustc/traits/query/normalize.rs        |  3 +-
 src/librustc/ty/context.rs                    | 19 +++-----
 src/librustc/ty/print/pretty.rs               |  2 +-
 src/librustc/ty/structural_impls.rs           | 46 +------------------
 src/librustc/ty/sty.rs                        | 19 ++++----
 src/librustc_codegen_ssa/mir/constant.rs      |  6 +--
 src/librustc_codegen_ssa/mir/operand.rs       |  2 +-
 src/librustc_mir/build/matches/mod.rs         |  4 +-
 src/librustc_mir/build/matches/test.rs        | 11 ++---
 src/librustc_mir/build/misc.rs                |  4 +-
 src/librustc_mir/const_eval.rs                | 14 +++---
 src/librustc_mir/hair/constant.rs             |  8 ++--
 src/librustc_mir/hair/cx/expr.rs              | 23 ++++------
 src/librustc_mir/hair/cx/mod.rs               | 12 ++---
 src/librustc_mir/hair/pattern/_match.rs       | 12 ++---
 src/librustc_mir/hair/pattern/mod.rs          | 24 +++++-----
 src/librustc_mir/interpret/operand.rs         |  4 +-
 src/librustc_mir/monomorphize/collector.rs    |  4 +-
 src/librustc_mir/shim.rs                      | 12 ++---
 src/librustc_mir/transform/const_prop.rs      |  2 +-
 src/librustc_mir/transform/elaborate_drops.rs |  4 +-
 src/librustc_mir/transform/generator.rs       |  4 +-
 src/librustc_mir/util/elaborate_drops.rs      |  4 +-
 src/librustc_typeck/check/mod.rs              |  2 +-
 src/librustdoc/clean/mod.rs                   |  8 +++-
 28 files changed, 114 insertions(+), 182 deletions(-)

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/mod.rs b/src/librustc/mir/mod.rs
index aebe0be50a330..94a37341baa23 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1653,25 +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| {
-                        (&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()
+                    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(_),
@@ -2327,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),
         })
     }
 
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index b5232e828c4cd..b37217a57bf28 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -411,7 +411,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;
                         }
@@ -425,7 +424,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 15524ca6e930c..3a61a7ec7ae34 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,
+            }),
         }
     }
 }
@@ -1809,14 +1812,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};
 
@@ -2581,9 +2576,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/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index bcc3bba060688..8598798b3488f 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1535,7 +1535,7 @@ define_print_and_forward_display! {
         p!(print_def_path(self.def_id, self.substs));
     }
 
-    ty::Const<'tcx> {
+    &'tcx ty::Const<'tcx> {
         match (self.val, &self.ty.sty) {
             | (ConstValue::Unevaluated(..), _)
             | (ConstValue::Infer(..), _)
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 35d0359dbcfd2..86883a14f687c 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 {
@@ -295,9 +294,6 @@ CloneTypeFoldableAndLiftImpls! {
     (),
     bool,
     usize,
-    u32,
-    crate::ty::BoundVar,
-    crate::ty::DebruijnIndex,
     crate::ty::layout::VariantIdx,
     u64,
     String,
@@ -314,8 +310,6 @@ CloneTypeFoldableAndLiftImpls! {
     ::rustc_target::spec::abi::Abi,
     crate::mir::Local,
     crate::mir::Promoted,
-    crate::mir::interpret::Scalar,
-    crate::mir::interpret::Pointer,
     crate::traits::Reveal,
     crate::ty::adjustment::AutoBorrowMutability,
     crate::ty::AdtKind,
@@ -793,44 +787,6 @@ BraceStructLiftImpl! {
     }
 }
 
-BraceStructLiftImpl! {
-    impl<'a, 'tcx> Lift<'tcx> for ty::Const<'a> {
-        type Lifted = ty::Const<'tcx>;
-        val, ty
-    }
-}
-
-EnumLiftImpl! {
-    impl<'a, 'tcx> Lift<'tcx> for interpret::ConstValue<'a> {
-        type Lifted = interpret::ConstValue<'tcx>;
-        (interpret::ConstValue::Unevaluated)(a, b),
-        (interpret::ConstValue::Param)(a),
-        (interpret::ConstValue::Infer)(a),
-        (interpret::ConstValue::Scalar)(a),
-        (interpret::ConstValue::Slice)(a, b),
-        (interpret::ConstValue::ByRef)(a, b),
-    }
-}
-
-EnumLiftImpl! {
-    impl<'a, 'tcx> Lift<'tcx> for ty::InferConst<'a> {
-        type Lifted = ty::InferConst<'tcx>;
-        (ty::InferConst::Var)(a),
-        (ty::InferConst::Fresh)(a),
-        (ty::InferConst::Canonical)(a, b),
-    }
-}
-
-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.
 //
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 760f3d60d0571..c632e089841b9 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -2212,13 +2212,14 @@ static_assert!(CONST_SIZE: ::std::mem::size_of::<Const<'static>>() == 48);
 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_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/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs
index 3b8e5b4495383..670f2da161974 100644
--- a/src/librustc_codegen_ssa/mir/operand.rs
+++ b/src/librustc_codegen_ssa/mir/operand.rs
@@ -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);
 
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 51d5c96083d8f..73a3c3be3aa57 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -747,12 +747,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>,
     },
 
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/const_eval.rs b/src/librustc_mir/const_eval.rs
index 866b6492d10bc..2bfc10f8e8c4e 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -65,7 +65,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,13 +79,13 @@ 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()),
@@ -104,7 +104,7 @@ fn op_to_const<'tcx>(
         Err(Immediate::ScalarPair(a, b)) =>
             ConstValue::Slice(a.not_undef().unwrap(), b.to_usize(ecx).unwrap()),
     };
-    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 +450,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 +473,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/hair/constant.rs b/src/librustc_mir/hair/constant.rs
index caadc6055b5c6..5ed16abb9a672 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| {
@@ -39,10 +39,10 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>(
         LitKind::Err(ref s) => {
             let s = s.as_str();
             let id = tcx.allocate_bytes(s.as_bytes());
-            return Ok(ty::Const {
+            return Ok(tcx.mk_const(ty::Const {
                 val: ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64),
                 ty: tcx.types.err,
-            });
+            }));
         },
         LitKind::ByteStr(ref data) => {
             let id = tcx.allocate_bytes(data);
@@ -71,7 +71,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..f58055ea28419 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,
         },
     }
@@ -898,9 +892,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 7aed0bace8c0b..06b5f491a83c6 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/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index fd4416fc2b763..83e17514c08f8 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -255,10 +255,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 +423,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.
@@ -1424,7 +1424,7 @@ 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>]
@@ -1824,7 +1824,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
                                         &cx.tcx, ptr, layout.size,
                                     ).ok()?;
                                     let scalar = scalar.not_undef().ok()?;
-                                    let value = ty::Const::from_scalar(scalar, ty);
+                                    let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
                                     let pattern = Pattern {
                                         ty,
                                         span: pat.span,
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 6a8ae47143591..3223c3d583629 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -151,7 +151,7 @@ pub enum PatternKind<'tcx> {
     },
 
     Constant {
-        value: ty::Const<'tcx>,
+        value: &'tcx ty::Const<'tcx>,
     },
 
     Range(PatternRange<'tcx>),
@@ -175,8 +175,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,
 }
@@ -290,15 +290,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
                 write!(f, "{}", subpattern)
             }
             PatternKind::Constant { value } => {
-                write!(f, "{}", &value)
+                write!(f, "{}", value)
             }
             PatternKind::Range(PatternRange { lo, hi, ty: _, end }) => {
-                write!(f, "{}", &lo)?;
+                write!(f, "{}", lo)?;
                 match end {
                     RangeEnd::Included => write!(f, "..=")?,
                     RangeEnd::Excluded => write!(f, "..")?,
                 }
-                write!(f, "{}", &hi)
+                write!(f, "{}", hi)
             }
             PatternKind::Slice { ref prefix, ref slice, ref suffix } |
             PatternKind::Array { ref prefix, ref slice, ref suffix } => {
@@ -941,7 +941,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> {
@@ -1204,7 +1204,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
             PatternKind::Constant {
                 value
             } => PatternKind::Constant {
-                value: value.fold_with(folder)
+                value,
             },
             PatternKind::Range(PatternRange {
                 lo,
@@ -1212,8 +1212,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,
             }),
@@ -1241,8 +1241,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);
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 9c2b491925f47..9481dd3cb8f8f 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 {
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 91cf0fbb9b44f..e0d6784789e2d 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,7 +1248,7 @@ 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>>,
 ) {
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_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a32745f27e1a0..ed4bb8da27daf 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4441,7 +4441,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 3a0a15526b0f4..5fc64a62a868e 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2958,7 +2958,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 {
@@ -4118,7 +4118,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) {
@@ -4133,6 +4133,10 @@ fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
             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
         },

From 3a4f5ab59949904180b8d8af6ff068747c601663 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Thu, 11 Apr 2019 11:11:11 +0200
Subject: [PATCH 08/42] Add test showing how byte slices are printed in MIR

---
 src/test/mir-opt/byte_slice.rs | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
 create mode 100644 src/test/mir-opt/byte_slice.rs

diff --git a/src/test/mir-opt/byte_slice.rs b/src/test/mir-opt/byte_slice.rs
new file mode 100644
index 0000000000000..ae5d7c4895f72
--- /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 Scalar(Ptr(Pointer { alloc_id: AllocId(0), offset: Size { raw: 0 }, tag: () })) : &[u8; 3];
+// ...
+// _2 = [const 5u8, const 120u8];
+// ...
+// END rustc.main.EraseRegions.after.mir

From f4f82ff0f4c7e3ebc689a9edf070dc2c5bebc613 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Thu, 11 Apr 2019 11:12:47 +0200
Subject: [PATCH 09/42] Refactor string constant printing to prep for byte
 string printing

---
 src/librustc/ty/print/pretty.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 8598798b3488f..18683e4d0ff08 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1569,18 +1569,18 @@ define_print_and_forward_display! {
                 ConstValue::Slice(place, len),
                 ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _),
             ) => {
-                let s = match (place, len) {
+                match (place, len) {
                     (_, 0) => "",
                     (Scalar::Ptr(ptr), len) => {
                         let alloc = cx.tcx().alloc_map.lock().unwrap_memory(ptr.alloc_id);
                         assert_eq!(len as usize as u64, len);
                         let slice =
                             &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];
-                        ::std::str::from_utf8(slice).expect("non utf8 str from miri")
+                        let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
+                        p!(write("{:?}", s))
                     },
                     _ => bug!("invalid slice: {:#?}", self),
                 };
-                p!(write("{:?}", s))
             },
             _ => p!(write("{:?} : ", self.val), print(self.ty)),
         }

From 1468f2048c611a0d9cc2c9ed28d6a034166e5dcb Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Thu, 11 Apr 2019 15:06:42 +0200
Subject: [PATCH 10/42] Make `ConstValue::Slice` solely take `[u8]` and `str`

---
 src/librustc/infer/freshen.rs                 |   2 +-
 src/librustc/mir/interpret/value.rs           |  26 ++--
 src/librustc/ty/print/pretty.rs               |  28 ++--
 src/librustc/ty/structural_impls.rs           |   4 +-
 src/librustc/ty/sty.rs                        |   2 +-
 src/librustc_codegen_ssa/mir/operand.rs       |  12 +-
 src/librustc_mir/const_eval.rs                |  32 ++++-
 src/librustc_mir/hair/constant.rs             |  10 +-
 src/librustc_mir/hair/pattern/_match.rs       | 123 +++++++-----------
 src/librustc_mir/hair/pattern/mod.rs          |  39 +++---
 src/librustc_mir/interpret/operand.rs         |  13 +-
 src/librustc_mir/monomorphize/collector.rs    |   4 +-
 src/test/ui/pattern/slice-pattern-const-2.rs  |   4 +-
 .../ui/pattern/slice-pattern-const-2.stderr   |  20 +--
 14 files changed, 157 insertions(+), 162 deletions(-)

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/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/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 18683e4d0ff08..c542c0d6b3fe8 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1566,21 +1566,27 @@ define_print_and_forward_display! {
                 => p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap())),
             (_, ty::FnDef(did, _)) => p!(write("{}", cx.tcx().def_path_str(*did))),
             (
-                ConstValue::Slice(place, len),
-                ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _),
+                ConstValue::Slice { data, start, end },
+                ty::Ref(_, slice_ty, _),
             ) => {
-                match (place, len) {
-                    (_, 0) => "",
-                    (Scalar::Ptr(ptr), len) => {
-                        let alloc = cx.tcx().alloc_map.lock().unwrap_memory(ptr.alloc_id);
-                        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");
+                let slice = &data.bytes[start..end];
+                match slice_ty.sty {
+                    ty::Str => {
+                        let s = ::std::str::from_utf8(slice)
+                            .expect("non utf8 str from miri");
                         p!(write("{:?}", s))
                     },
+                    ty::Slice(elem) if elem == cx.tcx().types.u8 => {
+                        p!(write("b\""));
+                        for &c in slice {
+                            for e in std::ascii::escape_default(c) {
+                                p!(write("{}", e));
+                            }
+                        }
+                        p!(write("\""));
+                    },
                     _ => bug!("invalid slice: {:#?}", self),
-                };
+                }
             },
             _ => p!(write("{:?} : ", self.val), print(self.ty)),
         }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 86883a14f687c..0daa567052d56 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -1345,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)),
         }
@@ -1358,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 c632e089841b9..75bb60674e7c5 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -2207,7 +2207,7 @@ 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]
diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs
index 670f2da161974..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;
@@ -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_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 2bfc10f8e8c4e..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;
@@ -89,7 +90,14 @@ fn op_to_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,8 +109,26 @@ 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,
+            }
+        },
     };
     ecx.tcx.mk_const(ty::Const { val, ty: op.layout.ty })
 }
diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs
index 5ed16abb9a672..d2c86d36238e1 100644
--- a/src/librustc_mir/hair/constant.rs
+++ b/src/librustc_mir/hair/constant.rs
@@ -33,14 +33,16 @@ 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());
+            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::new_slice(Scalar::Ptr(id.into()), s.len() as u64),
+                val: ConstValue::Slice{ data: allocation, start: 0, end: s.len() },
                 ty: tcx.types.err,
             }));
         },
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 83e17514c08f8..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),
         }
@@ -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,
                     ),
                     _ => {},
                 }
@@ -1431,42 +1433,17 @@ fn slice_pat_covered_by_const<'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(cx.tcx, 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 3223c3d583629..148211771ade9 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -12,11 +12,11 @@ use crate::hair::constant::*;
 
 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;
@@ -1292,22 +1292,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 9481dd3cb8f8f..407622dc2599b 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -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 e0d6784789e2d..b90db7646d492 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -1255,10 +1255,10 @@ fn collect_const<'a, '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/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
 

From d46c964eafc2457a0e41ad92bc07c5cffc30012b Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Thu, 11 Apr 2019 22:04:04 +0200
Subject: [PATCH 11/42] Render const byte slices in MIR

---
 src/librustc/ty/print/pretty.rs | 54 ++++++++++++++++++++-------------
 src/test/mir-opt/byte_slice.rs  |  2 +-
 2 files changed, 34 insertions(+), 22 deletions(-)

diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index c542c0d6b3fe8..0030a35fe3f08 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -6,6 +6,7 @@ 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::ty::layout::Size;
 use crate::mir::interpret::{ConstValue, sign_extend, Scalar};
 use syntax::symbol::{keywords, Symbol};
 use syntax::ast;
@@ -1536,6 +1537,7 @@ define_print_and_forward_display! {
     }
 
     &'tcx ty::Const<'tcx> {
+        let u8 = cx.tcx().types.u8;
         match (self.val, &self.ty.sty) {
             | (ConstValue::Unevaluated(..), _)
             | (ConstValue::Infer(..), _)
@@ -1565,28 +1567,38 @@ define_print_and_forward_display! {
             (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Char)
                 => p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap())),
             (_, ty::FnDef(did, _)) => p!(write("{}", cx.tcx().def_path_str(*did))),
-            (
-                ConstValue::Slice { data, start, end },
-                ty::Ref(_, slice_ty, _),
-            ) => {
-                let slice = &data.bytes[start..end];
-                match slice_ty.sty {
-                    ty::Str => {
-                        let s = ::std::str::from_utf8(slice)
-                            .expect("non utf8 str from miri");
-                        p!(write("{:?}", s))
-                    },
-                    ty::Slice(elem) if elem == cx.tcx().types.u8 => {
-                        p!(write("b\""));
-                        for &c in slice {
-                            for e in std::ascii::escape_default(c) {
-                                p!(write("{}", e));
-                            }
+            (_, ty::Ref(_, ref_ty, _)) => match (self.val, &ref_ty.sty) {
+                (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => {
+                    let n = n.unwrap_usize(cx.tcx());
+                    let slice = cx.tcx()
+                        .alloc_map.lock()
+                        .unwrap_memory(ptr.alloc_id)
+                        .get_bytes(&cx.tcx(), ptr, Size::from_bytes(n)).unwrap();
+                    p!(write("b\""));
+                    for &c in slice {
+                        for e in std::ascii::escape_default(c) {
+                            p!(write("{}", e));
                         }
-                        p!(write("\""));
-                    },
-                    _ => bug!("invalid slice: {:#?}", self),
-                }
+                    }
+                    p!(write("\""));
+                },
+                (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))
+                },
+                (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => {
+                    let slice = &data.bytes[start..end];
+                    p!(write("b\""));
+                    for &c in slice {
+                        for e in std::ascii::escape_default(c) {
+                            p!(write("{}", e));
+                        }
+                    }
+                    p!(write("\""));
+                },
+                _ => p!(write("{:?} : ", self.val), print(self.ty)),
             },
             _ => p!(write("{:?} : ", self.val), print(self.ty)),
         }
diff --git a/src/test/mir-opt/byte_slice.rs b/src/test/mir-opt/byte_slice.rs
index ae5d7c4895f72..23faf7e16a7ed 100644
--- a/src/test/mir-opt/byte_slice.rs
+++ b/src/test/mir-opt/byte_slice.rs
@@ -8,7 +8,7 @@ fn main() {
 // END RUST SOURCE
 // START rustc.main.EraseRegions.after.mir
 // ...
-// _1 = const Scalar(Ptr(Pointer { alloc_id: AllocId(0), offset: Size { raw: 0 }, tag: () })) : &[u8; 3];
+// _1 = const b"102111111";
 // ...
 // _2 = [const 5u8, const 120u8];
 // ...

From 46704bf94f1af0fc323628dd86a68226f46b56a2 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Mon, 15 Apr 2019 11:00:55 +0200
Subject: [PATCH 12/42] `u8` is printed as a number, not a character

---
 src/librustc/ty/print/pretty.rs | 4 ++--
 src/test/mir-opt/byte_slice.rs  | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 0030a35fe3f08..fa197f3505227 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1577,7 +1577,7 @@ define_print_and_forward_display! {
                     p!(write("b\""));
                     for &c in slice {
                         for e in std::ascii::escape_default(c) {
-                            p!(write("{}", e));
+                            p!(write("{}", e as char));
                         }
                     }
                     p!(write("\""));
@@ -1593,7 +1593,7 @@ define_print_and_forward_display! {
                     p!(write("b\""));
                     for &c in slice {
                         for e in std::ascii::escape_default(c) {
-                            p!(write("{}", e));
+                            p!(write("{}", e as char));
                         }
                     }
                     p!(write("\""));
diff --git a/src/test/mir-opt/byte_slice.rs b/src/test/mir-opt/byte_slice.rs
index 23faf7e16a7ed..7edfa3e1124db 100644
--- a/src/test/mir-opt/byte_slice.rs
+++ b/src/test/mir-opt/byte_slice.rs
@@ -8,7 +8,7 @@ fn main() {
 // END RUST SOURCE
 // START rustc.main.EraseRegions.after.mir
 // ...
-// _1 = const b"102111111";
+// _1 = const b"foo";
 // ...
 // _2 = [const 5u8, const 120u8];
 // ...

From 983f676d25135ac6cc478293a85b7cd8130d9b1a Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Wed, 17 Apr 2019 17:29:38 +0200
Subject: [PATCH 13/42] Render unresolved anon consts like closures

---
 src/librustc/ty/print/pretty.rs | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index fa197f3505227..15c2758a19e46 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1,5 +1,5 @@
 use crate::hir;
-use crate::hir::def::Namespace;
+use crate::hir::def::{Namespace, Def};
 use crate::hir::map::{DefPathData, DisambiguatedDefPathData};
 use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
@@ -1539,9 +1539,15 @@ define_print_and_forward_display! {
     &'tcx ty::Const<'tcx> {
         let u8 = cx.tcx().types.u8;
         match (self.val, &self.ty.sty) {
-            | (ConstValue::Unevaluated(..), _)
-            | (ConstValue::Infer(..), _)
-            => p!(write("_: "), print(self.ty)),
+            (ConstValue::Unevaluated(did, substs), _) => {
+                match cx.tcx().describe_def(did) {
+                    | Some(Def::Static(_, _))
+                    | Some(Def::Const(_))
+                    | Some(Def::AssociatedConst(_)) => p!(write("{}", cx.tcx().def_path_str(did))),
+                    _ => p!(write("_")),
+                }
+            }
+            (ConstValue::Infer(..), _) => p!(write("_: "), print(self.ty)),
             (ConstValue::Param(ParamConst { name, .. }), _) => p!(write("{}", name)),
             (ConstValue::Scalar(Scalar::Bits { bits: 0, .. }), ty::Bool) => p!(write("false")),
             (ConstValue::Scalar(Scalar::Bits { bits: 1, .. }), ty::Bool) => p!(write("true")),

From b7c094b146b8332403e88f1b3ab17bb4714bb0de Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Wed, 17 Apr 2019 17:50:47 +0200
Subject: [PATCH 14/42] Group common printing code during constant pretty
 printing

---
 src/librustc/ty/print/pretty.rs | 129 ++++++++++++++++++--------------
 1 file changed, 73 insertions(+), 56 deletions(-)

diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 15c2758a19e46..a9aa575b7ad1c 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1538,76 +1538,93 @@ define_print_and_forward_display! {
 
     &'tcx ty::Const<'tcx> {
         let u8 = cx.tcx().types.u8;
-        match (self.val, &self.ty.sty) {
-            (ConstValue::Unevaluated(did, substs), _) => {
-                match cx.tcx().describe_def(did) {
-                    | Some(Def::Static(_, _))
-                    | Some(Def::Const(_))
-                    | Some(Def::AssociatedConst(_)) => p!(write("{}", cx.tcx().def_path_str(did))),
-                    _ => p!(write("_")),
+        if let ty::FnDef(did, _) = self.ty.sty {
+            p!(write("{}", cx.tcx().def_path_str(did)));
+            return Ok(cx);
+        }
+        if let ConstValue::Unevaluated(did, substs) = self.val {
+            match cx.tcx().describe_def(did) {
+                | Some(Def::Static(_, _))
+                | Some(Def::Const(_, false))
+                | Some(Def::AssociatedConst(_)) => p!(write("{}", cx.tcx().def_path_str(did))),
+                _ => p!(write("_")),
+            }
+            return Ok(cx);
+        }
+        if let ConstValue::Infer(..) = self.val {
+            p!(write("_: "), print(self.ty));
+            return Ok(cx);
+        }
+        if let ConstValue::Param(ParamConst { name, .. }) = self.val {
+            p!(write("{}", name));
+            return Ok(cx);
+        }
+        if let ConstValue::Scalar(Scalar::Bits { bits, .. }) = self.val {
+            match self.ty.sty {
+                ty::Bool => {
+                    p!(write("{}", if bits == 0 { "false" } else { "true" }));
+                    return Ok(cx);
+                },
+                ty::Float(ast::FloatTy::F32) => {
+                    p!(write("{}f32", Single::from_bits(bits)));
+                    return Ok(cx);
+                },
+                ty::Float(ast::FloatTy::F64) => {
+                    p!(write("{}f64", Double::from_bits(bits)));
+                    return Ok(cx);
+                },
+                ty::Uint(ui) => {
+                    p!(write("{}{}", bits, ui));
+                    return Ok(cx);
+                },
+                ty::Int(i) =>{
+                    let ty = cx.tcx().lift_to_global(&self.ty).unwrap();
+                    let size = cx.tcx().layout_of(ty::ParamEnv::empty().and(ty))
+                        .unwrap()
+                        .size;
+                    p!(write("{}{}", sign_extend(bits, size) as i128, i));
+                    return Ok(cx);
+                },
+                ty::Char => {
+                    p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap()));
+                    return Ok(cx);
                 }
+                _ => {},
             }
-            (ConstValue::Infer(..), _) => p!(write("_: "), print(self.ty)),
-            (ConstValue::Param(ParamConst { name, .. }), _) => p!(write("{}", name)),
-            (ConstValue::Scalar(Scalar::Bits { bits: 0, .. }), ty::Bool) => p!(write("false")),
-            (ConstValue::Scalar(Scalar::Bits { bits: 1, .. }), ty::Bool) => p!(write("true")),
-            (ConstValue::Scalar(Scalar::Bits { bits, .. }), ty::Float(ast::FloatTy::F32)) =>
-                p!(write(
-                    "{}f32",
-                    Single::from_bits(bits)
-                )),
-            (ConstValue::Scalar(Scalar::Bits { bits, .. }), ty::Float(ast::FloatTy::F64)) =>
-                p!(write(
-                    "{}f64",
-                    Double::from_bits(bits)
-                )),
-            (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Uint(ui)) =>
-                p!(write("{}{}", bits, ui)),
-            (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Int(i)) => {
-                let ty = cx.tcx().lift_to_global(&self.ty).unwrap();
-                let size = cx.tcx().layout_of(ty::ParamEnv::empty().and(ty))
-                    .unwrap()
-                    .size;
-                p!(write("{}{}", sign_extend(bits, size) as i128, i))
-            },
-            (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Char)
-                => p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap())),
-            (_, ty::FnDef(did, _)) => p!(write("{}", cx.tcx().def_path_str(*did))),
-            (_, ty::Ref(_, ref_ty, _)) => match (self.val, &ref_ty.sty) {
+        }
+        if let ty::Ref(_, ref_ty, _) = self.ty.sty {
+            let byte_str = match (self.val, &ref_ty.sty) {
                 (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => {
                     let n = n.unwrap_usize(cx.tcx());
-                    let slice = cx.tcx()
+                    Some(cx.tcx()
                         .alloc_map.lock()
                         .unwrap_memory(ptr.alloc_id)
-                        .get_bytes(&cx.tcx(), ptr, Size::from_bytes(n)).unwrap();
-                    p!(write("b\""));
-                    for &c in slice {
-                        for e in std::ascii::escape_default(c) {
-                            p!(write("{}", e as char));
-                        }
-                    }
-                    p!(write("\""));
+                        .get_bytes(&cx.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))
+                    p!(write("{:?}", s));
+                    return Ok(cx);
                 },
-                (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => {
-                    let slice = &data.bytes[start..end];
-                    p!(write("b\""));
-                    for &c in slice {
-                        for e in std::ascii::escape_default(c) {
-                            p!(write("{}", e as char));
-                        }
+                _ => None,
+            };
+            if let Some(byte_str) = byte_str {
+                p!(write("b\""));
+                for &c in byte_str {
+                    for e in std::ascii::escape_default(c) {
+                        p!(write("{}", e as char));
                     }
-                    p!(write("\""));
-                },
-                _ => p!(write("{:?} : ", self.val), print(self.ty)),
-            },
-            _ => p!(write("{:?} : ", self.val), print(self.ty)),
+                }
+                p!(write("\""));
+                return Ok(cx);
+            }
         }
+        p!(write("{:?} : ", self.val), print(self.ty));
     }
 
     ty::ParamTy {

From f2d2250edc2936d1ef9339a24b700a07d4b10328 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Wed, 17 Apr 2019 18:19:59 +0200
Subject: [PATCH 15/42] Print generic args in function calls in MIR

---
 src/librustc/ty/print/pretty.rs           | 4 ++--
 src/test/mir-opt/box_expr.rs              | 2 +-
 src/test/mir-opt/inline-trait-method.rs   | 2 +-
 src/test/mir-opt/inline-trait-method_2.rs | 2 +-
 src/test/mir-opt/issue-49232.rs           | 2 +-
 src/test/mir-opt/unusual-item-types.rs    | 2 +-
 6 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index a9aa575b7ad1c..ec260530152e5 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1538,8 +1538,8 @@ define_print_and_forward_display! {
 
     &'tcx ty::Const<'tcx> {
         let u8 = cx.tcx().types.u8;
-        if let ty::FnDef(did, _) = self.ty.sty {
-            p!(write("{}", cx.tcx().def_path_str(did)));
+        if let ty::FnDef(did, substs) = self.ty.sty {
+            p!(print_value_path(did, substs));
             return Ok(cx);
         }
         if let ConstValue::Unevaluated(did, substs) = self.val {
diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs
index d4852db6d475e..4a5a4e0677aa4 100644
--- a/src/test/mir-opt/box_expr.rs
+++ b/src/test/mir-opt/box_expr.rs
@@ -54,7 +54,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/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-49232.rs b/src/test/mir-opt/issue-49232.rs
index 29446d2ecc23e..f72258dd9b998 100644
--- a/src/test/mir-opt/issue-49232.rs
+++ b/src/test/mir-opt/issue-49232.rs
@@ -96,7 +96,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/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs
index 606503151c985..93f17d976e6a1 100644
--- a/src/test/mir-opt/unusual-item-types.rs
+++ b/src/test/mir-opt/unusual-item-types.rs
@@ -68,7 +68,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
 

From 830ce7343e21c99c72e947523f4f68840eb15ea7 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Wed, 24 Apr 2019 14:10:05 +0200
Subject: [PATCH 16/42] Fix tidy

---
 src/test/mir-opt/unusual-item-types.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs
index 93f17d976e6a1..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;
 

From bb6f156f11eac564adb6de01ac181157afb10a73 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Wed, 24 Apr 2019 14:10:31 +0200
Subject: [PATCH 17/42] Use `write_char` to skip the formatting infrastructure

---
 src/librustc/ty/print/pretty.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index ec260530152e5..6241e049ae4bd 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1617,7 +1617,7 @@ define_print_and_forward_display! {
                 p!(write("b\""));
                 for &c in byte_str {
                     for e in std::ascii::escape_default(c) {
-                        p!(write("{}", e as char));
+                        cx.write_char(e as char)?;
                     }
                 }
                 p!(write("\""));

From 05d8b4cfde2b89b32a824820370f2145e03e9014 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Wed, 24 Apr 2019 14:10:52 +0200
Subject: [PATCH 18/42] Print unevaluted constants as `_` or as their source
 representation

---
 src/librustc/ty/print/pretty.rs | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 6241e049ae4bd..e0b737bff7a4c 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1544,10 +1544,19 @@ define_print_and_forward_display! {
         }
         if let ConstValue::Unevaluated(did, substs) = self.val {
             match cx.tcx().describe_def(did) {
-                | Some(Def::Static(_, _))
-                | Some(Def::Const(_, false))
-                | Some(Def::AssociatedConst(_)) => p!(write("{}", cx.tcx().def_path_str(did))),
-                _ => p!(write("_")),
+                | Some(Def::Static(_))
+                | Some(Def::Const(_))
+                | Some(Def::AssociatedConst(_)) => p!(print_value_path(did, substs)),
+                _ => if did.is_local() {
+                    let span = cx.tcx().def_span(did);
+                    if let Ok(snip) = cx.tcx().sess.source_map().span_to_snippet(span) {
+                        p!(write("{}", snip))
+                    } else {
+                        p!(write("_"))
+                    }
+                } else {
+                    p!(write("_"))
+                },
             }
             return Ok(cx);
         }

From 681680ddfa902f3818a73277483dff2460217e7c Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Wed, 24 Apr 2019 16:12:53 +0200
Subject: [PATCH 19/42] Update ui tests

---
 src/test/ui/consts/const_let_refutable.stderr | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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

From 816f75578de5df169640ec97b22ffd99820a70cc Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Mon, 18 Mar 2019 12:50:57 +0200
Subject: [PATCH 20/42] rustc: integrate ty::Const into ty::print as
 print_const.

---
 src/librustc/infer/error_reporting/mod.rs  |   8 +
 src/librustc/lint/context.rs               |  10 +-
 src/librustc/ty/print/mod.rs               |  14 ++
 src/librustc/ty/print/pretty.rs            | 227 +++++++++++----------
 src/librustc_codegen_utils/symbol_names.rs |   8 +
 5 files changed, 160 insertions(+), 107 deletions(-)

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/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/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 e0b737bff7a4c..19fbf498034be 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -175,6 +175,7 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
         Region = Self,
         Type = Self,
         DynExistential = Self,
+        Const = Self,
     > +
     fmt::Write
 {
@@ -667,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!(print(sz));
                 }
                 p!(write("]"))
             }
@@ -810,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().describe_def(did) {
+                | Some(Def::Static(_))
+                | Some(Def::Const(_))
+                | Some(Def::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("_"))
+                    }
+                } else {
+                    p!(write("_"))
+                },
+            }
+            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.
@@ -902,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
@@ -977,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,
@@ -1447,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.
@@ -1536,106 +1651,6 @@ define_print_and_forward_display! {
         p!(print_def_path(self.def_id, self.substs));
     }
 
-    &'tcx ty::Const<'tcx> {
-        let u8 = cx.tcx().types.u8;
-        if let ty::FnDef(did, substs) = self.ty.sty {
-            p!(print_value_path(did, substs));
-            return Ok(cx);
-        }
-        if let ConstValue::Unevaluated(did, substs) = self.val {
-            match cx.tcx().describe_def(did) {
-                | Some(Def::Static(_))
-                | Some(Def::Const(_))
-                | Some(Def::AssociatedConst(_)) => p!(print_value_path(did, substs)),
-                _ => if did.is_local() {
-                    let span = cx.tcx().def_span(did);
-                    if let Ok(snip) = cx.tcx().sess.source_map().span_to_snippet(span) {
-                        p!(write("{}", snip))
-                    } else {
-                        p!(write("_"))
-                    }
-                } else {
-                    p!(write("_"))
-                },
-            }
-            return Ok(cx);
-        }
-        if let ConstValue::Infer(..) = self.val {
-            p!(write("_: "), print(self.ty));
-            return Ok(cx);
-        }
-        if let ConstValue::Param(ParamConst { name, .. }) = self.val {
-            p!(write("{}", name));
-            return Ok(cx);
-        }
-        if let ConstValue::Scalar(Scalar::Bits { bits, .. }) = self.val {
-            match self.ty.sty {
-                ty::Bool => {
-                    p!(write("{}", if bits == 0 { "false" } else { "true" }));
-                    return Ok(cx);
-                },
-                ty::Float(ast::FloatTy::F32) => {
-                    p!(write("{}f32", Single::from_bits(bits)));
-                    return Ok(cx);
-                },
-                ty::Float(ast::FloatTy::F64) => {
-                    p!(write("{}f64", Double::from_bits(bits)));
-                    return Ok(cx);
-                },
-                ty::Uint(ui) => {
-                    p!(write("{}{}", bits, ui));
-                    return Ok(cx);
-                },
-                ty::Int(i) =>{
-                    let ty = cx.tcx().lift_to_global(&self.ty).unwrap();
-                    let size = cx.tcx().layout_of(ty::ParamEnv::empty().and(ty))
-                        .unwrap()
-                        .size;
-                    p!(write("{}{}", sign_extend(bits, size) as i128, i));
-                    return Ok(cx);
-                },
-                ty::Char => {
-                    p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap()));
-                    return Ok(cx);
-                }
-                _ => {},
-            }
-        }
-        if let ty::Ref(_, ref_ty, _) = self.ty.sty {
-            let byte_str = match (self.val, &ref_ty.sty) {
-                (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => {
-                    let n = n.unwrap_usize(cx.tcx());
-                    Some(cx.tcx()
-                        .alloc_map.lock()
-                        .unwrap_memory(ptr.alloc_id)
-                        .get_bytes(&cx.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(cx);
-                },
-                _ => None,
-            };
-            if let Some(byte_str) = byte_str {
-                p!(write("b\""));
-                for &c in byte_str {
-                    for e in std::ascii::escape_default(c) {
-                        cx.write_char(e as char)?;
-                    }
-                }
-                p!(write("\""));
-                return Ok(cx);
-            }
-        }
-        p!(write("{:?} : ", self.val), print(self.ty));
-    }
-
     ty::ParamTy {
         p!(write("{}", self.name))
     }
diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs
index d50a9a1607b24..deebfbadec658 100644
--- a/src/librustc_codegen_utils/symbol_names.rs
+++ b/src/librustc_codegen_utils/symbol_names.rs
@@ -391,6 +391,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 +437,13 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> {
         Ok(self)
     }
 
+    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,

From ed68cbeb9706b4248510145701e5e4d6056b082b Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Fri, 3 May 2019 10:59:04 +0200
Subject: [PATCH 21/42] Break cycle during array length printing

---
 src/librustc/ty/print/pretty.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 19fbf498034be..4e3128bae7404 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -671,7 +671,7 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
                 if let Some(n) = sz.assert_usize(self.tcx()) {
                     p!(write("{}", n));
                 } else {
-                    p!(print(sz));
+                    p!(write("_"));
                 }
                 p!(write("]"))
             }

From b4bbf9513ae7c4ca2299019e02f536b9aabefd0b Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 7 May 2019 17:47:52 +0200
Subject: [PATCH 22/42] Fix rebase fallout

---
 src/librustc/ty/print/pretty.rs                        | 10 +++++-----
 src/librustc_mir/monomorphize/item.rs                  |  2 +-
 .../ui/const-generics/cannot-infer-const-args.stderr   |  2 +-
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 4e3128bae7404..aea8baf4089c3 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1,5 +1,5 @@
 use crate::hir;
-use crate::hir::def::{Namespace, Def};
+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};
@@ -822,10 +822,10 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
             return Ok(self);
         }
         if let ConstValue::Unevaluated(did, substs) = ct.val {
-            match self.tcx().describe_def(did) {
-                | Some(Def::Static(_))
-                | Some(Def::Const(_))
-                | Some(Def::AssociatedConst(_)) => p!(print_value_path(did, substs)),
+            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) {
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/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
 

From 7902347d5e88681d1a691ecfc105cd3664cc22b3 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sat, 11 May 2019 15:48:47 +0200
Subject: [PATCH 23/42] Print types for unevaluated constants

---
 src/librustc/ty/print/pretty.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index aea8baf4089c3..6e3f283a44338 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -831,10 +831,10 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
                     if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
                         p!(write("{}", snip))
                     } else {
-                        p!(write("_"))
+                        p!(write("_: "), print(ct.ty))
                     }
                 } else {
-                    p!(write("_"))
+                    p!(write("_: "), print(ct.ty))
                 },
             }
             return Ok(self);

From 15acc323ea17b2285383f4c14344267d3de99e42 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sat, 11 May 2019 15:48:57 +0200
Subject: [PATCH 24/42] Update ui tests

---
 src/test/ui/pattern/const-pat-ice.stderr |  2 +-
 src/test/ui/symbol-names/impl2.rs        | 14 ++++++++++++++
 src/test/ui/symbol-names/impl2.stderr    |  8 ++++++++
 3 files changed, 23 insertions(+), 1 deletion(-)
 create mode 100644 src/test/ui/symbol-names/impl2.rs
 create mode 100644 src/test/ui/symbol-names/impl2.stderr

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/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
+

From 6a08e4ee2c8162e9952eb3d1010393ad14e13a0e Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Sat, 11 May 2019 16:04:14 +0200
Subject: [PATCH 25/42] Only print integers in symbol path's constants

---
 src/librustc_codegen_utils/symbol_names.rs | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs
index deebfbadec658..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};
@@ -438,10 +439,17 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> {
     }
 
     fn print_const(
-        self,
+        mut self,
         ct: &'tcx ty::Const<'tcx>,
     ) -> Result<Self::Const, Self::Error> {
-        self.pretty_print_const(ct)
+        // 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(

From d29f0d23c3624047a3f3671a8e352783e8796373 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Sun, 12 May 2019 19:55:16 +0300
Subject: [PATCH 26/42] Move token tree related lexer state to a separate
 struct

We only used a bunch of fields when tokenizing into a token tree,
so let's move them out of the base lexer
---
 src/libsyntax/parse/lexer/mod.rs        | 14 +---
 src/libsyntax/parse/lexer/tokentrees.rs | 96 +++++++++++++++++--------
 src/libsyntax/parse/mod.rs              |  9 +--
 3 files changed, 71 insertions(+), 48 deletions(-)

diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 2882acb0e780c..60494a6a2bdc7 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -66,15 +66,7 @@ pub struct StringReader<'a> {
     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> {
@@ -254,11 +246,7 @@ impl<'a> StringReader<'a> {
             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..a6e176c02a09b 100644
--- a/src/libsyntax/parse/lexer/tokentrees.rs
+++ b/src/libsyntax/parse/lexer/tokentrees.rs
@@ -1,14 +1,42 @@
+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,
+            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>,
+    /// 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();
 
-        while self.token != token::Eof {
+        while self.string_reader.token != token::Eof {
             tts.push(self.parse_token_tree()?);
         }
 
@@ -19,7 +47,7 @@ impl<'a> StringReader<'a> {
     fn parse_token_trees_until_close_delim(&mut self) -> TokenStream {
         let mut tts = vec![];
         loop {
-            if let token::CloseDelim(..) = self.token {
+            if let token::CloseDelim(..) = self.string_reader.token {
                 return TokenStream::new(tts);
             }
 
@@ -34,11 +62,12 @@ impl<'a> StringReader<'a> {
     }
 
     fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> {
-        let sm = self.sess.source_map();
-        match self.token {
+        let sm = self.string_reader.sess.source_map();
+        match self.string_reader.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 +75,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(
@@ -69,11 +97,11 @@ impl<'a> StringReader<'a> {
             },
             token::OpenDelim(delim) => {
                 // The span for beginning of the delimited section
-                let pre_span = self.span;
+                let pre_span = self.span();
 
                 // Parse the open delimiter.
-                self.open_braces.push((delim, self.span));
-                self.real_token();
+                self.open_braces.push((delim, self.span()));
+                self.string_reader.real_token();
 
                 // Parse the token trees within the delimiters.
                 // We stop at any delimiter so we can try to recover if the user
@@ -81,9 +109,9 @@ impl<'a> StringReader<'a> {
                 let tts = self.parse_token_trees_until_close_delim();
 
                 // Expand to cover the entire delimited token tree
-                let delim_span = DelimSpan::from_pair(pre_span, self.span);
+                let delim_span = DelimSpan::from_pair(pre_span, self.span());
 
-                match self.token {
+                match self.string_reader.token {
                     // Correct delimiter.
                     token::CloseDelim(d) if d == delim => {
                         let (open_brace, open_brace_span) = self.open_braces.pop().unwrap();
@@ -93,26 +121,26 @@ impl<'a> StringReader<'a> {
                             self.matching_delim_spans.clear();
                         } else {
                             self.matching_delim_spans.push(
-                                (open_brace, open_brace_span, self.span),
+                                (open_brace, open_brace_span, self.span()),
                             );
                         }
                         // Parse the close delimiter.
-                        self.real_token();
+                        self.string_reader.real_token();
                     }
                     // Incorrect delimiter.
                     token::CloseDelim(other) => {
                         let mut unclosed_delimiter = None;
                         let mut candidate = None;
-                        if self.last_unclosed_found_span != Some(self.span) {
+                        if self.last_unclosed_found_span != Some(self.span()) {
                             // do not complain about the same unclosed delimiter multiple times
-                            self.last_unclosed_found_span = Some(self.span);
+                            self.last_unclosed_found_span = Some(self.span());
                             // This is a conservative error: only report the last unclosed
                             // delimiter. The previous unclosed delimiters could actually be
                             // closed! The parser just hasn't gotten to them yet.
                             if let Some(&(_, sp)) = self.open_braces.last() {
                                 unclosed_delimiter = Some(sp);
                             };
-                            if let Some(current_padding) = sm.span_to_margin(self.span) {
+                            if let Some(current_padding) = sm.span_to_margin(self.span()) {
                                 for (brace, brace_span) in &self.open_braces {
                                     if let Some(padding) = sm.span_to_margin(*brace_span) {
                                         // high likelihood of these two corresponding
@@ -126,7 +154,7 @@ impl<'a> StringReader<'a> {
                             self.unmatched_braces.push(UnmatchedBrace {
                                 expected_delim: tok,
                                 found_delim: other,
-                                found_span: self.span,
+                                found_span: self.span(),
                                 unclosed_span: unclosed_delimiter,
                                 candidate_span: candidate,
                             });
@@ -142,7 +170,7 @@ impl<'a> StringReader<'a> {
                         //     bar(baz(
                         // }  // Incorrect delimiter but matches the earlier `{`
                         if !self.open_braces.iter().any(|&(b, _)| b == other) {
-                            self.real_token();
+                            self.string_reader.real_token();
                         }
                     }
                     token::Eof => {
@@ -162,22 +190,28 @@ impl<'a> StringReader<'a> {
             token::CloseDelim(_) => {
                 // An unexpected closing delimiter (i.e., there is no
                 // matching opening delimiter).
-                let token_str = token_to_string(&self.token);
+                let token_str = token_to_string(&self.string_reader.token);
                 let msg = format!("unexpected close delimiter: `{}`", token_str);
-                let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &msg);
-                err.span_label(self.span, "unexpected close delimiter");
+                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)
             },
             _ => {
-                let tt = TokenTree::Token(self.span, self.token.clone());
+                let tt = TokenTree::Token(self.span(), self.string_reader.token.clone());
                 // 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;
-                self.real_token();
-                let is_joint = raw.hi() == self.span_src_raw.lo() && token::is_op(&self.token);
+                let raw = self.string_reader.span_src_raw;
+                self.string_reader.real_token();
+                let is_joint = raw.hi() == self.string_reader.span_src_raw.lo()
+                    && token::is_op(&self.string_reader.token);
                 Ok((tt, if is_joint { Joint } else { NonJoint }))
             }
         }
     }
+
+    fn span(&self) -> Span {
+        self.string_reader.span
+    }
 }
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index be44b964ba5a7..1ddafb969c4b3 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -295,7 +295,7 @@ 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>,
@@ -303,14 +303,15 @@ pub fn maybe_file_to_stream(
 ) -> 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 (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)),

From b91e0a378690871fa744768f38d42bd90830bcd0 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Mon, 13 May 2019 12:06:37 +0300
Subject: [PATCH 27/42] move span and token to tt reader

---
 src/libsyntax/parse/lexer/mod.rs        | 12 -----
 src/libsyntax/parse/lexer/tokentrees.rs | 60 ++++++++++++++-----------
 src/libsyntax/parse/mod.rs              |  3 +-
 3 files changed, 35 insertions(+), 40 deletions(-)

diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 60494a6a2bdc7..9caa9ea807c1d 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -62,10 +62,6 @@ 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,
     override_span: Option<Span>,
 }
 
@@ -113,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)
     }
 
@@ -151,9 +145,6 @@ impl<'a> StringReader<'a> {
             }
         }
 
-        self.token = t.tok.clone();
-        self.span = t.sp;
-
         Ok(t)
     }
 
@@ -243,9 +234,6 @@ 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,
             override_span,
         }
     }
diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs
index a6e176c02a09b..1070d6dcb1b34 100644
--- a/src/libsyntax/parse/lexer/tokentrees.rs
+++ b/src/libsyntax/parse/lexer/tokentrees.rs
@@ -9,6 +9,8 @@ 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(),
@@ -21,6 +23,8 @@ impl<'a> StringReader<'a> {
 
 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>,
@@ -36,7 +40,8 @@ impl<'a> TokenTreesReader<'a> {
     fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
         let mut tts = Vec::new();
 
-        while self.string_reader.token != token::Eof {
+        self.real_token();
+        while self.token != token::Eof {
             tts.push(self.parse_token_tree()?);
         }
 
@@ -47,7 +52,7 @@ impl<'a> TokenTreesReader<'a> {
     fn parse_token_trees_until_close_delim(&mut self) -> TokenStream {
         let mut tts = vec![];
         loop {
-            if let token::CloseDelim(..) = self.string_reader.token {
+            if let token::CloseDelim(..) = self.token {
                 return TokenStream::new(tts);
             }
 
@@ -63,11 +68,11 @@ impl<'a> TokenTreesReader<'a> {
 
     fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> {
         let sm = self.string_reader.sess.source_map();
-        match self.string_reader.token {
+        match self.token {
             token::Eof => {
                 let msg = "this file contains an un-closed delimiter";
                 let mut err = self.string_reader.sess.span_diagnostic
-                    .struct_span_err(self.span(), msg);
+                    .struct_span_err(self.span, msg);
                 for &(_, sp) in &self.open_braces {
                     err.span_label(sp, "un-closed delimiter");
                 }
@@ -97,11 +102,11 @@ impl<'a> TokenTreesReader<'a> {
             },
             token::OpenDelim(delim) => {
                 // The span for beginning of the delimited section
-                let pre_span = self.span();
+                let pre_span = self.span;
 
                 // Parse the open delimiter.
-                self.open_braces.push((delim, self.span()));
-                self.string_reader.real_token();
+                self.open_braces.push((delim, self.span));
+                self.real_token();
 
                 // Parse the token trees within the delimiters.
                 // We stop at any delimiter so we can try to recover if the user
@@ -109,9 +114,9 @@ impl<'a> TokenTreesReader<'a> {
                 let tts = self.parse_token_trees_until_close_delim();
 
                 // Expand to cover the entire delimited token tree
-                let delim_span = DelimSpan::from_pair(pre_span, self.span());
+                let delim_span = DelimSpan::from_pair(pre_span, self.span);
 
-                match self.string_reader.token {
+                match self.token {
                     // Correct delimiter.
                     token::CloseDelim(d) if d == delim => {
                         let (open_brace, open_brace_span) = self.open_braces.pop().unwrap();
@@ -121,26 +126,26 @@ impl<'a> TokenTreesReader<'a> {
                             self.matching_delim_spans.clear();
                         } else {
                             self.matching_delim_spans.push(
-                                (open_brace, open_brace_span, self.span()),
+                                (open_brace, open_brace_span, self.span),
                             );
                         }
                         // Parse the close delimiter.
-                        self.string_reader.real_token();
+                        self.real_token();
                     }
                     // Incorrect delimiter.
                     token::CloseDelim(other) => {
                         let mut unclosed_delimiter = None;
                         let mut candidate = None;
-                        if self.last_unclosed_found_span != Some(self.span()) {
+                        if self.last_unclosed_found_span != Some(self.span) {
                             // do not complain about the same unclosed delimiter multiple times
-                            self.last_unclosed_found_span = Some(self.span());
+                            self.last_unclosed_found_span = Some(self.span);
                             // This is a conservative error: only report the last unclosed
                             // delimiter. The previous unclosed delimiters could actually be
                             // closed! The parser just hasn't gotten to them yet.
                             if let Some(&(_, sp)) = self.open_braces.last() {
                                 unclosed_delimiter = Some(sp);
                             };
-                            if let Some(current_padding) = sm.span_to_margin(self.span()) {
+                            if let Some(current_padding) = sm.span_to_margin(self.span) {
                                 for (brace, brace_span) in &self.open_braces {
                                     if let Some(padding) = sm.span_to_margin(*brace_span) {
                                         // high likelihood of these two corresponding
@@ -154,7 +159,7 @@ impl<'a> TokenTreesReader<'a> {
                             self.unmatched_braces.push(UnmatchedBrace {
                                 expected_delim: tok,
                                 found_delim: other,
-                                found_span: self.span(),
+                                found_span: self.span,
                                 unclosed_span: unclosed_delimiter,
                                 candidate_span: candidate,
                             });
@@ -170,7 +175,7 @@ impl<'a> TokenTreesReader<'a> {
                         //     bar(baz(
                         // }  // Incorrect delimiter but matches the earlier `{`
                         if !self.open_braces.iter().any(|&(b, _)| b == other) {
-                            self.string_reader.real_token();
+                            self.real_token();
                         }
                     }
                     token::Eof => {
@@ -190,28 +195,31 @@ impl<'a> TokenTreesReader<'a> {
             token::CloseDelim(_) => {
                 // An unexpected closing delimiter (i.e., there is no
                 // matching opening delimiter).
-                let token_str = token_to_string(&self.string_reader.token);
+                let token_str = token_to_string(&self.token);
                 let msg = format!("unexpected close delimiter: `{}`", token_str);
                 let mut err = self.string_reader.sess.span_diagnostic
-                    .struct_span_err(self.span(), &msg);
-                err.span_label(self.span(), "unexpected close delimiter");
+                    .struct_span_err(self.span, &msg);
+                err.span_label(self.span, "unexpected close delimiter");
                 Err(err)
             },
             _ => {
-                let tt = TokenTree::Token(self.span(), self.string_reader.token.clone());
+                let tt = TokenTree::Token(self.span, self.token.clone());
                 // 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.string_reader.span_src_raw;
-                self.string_reader.real_token();
-                let is_joint = raw.hi() == self.string_reader.span_src_raw.lo()
-                    && token::is_op(&self.string_reader.token);
+                let raw = self.string_reader.peek_span_src_raw;
+                self.real_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 span(&self) -> Span {
-        self.string_reader.span
+    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 1ddafb969c4b3..4a9a7aec6adde 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -301,8 +301,7 @@ pub fn maybe_file_to_stream(
     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 token_trees {

From e249f2e526cca687b78a766769c481cfb638f02e Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Mon, 13 May 2019 14:30:18 +0300
Subject: [PATCH 28/42] move raw span to tt reader

See https://github.com/rust-lang/rust/pull/50838/files#r283296243 for
explanation how jointness checking works with *next* pair
---
 src/libsyntax/parse/lexer/tokentrees.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs
index 1070d6dcb1b34..4bfc5bb16c0bb 100644
--- a/src/libsyntax/parse/lexer/tokentrees.rs
+++ b/src/libsyntax/parse/lexer/tokentrees.rs
@@ -207,6 +207,8 @@ impl<'a> TokenTreesReader<'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.
+                // 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.string_reader.peek_span_src_raw.lo()
@@ -222,4 +224,3 @@ impl<'a> TokenTreesReader<'a> {
         self.span = t.sp;
     }
 }
-

From 19a9109d332f596f77bb2b4e740650775193e496 Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Sat, 30 Mar 2019 21:49:52 +0000
Subject: [PATCH 29/42] Remove unused parameter from in(_opt)?_scope

---
 src/librustc_mir/build/block.rs           | 12 ++++++------
 src/librustc_mir/build/expr/as_operand.rs |  2 +-
 src/librustc_mir/build/expr/as_place.rs   |  2 +-
 src/librustc_mir/build/expr/as_rvalue.rs  |  2 +-
 src/librustc_mir/build/expr/as_temp.rs    |  2 +-
 src/librustc_mir/build/expr/into.rs       |  2 +-
 src/librustc_mir/build/expr/stmt.rs       |  2 +-
 src/librustc_mir/build/mod.rs             |  4 ++--
 src/librustc_mir/build/scope.rs           |  8 ++++----
 9 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index 7469aceee3a9e..d93223a4292c4 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))
                             })
@@ -128,9 +128,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             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.expr_into_pattern(block, pattern, init)
                                 })
                             }));
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..c60e197010067 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -43,7 +43,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)
             });
         }
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/mod.rs b/src/librustc_mir/build/mod.rs
index 16ab233bd2e36..b432ed47d0b8d 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
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 4aa463b37ab77..471304012c9a8 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -279,13 +279,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 +299,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 +329,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;

From 63f47b798f23f4d8fc0f5ca9feb252cf1328cc98 Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Sat, 30 Mar 2019 22:54:29 +0000
Subject: [PATCH 30/42] Give match arms an HirId and a Span

---
 src/librustc/hir/intravisit.rs      |  1 +
 src/librustc/hir/lowering.rs        |  8 ++++++++
 src/librustc/hir/map/collector.rs   | 10 ++++++++++
 src/librustc/hir/map/mod.rs         |  7 +++++++
 src/librustc/hir/mod.rs             |  4 ++++
 src/librustc/hir/print.rs           |  2 +-
 src/librustc_passes/hir_stats.rs    |  2 +-
 src/librustc_typeck/check/_match.rs | 15 +++++++++------
 src/libsyntax/ast.rs                |  1 +
 src/libsyntax/ext/build.rs          |  3 ++-
 src/libsyntax/mut_visit.rs          |  6 +++++-
 src/libsyntax/parse/parser.rs       |  4 ++++
 12 files changed, 53 insertions(+), 10 deletions(-)

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..75e1003374940 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1312,7 +1312,10 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_arm(&mut self, arm: &Arm) -> hir::Arm {
+        let LoweredNodeId { node_id: _, hir_id } = self.next_id();
+
         hir::Arm {
+            hir_id,
             attrs: self.lower_attrs(&arm.attrs),
             pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(),
             guard: match arm.guard {
@@ -1320,6 +1323,7 @@ impl<'a> LoweringContext<'a> {
                 _ => None,
             },
             body: P(self.lower_expr(&arm.body)),
+            span: arm.span,
         }
     }
 
@@ -5022,10 +5026,14 @@ impl<'a> LoweringContext<'a> {
     // Helper methods for building HIR.
 
     fn arm(&mut self, pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
+        let LoweredNodeId { node_id: _, hir_id } = self.next_id();
+
         hir::Arm {
+            hir_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_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..99b350b833274 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -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/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/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),
         })
     }
 

From 7a53e03eef488d8433091b6b6271382e7dbd60af Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Sat, 30 Mar 2019 23:00:07 +0000
Subject: [PATCH 31/42] Respect lint attributes on match arms

---
 src/librustc/lint/mod.rs                |  6 ++++++
 src/test/ui/lint/lint-match-arms.rs     | 18 ++++++++++++++++++
 src/test/ui/lint/lint-match-arms.stderr | 14 ++++++++++++++
 3 files changed, 38 insertions(+)
 create mode 100644 src/test/ui/lint/lint-match-arms.rs
 create mode 100644 src/test/ui/lint/lint-match-arms.stderr

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/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
+

From ca8db942fc551aac89fcf373863768e8280f12cc Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Tue, 2 Apr 2019 22:29:28 +0100
Subject: [PATCH 32/42] Handle the visibility/lint scope distinction better

* Don't generate an extra lint scope for each `let` statement.
* Place match guards inside the visiblility scope of the bindings for
  their arm.
---
 src/librustc/hir/lowering.rs                  |  8 ++---
 src/librustc_mir/build/block.rs               | 36 +++++++++++--------
 src/librustc_mir/build/matches/mod.rs         | 27 ++++----------
 src/librustc_mir/build/mod.rs                 | 11 +++---
 src/librustc_mir/hair/mod.rs                  | 11 ++----
 src/test/mir-opt/box_expr.rs                  |  4 +--
 src/test/mir-opt/issue-41110.rs               |  7 ++--
 src/test/mir-opt/issue-49232.rs               |  4 +--
 .../mir-opt/packed-struct-drop-aligned.rs     |  4 +--
 9 files changed, 45 insertions(+), 67 deletions(-)

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 75e1003374940..05aa7690663e1 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1312,10 +1312,8 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_arm(&mut self, arm: &Arm) -> hir::Arm {
-        let LoweredNodeId { node_id: _, hir_id } = self.next_id();
-
         hir::Arm {
-            hir_id,
+            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 {
@@ -5026,10 +5024,8 @@ impl<'a> LoweringContext<'a> {
     // Helper methods for building HIR.
 
     fn arm(&mut self, pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
-        let LoweredNodeId { node_id: _, hir_id } = self.next_id();
-
         hir::Arm {
-            hir_id,
+            hir_id: self.next_id(),
             attrs: hir_vec![],
             pats,
             guard: None,
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index d93223a4292c4..b5bab1585342a 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -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)), |this| {
                                 let scope = (init_scope, source_info);
                                 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/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 51d5c96083d8f..93a702dc44e25 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -259,12 +259,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             let scope = self.declare_bindings(
                 None,
                 body.span,
-                LintLevel::Inherited,
                 &arm.patterns[0],
                 ArmHasGuard(arm.guard.is_some()),
                 Some((Some(&scrutinee_place), scrutinee_span)),
             );
 
+            if let Some(source_scope) = scope {
+                this.source_scope = source_scope;
+            }
+
             for candidate in candidates {
                 self.bind_and_guard_matched_candidate(
                     candidate,
@@ -275,9 +278,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 );
             }
 
-            if let Some(source_scope) = scope {
-                self.source_scope = source_scope;
-            }
 
             unpack!(arm_block = self.into(destination, arm_block, body));
 
@@ -489,33 +489,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, this.source_scope };
                 let visibility_scope = visibility_scope.unwrap();
                 this.declare_binding(
                     source_info,
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index b432ed47d0b8d..8cd4ac0ad3ade 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -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/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/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs
index d4852db6d475e..ee6adfefe3e36 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);
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..3910183dee789 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;
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: {

From 531c2f8479c2d5e3078190ef37db524727ecd0ab Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Wed, 3 Apr 2019 19:21:51 +0100
Subject: [PATCH 33/42] Give match arms a drop/region scope

Also give arms the correct lint scope in MIR.
---
 src/librustc/cfg/construct.rs                 |  10 +-
 src/librustc/middle/region.rs                 |  34 +++--
 src/librustc_mir/build/matches/mod.rs         |  87 +++++++-----
 src/librustc_mir/build/scope.rs               |  84 +++++++++++-
 src/librustc_mir/hair/cx/expr.rs              |   8 +-
 src/test/mir-opt/match_false_edges.rs         | 126 +++++++++++-------
 src/test/mir-opt/match_test.rs                |  33 ++---
 src/test/mir-opt/remove_fake_borrows.rs       |  50 +++----
 src/test/ui/lint/lint-unused-mut-variables.rs |   8 ++
 .../ui/lint/lint-unused-mut-variables.stderr  |   4 +-
 10 files changed, 299 insertions(+), 145 deletions(-)

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/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/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 93a702dc44e25..091e39630d6cb 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,
-                &arm.patterns[0],
-                ArmHasGuard(arm.guard.is_some()),
-                Some((Some(&scrutinee_place), scrutinee_span)),
-            );
-
-            if let Some(source_scope) = scope {
-                this.source_scope = source_scope;
-            }
-
-            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 {
+                    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 },
             );
@@ -502,7 +505,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     visibility_scope =
                         Some(this.new_source_scope(scope_span, LintLevel::Inherited, None));
                 }
-                let source_info = SourceInfo { span, this.source_scope };
+                let source_info = SourceInfo { span, scope: this.source_scope };
                 let visibility_scope = visibility_scope.unwrap();
                 this.declare_binding(
                     source_info,
@@ -1315,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);
 
@@ -1497,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/scope.rs b/src/librustc_mir/build/scope.rs
index 471304012c9a8..0d1d40a8af633 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
@@ -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/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 50140880a368d..d623f149988c7 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -879,8 +879,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,
     }
 }
 
diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs
index 7ac36a22274f3..0850c552536c5 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(_1);
+//      StorageDead(_2);
+//      _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(_1);
+//      StorageDead(_2);
+//      _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(_1);
+//      StorageDead(_2);
+//      _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/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/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)]
    |        ^^^^^^^^^^

From bd8ecc6f5df1e3b54ca3e17da8360de4b07a1905 Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Wed, 3 Apr 2019 19:30:18 +0100
Subject: [PATCH 34/42] Remove MIR borrowck hack for old match scopes

---
 src/librustc_mir/dataflow/impls/mod.rs | 39 ++++++--------------------
 1 file changed, 8 insertions(+), 31 deletions(-)

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]);
             }
             _ => {}
         }

From decfc9b6f98ffab2cb588f048dda19ea90761f0b Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Wed, 3 Apr 2019 20:54:23 +0100
Subject: [PATCH 35/42] Emit fake borrows for all tests

I was incorrectly under the impression that this would only lead to
duplicates. See `mir-opt/match-arm-scope.rs` (upcomming commit) for a
case where we didn't emit a fake borrow of `items.1`.
---
 src/librustc_mir/build/matches/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 091e39630d6cb..58ca35abcb123 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -870,7 +870,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             span,
             untested_candidates,
             join_block,
-            &mut None,
+            fake_borrows,
         )
     }
 

From 4a6ba5109a012c2ed493ff5a9861738e8594a736 Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Wed, 3 Apr 2019 21:13:51 +0100
Subject: [PATCH 36/42] Schedule storage-dead of temporaries sooner

This ensures that we will correctly generate a storage-dead if the
initializing expression diverges.
---
 src/librustc_mir/build/expr/as_temp.rs        | 40 +++++++++++++------
 src/test/mir-opt/issue-49232.rs               |  1 -
 src/test/mir-opt/match_false_edges.rs         |  6 +--
 .../mir-opt/storage_live_dead_in_statics.rs   |  2 +-
 4 files changed, 32 insertions(+), 17 deletions(-)

diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index c60e197010067..ac70bf30e457b 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::*;
@@ -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/test/mir-opt/issue-49232.rs b/src/test/mir-opt/issue-49232.rs
index 3910183dee789..bf22f00b50552 100644
--- a/src/test/mir-opt/issue-49232.rs
+++ b/src/test/mir-opt/issue-49232.rs
@@ -86,7 +86,6 @@ fn main() {
 //         unreachable;
 //     }
 //     bb17: {
-//         StorageDead(_4);
 //         goto -> bb18;
 //     }
 //     bb18: {
diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs
index 0850c552536c5..6979924c8cd90 100644
--- a/src/test/mir-opt/match_false_edges.rs
+++ b/src/test/mir-opt/match_false_edges.rs
@@ -109,8 +109,8 @@ fn main() {
 //      goto -> bb13;
 //  }
 //  bb13: {
-//      StorageDead(_1);
 //      StorageDead(_2);
+//      StorageDead(_1);
 //      _0 = ();
 //      return;
 //  }
@@ -186,8 +186,8 @@ fn main() {
 //      goto -> bb13;
 //  }
 //  bb13: {
-//      StorageDead(_1);
 //      StorageDead(_2);
+//      StorageDead(_1);
 //      _0 = ();
 //      return;
 //  }
@@ -289,8 +289,8 @@ fn main() {
 //      goto -> bb17;
 //  }
 //  bb17: {
-//      StorageDead(_1);
 //      StorageDead(_2);
+//      StorageDead(_1);
 //      _0 = ();
 //      return;
 //  }
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;
 //    }
 //}

From 47c4e8c637a72c65b69fa21bf9cfd4ca184065fe Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Wed, 3 Apr 2019 21:21:53 +0100
Subject: [PATCH 37/42] Add a test for match scopes

---
 src/test/mir-opt/match-arm-scopes.rs | 245 +++++++++++++++++++++++++++
 1 file changed, 245 insertions(+)
 create mode 100644 src/test/mir-opt/match-arm-scopes.rs

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

From 8094d6e1cfe652c119f34f85e07148a2e65532e0 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Mon, 22 Apr 2019 20:35:00 +0200
Subject: [PATCH 38/42] Comment style fixes

Co-Authored-By: matthewjasper <mjjasper1@gmail.com>
---
 src/librustc_mir/build/expr/as_temp.rs | 4 ++--
 src/librustc_mir/build/scope.rs        | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index ac70bf30e457b..cffd8fb2892f5 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -75,8 +75,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 },
             );
 
-            // 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.
+            // 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
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 0d1d40a8af633..34df40ae180af 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -900,7 +900,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// * 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.
+    /// * The drop must be of `DropKind::Storage`.
     ///
     /// This is used for the boolean holding the result of the match guard. We
     /// do this because:

From 5b5255da4e7a9a3dd93a814687c53225a55a6e42 Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Sun, 5 May 2019 17:32:52 +0100
Subject: [PATCH 39/42] Fix match ergonomics suggestion

---
 src/librustc_typeck/check/_match.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 99b350b833274..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) {

From ea93215576ff04cab3bdb78c0d16ea7253488f40 Mon Sep 17 00:00:00 2001
From: Wesley Wiser <wwiser@gmail.com>
Date: Mon, 13 May 2019 22:15:55 -0400
Subject: [PATCH 40/42] Bump measureme dependency to 0.3

measureme@0.3 adds a version header to the binary file format which will
help reduce tool breakage in the future.
---
 Cargo.lock              | 6 +++---
 src/librustc/Cargo.toml | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

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/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.

From 441ca638cc131074481436c146e3d3aee1be75df Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Tue, 14 May 2019 10:55:55 -0700
Subject: [PATCH 41/42] Update LLVM to fix assertion when compiling to wasm

More details can be found in #60540!

Closes #60540
---
 src/llvm-project | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/llvm-project b/src/llvm-project
index 84abffda0e03b..eb38a1888d1d2 160000
--- a/src/llvm-project
+++ b/src/llvm-project
@@ -1 +1 @@
-Subproject commit 84abffda0e03b03c62bdfc3cfeda1c2cf1f88c85
+Subproject commit eb38a1888d1d29b2d2c6b31428a5201cd8fba0ff

From 3646b3c3d9f60c0632668943ca65beb259d035f9 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Tue, 14 May 2019 21:33:22 +0300
Subject: [PATCH 42/42] rustbuild/LLVM: Do not print installation messages for
 up-to-date files

---
 src/bootstrap/native.rs | 4 ++++
 1 file changed, 4 insertions(+)

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");
     }