about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Scherer <github35764891676564198441@oli-obk.de>2020-09-26 15:15:35 +0200
committeroli <github35764891676564198441@oli-obk.de>2020-11-04 09:58:59 +0000
commit362123dd7577daa4cf737bc8f50146beedd3d944 (patch)
treed0fa1d0538039e2f7cb227eb6323f07fcc6ba74f
parent56293097f7f877f1350a6cd00f79d03132f16515 (diff)
downloadrust-362123dd7577daa4cf737bc8f50146beedd3d944.tar.gz
rust-362123dd7577daa4cf737bc8f50146beedd3d944.zip
Split the "raw integer bytes" part out of `Scalar`
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs8
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs107
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs7
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs239
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs57
-rw-r--r--compiler/rustc_mir/src/const_eval/eval_queries.rs4
-rw-r--r--compiler/rustc_mir/src/const_eval/machine.rs10
-rw-r--r--compiler/rustc_mir/src/interpret/operand.rs15
-rw-r--r--compiler/rustc_mir/src/interpret/place.rs8
-rw-r--r--compiler/rustc_mir/src/transform/const_prop.rs7
-rw-r--r--compiler/rustc_mir/src/transform/simplify_comparison_integral.rs12
-rw-r--r--src/librustdoc/clean/utils.rs9
-rw-r--r--src/test/ui/symbol-names/impl1.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/consts.rs17
17 files changed, 325 insertions, 184 deletions
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 7633dd0600d..8bcb8b62076 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -12,7 +12,7 @@ use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::*;
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar};
-use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::ty::{layout::TyAndLayout, ScalarInt};
 use rustc_span::symbol::Symbol;
 use rustc_target::abi::{self, AddressSpace, HasDataLayout, LayoutOf, Pointer, Size};
 
