From 090747632dfd6a0748bb0b2e2d02de4af321ab84 Mon Sep 17 00:00:00 2001
From: Oli Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 16 Mar 2021 11:58:53 +0000
Subject: [PATCH 1/6] Add pretty printer support for `ConstValue` without going
 through ty::Const

---
 .../rustc_infer/src/infer/error_reporting/mod.rs  |  9 +++++++++
 compiler/rustc_lint/src/context.rs                |  9 +++++++++
 compiler/rustc_middle/src/ty/print/mod.rs         | 15 +++++++++++++++
 compiler/rustc_middle/src/ty/print/pretty.rs      |  8 ++++++++
 .../src/interpret/intrinsics/type_name.rs         | 10 +++++++++-
 compiler/rustc_symbol_mangling/src/legacy.rs      |  8 ++++++++
 compiler/rustc_symbol_mangling/src/v0.rs          |  9 +++++++++
 7 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index e3a79fe265330..da7be40612a0a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -65,6 +65,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{Item, ItemKind, Node};
 use rustc_middle::dep_graph::DepContext;
+use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{
     self,
@@ -524,6 +525,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 Err(NonTrivialPath)
             }
 
+            fn print_const_value(
+                self,
+                _value: ConstValue<'tcx>,
+                _ty: Ty<'tcx>,
+            ) -> Result<Self::Const, Self::Error> {
+                Err(NonTrivialPath)
+            }
+
             fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
                 Ok(vec![self.tcx.crate_name(cnum).to_string()])
             }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index c44df407f6b3a..43ac476cac722 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -31,6 +31,7 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::middle::stability;
+use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::layout::{LayoutError, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
@@ -943,6 +944,14 @@ impl<'tcx> LateContext<'tcx> {
                 Ok(())
             }
 
+            fn print_const_value(
+                self,
+                _val: ConstValue<'tcx>,
+                _ty: Ty<'tcx>,
+            ) -> Result<Self::Const, Self::Error> {
+                Ok(())
+            }
+
             fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
                 Ok(vec![self.tcx.crate_name(cnum)])
             }
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 13e2122a619dc..2083f35ed1740 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -1,3 +1,4 @@
+use crate::mir::interpret::ConstValue;
 use crate::ty::subst::{GenericArg, Subst};
 use crate::ty::{self, DefIdTree, Ty, TyCtxt};
 
@@ -68,6 +69,12 @@ pub trait Printer<'tcx>: Sized {
 
     fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error>;
 
+    fn print_const_value(
+        self,
+        val: ConstValue<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Result<Self::Const, Self::Error>;
+
     fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error>;
 
     fn path_qualified(
@@ -362,3 +369,11 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::Const<'tcx> {
         cx.print_const(self)
     }
 }
