diff options
| author | Oliver Scherer <github35764891676564198441@oli-obk.de> | 2020-09-26 15:15:35 +0200 | 
|---|---|---|
| committer | oli <github35764891676564198441@oli-obk.de> | 2020-11-04 09:58:59 +0000 | 
| commit | 362123dd7577daa4cf737bc8f50146beedd3d944 (patch) | |
| tree | d0fa1d0538039e2f7cb227eb6323f07fcc6ba74f | |
| parent | 56293097f7f877f1350a6cd00f79d03132f16515 (diff) | |
| download | rust-362123dd7577daa4cf737bc8f50146beedd3d944.tar.gz rust-362123dd7577daa4cf737bc8f50146beedd3d944.zip  | |
Split the "raw integer bytes" part out of `Scalar`
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/common.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/lib.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/interpret/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/interpret/value.rs | 107 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/mod.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/consts/int.rs | 239 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/print/pretty.rs | 57 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/const_eval/eval_queries.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/const_eval/machine.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/interpret/operand.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/interpret/place.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/transform/const_prop.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/transform/simplify_comparison_integral.rs | 12 | ||||
| -rw-r--r-- | src/librustdoc/clean/utils.rs | 9 | ||||
| -rw-r--r-- | src/test/ui/symbol-names/impl1.rs | 4 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_lints/src/consts.rs | 17 | 
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 },  | 