@@ -230,12 +230,12 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     fn scalar_to_backend(&self, cv: Scalar, layout: &abi::Scalar, llty: &'ll Type) -> &'ll Value {
         let bitsize = if layout.is_bool() { 1 } else { layout.value.size(self).bits() };
         match cv {
-            Scalar::Raw { size: 0, .. } => {
+            Scalar::Raw(ScalarInt::ZST) => {
                 assert_eq!(0, layout.value.size(self).bytes());
                 self.const_undef(self.type_ix(0))
             }
-            Scalar::Raw { data, size } => {
-                assert_eq!(size as u64, layout.value.size(self).bytes());
+            Scalar::Raw(int) => {
+                let data = int.assert_bits(layout.value.size(self));
                 let llval = self.const_uint_big(self.type_ix(bitsize), data);
                 if layout.value == Pointer {
                     unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 4b915fe020f..4a1d5459d1e 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -24,6 +24,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(array_windows)]
+#![feature(assoc_char_funcs)]
 #![feature(backtrace)]
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index b5beb3babe2..c94a882df01 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -71,7 +71,7 @@ macro_rules! throw_inval {
 
 #[macro_export]
 macro_rules! throw_ub {
-    ($($tt:tt)*) => { Err::<!, _>(err_ub!($($tt)*))? };
+    ($($tt:tt)*) => { Err::<!, _>($crate::err_ub!($($tt)*))? };
 }
 
 #[macro_export]
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index cb8782ce817..d3a75cd099e 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -8,9 +8,9 @@ use rustc_apfloat::{
 use rustc_macros::HashStable;
 use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
 
-use crate::ty::{ParamEnv, Ty, TyCtxt};
+use crate::ty::{ParamEnv, ScalarInt, Ty, TyCtxt};
 
-use super::{sign_extend, truncate, AllocId, Allocation, InterpResult, Pointer, PointerArithmetic};
+use super::{sign_extend, AllocId, Allocation, InterpResult, Pointer, PointerArithmetic};
 
 /// Represents the result of const evaluation via the `eval_to_allocation` query.
 #[derive(Clone, HashStable, TyEncodable, TyDecodable)]
@@ -103,12 +103,7 @@ impl<'tcx> ConstValue<'tcx> {
 #[derive(HashStable)]
 pub enum Scalar<Tag = ()> {
     /// The raw bytes of a simple value.
-    Raw {
-        /// The first `size` bytes of `data` are the value.
-        /// Do not try to read less or more bytes than that. The remaining bytes must be 0.
-        data: u128,
-        size: u8,
-    },
+    Raw(ScalarInt),
 
     /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
     /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
@@ -125,16 +120,7 @@ impl<Tag: fmt::Debug> fmt::Debug for Scalar<Tag> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Scalar::Ptr(ptr) => write!(f, "{:?}", ptr),
-            &Scalar::Raw { data, size } => {
-                Scalar::check_data(data, size);
-                if size == 0 {
-                    write!(f, "<ZST>")
-                } else {
-                    // Format as hex number wide enough to fit any value of the given `size`.
-                    // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
-                    write!(f, "0x{:>0width$x}", data, width = (size * 2) as usize)
-                }
-            }
+            Scalar::Raw(int) => write!(f, "{:?}", int),
         }
     }
 }
@@ -163,21 +149,6 @@ impl<Tag> From<Double> for Scalar<Tag> {
 }
 
 impl Scalar<()> {
-    /// Make sure the `data` fits in `size`.
-    /// This is guaranteed by all constructors here, but since the enum variants are public,
-    /// it could still be violated (even though no code outside this file should
-    /// construct `Scalar`s).
-    #[inline(always)]
-    fn check_data(data: u128, size: u8) {
-        debug_assert_eq!(
-            truncate(data, Size::from_bytes(u64::from(size))),
-            data,
-            "Scalar value {:#x} exceeds size of {} bytes",
-            data,
-            size
-        );
-    }
-
     /// Tag this scalar with `new_tag` if it is a pointer, leave it unchanged otherwise.
     ///
     /// Used by `MemPlace::replace_tag`.
@@ -185,7 +156,7 @@ impl Scalar<()> {
     pub fn with_tag<Tag>(self, new_tag: Tag) -> Scalar<Tag> {
         match self {
             Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_tag(new_tag)),
-            Scalar::Raw { data, size } => Scalar::Raw { data, size },
+            Scalar::Raw(int) => Scalar::Raw(int),
         }
     }
 }
@@ -198,18 +169,18 @@ impl<'tcx, Tag> Scalar<Tag> {
     pub fn erase_tag(self) -> Scalar {
         match self {
             Scalar::Ptr(ptr) => Scalar::Ptr(ptr.erase_tag()),
-            Scalar::Raw { data, size } => Scalar::Raw { data, size },
+            Scalar::Raw(int) => Scalar::Raw(int),
         }
     }
 
     #[inline]
     pub fn null_ptr(cx: &impl HasDataLayout) -> Self {
-        Scalar::Raw { data: 0, size: cx.data_layout().pointer_size.bytes() as u8 }
+        Scalar::Raw(ScalarInt::null(cx.data_layout().pointer_size))
     }
 
     #[inline]
     pub fn zst() -> Self {
-        Scalar::Raw { data: 0, size: 0 }
+        Scalar::Raw(ScalarInt::zst())
     }
 
     #[inline(always)]
@@ -220,10 +191,7 @@ impl<'tcx, Tag> Scalar<Tag> {
         f_ptr: impl FnOnce(Pointer<Tag>) -> InterpResult<'tcx, Pointer<Tag>>,
     ) -> InterpResult<'tcx, Self> {
         match self {
-            Scalar::Raw { data, size } => {
-                assert_eq!(u64::from(size), dl.pointer_size.bytes());
-                Ok(Scalar::Raw { data: u128::from(f_int(u64::try_from(data).unwrap())?), size })
-            }
+            Scalar::Raw(int) => Ok(Scalar::Raw(int.ptr_sized_op(dl, f_int)?)),
             Scalar::Ptr(ptr) => Ok(Scalar::Ptr(f_ptr(ptr)?)),
         }
     }
@@ -264,24 +232,17 @@ impl<'tcx, Tag> Scalar<Tag> {
 
     #[inline]
     pub fn from_bool(b: bool) -> Self {
-        // Guaranteed to be truncated and does not need sign extension.
-        Scalar::Raw { data: b as u128, size: 1 }
+        Scalar::Raw(b.into())
     }
 
     #[inline]
     pub fn from_char(c: char) -> Self {
-        // Guaranteed to be truncated and does not need sign extension.
-        Scalar::Raw { data: c as u128, size: 4 }
+        Scalar::Raw(c.into())
     }
 
     #[inline]
     pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
-        let i = i.into();
-        if truncate(i, size) == i {
-            Some(Scalar::Raw { data: i, size: size.bytes() as u8 })
-        } else {
-            None
-        }
+        ScalarInt::try_from_uint(i, size).map(Scalar::Raw)
     }
 
     #[inline]
@@ -293,26 +254,22 @@ impl<'tcx, Tag> Scalar<Tag> {
 
     #[inline]
     pub fn from_u8(i: u8) -> Self {
-        // Guaranteed to be truncated and does not need sign extension.
-        Scalar::Raw { data: i.into(), size: 1 }
+        Scalar::Raw(i.into())
     }
 
     #[inline]
     pub fn from_u16(i: u16) -> Self {
-        // Guaranteed to be truncated and does not need sign extension.
-        Scalar::Raw { data: i.into(), size: 2 }
+        Scalar::Raw(i.into())
     }
 
     #[inline]
     pub fn from_u32(i: u32) -> Self {
-        // Guaranteed to be truncated and does not need sign extension.
-        Scalar::Raw { data: i.into(), size: 4 }
+        Scalar::Raw(i.into())
     }
 
     #[inline]
     pub fn from_u64(i: u64) -> Self {
-        // Guaranteed to be truncated and does not need sign extension.
-        Scalar::Raw { data: i.into(), size: 8 }
+        Scalar::Raw(i.into())
     }
 
     #[inline]
@@ -322,14 +279,7 @@ impl<'tcx, Tag> Scalar<Tag> {
 
     #[inline]
     pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
-        let i = i.into();
-        // `into` performed sign extension, we have to truncate
-        let truncated = truncate(i as u128, size);
-        if sign_extend(truncated, size) as i128 == i {
-            Some(Scalar::Raw { data: truncated, size: size.bytes() as u8 })
-        } else {
-            None
-        }
+        ScalarInt::try_from_int(i, size).map(Scalar::Raw)
     }
 
     #[inline]
@@ -366,14 +316,12 @@ impl<'tcx, Tag> Scalar<Tag> {
 
     #[inline]
     pub fn from_f32(f: Single) -> Self {
-        // We trust apfloat to give us properly truncated data.
-        Scalar::Raw { data: f.to_bits(), size: 4 }
+        Scalar::Raw(f.into())
     }
 
     #[inline]
     pub fn from_f64(f: Double) -> Self {
-        // We trust apfloat to give us properly truncated data.
-        Scalar::Raw { data: f.to_bits(), size: 8 }
+        Scalar::Raw(f.into())
     }
 
     /// This is very rarely the method you want!  You should dispatch on the type
@@ -388,11 +336,7 @@ impl<'tcx, Tag> Scalar<Tag> {
     ) -> Result<u128, Pointer<Tag>> {
         assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
         match self {
-            Scalar::Raw { data, size } => {
-                assert_eq!(target_size.bytes(), u64::from(size));
-                Scalar::check_data(data, size);
-                Ok(data)
-            }
+            Scalar::Raw(int) => Ok(int.assert_bits(target_size)),
             Scalar::Ptr(ptr) => {
                 assert_eq!(target_size, cx.data_layout().pointer_size);
                 Err(ptr)
@@ -406,16 +350,7 @@ impl<'tcx, Tag> Scalar<Tag> {
     fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
         assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
         match self {
-            Scalar::Raw { data, size } => {
-                if target_size.bytes() != u64::from(size) {
-                    throw_ub!(ScalarSizeMismatch {
-                        target_size: target_size.bytes(),
-                        data_size: u64::from(size),
-                    });
-                }
-                Scalar::check_data(data, size);
-                Ok(data)
-            }
+            Scalar::Raw(int) => int.to_bits(target_size),
             Scalar::Ptr(_) => throw_unsup!(ReadPointerAsBytes),
         }
     }
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index b6b6c968501..db89a4ad4b6 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -28,7 +28,6 @@ use rustc_index::vec::{Idx, IndexVec};
 use rustc_serialize::{Decodable, Encodable};
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi;
 use rustc_target::asm::InlineAsmRegOrRegClass;
 use std::borrow::Cow;
 use std::fmt::{self, Debug, Display, Formatter, Write};
@@ -1952,10 +1951,10 @@ impl<'tcx> Operand<'tcx> {
                 .layout_of(param_env_and_ty)
                 .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e))
                 .size;
-            let scalar_size = abi::Size::from_bytes(match val {
-                Scalar::Raw { size, .. } => size,
+            let scalar_size = match val {
+                Scalar::Raw(int) => int.size(),
                 _ => panic!("Invalid scalar type {:?}", val),
-            });
+            };
             scalar_size == type_size
         });
         Operand::Constant(box Constant {
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index ced0429deab..807005b4595 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -1,31 +1,34 @@
-use crate::mir::interpret::truncate;
-use rustc_target::abi::Size;
+use crate::mir::interpret::{sign_extend, truncate, InterpErrorInfo, InterpResult};
+use crate::throw_ub;
+use rustc_apfloat::ieee::{Double, Single};
+use rustc_apfloat::Float;
+use rustc_macros::HashStable;
+use rustc_target::abi::{Size, TargetDataLayout};
+use std::convert::{TryFrom, TryInto};
+use std::fmt;
 
 #[derive(Copy, Clone)]
 /// A type for representing any integer. Only used for printing.
-// FIXME: Use this for the integer-tree representation needed for type level ints and
-// const generics?
 pub struct ConstInt {
-    /// Number of bytes of the integer. Only 1, 2, 4, 8, 16 are legal values.
-    size: u8,
+    /// The "untyped" variant of `ConstInt`.
+    int: ScalarInt,
     /// Whether the value is of a signed integer type.
     signed: bool,
     /// Whether the value is a `usize` or `isize` type.
     is_ptr_sized_integral: bool,
-    /// Raw memory of the integer. All bytes beyond the `size` are unused and must be zero.
-    raw: u128,
 }
 
 impl ConstInt {
-    pub fn new(raw: u128, size: Size, signed: bool, is_ptr_sized_integral: bool) -> Self {
-        assert!(raw <= truncate(u128::MAX, size));
-        Self { raw, size: size.bytes() as u8, signed, is_ptr_sized_integral }
+    pub fn new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self {
+        Self { int, signed, is_ptr_sized_integral }
     }
 }
 
 impl std::fmt::Debug for ConstInt {
     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        let Self { size, signed, raw, is_ptr_sized_integral } = *self;
+        let Self { int, signed, is_ptr_sized_integral } = *self;
+        let size = int.size().bytes();
+        let raw = int.data();
         if signed {
             let bit_size = size * 8;
             let min = 1u128 << (bit_size - 1);
@@ -109,3 +112,215 @@ impl std::fmt::Debug for ConstInt {
         }
     }
 }
+
+// FIXME: reuse in `super::int::ConstInt` and `Scalar::Bits`
+/// The raw bytes of a simple value.
+#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)]
+#[derive(HashStable)]
+pub struct ScalarInt {
+    /// The first `size` bytes of `data` are the value.
+    /// Do not try to read less or more bytes than that. The remaining bytes must be 0.
+    ///
+    /// This is an array in order to allow this type to be optimally embedded in enums
+    /// (like Scalar).
+    bytes: [u8; 16],
+    size: u8,
+}
+
+impl ScalarInt {
+    pub const TRUE: ScalarInt = ScalarInt { bytes: 1_u128.to_ne_bytes(), size: 1 };
+
+    pub const FALSE: ScalarInt = ScalarInt { bytes: 0_u128.to_ne_bytes(), size: 1 };
+
+    pub const ZST: ScalarInt = ScalarInt { bytes: 0_u128.to_ne_bytes(), size: 0 };
+
+    fn data(self) -> u128 {
+        u128::from_ne_bytes(self.bytes)
+    }
+
+    #[inline]
+    pub fn size(self) -> Size {
+        Size::from_bytes(self.size)
+    }
+
+    /// Make sure the `data` fits in `size`.
+    /// This is guaranteed by all constructors here, but since the enum variants are public,
+    /// it could still be violated (even though no code outside this file should
+    /// construct `Scalar`s).
+    #[inline(always)]
+    fn check_data(self) {
+        debug_assert_eq!(
+            truncate(self.data(), self.size()),
+            self.data(),
+            "Scalar value {:#x} exceeds size of {} bytes",
+            self.data(),
+            self.size
+        );
+    }
+
+    #[inline]
+    pub fn zst() -> Self {
+        Self::null(Size::ZERO)
+    }
+
+    #[inline]
+    pub fn null(size: Size) -> Self {
+        Self { bytes: [0; 16], size: size.bytes() as u8 }
+    }
+
+    pub(crate) fn ptr_sized_op<'tcx>(
+        self,
+        dl: &TargetDataLayout,
+        f_int: impl FnOnce(u64) -> InterpResult<'tcx, u64>,
+    ) -> InterpResult<'tcx, Self> {
+        assert_eq!(u64::from(self.size), dl.pointer_size.bytes());
+        Ok(Self {
+            bytes: u128::from(f_int(u64::try_from(self.data()).unwrap())?).to_ne_bytes(),
+            size: self.size,
+        })
+    }
+
+    #[inline]
+    pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
+        let data = i.into();
+        if truncate(data, size) == data {
+            Some(Self { bytes: data.to_ne_bytes(), size: size.bytes() as u8 })
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
+        let i = i.into();
+        // `into` performed sign extension, we have to truncate
+        let truncated = truncate(i as u128, size);
+        if sign_extend(truncated, size) as i128 == i {
+            Some(Self { bytes: truncated.to_ne_bytes(), size: size.bytes() as u8 })
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    pub fn assert_bits(self, target_size: Size) -> u128 {
+        assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
+        assert_eq!(target_size.bytes(), u64::from(self.size));
+        self.check_data();
+        self.data()
+    }
+
+    #[inline]
+    pub fn to_bits(self, target_size: Size) -> InterpResult<'static, u128> {
+        assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
+        if target_size.bytes() != u64::from(self.size) {
+            throw_ub!(ScalarSizeMismatch {
+                target_size: target_size.bytes(),
+                data_size: u64::from(self.size),
+            });
+        }
+        self.check_data();
+        Ok(self.data())
+    }
+}
+
+macro_rules! from {
+    ($($ty:ty),*) => {
+        $(
+            impl From<$ty> for ScalarInt {
+                #[inline]
+                fn from(u: $ty) -> Self {
+                    Self {
+                        bytes: u128::from(u).to_ne_bytes(),
+                        size: std::mem::size_of::<$ty>() as u8,
+                    }
+                }
+            }
+        )*
+    }
+}
+
+macro_rules! try_from {
+    ($($ty:ty),*) => {
+        $(
+            impl TryFrom<ScalarInt> for $ty {
+                type Error = InterpErrorInfo<'static>;
+                #[inline]
+                fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
+                    int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>())).map(|u| u.try_into().unwrap())
+                }
+            }
+        )*
+    }
+}
+
+from!(u8, u16, u32, u64, u128, bool);
+try_from!(u8, u16, u32, u64, u128);
+
+impl From<char> for ScalarInt {
+    #[inline]
+    fn from(c: char) -> Self {
+        Self { bytes: (c as u128).to_ne_bytes(), size: std::mem::size_of::<char>() as u8 }
+    }
+}
+
+impl TryFrom<ScalarInt> for char {
+    type Error = InterpErrorInfo<'static>;
+    #[inline]
+    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
+        int.to_bits(Size::from_bytes(std::mem::size_of::<char>()))
+            .map(|u| char::from_u32(u.try_into().unwrap()).unwrap())
+    }
+}
+
+impl From<Single> for ScalarInt {
+    #[inline]
+    fn from(f: Single) -> Self {
+        // We trust apfloat to give us properly truncated data.
+        Self { bytes: f.to_bits().to_ne_bytes(), size: 4 }
+    }
+}
+
+impl TryFrom<ScalarInt> for Single {
+    type Error = InterpErrorInfo<'static>;
+    #[inline]
+    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
+        int.to_bits(Size::from_bytes(4)).map(Self::from_bits)
+    }
+}
+
+impl From<Double> for ScalarInt {
+    #[inline]
+    fn from(f: Double) -> Self {
+        // We trust apfloat to give us properly truncated data.
+        Self { bytes: f.to_bits().to_ne_bytes(), size: 8 }
+    }
+}
+
+impl TryFrom<ScalarInt> for Double {
+    type Error = InterpErrorInfo<'static>;
+    #[inline]
+    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
+        int.to_bits(Size::from_bytes(8)).map(Self::from_bits)
+    }
+}
+
+impl fmt::Debug for ScalarInt {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self.size == 0 {
+            self.check_data();
+            write!(f, "<ZST>")
+        } else {
+            write!(f, "0x{:x}", self)
+        }
+    }
+}
+
+impl fmt::LowerHex for ScalarInt {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.check_data();
+        // Format as hex number wide enough to fit any value of the given `size`.
+        // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
+        write!(f, "{:01$x}", self.data(), self.size as usize * 2)
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 096c53ca996..0a7bec1a342 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -87,7 +87,7 @@ pub use self::trait_def::TraitDef;
 
 pub use self::query::queries;
 
-pub use self::consts::{Const, ConstInt, ConstKind, InferConst};
+pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt};
 
 pub mod _match;
 pub mod adjustment;
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index fa38bddcae2..f972a4cc1ac 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1,12 +1,9 @@
 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
 use crate::mir::interpret::{AllocId, ConstValue, GlobalAlloc, Pointer, Scalar};