+
+impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for (ConstValue<'tcx>, Ty<'tcx>) {
+    type Output = P::Const;
+    type Error = P::Error;
+    fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
+        cx.print_const_value(self.0, self.1)
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index cb326996111b7..44fa4eb71d801 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1458,6 +1458,14 @@ impl<F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> {
         self.pretty_print_const(ct, true)
     }
 
+    fn print_const_value(
+        self,
+        val: ConstValue<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Result<Self::Const, Self::Error> {
+        self.pretty_print_const_value(val, ty, true)
+    }
+
     fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
         self.empty_path = true;
         if cnum == LOCAL_CRATE {
diff --git a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs
index a7012cd63f313..b1d7179cc8c6d 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs
@@ -1,6 +1,6 @@
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::definitions::DisambiguatedDefPathData;
-use rustc_middle::mir::interpret::Allocation;
+use rustc_middle::mir::interpret::{Allocation, ConstValue};
 use rustc_middle::ty::{
     self,
     print::{PrettyPrinter, Print, Printer},
@@ -72,6 +72,14 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
         self.pretty_print_const(ct, false)
     }
 
+    fn print_const_value(
+        self,
+        val: ConstValue<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Result<Self::Const, Self::Error> {
+        self.pretty_print_const_value(val, ty, false)
+    }
+
     fn print_dyn_existential(
         mut self,
         predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 0c64fe6ea60a9..43732b98b46e1 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -253,6 +253,14 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> {
         Ok(self)
     }
 
+    fn print_const_value(
+        self,
+        value: ConstValue<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Result<Self::Const, Self::Error> {
+        bug!("symbol mangling should never see MIR constants, but saw {:?}:{:?}", value, ty)
+    }
+
     fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
         self.write_str(&self.tcx.crate_name(cnum).as_str())?;
         Ok(self)
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 14442806fc0b7..bcc622551f768 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -3,6 +3,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
+use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::print::{Print, Printer};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
@@ -590,6 +591,14 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
         Ok(self)
     }
 
+    fn print_const_value(
+        self,
+        value: ConstValue<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Result<Self::Const, Self::Error> {
+        bug!("symbol mangling should never see MIR constants, but saw {:?}:{:?}", value, ty)
+    }
+
     fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
         self.push("C");
         let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();

From 0502d429962d42a75a750aeb2a88b5216cbade6c Mon Sep 17 00:00:00 2001
From: Oli Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 16 Mar 2021 17:16:36 +0000
Subject: [PATCH 2/6] Add some convenience methods to `ScalarInt`

---
 compiler/rustc_middle/src/ty/consts/int.rs | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index 8ed8ea6a0bc55..c8a507edae6f4 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -202,6 +202,23 @@ impl ScalarInt {
         Ok(Self::try_from_uint(f_int(u64::try_from(self.data).unwrap())?, self.size()).unwrap())
     }
 
+    #[inline]
+    pub fn from_uint(i: impl Into<u128>, size: Size) -> Self {
+        let i = i.into();
+        Self::try_from_uint(i, size)
+            .unwrap_or_else(|| bug!("Unsigned value {:#x} does not fit in {} bits", i, size.bits()))
+    }
+
+    #[inline]
+    pub fn from_bool(b: bool) -> Self {
+        Self::from_uint(b as u8, Size::from_bytes(1))
+    }
+
+    #[inline]
+    pub fn from_char(c: char) -> Self {
+        Self::from_uint(c as u32, Size::from_bytes(4))
+    }
+
     #[inline]
     pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
         let data = i.into();

From aca10b380d25c606638d713084989ddadc01e188 Mon Sep 17 00:00:00 2001
From: Oli Scherer <github35764891676564198441@oli-obk.de>
Date: Wed, 17 Mar 2021 11:49:03 +0000
Subject: [PATCH 3/6] Simplify IntRange::from_const

---
 .../src/thir/pattern/deconstruct_pat.rs       | 33 ++++++++-----------
 1 file changed, 13 insertions(+), 20 deletions(-)

diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 4b5b648c5044f..925c555dbbea1 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -52,7 +52,6 @@ use rustc_data_structures::captures::Captures;
 use rustc_index::vec::Idx;
 
 use rustc_hir::{HirId, RangeEnd};
-use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::mir::Field;
 use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
 use rustc_middle::ty::layout::IntegerExt;
@@ -115,26 +114,20 @@ impl IntRange {
         param_env: ty::ParamEnv<'tcx>,
         value: &Const<'tcx>,
     ) -> Option<IntRange> {
-        if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) {
-            let ty = value.ty;
-            let val = (|| {
-                if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val {
-                    // For this specific pattern we can skip a lot of effort and go
-                    // straight to the result, after doing a bit of checking. (We
-                    // could remove this branch and just fall through, which
-                    // is more general but much slower.)
-                    if let Ok(bits) = scalar.to_bits_or_ptr(target_size, &tcx) {
-                        return Some(bits);
-                    }
-                }
-                // This is a more general form of the previous case.
-                value.try_eval_bits(tcx, param_env, ty)
-            })()?;
-            let val = val ^ bias;
-            Some(IntRange { range: val..=val })
+        let (target_size, bias) = Self::integral_size_and_signed_bias(tcx, value.ty)?;
+        let ty = value.ty;
+        let val = if let Some(int) = value.val.try_to_scalar_int() {
+            // For this specific pattern we can skip a lot of effort and go
+            // straight to the result, after doing a bit of checking. (We
+            // could remove this branch and just always use try_eval_bits, which
+            // is more general but much slower.)
+            int.assert_bits(target_size)
         } else {
-            None
-        }
+            // This is a more general form of the previous case.
+            value.try_eval_bits(tcx, param_env, ty)?
+        };
+        let val = val ^ bias;
+        Some(IntRange { range: val..=val })
     }
 
     #[inline]

From 987b9fccdd40ef95fd9a5d40c15d03ba6d8d24f0 Mon Sep 17 00:00:00 2001
From: Oli Scherer <github35764891676564198441@oli-obk.de>
Date: Wed, 17 Mar 2021 13:01:34 +0000
Subject: [PATCH 4/6] Encode int/float/bool/char patterns directly as
 `ScalarInt`

---
 compiler/rustc_middle/src/thir.rs             | 14 +++--
 .../src/build/matches/simplify.rs             | 28 ++++-----
 .../rustc_mir_build/src/build/matches/test.rs | 28 ++++++---
 .../src/thir/pattern/deconstruct_pat.rs       | 59 ++++++++++++++-----
 .../rustc_mir_build/src/thir/pattern/mod.rs   | 21 ++++++-
 compiler/rustc_mir_build/src/thir/visit.rs    |  5 +-
 ...ch_test.main.SimplifyCfg-initial.after.mir | 26 ++++----
 .../ui/consts/const-match-check.eval1.stderr  |  4 +-
 .../ui/consts/const-match-check.eval2.stderr  |  4 +-
 .../consts/const-match-check.matchck.stderr   | 16 ++---
 .../ui/consts/const-pattern-irrefutable.rs    |  6 +-
 .../consts/const-pattern-irrefutable.stderr   |  6 +-
 ...oop-refutable-pattern-error-message.stderr |  4 +-
 ...alf-open-range-pats-exhaustive-fail.stderr | 44 +++++++-------
 .../exhaustiveness-non-exhaustive.rs          |  6 +-
 .../exhaustiveness-non-exhaustive.stderr      | 12 ++--
 ...een-expanded-earlier-non-exhaustive.stderr |  8 +--
 src/test/ui/pattern/usefulness/guards.stderr  |  4 +-
 .../integer-ranges/exhaustiveness.stderr      |  8 +--
 .../match-byte-array-patterns-2.stderr        |  4 +-
 .../usefulness/match-non-exhaustive.stderr    |  4 +-
 .../usefulness/non-exhaustive-match.rs        |  4 +-
 .../usefulness/non-exhaustive-match.stderr    |  4 +-
 .../usefulness/refutable-pattern-errors.rs    |  2 +-
 .../refutable-pattern-errors.stderr           |  4 +-
 .../const-pat-non-exaustive-let-new-var.rs    |  2 +-
 ...const-pat-non-exaustive-let-new-var.stderr |  2 +-
 27 files changed, 193 insertions(+), 136 deletions(-)

diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index cdefc9effa1e9..7766db5f468b1 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -26,6 +26,7 @@ use rustc_middle::ty::{self, AdtDef, Const, Ty, UpvarSubsts, UserType};
 use rustc_middle::ty::{
     CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
 };
+use rustc_middle::ty::{ConstInt, ScalarInt};
 use rustc_span::{Span, Symbol, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_target::asm::InlineAsmRegOrRegClass;
@@ -668,8 +669,9 @@ pub enum PatKind<'tcx> {
 
 #[derive(Copy, Clone, Debug, PartialEq, HashStable)]
 pub struct PatRange<'tcx> {
-    pub lo: &'tcx ty::Const<'tcx>,
-    pub hi: &'tcx ty::Const<'tcx>,
+    pub lo: ScalarInt,
+    pub hi: ScalarInt,
+    pub ty: Ty<'tcx>,
     pub end: RangeEnd,
 }
 
@@ -788,10 +790,12 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                 write!(f, "{}", subpattern)
             }
             PatKind::Constant { value } => write!(f, "{}", value),
-            PatKind::Range(PatRange { lo, hi, end }) => {
-                write!(f, "{}", lo)?;
+            PatKind::Range(PatRange { lo, hi, end, ty }) => {
+                let lo = ConstInt::new(lo, ty.is_signed(), ty.is_ptr_sized_integral());
+                let hi = ConstInt::new(hi, ty.is_signed(), ty.is_ptr_sized_integral());
+                write!(f, "{:?}", lo)?;
                 write!(f, "{}", end)?;
-                write!(f, "{}", hi)
+                write!(f, "{:?}", hi)
             }
             PatKind::Slice { ref prefix, ref slice, ref suffix }
             | PatKind::Array { ref prefix, ref slice, ref suffix } => {
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 13cfc3695cc9f..cde6d2c30182d 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -196,8 +196,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 Err(match_pair)
             }
 
-            PatKind::Range(PatRange { lo, hi, end }) => {
-                let (range, bias) = match *lo.ty.kind() {
+            PatKind::Range(PatRange { lo, hi, end, ty }) => {
+                let (range, bias) = match *ty.kind() {
                     ty::Char => {
                         (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
                     }
@@ -215,18 +215,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     _ => (None, 0),
                 };
                 if let Some((min, max, sz)) = range {
-                    if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) {
-                        // We want to compare ranges numerically, but the order of the bitwise
-                        // representation of signed integers does not match their numeric order.
-                        // Thus, to correct the ordering, we need to shift the range of signed
-                        // integers to correct the comparison. This is achieved by XORing with a
-                        // bias (see pattern/_match.rs for another pertinent example of this
-                        // pattern).
-                        let (lo, hi) = (lo ^ bias, hi ^ bias);
-                        if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
-                            // Irrefutable pattern match.
-                            return Ok(());
-                        }
+                    let lo = lo.assert_bits(sz);
+                    let hi = hi.assert_bits(sz);
+                    // We want to compare ranges numerically, but the order of the bitwise
+                    // representation of signed integers does not match their numeric order.
+                    // Thus, to correct the ordering, we need to shift the range of signed
+                    // integers to correct the comparison. This is achieved by XORing with a
+                    // bias (see pattern/_match.rs for another pertinent example of this
+                    // pattern).
+                    let (lo, hi) = (lo ^ bias, hi ^ bias);
+                    if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
+                        // Irrefutable pattern match.
+                        return Ok(());
                     }
                 }
                 Err(match_pair)
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index c87f42738c67f..2578562766af3 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -12,6 +12,7 @@ use crate::thir::pattern::compare_const_vals;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::{LangItem, RangeEnd};
 use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use rustc_middle::ty::subst::{GenericArg, Subst};
@@ -58,8 +59,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             },
 
             PatKind::Range(range) => {
-                assert_eq!(range.lo.ty, match_pair.pattern.ty);
-                assert_eq!(range.hi.ty, match_pair.pattern.ty);
+                assert_eq!(range.ty, match_pair.pattern.ty);
                 Test { span: match_pair.pattern.span, kind: TestKind::Range(range) }
             }
 
@@ -271,11 +271,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 }
             }
 
-            TestKind::Range(PatRange { ref lo, ref hi, ref end }) => {
+            TestKind::Range(PatRange { lo, hi, ref end, ty }) => {
                 let lower_bound_success = self.cfg.start_new_block();
                 let target_blocks = make_target_blocks(self);
 
                 // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
+                let lo = ty::Const::from_value(self.tcx, ConstValue::Scalar(lo.into()), ty);
+                let hi = ty::Const::from_value(self.tcx, ConstValue::Scalar(hi.into()), ty);
                 let lo = self.literal_operand(test.span, lo);
                 let hi = self.literal_operand(test.span, hi);
                 let val = Operand::Copy(place);
@@ -640,9 +642,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                     let tcx = self.tcx;
 
-                    let test_ty = test.lo.ty;
-                    let lo = compare_const_vals(tcx, test.lo, pat.hi, self.param_env, test_ty)?;
-                    let hi = compare_const_vals(tcx, test.hi, pat.lo, self.param_env, test_ty)?;
+                    let test_ty = match_pair.pattern.ty;
+                    let test_lo =
+                        ty::Const::from_value(tcx, ConstValue::Scalar(test.lo.into()), test_ty);
+                    let test_hi =
+                        ty::Const::from_value(tcx, ConstValue::Scalar(test.hi.into()), test_ty);
+                    let pat_lo =
+                        ty::Const::from_value(tcx, ConstValue::Scalar(test.lo.into()), test_ty);
+                    let pat_hi =
+                        ty::Const::from_value(tcx, ConstValue::Scalar(test.hi.into()), test_ty);
+                    let lo = compare_const_vals(tcx, test_lo, pat_hi, self.param_env, test_ty)?;
+                    let hi = compare_const_vals(tcx, test_hi, pat_lo, self.param_env, test_ty)?;
 
                     match (test.end, pat.end, lo, hi) {
                         // pat < test
@@ -769,8 +779,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         let tcx = self.tcx;
 
-        let a = compare_const_vals(tcx, range.lo, value, self.param_env, range.lo.ty)?;
-        let b = compare_const_vals(tcx, value, range.hi, self.param_env, range.lo.ty)?;
+        let lo = ty::Const::from_value(tcx, ConstValue::Scalar(range.lo.into()), value.ty);
+        let hi = ty::Const::from_value(tcx, ConstValue::Scalar(range.hi.into()), value.ty);
+        let a = compare_const_vals(tcx, lo, value, self.param_env, value.ty)?;
+        let b = compare_const_vals(tcx, value, hi, self.param_env, value.ty)?;
 
         match (b, range.end) {
             (Less, _) | (Equal, RangeEnd::Included) if a != Greater => Some(true),
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 925c555dbbea1..a9492f02fe7f4 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -52,10 +52,11 @@ use rustc_data_structures::captures::Captures;
 use rustc_index::vec::Idx;
 
 use rustc_hir::{HirId, RangeEnd};
+use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::mir::Field;
 use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
 use rustc_middle::ty::layout::IntegerExt;
-use rustc_middle::ty::{self, Const, Ty, TyCtxt};
+use rustc_middle::ty::{self, Const, ScalarInt, Ty, TyCtxt};
 use rustc_session::lint;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{Integer, Size, VariantIdx};
@@ -202,14 +203,18 @@ impl IntRange {
         let bias = IntRange::signed_bias(tcx, ty);
         let (lo, hi) = (lo ^ bias, hi ^ bias);
 
-        let env = ty::ParamEnv::empty().and(ty);
-        let lo_const = ty::Const::from_bits(tcx, lo, env);
-        let hi_const = ty::Const::from_bits(tcx, hi, env);
-
         let kind = if lo == hi {
-            PatKind::Constant { value: lo_const }
+            let ty = ty::ParamEnv::empty().and(ty);
+            PatKind::Constant { value: ty::Const::from_bits(tcx, lo, ty) }
         } else {
-            PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included })
+            let param_env_and_ty = ty::ParamEnv::empty().and(ty);
+            let size = tcx.layout_of(param_env_and_ty).unwrap().size;
+            PatKind::Range(PatRange {
+                lo: ScalarInt::from_uint(lo, size),
+                hi: ScalarInt::from_uint(hi, size),
+                end: RangeEnd::Included,
+                ty,
+            })
         };
 
         Pat { ty, span: DUMMY_SP, kind: Box::new(kind) }
@@ -586,7 +591,7 @@ pub(super) enum Constructor<'tcx> {
     /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
     IntRange(IntRange),
     /// Ranges of floating-point literal values (`2.0..=5.2`).
-    FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
+    FloatRange(ScalarInt, ScalarInt, RangeEnd),
     /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
     Str(&'tcx ty::Const<'tcx>),
     /// Array and slice patterns.
@@ -647,7 +652,11 @@ impl<'tcx> Constructor<'tcx> {
                     IntRange(int_range)
                 } else {
                     match pat.ty.kind() {
-                        ty::Float(_) => FloatRange(value, value, RangeEnd::Included),
+                        ty::Float(_) => {
+                            let value =
+                                value.val.eval(cx.tcx, cx.param_env).try_to_scalar_int().unwrap();
+                            FloatRange(value, value, RangeEnd::Included)
+                        }
                         // In `expand_pattern`, we convert string literals to `&CONST` patterns with
                         // `CONST` a pattern of type `str`. In truth this contains a constant of type
                         // `&str`.
@@ -659,13 +668,13 @@ impl<'tcx> Constructor<'tcx> {
                     }
                 }
             }
-            &PatKind::Range(PatRange { lo, hi, end }) => {
-                let ty = lo.ty;
+            &PatKind::Range(PatRange { lo, hi, end, ty }) => {
+                let size = cx.tcx.layout_of(cx.param_env.and(ty)).unwrap().size;
                 if let Some(int_range) = IntRange::from_range(
                     cx.tcx,
-                    lo.eval_bits(cx.tcx, cx.param_env, lo.ty),
-                    hi.eval_bits(cx.tcx, cx.param_env, hi.ty),
-                    ty,
+                    lo.assert_bits(size),
+                    hi.assert_bits(size),
+                    pat.ty,
                     &end,
                 ) {
                     IntRange(int_range)
@@ -759,6 +768,26 @@ impl<'tcx> Constructor<'tcx> {
                 FloatRange(self_from, self_to, self_end),
                 FloatRange(other_from, other_to, other_end),
             ) => {
+                let self_to = ty::Const::from_value(
+                    pcx.cx.tcx,
+                    ConstValue::Scalar((*self_to).into()),
+                    pcx.ty,
+                );
+                let other_to = ty::Const::from_value(
+                    pcx.cx.tcx,
+                    ConstValue::Scalar((*other_to).into()),
+                    pcx.ty,
+                );
+                let self_from = ty::Const::from_value(
+                    pcx.cx.tcx,
+                    ConstValue::Scalar((*self_from).into()),
+                    pcx.ty,
+                );
+                let other_from = ty::Const::from_value(
+                    pcx.cx.tcx,
+                    ConstValue::Scalar((*other_from).into()),
+                    pcx.ty,
+                );
                 match (
                     compare_const_vals(pcx.cx.tcx, self_to, other_to, pcx.cx.param_env, pcx.ty),
                     compare_const_vals(pcx.cx.tcx, self_from, other_from, pcx.cx.param_env, pcx.ty),
@@ -1253,7 +1282,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
                 }
             },
             &Str(value) => PatKind::Constant { value },
-            &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
+            &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end, ty: pcx.ty }),
             IntRange(range) => return range.to_pat(pcx.cx.tcx, pcx.ty),
             NonExhaustive => PatKind::Wild,
             Wildcard => return Pat::wildcard_from_ty(pcx.ty),
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 3ea76fb99d531..081ff09f59e91 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -130,10 +130,23 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         assert_eq!(lo.ty, ty);
         assert_eq!(hi.ty, ty);
         let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env, ty);
+        let lo_const = lo;
+        let lo = lo
+            .val
+            .eval(self.tcx, self.param_env)
+            .try_to_scalar_int()
+            .expect("range patterns must be integral");
+        let hi = hi
+            .val
+            .eval(self.tcx, self.param_env)
+            .try_to_scalar_int()
+            .expect("range patterns must be integral");
         match (end, cmp) {
             // `x..y` where `x < y`.
             // Non-empty because the range includes at least `x`.
-            (RangeEnd::Excluded, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }),
+            (RangeEnd::Excluded, Some(Ordering::Less)) => {
+                PatKind::Range(PatRange { lo, hi, end, ty })
+            }
             // `x..y` where `x >= y`. The range is empty => error.
             (RangeEnd::Excluded, _) => {
                 struct_span_err!(
@@ -146,9 +159,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 PatKind::Wild
             }
             // `x..=y` where `x == y`.
-            (RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo },
+            (RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo_const },
             // `x..=y` where `x < y`.
-            (RangeEnd::Included, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }),
+            (RangeEnd::Included, Some(Ordering::Less)) => {
+                PatKind::Range(PatRange { lo, hi, end, ty })
+            }
             // `x..=y` where `x > y` hence the range is empty => error.
             (RangeEnd::Included, _) => {
                 let mut err = struct_span_err!(
diff --git a/compiler/rustc_mir_build/src/thir/visit.rs b/compiler/rustc_mir_build/src/thir/visit.rs
index f611bb6eb43e9..6f699b8c8d910 100644
--- a/compiler/rustc_mir_build/src/thir/visit.rs
+++ b/compiler/rustc_mir_build/src/thir/visit.rs
@@ -213,10 +213,7 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'
             }
         }
         Constant { value } => visitor.visit_const(value),
-        Range(range) => {
-            visitor.visit_const(range.lo);
-            visitor.visit_const(range.hi);
-        }
+        Range(PatRange { lo: _, hi: _, ty: _, end: _ }) => {}
         Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
             for subpattern in prefix {
                 visitor.visit_pat(&subpattern);
diff --git a/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir
index 5bb910947ca25..e050b5ea0b4ee 100644
--- a/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir
+++ b/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir
@@ -28,43 +28,43 @@ fn main() -> () {
         StorageLive(_3);                 // scope 2 at $DIR/match_test.rs:12:5: 17:6
         FakeRead(ForMatchedPlace(None), _1); // scope 2 at $DIR/match_test.rs:12:11: 12:12
         _6 = Le(const 0_i32, _1);        // scope 2 at $DIR/match_test.rs:13:9: 13:14
-        switchInt(move _6) -> [false: bb4, otherwise: bb1]; // scope 2 at $DIR/match_test.rs:13:9: 13:14
+        switchInt(move _6) -> [false: bb3, otherwise: bb1]; // scope 2 at $DIR/match_test.rs:13:9: 13:14
     }
 
     bb1: {
         _7 = Lt(_1, const 10_i32);       // scope 2 at $DIR/match_test.rs:13:9: 13:14
-        switchInt(move _7) -> [false: bb4, otherwise: bb2]; // scope 2 at $DIR/match_test.rs:13:9: 13:14
+        switchInt(move _7) -> [false: bb3, otherwise: bb2]; // scope 2 at $DIR/match_test.rs:13:9: 13:14
     }
 
     bb2: {
-        falseEdge -> [real: bb9, imaginary: bb6]; // scope 2 at $DIR/match_test.rs:13:9: 13:14
+        falseEdge -> [real: bb9, imaginary: bb5]; // scope 2 at $DIR/match_test.rs:13:9: 13:14
     }
 
     bb3: {
-        _3 = const 3_i32;                // scope 2 at $DIR/match_test.rs:16:14: 16:15
-        goto -> bb14;                    // scope 2 at $DIR/match_test.rs:12:5: 17:6
+        _4 = Le(const 10_i32, _1);       // scope 2 at $DIR/match_test.rs:14:9: 14:16
+        switchInt(move _4) -> [false: bb6, otherwise: bb4]; // scope 2 at $DIR/match_test.rs:14:9: 14:16
     }
 
     bb4: {
-        _4 = Le(const 10_i32, _1);       // scope 2 at $DIR/match_test.rs:14:9: 14:16
-        switchInt(move _4) -> [false: bb7, otherwise: bb5]; // scope 2 at $DIR/match_test.rs:14:9: 14:16
+        _5 = Le(_1, const 20_i32);       // scope 2 at $DIR/match_test.rs:14:9: 14:16
+        switchInt(move _5) -> [false: bb6, otherwise: bb5]; // scope 2 at $DIR/match_test.rs:14:9: 14:16
     }
 
     bb5: {
-        _5 = Le(_1, const 20_i32);       // scope 2 at $DIR/match_test.rs:14:9: 14:16
-        switchInt(move _5) -> [false: bb7, otherwise: bb6]; // scope 2 at $DIR/match_test.rs:14:9: 14:16
+        falseEdge -> [real: bb12, imaginary: bb7]; // scope 2 at $DIR/match_test.rs:14:9: 14:16
     }
 
     bb6: {
-        falseEdge -> [real: bb12, imaginary: bb8]; // scope 2 at $DIR/match_test.rs:14:9: 14:16
+        switchInt(_1) -> [-1_i32: bb7, otherwise: bb8]; // scope 2 at $DIR/match_test.rs:15:9: 15:11
     }
 
     bb7: {
-        switchInt(_1) -> [-1_i32: bb8, otherwise: bb3]; // scope 2 at $DIR/match_test.rs:15:9: 15:11
+        falseEdge -> [real: bb13, imaginary: bb8]; // scope 2 at $DIR/match_test.rs:15:9: 15:11
     }
 
     bb8: {
-        falseEdge -> [real: bb13, imaginary: bb3]; // scope 2 at $DIR/match_test.rs:15:9: 15:11
+        _3 = const 3_i32;                // scope 2 at $DIR/match_test.rs:16:14: 16:15
+        goto -> bb14;                    // scope 2 at $DIR/match_test.rs:12:5: 17:6
     }
 
     bb9: {
@@ -83,7 +83,7 @@ fn main() -> () {
 
     bb11: {
         StorageDead(_9);                 // scope 2 at $DIR/match_test.rs:13:23: 13:24
-        falseEdge -> [real: bb3, imaginary: bb6]; // scope 2 at $DIR/match_test.rs:13:18: 13:19
+        falseEdge -> [real: bb3, imaginary: bb5]; // scope 2 at $DIR/match_test.rs:13:18: 13:19
     }
 
     bb12: {
diff --git a/src/test/ui/consts/const-match-check.eval1.stderr b/src/test/ui/consts/const-match-check.eval1.stderr
index eb6b0774e152c..2194b3f1b0363 100644
--- a/src/test/ui/consts/const-match-check.eval1.stderr
+++ b/src/test/ui/consts/const-match-check.eval1.stderr
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `1..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:25:15
    |
 LL |     A = { let 0 = 0; 0 },
-   |               ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+   |               ^ patterns `i32::MIN..=-1` and `1..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
diff --git a/src/test/ui/consts/const-match-check.eval2.stderr b/src/test/ui/consts/const-match-check.eval2.stderr
index 756426d84a479..e4844feec28d3 100644
--- a/src/test/ui/consts/const-match-check.eval2.stderr
+++ b/src/test/ui/consts/const-match-check.eval2.stderr
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `1..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:31:24
    |
 LL |     let x: [i32; { let 0 = 0; 0 }] = [];
-   |                        ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+   |                        ^ patterns `i32::MIN..=-1` and `1..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
diff --git a/src/test/ui/consts/const-match-check.matchck.stderr b/src/test/ui/consts/const-match-check.matchck.stderr
index 84600bb1b8aad..9e5cc99bcf9d6 100644
--- a/src/test/ui/consts/const-match-check.matchck.stderr
+++ b/src/test/ui/consts/const-match-check.matchck.stderr
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `1..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:4:22
    |
 LL | const X: i32 = { let 0 = 0; 0 };
-   |                      ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+   |                      ^ patterns `i32::MIN..=-1` and `1..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
@@ -12,11 +12,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched
 LL | const X: i32 = { if let 0 = 0 { /* */ } 0 };
    |                  ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `1..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:8:23
    |
 LL | static Y: i32 = { let 0 = 0; 0 };
-   |                       ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+   |                       ^ patterns `i32::MIN..=-1` and `1..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
@@ -26,11 +26,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched
 LL | static Y: i32 = { if let 0 = 0 { /* */ } 0 };
    |                   ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `1..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:13:26
    |
 LL |     const X: i32 = { let 0 = 0; 0 };
-   |                          ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+   |                          ^ patterns `i32::MIN..=-1` and `1..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
@@ -40,11 +40,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched
 LL |     const X: i32 = { if let 0 = 0 { /* */ } 0 };
    |                      ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `1..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:19:26
    |
 LL |     const X: i32 = { let 0 = 0; 0 };
-   |                          ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+   |                          ^ patterns `i32::MIN..=-1` and `1..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
diff --git a/src/test/ui/consts/const-pattern-irrefutable.rs b/src/test/ui/consts/const-pattern-irrefutable.rs
index 2105c12a1680a..593ebfbec07c2 100644
--- a/src/test/ui/consts/const-pattern-irrefutable.rs
+++ b/src/test/ui/consts/const-pattern-irrefutable.rs
@@ -9,8 +9,8 @@ use foo::d;
 const a: u8 = 2;
 
 fn main() {
-    let a = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX
-    let c = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX
-    let d = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX
+    let a = 4; //~ ERROR refutable pattern in local binding: `0..=1` and `3..=u8::MAX
+    let c = 4; //~ ERROR refutable pattern in local binding: `0..=1` and `3..=u8::MAX
+    let d = 4; //~ ERROR refutable pattern in local binding: `0..=1` and `3..=u8::MAX
     fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115).
 }
diff --git a/src/test/ui/consts/const-pattern-irrefutable.stderr b/src/test/ui/consts/const-pattern-irrefutable.stderr
index 3e3bc1979a2e0..ff5e478e991c8 100644
--- a/src/test/ui/consts/const-pattern-irrefutable.stderr
+++ b/src/test/ui/consts/const-pattern-irrefutable.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
+error[E0005]: refutable pattern in local binding: `0..=1` and `3..=u8::MAX` not covered
   --> $DIR/const-pattern-irrefutable.rs:12:9
    |
 LL | const a: u8 = 2;
@@ -12,7 +12,7 @@ LL |     let a = 4;
    |
    = note: the matched value is of type `u8`
 
-error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
+error[E0005]: refutable pattern in local binding: `0..=1` and `3..=u8::MAX` not covered
   --> $DIR/const-pattern-irrefutable.rs:13:9
    |
 LL |     pub const b: u8 = 2;
@@ -26,7 +26,7 @@ LL |     let c = 4;
    |
    = note: the matched value is of type `u8`
 
-error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
+error[E0005]: refutable pattern in local binding: `0..=1` and `3..=u8::MAX` not covered
   --> $DIR/const-pattern-irrefutable.rs:14:9
    |
 LL |     pub const d: u8 = 2;
diff --git a/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr b/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr
index 20b689aa5e0af..bd662549b1e1c 100644
--- a/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr
+++ b/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in `for` loop binding: `&i32::MIN..=0_i32` and `&2_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in `for` loop binding: `&i32::MIN..=0` and `&2..=i32::MAX` not covered
   --> $DIR/for-loop-refutable-pattern-error-message.rs:2:9
    |
 LL |     for &1 in [1].iter() {}
-   |         ^^ patterns `&i32::MIN..=0_i32` and `&2_i32..=i32::MAX` not covered
+   |         ^^ patterns `&i32::MIN..=0` and `&2..=i32::MAX` not covered
    |
    = note: the matched value is of type `&i32`
 
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
index 14dbca60b78f2..6ec0f7702efc4 100644
--- a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
+++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
@@ -25,11 +25,11 @@ LL |     m!('a', ..core::char::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `char`
 
-error[E0004]: non-exhaustive patterns: `'\u{10fffe}'..='\u{10ffff}'` not covered
+error[E0004]: non-exhaustive patterns: `1114110..=1114111` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8
    |
 LL |     m!('a', ..ALMOST_MAX);
-   |        ^^^ pattern `'\u{10fffe}'..='\u{10ffff}'` not covered
+   |        ^^^ pattern `1114110..=1114111` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `char`
@@ -79,11 +79,11 @@ LL |         m!(0, ..u8::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
 
-error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered
+error[E0004]: non-exhaustive patterns: `254..=u8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `254_u8..=u8::MAX` not covered
+   |            ^ pattern `254..=u8::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
@@ -133,11 +133,11 @@ LL |         m!(0, ..u16::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
 
-error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered
+error[E0004]: non-exhaustive patterns: `65534..=u16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `65534_u16..=u16::MAX` not covered
+   |            ^ pattern `65534..=u16::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
@@ -187,11 +187,11 @@ LL |         m!(0, ..u32::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
 
-error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered
+error[E0004]: non-exhaustive patterns: `4294967294..=u32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `4294967294_u32..=u32::MAX` not covered
+   |            ^ pattern `4294967294..=u32::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
@@ -241,11 +241,11 @@ LL |         m!(0, ..u64::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
 
-error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not covered
+error[E0004]: non-exhaustive patterns: `18446744073709551614..=u64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `18446744073709551614_u64..=u64::MAX` not covered
+   |            ^ pattern `18446744073709551614..=u64::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
@@ -295,11 +295,11 @@ LL |         m!(0, ..u128::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
 
-error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
+error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454..=u128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
+   |            ^ pattern `340282366920938463463374607431768211454..=u128::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
@@ -349,11 +349,11 @@ LL |         m!(0, ..i8::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
 
-error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered
+error[E0004]: non-exhaustive patterns: `126..=i8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `126_i8..=i8::MAX` not covered
+   |            ^ pattern `126..=i8::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
@@ -403,11 +403,11 @@ LL |         m!(0, ..i16::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
 
-error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered
+error[E0004]: non-exhaustive patterns: `32766..=i16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `32766_i16..=i16::MAX` not covered
+   |            ^ pattern `32766..=i16::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
@@ -457,11 +457,11 @@ LL |         m!(0, ..i32::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
 
-error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered
+error[E0004]: non-exhaustive patterns: `2147483646..=i32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `2147483646_i32..=i32::MAX` not covered
+   |            ^ pattern `2147483646..=i32::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
@@ -511,11 +511,11 @@ LL |         m!(0, ..i64::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
 
-error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not covered
+error[E0004]: non-exhaustive patterns: `9223372036854775806..=i64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `9223372036854775806_i64..=i64::MAX` not covered
+   |            ^ pattern `9223372036854775806..=i64::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
@@ -565,11 +565,11 @@ LL |         m!(0, ..i128::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
 
-error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
+error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726..=i128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
+   |            ^ pattern `170141183460469231731687303715884105726..=i128::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs
index 5999e04e0e2dd..037423e39c5f3 100644
--- a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs
+++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs
@@ -3,15 +3,15 @@
 // We wrap patterns in a tuple because top-level or-patterns were special-cased.
 fn main() {
     match (0u8, 0u8) {
-        //~^ ERROR non-exhaustive patterns: `(2_u8..=u8::MAX, _)`
+        //~^ ERROR non-exhaustive patterns: `(2..=u8::MAX, _)`
         (0 | 1, 2 | 3) => {}
     }
     match ((0u8,),) {
-        //~^ ERROR non-exhaustive patterns: `((4_u8..=u8::MAX))`
+        //~^ ERROR non-exhaustive patterns: `((4..=u8::MAX))`
         ((0 | 1,) | (2 | 3,),) => {}
     }
     match (Some(0u8),) {
-        //~^ ERROR non-exhaustive patterns: `(Some(2_u8..=u8::MAX))`
+        //~^ ERROR non-exhaustive patterns: `(Some(2..=u8::MAX))`
         (None | Some(0 | 1),) => {}
     }
 }
diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
index 44f334eee9386..b2d81fdb52281 100644
--- a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
+++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
@@ -1,26 +1,26 @@
-error[E0004]: non-exhaustive patterns: `(2_u8..=u8::MAX, _)` not covered
+error[E0004]: non-exhaustive patterns: `(2..=u8::MAX, _)` not covered
   --> $DIR/exhaustiveness-non-exhaustive.rs:5:11
    |
 LL |     match (0u8, 0u8) {
-   |           ^^^^^^^^^^ pattern `(2_u8..=u8::MAX, _)` not covered
+   |           ^^^^^^^^^^ pattern `(2..=u8::MAX, _)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(u8, u8)`
 
-error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX))` not covered
+error[E0004]: non-exhaustive patterns: `((4..=u8::MAX))` not covered
   --> $DIR/exhaustiveness-non-exhaustive.rs:9:11
    |
 LL |     match ((0u8,),) {
-   |           ^^^^^^^^^ pattern `((4_u8..=u8::MAX))` not covered
+   |           ^^^^^^^^^ pattern `((4..=u8::MAX))` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `((u8,),)`
 
-error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` not covered
+error[E0004]: non-exhaustive patterns: `(Some(2..=u8::MAX))` not covered
   --> $DIR/exhaustiveness-non-exhaustive.rs:13:11
    |
 LL |     match (Some(0u8),) {
-   |           ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX))` not covered
+   |           ^^^^^^^^^^^^ pattern `(Some(2..=u8::MAX))` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(Option<u8>,)`
diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
index 61175b84ee1de..8355959c249e4 100644
--- a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
+++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `3..=i32::MAX` not covered
   --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:2:10
    |
 LL |     let (0 | (1 | 2)) = 0;
-   |          ^^^^^^^^^^^ patterns `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
+   |          ^^^^^^^^^^^ patterns `i32::MIN..=-1` and `3..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
@@ -12,11 +12,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched
 LL |     if let (0 | (1 | 2)) = 0 { /* */ }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
+error[E0004]: non-exhaustive patterns: `i32::MIN..=-1` and `3..=i32::MAX` not covered
   --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:3:11
    |
 LL |     match 0 {
-   |           ^ patterns `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
+   |           ^ patterns `i32::MIN..=-1` and `3..=i32::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
diff --git a/src/test/ui/pattern/usefulness/guards.stderr b/src/test/ui/pattern/usefulness/guards.stderr
index 61f7facb330da..7a5fd66ce003d 100644
--- a/src/test/ui/pattern/usefulness/guards.stderr
+++ b/src/test/ui/pattern/usefulness/guards.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered
+error[E0004]: non-exhaustive patterns: `128..=u8::MAX` not covered
   --> $DIR/guards.rs:12:11
    |
 LL |     match 0u8 {
-   |           ^^^ pattern `128_u8..=u8::MAX` not covered
+   |           ^^^ pattern `128..=u8::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
index b1440375494b1..48dabdcc2bca5 100644
--- a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
+++ b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
@@ -79,11 +79,11 @@ LL |     m!(0u128, 0..=ALMOST_MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
 
-error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
+error[E0004]: non-exhaustive patterns: `5..=u128::MAX` not covered
   --> $DIR/exhaustiveness.rs:61:8
    |
 LL |     m!(0u128, 0..=4);
-   |        ^^^^^ pattern `5_u128..=u128::MAX` not covered
+   |        ^^^^^ pattern `5..=u128::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
@@ -97,11 +97,11 @@ LL |     m!(0u128, 1..=u128::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
 
-error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered
+error[E0004]: non-exhaustive patterns: `(126..=127, false)` not covered
   --> $DIR/exhaustiveness.rs:70:11
    |
 LL |     match (0u8, true) {
-   |           ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered
+   |           ^^^^^^^^^^^ pattern `(126..=127, false)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(u8, bool)`
diff --git a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
index ffc8433403fd5..95187fa0b35d0 100644
--- a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
+++ b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
+error[E0004]: non-exhaustive patterns: `&[0..=64, _, _, _]` and `&[66..=u8::MAX, _, _, _]` not covered
   --> $DIR/match-byte-array-patterns-2.rs:4:11
    |
 LL |     match buf {
-   |           ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
+   |           ^^^ patterns `&[0..=64, _, _, _]` and `&[66..=u8::MAX, _, _, _]` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[u8; 4]`
diff --git a/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr b/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr
index a35d61e4b710b..cbfe3a5e97489 100644
--- a/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr
+++ b/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered
+error[E0004]: non-exhaustive patterns: `i32::MIN..=0` and `2..=i32::MAX` not covered
   --> $DIR/match-non-exhaustive.rs:2:11
    |
 LL |     match 0 { 1 => () }
-   |           ^ patterns `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered
+   |           ^ patterns `i32::MIN..=0` and `2..=i32::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs
index 4ff12aa2ff5e2..af9513874b44a 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs
@@ -11,8 +11,8 @@ fn main() {
     match Some(10) { //~ ERROR non-exhaustive patterns: `Some(_)` not covered
       None => {}
     }
-    match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)`
-                      //  and `(_, _, 5_i32..=i32::MAX)` not covered
+    match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, i32::MIN..=3)`
+                      //  and `(_, _, 5..=i32::MAX)` not covered
       (_, _, 4) => {}
     }
     match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` and `(B, B)` not covered
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr
index c953cd314406e..c29637d74a9ba 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr
@@ -36,11 +36,11 @@ LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `Option<i32>`
 
-error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
+error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3)` and `(_, _, 5..=i32::MAX)` not covered
   --> $DIR/non-exhaustive-match.rs:14:11
    |
 LL |     match (2, 3, 4) {
-   |           ^^^^^^^^^ patterns `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
+   |           ^^^^^^^^^ patterns `(_, _, i32::MIN..=3)` and `(_, _, 5..=i32::MAX)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(i32, i32, i32)`
diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs b/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs
index 7c9aa51e7484c..cc0a0abd10c69 100644
--- a/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs
+++ b/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs
@@ -3,5 +3,5 @@ fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
 
 fn main() {
     let (1, (Some(1), 2..=3)) = (1, (None, 2));
-    //~^ ERROR refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
+    //~^ ERROR refutable pattern in local binding: `(i32::MIN..=0, _)` and `(2..=i32::MAX, _)` not covered
 }
diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr
index 74ec646e31cca..027371936d3c9 100644
--- a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr
+++ b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr
@@ -6,11 +6,11 @@ LL | fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
    |
    = note: the matched value is of type `(isize, (Option<isize>, isize))`
 
-error[E0005]: refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
+error[E0005]: refutable pattern in local binding: `(i32::MIN..=0, _)` and `(2..=i32::MAX, _)` not covered
   --> $DIR/refutable-pattern-errors.rs:5:9
    |
 LL |     let (1, (Some(1), 2..=3)) = (1, (None, 2));
-   |         ^^^^^^^^^^^^^^^^^^^^^ patterns `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
+   |         ^^^^^^^^^^^^^^^^^^^^^ patterns `(i32::MIN..=0, _)` and `(2..=i32::MAX, _)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
diff --git a/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.rs b/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
index ac819dce6db2b..53fd5a5e3a51f 100644
--- a/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
+++ b/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
@@ -1,6 +1,6 @@
 fn main() {
     let A = 3;
-    //~^ ERROR refutable pattern in local binding: `i32::MIN..=1_i32` and
+    //~^ ERROR refutable pattern in local binding: `i32::MIN..=1` and
     //~| interpreted as a constant pattern, not a new variable
     //~| HELP introduce a variable instead
     //~| SUGGESTION a_var
diff --git a/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
index af64c09d5cadb..bfff3d3b8ec06 100644
--- a/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
+++ b/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=1` and `3..=i32::MAX` not covered
   --> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9
    |
 LL |     let A = 3;

From b2a2286f0068aa5fe557213ce665a434677bdd63 Mon Sep 17 00:00:00 2001
From: Oli Scherer <github35764891676564198441@oli-obk.de>
Date: Wed, 17 Mar 2021 13:51:14 +0000
Subject: [PATCH 5/6] Use ScalarInt as early as possible... ...instead of
 carrying around ty::Const and erroring later

---
 compiler/rustc_middle/src/ty/util.rs          | 32 ++++++-------
 .../rustc_mir_build/src/thir/pattern/mod.rs   | 33 +++++--------
 .../clippy/clippy_lints/src/enum_clike.rs     |  6 +--
 src/tools/clippy/clippy_lints/src/matches.rs  | 11 ++++-
 src/tools/clippy/clippy_utils/src/consts.rs   | 48 ++++++++-----------
 5 files changed, 61 insertions(+), 69 deletions(-)

diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 485be4c9987bd..ef327b84af036 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -23,6 +23,8 @@ use rustc_target::abi::{Integer, Size, TargetDataLayout};
 use smallvec::SmallVec;
 use std::{fmt, iter};
 
+use super::ScalarInt;
+
 #[derive(Copy, Clone, Debug)]
 pub struct Discr<'tcx> {
     /// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`).
@@ -616,40 +618,38 @@ impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> {
 impl<'tcx> ty::TyS<'tcx> {
     /// Returns the maximum value for the given numeric type (including `char`s)
     /// or returns `None` if the type is not numeric.
-    pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> {
-        let val = match self.kind() {
+    pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<ScalarInt> {
+        match self.kind() {
             ty::Int(_) | ty::Uint(_) => {
                 let (size, signed) = int_size_and_signed(tcx, self);
                 let val = if signed { signed_max(size) as u128 } else { unsigned_max(size) };
-                Some(val)
+                Some(ScalarInt::from_uint(val, size))
             }
-            ty::Char => Some(std::char::MAX as u128),
+            ty::Char => Some(ScalarInt::from(std::char::MAX)),
             ty::Float(fty) => Some(match fty {
-                ty::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(),
-                ty::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(),
+                ty::FloatTy::F32 => ScalarInt::from(rustc_apfloat::ieee::Single::INFINITY),
+                ty::FloatTy::F64 => ScalarInt::from(rustc_apfloat::ieee::Double::INFINITY),
             }),
             _ => None,
-        };
-        val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
+        }
     }
 
     /// Returns the minimum value for the given numeric type (including `char`s)
     /// or returns `None` if the type is not numeric.
-    pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> {
-        let val = match self.kind() {
+    pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<ScalarInt> {
+        match self.kind() {
             ty::Int(_) | ty::Uint(_) => {
                 let (size, signed) = int_size_and_signed(tcx, self);
                 let val = if signed { size.truncate(signed_min(size) as u128) } else { 0 };
-                Some(val)
+                Some(ScalarInt::from_uint(val, size))
             }
-            ty::Char => Some(0),
+            ty::Char => Some(ScalarInt::from('\0')),
             ty::Float(fty) => Some(match fty {
-                ty::FloatTy::F32 => (-::rustc_apfloat::ieee::Single::INFINITY).to_bits(),
-                ty::FloatTy::F64 => (-::rustc_apfloat::ieee::Double::INFINITY).to_bits(),
+                ty::FloatTy::F32 => ScalarInt::from(-::rustc_apfloat::ieee::Single::INFINITY),
+                ty::FloatTy::F64 => ScalarInt::from(-::rustc_apfloat::ieee::Double::INFINITY),
             }),
             _ => None,
-        };
-        val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
+        }
     }
 
     /// Checks whether values of this type `T` are *moved* or *copied*
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 081ff09f59e91..3af3913596e08 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -21,7 +21,7 @@ use rustc_middle::mir::UserTypeProjection;
 use rustc_middle::mir::{BorrowKind, Field, Mutability};
 use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
 use rustc_middle::ty::subst::{GenericArg, SubstsRef};
-use rustc_middle::ty::{self, AdtDef, DefIdTree, Region, Ty, TyCtxt, UserType};
+use rustc_middle::ty::{self, AdtDef, DefIdTree, Region, ScalarInt, Ty, TyCtxt, UserType};
 use rustc_span::{Span, Symbol};
 
 use std::cmp::Ordering;
@@ -122,25 +122,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     fn lower_pattern_range(
         &mut self,
         ty: Ty<'tcx>,
-        lo: &'tcx ty::Const<'tcx>,
-        hi: &'tcx ty::Const<'tcx>,
+        lo: ScalarInt,
+        hi: ScalarInt,
         end: RangeEnd,
         span: Span,
     ) -> PatKind<'tcx> {
-        assert_eq!(lo.ty, ty);
-        assert_eq!(hi.ty, ty);
-        let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env, ty);
-        let lo_const = lo;
-        let lo = lo
-            .val
-            .eval(self.tcx, self.param_env)
-            .try_to_scalar_int()
-            .expect("range patterns must be integral");
-        let hi = hi
-            .val
-            .eval(self.tcx, self.param_env)
-            .try_to_scalar_int()
-            .expect("range patterns must be integral");
+        let lo_const = ty::Const::from_value(self.tcx, ConstValue::Scalar(lo.into()), ty);
+        let hi_const = ty::Const::from_value(self.tcx, ConstValue::Scalar(hi.into()), ty);
+        let cmp = compare_const_vals(self.tcx, lo_const, hi_const, self.param_env, ty);
         match (end, cmp) {
             // `x..y` where `x < y`.
             // Non-empty because the range includes at least `x`.
@@ -193,16 +182,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         ty: Ty<'tcx>,
         lo: Option<&PatKind<'tcx>>,
         hi: Option<&PatKind<'tcx>>,
-    ) -> Option<(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>)> {
+    ) -> Option<(ScalarInt, ScalarInt)> {
+        let eval =
+            |value: &ty::Const<'tcx>| value.val.eval(self.tcx, self.param_env).try_to_scalar_int();
         match (lo, hi) {
             (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => {
-                Some((lo, hi))
+                Some((eval(lo)?, eval(hi)?))
             }
             (Some(PatKind::Constant { value: lo }), None) => {
-                Some((lo, ty.numeric_max_val(self.tcx)?))
+                Some((eval(lo)?, ty.numeric_max_val(self.tcx)?))
             }
             (None, Some(PatKind::Constant { value: hi })) => {
-                Some((ty.numeric_min_val(self.tcx)?, hi))
+                Some((ty.numeric_min_val(self.tcx)?, eval(hi)?))
             }
             _ => None,
         }
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index 021136ac5e019..1ffb665feb675 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -1,7 +1,6 @@
 //! lint on C-like enums that are `repr(isize/usize)` and have values that
 //! don't fit into an `i32`
 
-use clippy_utils::consts::{miri_to_const, Constant};
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -50,8 +49,9 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
                         .tcx
                         .const_eval_poly(def_id.to_def_id())
                         .ok()
-                        .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty));
-                    if let Some(Constant::Int(val)) = constant.and_then(miri_to_const) {
+                        .and_then(|c| c.try_to_scalar_int());
+                    if let Some(scalar) = constant {
+                        let val = scalar.to_bits(cx.tcx.layout_of(cx.param_env.and(ty)).unwrap().size).unwrap();
                         if let ty::Adt(adt, _) = ty.kind() {
                             if adt.is_enum() {
                                 ty = adt.repr.discr_type().to_ty(cx.tcx);
diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs
index f1e3492c4ecc5..d75c8b0a5fc2a 100644
--- a/src/tools/clippy/clippy_lints/src/matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches.rs
@@ -25,6 +25,7 @@ use rustc_hir::{HirIdMap, HirIdSet};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty, TyS, VariantDef};
+use rustc_middle::mir::{self, interpret::ConstValue};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::{Span, Spanned};
@@ -1533,11 +1534,17 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
                 if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
                     let lhs = match lhs {
                         Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0,
-                        None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?,
+                        None => miri_to_const(mir::ConstantKind::Val(
+                            ConstValue::Scalar(ty.numeric_min_val(cx.tcx)?.into()),
+                            ty,
+                        ))?,
                     };
                     let rhs = match rhs {
                         Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
-                        None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
+                        None => miri_to_const(mir::ConstantKind::Val(
+                            ConstValue::Scalar(ty.numeric_max_val(cx.tcx)?.into()),
+                            ty,
+                        ))?,
                     };
                     let rhs = match range_end {
                         RangeEnd::Included => Bound::Included(rhs),
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 15c27d1a996d7..b62a0e08cf769 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -7,7 +7,7 @@ use rustc_data_structures::sync::Lrc;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, QPath, UnOp};
 use rustc_lint::LateContext;
-use rustc_middle::mir::interpret::Scalar;
+use rustc_middle::mir;
 use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
@@ -354,7 +354,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                         None,
                     )
                     .ok()
-                    .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
+                    .map(|val| mir::ConstantKind::Val(val, ty))?;
                 let result = miri_to_const(result);
                 if result.is_some() {
                     self.needed_resolution = true;
@@ -505,34 +505,28 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
     }
 }
 
-pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
+pub fn miri_to_const(result: mir::ConstantKind<'tcx>) -> Option<Constant> {
     use rustc_middle::mir::interpret::ConstValue;
-    match result.val {
-        ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(int))) => {
-            match result.ty.kind() {
-                ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
-                ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
+    match *result.ty().kind() {
+        ty::Bool => Some(Constant::Bool(result.try_to_scalar_int()? == ScalarInt::TRUE)),
+        ty::Uint(_) | ty::Int(_) => {
+            let int = result.try_to_scalar_int()?;
+            Some(Constant::Int(int.assert_bits(int.size())))
+        }
                 ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
-                    int.try_into().expect("invalid f32 bit representation"),
+            result.try_to_scalar_int()?.try_into().expect("invalid f32 bit representation"),
                 ))),
                 ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
-                    int.try_into().expect("invalid f64 bit representation"),
+            result.try_to_scalar_int()?.try_into().expect("invalid f64 bit representation"),
                 ))),
-                ty::RawPtr(type_and_mut) => {
-                    if let ty::Uint(_) = type_and_mut.ty.kind() {
-                        return Some(Constant::RawPtr(int.assert_bits(int.size())));
+        ty::RawPtr(_) => {
+            let int = result.try_to_scalar_int()?;
+            Some(Constant::RawPtr(int.assert_bits(int.size())))
                     }
-                    None
-                },
-                // FIXME: implement other conversions.
-                _ => None,
-            }
-        },
-        ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind() {
             ty::Ref(_, tam, _) => match tam.kind() {
-                ty::Str => String::from_utf8(
-                    data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)
-                        .to_owned(),
+            ty::Str => match result.try_to_value()? {
+                ConstValue::Slice { data, start, end } => String::from_utf8(
+                    data.inspect_with_uninit_and_ptr_outside_interpreter(start..end).to_owned(),
                 )
                 .ok()
                 .map(Constant::Str),
@@ -540,9 +534,9 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
             },
             _ => None,
         },
-        ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind() {
-            ty::Array(sub_type, len) => match sub_type.kind() {
-                ty::Float(FloatTy::F32) => match miri_to_const(len) {
+        ty::Array(sub_type, len) => match result.try_to_value()? {
+            ConstValue::ByRef { alloc, offset: _ } => match sub_type.kind() {
+                ty::Float(FloatTy::F32) => match miri_to_const(len.into()) {
                     Some(Constant::Int(len)) => alloc
                         .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
                         .to_owned()
@@ -556,7 +550,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
                         .map(Constant::Vec),
                     _ => None,
                 },
-                ty::Float(FloatTy::F64) => match miri_to_const(len) {
+                ty::Float(FloatTy::F64) => match miri_to_const(len.into()) {
                     Some(Constant::Int(len)) => alloc
                         .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize))
                         .to_owned()

From 562cbc9c5b3121b1f29d06dc059ee66652bc476f Mon Sep 17 00:00:00 2001
From: Oli Scherer <github35764891676564198441@oli-obk.de>
Date: Thu, 1 Apr 2021 14:03:40 +0000
Subject: [PATCH 6/6] Stop using ty::Const in `deref_const` and
 `destructure_const` in preparation of value trees making such operations on
 `ty::Const` obsolete.

---
 .../rustc_codegen_ssa/src/mir/constant.rs     | 10 +++---
 compiler/rustc_middle/src/mir/mod.rs          | 21 ++++++++++++
 compiler/rustc_middle/src/mir/query.rs        |  4 +--
 .../rustc_middle/src/mir/type_foldable.rs     | 10 ++++++
 compiler/rustc_middle/src/query/mod.rs        |  6 ++--
 compiler/rustc_middle/src/ty/print/pretty.rs  |  6 ++--
 compiler/rustc_middle/src/ty/relate.rs        | 23 ++++++++-----
 compiler/rustc_mir/src/const_eval/mod.rs      | 20 ++++++-----
 compiler/rustc_mir/src/lib.rs                 |  8 ++---
 .../src/thir/pattern/const_to_pat.rs          | 33 ++++++++++++-------
 compiler/rustc_query_impl/src/keys.rs         |  9 +++++
 .../clippy/clippy_lints/src/non_copy_const.rs | 14 ++++----
 12 files changed, 109 insertions(+), 55 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index fa8a53e60b169..f3e4b32300b4f 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -57,15 +57,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     ) -> (Bx::Value, Ty<'tcx>) {
         constant
             .map(|val| {
-                let field_ty = ty.builtin_index().unwrap();
-                let c = ty::Const::from_value(bx.tcx(), val, ty);
                 let values: Vec<_> = bx
                     .tcx()
-                    .destructure_const(ty::ParamEnv::reveal_all().and(&c))
+                    .destructure_const(ty::ParamEnv::reveal_all().and((val, ty)))
                     .fields
                     .iter()
-                    .map(|field| {
-                        if let Some(prim) = field.val.try_to_scalar() {
+                    .map(|(field, field_ty)| {
+                        if let Some(prim) = field.try_to_scalar() {
                             let layout = bx.layout_of(field_ty);
                             let scalar = match layout.abi {
                                 Abi::Scalar(ref x) => x,
@@ -78,7 +76,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     })
                     .collect();
                 let llval = bx.const_struct(&values, false);
-                (llval, c.ty)
+                (llval, ty)
             })
             .unwrap_or_else(|_| {
                 bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time");
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 672686410f9bf..3181ff66ab7f8 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2543,6 +2543,27 @@ impl ConstantKind<'tcx> {
         }
     }
 
+    #[inline]
+    /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
+    pub fn eval_bits(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> u128 {
+        match self {
+            Self::Ty(ct) => ct.eval_bits(tcx, param_env, ty),
+            Self::Val(val, t) => {
+                assert_eq!(*t, ty);
+                let size = tcx
+                    .layout_of(param_env.with_reveal_all_normalized(tcx).and(ty))
+                    .expect("could not normalize type")
+                    .size;
+                val.try_to_scalar_int().unwrap().assert_bits(size)
+            }
+        }
+    }
+
     #[inline]
     pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
         match self {
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 4fb737f463a86..685ac89ee0bd8 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -16,7 +16,7 @@ use smallvec::SmallVec;
 use std::cell::Cell;
 use std::fmt::{self, Debug};
 
-use super::{Field, SourceInfo};
+use super::{interpret::ConstValue, Field, SourceInfo};
 
 #[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
 pub enum UnsafetyViolationKind {
@@ -379,7 +379,7 @@ pub enum ClosureOutlivesSubject<'tcx> {
 #[derive(Copy, Clone, Debug, HashStable)]
 pub struct DestructuredConst<'tcx> {
     pub variant: Option<VariantIdx>,
-    pub fields: &'tcx [&'tcx ty::Const<'tcx>],
+    pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)],
 }
 
 /// Coverage information summarized from a MIR if instrumented for source code coverage (see
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index f3124e5bf424e..c7bcae947ef98 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -367,3 +367,13 @@ impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
         }
     }
 }
+
+impl<'tcx> TypeFoldable<'tcx> for interpret::ConstValue<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
+        self
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        ControlFlow::CONTINUE
+    }
+}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 9a2f1149316e2..471bb68a7db52 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -828,7 +828,7 @@ rustc_queries! {
     /// Destructure a constant ADT or array into its variant index and its
     /// field values.
     query destructure_const(
-        key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
+        key: ty::ParamEnvAnd<'tcx, (ConstValue<'tcx>, Ty<'tcx>)>
     ) -> mir::DestructuredConst<'tcx> {
         desc { "destructure constant" }
     }
@@ -836,8 +836,8 @@ rustc_queries! {
     /// Dereference a constant reference or raw pointer and turn the result into a constant
     /// again.
     query deref_const(
-        key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
-    ) -> &'tcx ty::Const<'tcx> {
+        key: ty::ParamEnvAnd<'tcx, (ConstValue<'tcx>, Ty<'tcx>)>
+    ) -> (ConstValue<'tcx>, Ty<'tcx>) {
         desc { "deref constant" }
     }
 
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 44fa4eb71d801..1ca7fef102873 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1200,10 +1200,8 @@ pub trait PrettyPrinter<'tcx>:
             // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
             // correct `ty::ParamEnv` to allow printing *all* constant values.
             (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
-                let contents = self.tcx().destructure_const(
-                    ty::ParamEnv::reveal_all()
-                        .and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })),
-                );
+                let contents =
+                    self.tcx().destructure_const(ty::ParamEnv::reveal_all().and((ct, ty)));
                 let fields = contents.fields.iter().copied();
 
                 match *ty.kind() {
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 3f426b13688fe..d1ab23b6fd3e8 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -546,7 +546,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
         (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) => a_p.index == b_p.index,
         (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
         (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => {
-            check_const_value_eq(relation, a_val, b_val, a, b)?
+            check_const_value_eq(relation, a_val, b_val, a.ty, b.ty)?
         }
 
         (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
@@ -585,10 +585,8 @@ fn check_const_value_eq<R: TypeRelation<'tcx>>(
     relation: &mut R,
     a_val: ConstValue<'tcx>,
     b_val: ConstValue<'tcx>,
-    // FIXME(oli-obk): these arguments should go away with valtrees
-    a: &'tcx ty::Const<'tcx>,
-    b: &'tcx ty::Const<'tcx>,
-    // FIXME(oli-obk): this should just be `bool` with valtrees
+    a_ty: Ty<'tcx>,
+    b_ty: Ty<'tcx>,
 ) -> RelateResult<'tcx, bool> {
     let tcx = relation.tcx();
     Ok(match (a_val, b_val) {
@@ -610,13 +608,20 @@ fn check_const_value_eq<R: TypeRelation<'tcx>>(
         }
 
         (ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => {
-            let a_destructured = tcx.destructure_const(relation.param_env().and(a));
-            let b_destructured = tcx.destructure_const(relation.param_env().and(b));
+            let a_destructured = tcx.destructure_const(relation.param_env().and((a_val, a_ty)));
+            let b_destructured = tcx.destructure_const(relation.param_env().and((b_val, b_ty)));
 
             // Both the variant and each field have to be equal.
             if a_destructured.variant == b_destructured.variant {
-                for (a_field, b_field) in iter::zip(a_destructured.fields, b_destructured.fields) {
-                    relation.consts(a_field, b_field)?;
+                for (&(a_val, a_ty), &(b_val, b_ty)) in
+                    iter::zip(a_destructured.fields, b_destructured.fields)
+                {
+                    let is_match = check_const_value_eq(relation, a_val, b_val, a_ty, b_ty)?;
+                    if !is_match {
+                        let a = ty::Const::from_value(relation.tcx(), a_val, a_ty);
+                        let b = ty::Const::from_value(relation.tcx(), b_val, b_ty);
+                        return Err(TypeError::ConstMismatch(expected_found(relation, a, b)));
+                    }
                 }
 
                 true
diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs
index 6a514e9f62fce..6609205616dee 100644
--- a/compiler/rustc_mir/src/const_eval/mod.rs
+++ b/compiler/rustc_mir/src/const_eval/mod.rs
@@ -3,7 +3,7 @@
 use std::convert::TryFrom;
 
 use rustc_hir::Mutability;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{
     mir::{self, interpret::ConstAlloc},
     ty::ScalarInt,
@@ -139,14 +139,15 @@ fn const_to_valtree_inner<'tcx>(
 pub(crate) fn destructure_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    val: &'tcx ty::Const<'tcx>,
+    val: ConstValue<'tcx>,
+    ty: Ty<'tcx>,
 ) -> mir::DestructuredConst<'tcx> {
     trace!("destructure_const: {:?}", val);
     let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
-    let op = ecx.const_to_op(val, None).unwrap();
+    let op = ecx.const_val_to_op(val, ty, None).unwrap();
 
     // We go to `usize` as we cannot allocate anything bigger anyway.
-    let (field_count, variant, down) = match val.ty.kind() {
+    let (field_count, variant, down) = match op.layout.ty.kind() {
         ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
         ty::Adt(def, _) if def.variants.is_empty() => {
             return mir::DestructuredConst { variant: None, fields: &[] };
@@ -163,7 +164,7 @@ pub(crate) fn destructure_const<'tcx>(
     let fields_iter = (0..field_count).map(|i| {
         let field_op = ecx.operand_field(&down, i).unwrap();
         let val = op_to_const(&ecx, &field_op);
-        ty::Const::from_value(tcx, val, field_op.layout.ty)
+        (val, field_op.layout.ty)
     });
     let fields = tcx.arena.alloc_from_iter(fields_iter);
 
@@ -173,11 +174,12 @@ pub(crate) fn destructure_const<'tcx>(
 pub(crate) fn deref_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    val: &'tcx ty::Const<'tcx>,
-) -> &'tcx ty::Const<'tcx> {
+    val: ConstValue<'tcx>,
+    ty: Ty<'tcx>,
+) -> (ConstValue<'tcx>, Ty<'tcx>) {
     trace!("deref_const: {:?}", val);
     let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
-    let op = ecx.const_to_op(val, None).unwrap();
+    let op = ecx.const_val_to_op(val, ty, None).unwrap();
     let mplace = ecx.deref_operand(&op).unwrap();
     if let Scalar::Ptr(ptr) = mplace.ptr {
         assert_eq!(
@@ -203,5 +205,5 @@ pub(crate) fn deref_const<'tcx>(
         },
     };
 
-    tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty })
+    (op_to_const(&ecx, &mplace.into()), ty)
 }
diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs
index a58ded9cfd3a4..3303ec4ebf71c 100644
--- a/compiler/rustc_mir/src/lib.rs
+++ b/compiler/rustc_mir/src/lib.rs
@@ -61,15 +61,15 @@ pub fn provide(providers: &mut Providers) {
     providers.mir_callgraph_reachable = transform::inline::cycle::mir_callgraph_reachable;
     providers.mir_inliner_callees = transform::inline::cycle::mir_inliner_callees;
     providers.destructure_const = |tcx, param_env_and_value| {
-        let (param_env, value) = param_env_and_value.into_parts();
-        const_eval::destructure_const(tcx, param_env, value)
+        let (param_env, (value, ty)) = param_env_and_value.into_parts();
+        const_eval::destructure_const(tcx, param_env, value, ty)
     };
     providers.const_to_valtree = |tcx, param_env_and_value| {
         let (param_env, raw) = param_env_and_value.into_parts();
         const_eval::const_to_valtree(tcx, param_env, raw)
     };
     providers.deref_const = |tcx, param_env_and_value| {
-        let (param_env, value) = param_env_and_value.into_parts();
-        const_eval::deref_const(tcx, param_env, value)
+        let (param_env, (value, ty)) = param_env_and_value.into_parts();
+        const_eval::deref_const(tcx, param_env, value, ty)
     };
 }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 369fff00456a7..dffadc7aab1d6 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,6 +1,7 @@
 use rustc_hir as hir;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::mir::Field;
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -249,11 +250,13 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
 
     fn field_pats(
         &self,
-        vals: impl Iterator<Item = &'tcx ty::Const<'tcx>>,
+        vals: impl Iterator<Item = (ConstValue<'tcx>, Ty<'tcx>)>,
     ) -> Result<Vec<FieldPat<'tcx>>, FallbackToConstRef> {
+        let tcx = self.tcx();
         vals.enumerate()
-            .map(|(idx, val)| {
+            .map(|(idx, (val, ty))| {
                 let field = Field::new(idx);
+                let val = ty::Const::from_value(tcx, val, ty);
                 Ok(FieldPat { field, pattern: self.recur(val, false)? })
             })
             .collect()
@@ -357,7 +360,9 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                 PatKind::Wild
             }
             ty::Adt(adt_def, substs) if adt_def.is_enum() => {
-                let destructured = tcx.destructure_const(param_env.and(cv));
+                let destructured = tcx.destructure_const(
+                    param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)),
+                );
                 PatKind::Variant {
                     adt_def,
                     substs,
@@ -368,15 +373,19 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                 }
             }
             ty::Tuple(_) | ty::Adt(_, _) => {
-                let destructured = tcx.destructure_const(param_env.and(cv));
+                let destructured = tcx.destructure_const(
+                    param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)),
+                );
                 PatKind::Leaf { subpatterns: self.field_pats(destructured.fields.iter().copied())? }
             }
             ty::Array(..) => PatKind::Array {
                 prefix: tcx
-                    .destructure_const(param_env.and(cv))
+                    .destructure_const(
+                        param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)),
+                    )
                     .fields
                     .iter()
-                    .map(|val| self.recur(val, false))
+                    .map(|&(val, ty)| self.recur(ty::Const::from_value(tcx, val, ty), false))
                     .collect::<Result<_, _>>()?,
                 slice: None,
                 suffix: Vec::new(),
@@ -404,7 +413,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                 // arrays.
                 ty::Array(..) if !self.treat_byte_string_as_slice => {
                     let old = self.behind_reference.replace(true);
-                    let array = tcx.deref_const(self.param_env.and(cv));
+                    let array = tcx.deref_const(self.param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)));
                     let val = PatKind::Deref {
                         subpattern: Pat {
                             kind: Box::new(PatKind::Array {
@@ -412,7 +421,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                                     .destructure_const(param_env.and(array))
                                     .fields
                                     .iter()
-                                    .map(|val| self.recur(val, false))
+                                    .map(|&(val, ty)| self.recur(ty::Const::from_value(tcx, val, ty), false))
                                     .collect::<Result<_, _>>()?,
                                 slice: None,
                                 suffix: vec![],
@@ -430,7 +439,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                 // pattern.
                 ty::Slice(elem_ty) => {
                     let old = self.behind_reference.replace(true);
-                    let array = tcx.deref_const(self.param_env.and(cv));
+                    let array = tcx.deref_const(self.param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)));
                     let val = PatKind::Deref {
                         subpattern: Pat {
                             kind: Box::new(PatKind::Slice {
@@ -438,7 +447,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                                     .destructure_const(param_env.and(array))
                                     .fields
                                     .iter()
-                                    .map(|val| self.recur(val, false))
+                                    .map(|&(val, ty)| self.recur(ty::Const::from_value(tcx, val, ty), false))
                                     .collect::<Result<_, _>>()?,
                                 slice: None,
                                 suffix: vec![],
@@ -493,7 +502,9 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                     // we fall back to a const pattern. If we do not do this, we may end up with
                     // a !structural-match constant that is not of reference type, which makes it
                     // very hard to invoke `PartialEq::eq` on it as a fallback.
-                    let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) {
+                    let (val, ty) = tcx.deref_const(self.param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)));
+                    let deref_cv = ty::Const::from_value(tcx, val, ty);
+                    let val = match self.recur(deref_cv, false) {
                         Ok(subpattern) => PatKind::Deref { subpattern },
                         Err(_) => PatKind::Constant { value: cv },
                     };
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index b3cc7de4662a5..5c711673e6240 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -311,6 +311,15 @@ impl<'tcx> Key for &'tcx ty::Const<'tcx> {
     }
 }
 
+impl<'tcx> Key for (mir::interpret::ConstValue<'tcx>, Ty<'tcx>) {
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+    fn default_span(&self, _: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
 impl<'tcx> Key for Ty<'tcx> {
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index d775cd7c7f740..15f4c04857651 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -16,7 +16,7 @@ use rustc_infer::traits::specialization_graph;
 use rustc_lint::{LateContext, LateLintPass, Lint};
 use rustc_middle::mir::interpret::{ConstValue, ErrorHandled};
 use rustc_middle::ty::adjustment::Adjust;
-use rustc_middle::ty::{self, AssocKind, Const, Ty};
+use rustc_middle::ty::{self, AssocKind, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{InnerSpan, Span, DUMMY_SP};
 use rustc_typeck::hir_ty_to_ty;
@@ -129,15 +129,15 @@ fn is_value_unfrozen_raw<'tcx>(
     result: Result<ConstValue<'tcx>, ErrorHandled>,
     ty: Ty<'tcx>,
 ) -> bool {
-    fn inner<'tcx>(cx: &LateContext<'tcx>, val: &'tcx Const<'tcx>) -> bool {
-        match val.ty.kind() {
+    fn inner<'tcx>(cx: &LateContext<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> bool {
+        match ty.kind() {
             // the fact that we have to dig into every structs to search enums
             // leads us to the point checking `UnsafeCell` directly is the only option.
             ty::Adt(ty_def, ..) if Some(ty_def.did) == cx.tcx.lang_items().unsafe_cell_type() => true,
             ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => {
-                let val = cx.tcx.destructure_const(cx.param_env.and(val));
-                val.fields.iter().any(|field| inner(cx, field))
-            },
+                let val = cx.tcx.destructure_const(cx.param_env.and((val, ty)));
+                val.fields.iter().any(|&(f, f_ty)| inner(cx, f, f_ty))
+            }
             _ => false,
         }
     }
@@ -167,7 +167,7 @@ fn is_value_unfrozen_raw<'tcx>(
             // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
             err == ErrorHandled::TooGeneric
         },
-        |val| inner(cx, Const::from_value(cx.tcx, val, ty)),
+        |val| inner(cx, val, ty),
     )
 }