-use crate::ty::layout::IntegerExt;
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
-use crate::ty::{self, ConstInt, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
 use rustc_apfloat::ieee::{Double, Single};
-use rustc_apfloat::Float;
 use rustc_ast as ast;
-use rustc_attr::{SignedInt, UnsignedInt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
@@ -15,12 +12,13 @@ use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathD
 use rustc_hir::ItemKind;
 use rustc_session::config::TrimmedDefPaths;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_target::abi::{Integer, Size};
+use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
 
 use std::cell::Cell;
 use std::char;
 use std::collections::BTreeMap;
+use std::convert::TryFrom;
 use std::fmt::{self, Write as _};
 use std::ops::{ControlFlow, Deref, DerefMut};
 
@@ -960,11 +958,7 @@ pub trait PrettyPrinter<'tcx>:
                             ty::Array(
                                 ty::TyS { kind: ty::Uint(ast::UintTy::U8), .. },
                                 ty::Const {
-                                    val:
-                                        ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw {
-                                            data,
-                                            ..
-                                        })),
+                                    val: ty::ConstKind::Value(ConstValue::Scalar(int)),
                                     ..
                                 },
                             ),
@@ -974,8 +968,9 @@ pub trait PrettyPrinter<'tcx>:
                 ),
             ) => match self.tcx().get_global_alloc(ptr.alloc_id) {
                 Some(GlobalAlloc::Memory(alloc)) => {
-                    if let Ok(byte_str) = alloc.get_bytes(&self.tcx(), ptr, Size::from_bytes(*data))
-                    {
+                    let bytes = int.assert_bits(self.tcx().data_layout.pointer_size);
+                    let size = Size::from_bytes(bytes);
+                    if let Ok(byte_str) = alloc.get_bytes(&self.tcx(), ptr, size) {
                         p!(pretty_print_byte_str(byte_str))
                     } else {
                         p!("<too short allocation>")
@@ -987,32 +982,28 @@ pub trait PrettyPrinter<'tcx>:
                 None => p!("<dangling pointer>"),
             },
             // Bool
-            (Scalar::Raw { data: 0, .. }, ty::Bool) => p!("false"),
-            (Scalar::Raw { data: 1, .. }, ty::Bool) => p!("true"),
+            (Scalar::Raw(ScalarInt::FALSE), ty::Bool) => p!("false"),
+            (Scalar::Raw(ScalarInt::TRUE), ty::Bool) => p!("true"),
             // Float
-            (Scalar::Raw { data, .. }, ty::Float(ast::FloatTy::F32)) => {
-                p!(write("{}f32", Single::from_bits(data)))
+            (Scalar::Raw(int), ty::Float(ast::FloatTy::F32)) => {
+                p!(write("{}f32", Single::try_from(int).unwrap()))
             }
-            (Scalar::Raw { data, .. }, ty::Float(ast::FloatTy::F64)) => {
-                p!(write("{}f64", Double::from_bits(data)))
+            (Scalar::Raw(int), ty::Float(ast::FloatTy::F64)) => {
+                p!(write("{}f64", Double::try_from(int).unwrap()))
             }
             // Int
-            (Scalar::Raw { data, .. }, ty::Uint(ui)) => {
-                let size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size();
-                let int = ConstInt::new(data, size, false, ty.is_ptr_sized_integral());
-                if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) }
-            }
-            (Scalar::Raw { data, .. }, ty::Int(i)) => {
-                let size = Integer::from_attr(&self.tcx(), SignedInt(*i)).size();
-                let int = ConstInt::new(data, size, true, ty.is_ptr_sized_integral());
+            (Scalar::Raw(int), ty::Uint(_) | ty::Int(_)) => {
+                let int =
+                    ConstInt::new(int, matches!(ty.kind(), ty::Int(_)), ty.is_ptr_sized_integral());
                 if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) }
             }
             // Char
-            (Scalar::Raw { data, .. }, ty::Char) if char::from_u32(data as u32).is_some() => {
-                p!(write("{:?}", char::from_u32(data as u32).unwrap()))
+            (Scalar::Raw(int), ty::Char) if char::try_from(int).is_ok() => {
+                p!(write("{:?}", char::try_from(int).unwrap()))
             }
             // Raw pointers
-            (Scalar::Raw { data, .. }, ty::RawPtr(_)) => {
+            (Scalar::Raw(int), ty::RawPtr(_)) => {
+                let data = int.assert_bits(self.tcx().data_layout.pointer_size);
                 self = self.typed_value(
                     |mut this| {
                         write!(this, "0x{:x}", data)?;
@@ -1034,14 +1025,14 @@ pub trait PrettyPrinter<'tcx>:
                 )?;
             }
             // For function type zsts just printing the path is enough
-            (Scalar::Raw { size: 0, .. }, ty::FnDef(d, s)) => p!(print_value_path(*d, s)),
+            (Scalar::Raw(ScalarInt::ZST), ty::FnDef(d, s)) => p!(print_value_path(*d, s)),
             // Nontrivial types with scalar bit representation
-            (Scalar::Raw { data, size }, _) => {
+            (Scalar::Raw(int), _) => {
                 let print = |mut this: Self| {
-                    if size == 0 {
+                    if int.size() == Size::ZERO {
                         write!(this, "transmute(())")?;
                     } else {
-                        write!(this, "transmute(0x{:01$x})", data, size as usize * 2)?;
+                        write!(this, "transmute(0x{:x})", int)?;
                     }
                     Ok(this)
                 };
diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs
index 7b9a4ec873d..37bb841a34b 100644
--- a/compiler/rustc_mir/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs
@@ -137,10 +137,10 @@ pub(super) fn op_to_const<'tcx>(
             let alloc = ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory();
             ConstValue::ByRef { alloc, offset: ptr.offset }
         }
-        Scalar::Raw { data, .. } => {
+        Scalar::Raw(int) => {
             assert!(mplace.layout.is_zst());
             assert_eq!(
-                u64::try_from(data).unwrap() % mplace.layout.align.abi.bytes(),
+                u64::try_from(int).unwrap() % mplace.layout.align.abi.bytes(),
                 0,
                 "this MPlaceTy must come from a validated constant, thus we can assume the \
                 alignment is correct",
diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs
index 7e2cae09481..b734c724274 100644
--- a/compiler/rustc_mir/src/const_eval/machine.rs
+++ b/compiler/rustc_mir/src/const_eval/machine.rs
@@ -1,6 +1,6 @@
 use rustc_middle::mir;
 use rustc_middle::ty::layout::HasTyCtxt;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, ScalarInt, Ty};
 use std::borrow::Borrow;
 use std::collections::hash_map::Entry;
 use std::hash::Hash;
@@ -194,13 +194,13 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
     fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> bool {
         match (a, b) {
             // Comparisons between integers are always known.
-            (Scalar::Raw { .. }, Scalar::Raw { .. }) => a != b,
+            (Scalar::Raw(_), Scalar::Raw(_)) => a != b,
             // Comparisons of abstract pointers with null pointers are known if the pointer
             // is in bounds, because if they are in bounds, the pointer can't be null.
-            (Scalar::Raw { data: 0, .. }, Scalar::Ptr(ptr))
-            | (Scalar::Ptr(ptr), Scalar::Raw { data: 0, .. }) => !self.memory.ptr_may_be_null(ptr),
             // Inequality with integers other than null can never be known for sure.
-            (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false,
+            (Scalar::Raw(int), Scalar::Ptr(ptr)) | (Scalar::Ptr(ptr), Scalar::Raw(int)) => {
+                int == ScalarInt::null(int.size()) && !self.memory.ptr_may_be_null(ptr)
+            }
             // FIXME: return `true` for at least some comparisons where we can reliably
             // determine the result of runtime inequality tests at compile-time.
             // Examples include comparison of addresses in different static items.
diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs
index 3c68b1c8355..bdb72297f00 100644
--- a/compiler/rustc_mir/src/interpret/operand.rs
+++ b/compiler/rustc_mir/src/interpret/operand.rs
@@ -211,14 +211,11 @@ impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> {
     #[inline]
     pub fn to_const_int(self) -> ConstInt {
         assert!(self.layout.ty.is_integral());
-        ConstInt::new(
-            self.to_scalar()
-                .expect("to_const_int doesn't work on scalar pairs")
-                .assert_bits(self.layout.size),
-            self.layout.size,
-            self.layout.ty.is_signed(),
-            self.layout.ty.is_ptr_sized_integral(),
-        )
+        let int = match self.to_scalar().expect("to_const_int doesn't work on scalar pairs") {
+            Scalar::Raw(int) => int,
+            Scalar::Ptr(_) => bug!("to_const_int doesn't work on pointers"),
+        };
+        ConstInt::new(int, self.layout.ty.is_signed(), self.layout.ty.is_ptr_sized_integral())
     }
 }
 
@@ -544,7 +541,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let tag_scalar = |scalar| -> InterpResult<'tcx, _> {
             Ok(match scalar {
                 Scalar::Ptr(ptr) => Scalar::Ptr(self.global_base_pointer(ptr)?),
-                Scalar::Raw { data, size } => Scalar::Raw { data, size },
+                Scalar::Raw(int) => Scalar::Raw(int),
             })
         };
         // Early-return cases.
diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs
index fe25f8ce962..ceae436b18e 100644
--- a/compiler/rustc_mir/src/interpret/place.rs
+++ b/compiler/rustc_mir/src/interpret/place.rs
@@ -721,12 +721,8 @@ where
                     dest.layout.size,
                     "Size mismatch when writing pointer"
                 ),
-                Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::Raw { size, .. })) => {
-                    assert_eq!(
-                        Size::from_bytes(size),
-                        dest.layout.size,
-                        "Size mismatch when writing bits"
-                    )
+                Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::Raw(int))) => {
+                    assert_eq!(int.size(), dest.layout.size, "Size mismatch when writing bits")
                 }
                 Immediate::Scalar(ScalarMaybeUninit::Uninit) => {} // uninit can have any size
                 Immediate::ScalarPair(_, _) => {
diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs
index d47e549b7be..620b9ac673a 100644
--- a/compiler/rustc_mir/src/transform/const_prop.rs
+++ b/compiler/rustc_mir/src/transform/const_prop.rs
@@ -19,7 +19,9 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutError, TyAndLayout};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{self, ConstInt, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{
+    self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable,
+};
 use rustc_session::lint;
 use rustc_span::{def_id::DefId, Span};
 use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TargetDataLayout};
@@ -578,8 +580,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                             Some(l) => l.to_const_int(),
                             // Invent a dummy value, the diagnostic ignores it anyway
                             None => ConstInt::new(
-                                1,
-                                left_size,
+                                ScalarInt::try_from_uint(1_u8, left_size).unwrap(),
                                 left_ty.is_signed(),
                                 left_ty.is_ptr_sized_integral(),
                             ),
diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
index 6372f8960dd..2ed27a6ed0a 100644
--- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
@@ -26,22 +26,26 @@ use rustc_middle::{
 pub struct SimplifyComparisonIntegral;
 
 impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
-    fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("Running SimplifyComparisonIntegral on {:?}", body.source);
 
         let helper = OptimizationFinder { body };
         let opts = helper.find_optimizations();
         let mut storage_deads_to_insert = vec![];
         let mut storage_deads_to_remove: Vec<(usize, BasicBlock)> = vec![];
+        let param_env = tcx.param_env(body.source.def_id());
         for opt in opts {
             trace!("SUCCESS: Applying {:?}", opt);
             // replace terminator with a switchInt that switches on the integer directly
             let bbs = &mut body.basic_blocks_mut();
             let bb = &mut bbs[opt.bb_idx];
-            // We only use the bits for the untyped, not length checked `values` field. Thus we are
-            // not using any of the convenience wrappers here and directly access the bits.
             let new_value = match opt.branch_value_scalar {
-                Scalar::Raw { data, .. } => data,
+                Scalar::Raw(int) => {
+                    let layout = tcx
+                        .layout_of(param_env.and(opt.branch_value_ty))
+                        .expect("if we have an evaluated constant we must know the layout");
+                    int.assert_bits(layout.size)
+                }
                 Scalar::Ptr(_) => continue,
             };
             const FALSE: u128 = 0;
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index b0ed233f5ec..167b06428e5 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -14,7 +14,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_middle::mir::interpret::{sign_extend, ConstValue, Scalar};
+use rustc_middle::mir::interpret::{sign_extend, ConstValue};
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::{self, DefIdTree, Ty};
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -499,12 +499,13 @@ fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const
     // Use a slightly different format for integer types which always shows the actual value.
     // For all other types, fallback to the original `pretty_print_const`.
     match (ct.val, ct.ty.kind()) {
-        (ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, .. })), ty::Uint(ui)) => {
-            format!("{}{}", format_integer_with_underscore_sep(&data.to_string()), ui.name_str())
+        (ty::ConstKind::Value(ConstValue::Scalar(int)), ty::Uint(ui)) => {
+            format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
         }
-        (ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, .. })), ty::Int(i)) => {
+        (ty::ConstKind::Value(ConstValue::Scalar(int)), ty::Int(i)) => {
             let ty = cx.tcx.lift(ct.ty).unwrap();
             let size = cx.tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
+            let data = int.assert_bits(size);
             let sign_extended_data = sign_extend(data, size) as i128;
 
             format!(
diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs
index 1ada54cc102..ff4a8b1ad0a 100644
--- a/src/test/ui/symbol-names/impl1.rs
+++ b/src/test/ui/symbol-names/impl1.rs
@@ -3,8 +3,8 @@
 // revisions: legacy v0
 //[legacy]compile-flags: -Z symbol-mangling-version=legacy
     //[v0]compile-flags: -Z symbol-mangling-version=v0
-//[legacy]normalize-stderr-32bit: "hee444285569b39c2" -> "SYMBOL_HASH"
-//[legacy]normalize-stderr-64bit: "h310ea0259fc3d32d" -> "SYMBOL_HASH"
+//[legacy]normalize-stderr-32bit: "h30edc7aa010c48ae" -> "SYMBOL_HASH"
+//[legacy]normalize-stderr-64bit: "h56362331c4f93d19" -> "SYMBOL_HASH"
 
 #![feature(optin_builtin_traits, rustc_attrs)]
 #![allow(dead_code)]
diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs
index c5e33b288a9..b54d2654579 100644
--- a/src/tools/clippy/clippy_lints/src/consts.rs
+++ b/src/tools/clippy/clippy_lints/src/consts.rs
@@ -8,8 +8,9 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty::subst::{Subst, SubstsRef};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, ScalarInt};
 use rustc_middle::{bug, span_bug};
+use rustc_middle::mir::interpret::Scalar;
 use rustc_span::symbol::Symbol;
 use std::cmp::Ordering::{self, Equal};
 use std::convert::TryInto;
@@ -500,21 +501,21 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
 }
 
 pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
-    use rustc_middle::mir::interpret::{ConstValue, Scalar};
+    use rustc_middle::mir::interpret::{ConstValue};
     match result.val {
-        ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data: d, .. })) => {
+        ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw(int))) => {
             match result.ty.kind() {
-                ty::Bool => Some(Constant::Bool(d == 1)),
-                ty::Uint(_) | ty::Int(_) => Some(Constant::Int(d)),
+                ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
+                ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
                 ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
-                    d.try_into().expect("invalid f32 bit representation"),
+                    int.try_into().expect("invalid f32 bit representation"),
                 ))),
                 ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
-                    d.try_into().expect("invalid f64 bit representation"),
+                    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(d));
+                        return Some(Constant::RawPtr(int.assert_bits(int.size())));
                     }
                     None
                 },