From 362123dd7577daa4cf737bc8f50146beedd3d944 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 26 Sep 2020 15:15:35 +0200 Subject: [PATCH 01/26] Split the "raw integer bytes" part out of `Scalar` --- compiler/rustc_codegen_llvm/src/common.rs | 8 +- compiler/rustc_middle/src/lib.rs | 1 + .../rustc_middle/src/mir/interpret/mod.rs | 2 +- .../rustc_middle/src/mir/interpret/value.rs | 107 ++------ compiler/rustc_middle/src/mir/mod.rs | 7 +- compiler/rustc_middle/src/ty/consts/int.rs | 239 +++++++++++++++++- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 57 ++--- .../rustc_mir/src/const_eval/eval_queries.rs | 4 +- compiler/rustc_mir/src/const_eval/machine.rs | 10 +- compiler/rustc_mir/src/interpret/operand.rs | 15 +- compiler/rustc_mir/src/interpret/place.rs | 8 +- .../rustc_mir/src/transform/const_prop.rs | 7 +- .../transform/simplify_comparison_integral.rs | 12 +- src/librustdoc/clean/utils.rs | 9 +- src/test/ui/symbol-names/impl1.rs | 4 +- 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 7633dd0600d5f..8bcb8b62076e7 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 4b915fe020fc3..4a1d5459d1eec 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 b5beb3babe239..c94a882df0124 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 cb8782ce8170a..d3a75cd099e38 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 { /// 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 fmt::Debug for Scalar { 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, "") - } 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 From for Scalar { } 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(self, new_tag: Tag) -> Scalar { 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 { 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 { f_ptr: impl FnOnce(Pointer) -> InterpResult<'tcx, Pointer>, ) -> 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 { #[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, size: Size) -> Option { - 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 { #[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 { #[inline] pub fn try_from_int(i: impl Into, size: Size) -> Option { - 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 { #[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 { ) -> Result> { 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 { 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 b6b6c968501a3..db89a4ad4b64d 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 ced0429deab93..807005b4595e8 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, size: Size) -> Option { + 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, size: Size) -> Option { + 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 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 for ScalarInt { + #[inline] + fn from(c: char) -> Self { + Self { bytes: (c as u128).to_ne_bytes(), size: std::mem::size_of::() as u8 } + } +} + +impl TryFrom 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::())) + .map(|u| char::from_u32(u.try_into().unwrap()).unwrap()) + } +} + +impl From 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 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 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 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, "") + } 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 096c53ca9964c..0a7bec1a342f3 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 fa38bddcae2c5..f972a4cc1ac15 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!("") @@ -987,32 +982,28 @@ pub trait PrettyPrinter<'tcx>: None => p!(""), }, // 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 7b9a4ec873d0a..37bb841a34b87 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 7e2cae094811a..b734c724274af 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 3c68b1c8355d5..bdb72297f0041 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 fe25f8ce962f0..ceae436b18e53 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 d47e549b7be37..620b9ac673a65 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 6372f8960ddb6..2ed27a6ed0a95 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 b0ed233f5ec7f..167b06428e50c 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 1ada54cc102ed..ff4a8b1ad0a5c 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 c5e33b288a9c7..b54d2654579f7 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 { - 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 }, From eac309984fc102f15d5d1d3401d3f53b076f371d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 1 Oct 2020 09:47:36 +0200 Subject: [PATCH 02/26] Encode `ScalarInt::bytes` as `u128` instead of `[u8; 16]` to see if that caused the performance regression --- compiler/rustc_middle/src/ty/consts/int.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 807005b4595e8..cd6c86916d015 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -3,6 +3,7 @@ use crate::throw_ub; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; use rustc_macros::HashStable; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_target::abi::{Size, TargetDataLayout}; use std::convert::{TryFrom, TryInto}; use std::fmt; @@ -115,7 +116,7 @@ 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(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(HashStable)] pub struct ScalarInt { /// The first `size` bytes of `data` are the value. @@ -127,6 +128,19 @@ pub struct ScalarInt { size: u8, } +impl Encodable for ScalarInt { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_u128(self.data())?; + s.emit_u8(self.size) + } +} + +impl Decodable for ScalarInt { + fn decode(d: &mut D) -> Result { + Ok(ScalarInt { bytes: d.read_u128()?.to_ne_bytes(), size: d.read_u8()? }) + } +} + impl ScalarInt { pub const TRUE: ScalarInt = ScalarInt { bytes: 1_u128.to_ne_bytes(), size: 1 }; From ed7a4adeb326c9957b4a2514a69cbae4276ab028 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 1 Oct 2020 12:51:44 +0200 Subject: [PATCH 03/26] 32 bit platforms don't have 64 bit pointers --- compiler/rustc_mir/src/const_eval/eval_queries.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 37bb841a34b87..fce23abdfce30 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, subst::Subst, TyCtxt}; use rustc_span::source_map::Span; use rustc_target::abi::{Abi, LayoutOf}; -use std::convert::{TryFrom, TryInto}; +use std::convert::TryInto; pub fn note_on_undefined_behavior_error() -> &'static str { "The rules on what exactly is undefined behavior aren't clear, \ @@ -140,7 +140,8 @@ pub(super) fn op_to_const<'tcx>( Scalar::Raw(int) => { assert!(mplace.layout.is_zst()); assert_eq!( - u64::try_from(int).unwrap() % mplace.layout.align.abi.bytes(), + int.assert_bits(ecx.tcx.data_layout.pointer_size) + % u128::from(mplace.layout.align.abi.bytes()), 0, "this MPlaceTy must come from a validated constant, thus we can assume the \ alignment is correct", From 02131f4dcd0c85f6b3cc7e8d6a5845a6bdd30ff5 Mon Sep 17 00:00:00 2001 From: oli Date: Thu, 29 Oct 2020 10:15:54 +0000 Subject: [PATCH 04/26] Use packed struct instead of manually packing into an array --- compiler/rustc_middle/src/ty/consts/int.rs | 67 ++++++++++---------- compiler/rustc_middle/src/ty/print/pretty.rs | 8 ++- src/test/ui/symbol-names/impl1.rs | 4 +- 3 files changed, 41 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index cd6c86916d015..6b8e9edc13ccf 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -2,7 +2,6 @@ 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_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_target::abi::{Size, TargetDataLayout}; use std::convert::{TryFrom, TryInto}; @@ -29,7 +28,7 @@ impl std::fmt::Debug for ConstInt { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let Self { int, signed, is_ptr_sized_integral } = *self; let size = int.size().bytes(); - let raw = int.data(); + let raw = int.data; if signed { let bit_size = size * 8; let min = 1u128 << (bit_size - 1); @@ -116,41 +115,46 @@ impl std::fmt::Debug for ConstInt { // FIXME: reuse in `super::int::ConstInt` and `Scalar::Bits` /// The raw bytes of a simple value. +/// +/// This is a packed struct in order to allow this type to be optimally embedded in enums +/// (like Scalar). #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] -#[derive(HashStable)] +#[repr(packed)] 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], + data: u128, size: u8, } +// Cannot derive these, as the derives take references to the fields, and we +// can't take references to fields of packed structs. +impl crate::ty::HashStable for ScalarInt { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut crate::ty::StableHasher) { + { self.data }.hash_stable(hcx, hasher); + self.size.hash_stable(hcx, hasher); + } +} + impl Encodable for ScalarInt { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_u128(self.data())?; + s.emit_u128(self.data)?; s.emit_u8(self.size) } } impl Decodable for ScalarInt { fn decode(d: &mut D) -> Result { - Ok(ScalarInt { bytes: d.read_u128()?.to_ne_bytes(), size: d.read_u8()? }) + Ok(ScalarInt { data: d.read_u128()?, size: d.read_u8()? }) } } impl ScalarInt { - pub const TRUE: ScalarInt = ScalarInt { bytes: 1_u128.to_ne_bytes(), size: 1 }; + pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: 1 }; - pub const FALSE: ScalarInt = ScalarInt { bytes: 0_u128.to_ne_bytes(), size: 1 }; + pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, 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) - } + pub const ZST: ScalarInt = ScalarInt { data: 0_u128, size: 0 }; #[inline] pub fn size(self) -> Size { @@ -164,10 +168,10 @@ impl ScalarInt { #[inline(always)] fn check_data(self) { debug_assert_eq!( - truncate(self.data(), self.size()), - self.data(), + truncate(self.data, self.size()), + { self.data }, "Scalar value {:#x} exceeds size of {} bytes", - self.data(), + { self.data }, self.size ); } @@ -179,7 +183,7 @@ impl ScalarInt { #[inline] pub fn null(size: Size) -> Self { - Self { bytes: [0; 16], size: size.bytes() as u8 } + Self { data: 0, size: size.bytes() as u8 } } pub(crate) fn ptr_sized_op<'tcx>( @@ -188,17 +192,14 @@ impl ScalarInt { 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, - }) + Ok(Self { data: u128::from(f_int(u64::try_from(self.data).unwrap())?), size: self.size }) } #[inline] pub fn try_from_uint(i: impl Into, size: Size) -> Option { let data = i.into(); if truncate(data, size) == data { - Some(Self { bytes: data.to_ne_bytes(), size: size.bytes() as u8 }) + Some(Self { data, size: size.bytes() as u8 }) } else { None } @@ -210,7 +211,7 @@ impl ScalarInt { // `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 }) + Some(Self { data: truncated, size: size.bytes() as u8 }) } else { None } @@ -221,7 +222,7 @@ impl ScalarInt { 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() + self.data } #[inline] @@ -234,7 +235,7 @@ impl ScalarInt { }); } self.check_data(); - Ok(self.data()) + Ok(self.data) } } @@ -245,7 +246,7 @@ macro_rules! from { #[inline] fn from(u: $ty) -> Self { Self { - bytes: u128::from(u).to_ne_bytes(), + data: u128::from(u), size: std::mem::size_of::<$ty>() as u8, } } @@ -274,7 +275,7 @@ try_from!(u8, u16, u32, u64, u128); impl From for ScalarInt { #[inline] fn from(c: char) -> Self { - Self { bytes: (c as u128).to_ne_bytes(), size: std::mem::size_of::() as u8 } + Self { data: c as u128, size: std::mem::size_of::() as u8 } } } @@ -291,7 +292,7 @@ impl From 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 } + Self { data: f.to_bits(), size: 4 } } } @@ -307,7 +308,7 @@ impl From 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 } + Self { data: f.to_bits(), size: 8 } } } @@ -335,6 +336,6 @@ impl fmt::LowerHex for ScalarInt { 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) + write!(f, "{:01$x}", { self.data }, self.size as usize * 2) } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f972a4cc1ac15..27ba6c9d49c52 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -982,8 +982,8 @@ pub trait PrettyPrinter<'tcx>: None => p!(""), }, // Bool - (Scalar::Raw(ScalarInt::FALSE), ty::Bool) => p!("false"), - (Scalar::Raw(ScalarInt::TRUE), ty::Bool) => p!("true"), + (Scalar::Raw(int), ty::Bool) if int == ScalarInt::FALSE => p!("false"), + (Scalar::Raw(int), ty::Bool) if int == ScalarInt::TRUE => p!("true"), // Float (Scalar::Raw(int), ty::Float(ast::FloatTy::F32)) => { p!(write("{}f32", Single::try_from(int).unwrap())) @@ -1025,7 +1025,9 @@ pub trait PrettyPrinter<'tcx>: )?; } // For function type zsts just printing the path is enough - (Scalar::Raw(ScalarInt::ZST), ty::FnDef(d, s)) => p!(print_value_path(*d, s)), + (Scalar::Raw(int), ty::FnDef(d, s)) if int == ScalarInt::ZST => { + p!(print_value_path(*d, s)) + } // Nontrivial types with scalar bit representation (Scalar::Raw(int), _) => { let print = |mut this: Self| { diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index ff4a8b1ad0a5c..1ada54cc102ed 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: "h30edc7aa010c48ae" -> "SYMBOL_HASH" -//[legacy]normalize-stderr-64bit: "h56362331c4f93d19" -> "SYMBOL_HASH" +//[legacy]normalize-stderr-32bit: "hee444285569b39c2" -> "SYMBOL_HASH" +//[legacy]normalize-stderr-64bit: "h310ea0259fc3d32d" -> "SYMBOL_HASH" #![feature(optin_builtin_traits, rustc_attrs)] #![allow(dead_code)] From c47857478628445730af1d464e55a7f980c01837 Mon Sep 17 00:00:00 2001 From: oli Date: Thu, 29 Oct 2020 10:29:26 +0000 Subject: [PATCH 05/26] Explain the use of blocks around `self.data` accesses --- compiler/rustc_middle/src/ty/consts/int.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 6b8e9edc13ccf..298e3f5de6fc3 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -131,6 +131,10 @@ pub struct ScalarInt { // can't take references to fields of packed structs. impl crate::ty::HashStable for ScalarInt { fn hash_stable(&self, hcx: &mut CTX, hasher: &mut crate::ty::StableHasher) { + // Using a block `{self.data}` here to force a copy instead of using `self.data` + // directly, because `hash_stable` takes `&self` and would thus borrow `self.data`. + // Since `Self` is a packed struct, that would create a possibly unaligned reference, + // which is UB on a lot of platforms. { self.data }.hash_stable(hcx, hasher); self.size.hash_stable(hcx, hasher); } @@ -167,6 +171,11 @@ impl ScalarInt { /// construct `Scalar`s). #[inline(always)] fn check_data(self) { + // Using a block `{self.data}` here to force a copy instead of using `self.data` + // directly, because `assert_eq` takes references to its arguments and formatting + // arguments and would thus borrow `self.data`. Since `Self` + // is a packed struct, that would create a possibly unaligned reference, which + // is UB on a lot of platforms. debug_assert_eq!( truncate(self.data, self.size()), { self.data }, @@ -336,6 +345,11 @@ impl fmt::LowerHex for ScalarInt { 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". + // Using a block `{self.data}` here to force a copy instead of using `self.data` + // directly, because `write!` takes references to its formatting arguments and + // would thus borrow `self.data`. Since `Self` + // is a packed struct, that would create a possibly unaligned reference, which + // is UB on a lot of platforms. write!(f, "{:01$x}", { self.data }, self.size as usize * 2) } } From 3a7970848cf3b525e94357fc9b01053b1ad15bcd Mon Sep 17 00:00:00 2001 From: oli Date: Thu, 29 Oct 2020 13:30:47 +0000 Subject: [PATCH 06/26] Fix cranelift build --- compiler/rustc_codegen_cranelift/src/base.rs | 3 ++- compiler/rustc_codegen_cranelift/src/constant.rs | 5 ++--- .../rustc_codegen_cranelift/src/discriminant.rs | 7 ++++--- .../rustc_codegen_cranelift/src/intrinsics/mod.rs | 3 ++- .../rustc_codegen_cranelift/src/value_and_place.rs | 6 ++++-- compiler/rustc_middle/src/ty/consts/int.rs | 14 ++++++++++++++ 6 files changed, 28 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 5474e5960f100..2097f9d288705 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -499,7 +499,7 @@ fn codegen_stmt<'tcx>( UnOp::Neg => match layout.ty.kind() { ty::Int(IntTy::I128) => { // FIXME remove this case once ineg.i128 works - let zero = CValue::const_val(fx, layout, 0); + let zero = CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size)); crate::num::codegen_int_binop(fx, BinOp::Sub, zero, operand) } ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout), @@ -592,6 +592,7 @@ fn codegen_stmt<'tcx>( } else { discr.val }; + let discr = discr.into(); let discr = CValue::const_val(fx, fx.layout_of(to_ty), discr); lval.write_cvalue(fx, discr); diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index ce1d5ed2e6178..d362a0273730e 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -186,9 +186,8 @@ pub(crate) fn codegen_const_value<'tcx>( } match x { - Scalar::Raw { data, size } => { - assert_eq!(u64::from(size), layout.size.bytes()); - CValue::const_val(fx, layout, data) + Scalar::Raw(int) => { + CValue::const_val(fx, layout, int) } Scalar::Ptr(ptr) => { let alloc_kind = fx.tcx.get_global_alloc(ptr.alloc_id); diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs index d15bc36ad05ef..6c9fb8e051b3c 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -30,7 +30,8 @@ pub(crate) fn codegen_set_discriminant<'tcx>( .ty .discriminant_for_variant(fx.tcx, variant_index) .unwrap() - .val; + .val + .into(); let discr = CValue::const_val(fx, ptr.layout(), to); ptr.write_cvalue(fx, discr); } @@ -49,7 +50,7 @@ pub(crate) fn codegen_set_discriminant<'tcx>( let niche = place.place_field(fx, mir::Field::new(tag_field)); let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); let niche_value = u128::from(niche_value).wrapping_add(niche_start); - let niche_llval = CValue::const_val(fx, niche.layout(), niche_value); + let niche_llval = CValue::const_val(fx, niche.layout(), niche_value.into()); niche.write_cvalue(fx, niche_llval); } } @@ -77,7 +78,7 @@ pub(crate) fn codegen_get_discriminant<'tcx>( .ty .discriminant_for_variant(fx.tcx, *index) .map_or(u128::from(index.as_u32()), |discr| discr.val); - return CValue::const_val(fx, dest_layout, discr_val); + return CValue::const_val(fx, dest_layout, discr_val.into()); } Variants::Multiple { tag, diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index a5f45b7abf4c8..ab16fabd348a5 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1064,7 +1064,8 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( fx.bcx.ins().call_indirect(f_sig, f, &[data]); - let ret_val = CValue::const_val(fx, ret.layout(), 0); + let layout = ret.layout(); + let ret_val = CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size)); ret.write_cvalue(fx, ret_val); }; diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 2b9ea5273b608..a40686b193197 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -231,15 +231,16 @@ impl<'tcx> CValue<'tcx> { pub(crate) fn const_val( fx: &mut FunctionCx<'_, 'tcx, impl Module>, layout: TyAndLayout<'tcx>, - const_val: u128, + const_val: ty::ScalarInt, ) -> CValue<'tcx> { + assert_eq!(const_val.size(), layout.size); use cranelift_codegen::ir::immediates::{Ieee32, Ieee64}; let clif_ty = fx.clif_type(layout.ty).unwrap(); if let ty::Bool = layout.ty.kind() { assert!( - const_val == 0 || const_val == 1, + const_val == ty::ScalarInt::FALSE || const_val == ty::ScalarInt::TRUE, "Invalid bool 0x{:032X}", const_val ); @@ -247,6 +248,7 @@ impl<'tcx> CValue<'tcx> { let val = match layout.ty.kind() { ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => { + let const_val = const_val.to_bits(layout.size).unwrap(); let lsb = fx.bcx.ins().iconst(types::I64, const_val as u64 as i64); let msb = fx .bcx diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 298e3f5de6fc3..32e0eac00a741 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -353,3 +353,17 @@ impl fmt::LowerHex for ScalarInt { write!(f, "{:01$x}", { self.data }, self.size as usize * 2) } } + +impl fmt::UpperHex 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". + // Using a block `{self.data}` here to force a copy instead of using `self.data` + // directly, because `write!` takes references to its formatting arguments and + // would thus borrow `self.data`. Since `Self` + // is a packed struct, that would create a possibly unaligned reference, which + // is UB on a lot of platforms. + write!(f, "{:01$X}", { self.data }, self.size as usize * 2) + } +} From df4d717d0b150375057bd067356a4c7fe3c27551 Mon Sep 17 00:00:00 2001 From: oli Date: Sun, 1 Nov 2020 16:57:03 +0000 Subject: [PATCH 07/26] s/Scalar::Raw/Scalar::Int --- .../rustc_codegen_cranelift/src/constant.rs | 2 +- compiler/rustc_codegen_llvm/src/common.rs | 4 +- .../rustc_middle/src/mir/interpret/value.rs | 44 +++++++++---------- compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 18 ++++---- .../rustc_mir/src/const_eval/eval_queries.rs | 4 +- compiler/rustc_mir/src/const_eval/machine.rs | 8 ++-- compiler/rustc_mir/src/interpret/operand.rs | 4 +- compiler/rustc_mir/src/interpret/place.rs | 2 +- .../transform/simplify_comparison_integral.rs | 2 +- compiler/rustc_mir/src/util/pretty.rs | 2 +- compiler/rustc_symbol_mangling/src/legacy.rs | 2 +- src/tools/clippy/clippy_lints/src/consts.rs | 2 +- 13 files changed, 48 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index d362a0273730e..41cfae4ca6e26 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -186,7 +186,7 @@ pub(crate) fn codegen_const_value<'tcx>( } match x { - Scalar::Raw(int) => { + Scalar::Int(int) => { CValue::const_val(fx, layout, int) } Scalar::Ptr(ptr) => { diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 8bcb8b62076e7..34e1b7a60451e 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -230,11 +230,11 @@ 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(ScalarInt::ZST) => { + Scalar::Int(ScalarInt::ZST) => { assert_eq!(0, layout.value.size(self).bytes()); self.const_undef(self.type_ix(0)) } - Scalar::Raw(int) => { + Scalar::Int(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 { diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index d3a75cd099e38..c0fff98dc55b2 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -103,7 +103,7 @@ impl<'tcx> ConstValue<'tcx> { #[derive(HashStable)] pub enum Scalar { /// The raw bytes of a simple value. - Raw(ScalarInt), + Int(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 @@ -120,7 +120,7 @@ impl fmt::Debug for Scalar { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(ptr) => write!(f, "{:?}", ptr), - Scalar::Raw(int) => write!(f, "{:?}", int), + Scalar::Int(int) => write!(f, "{:?}", int), } } } @@ -129,7 +129,7 @@ impl fmt::Display for Scalar { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(ptr) => write!(f, "pointer to {}", ptr), - Scalar::Raw { .. } => fmt::Debug::fmt(self, f), + Scalar::Int { .. } => fmt::Debug::fmt(self, f), } } } @@ -156,7 +156,7 @@ impl Scalar<()> { pub fn with_tag(self, new_tag: Tag) -> Scalar { match self { Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_tag(new_tag)), - Scalar::Raw(int) => Scalar::Raw(int), + Scalar::Int(int) => Scalar::Int(int), } } } @@ -169,18 +169,18 @@ impl<'tcx, Tag> Scalar { pub fn erase_tag(self) -> Scalar { match self { Scalar::Ptr(ptr) => Scalar::Ptr(ptr.erase_tag()), - Scalar::Raw(int) => Scalar::Raw(int), + Scalar::Int(int) => Scalar::Int(int), } } #[inline] pub fn null_ptr(cx: &impl HasDataLayout) -> Self { - Scalar::Raw(ScalarInt::null(cx.data_layout().pointer_size)) + Scalar::Int(ScalarInt::null(cx.data_layout().pointer_size)) } #[inline] pub fn zst() -> Self { - Scalar::Raw(ScalarInt::zst()) + Scalar::Int(ScalarInt::zst()) } #[inline(always)] @@ -191,7 +191,7 @@ impl<'tcx, Tag> Scalar { f_ptr: impl FnOnce(Pointer) -> InterpResult<'tcx, Pointer>, ) -> InterpResult<'tcx, Self> { match self { - Scalar::Raw(int) => Ok(Scalar::Raw(int.ptr_sized_op(dl, f_int)?)), + Scalar::Int(int) => Ok(Scalar::Int(int.ptr_sized_op(dl, f_int)?)), Scalar::Ptr(ptr) => Ok(Scalar::Ptr(f_ptr(ptr)?)), } } @@ -232,17 +232,17 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn from_bool(b: bool) -> Self { - Scalar::Raw(b.into()) + Scalar::Int(b.into()) } #[inline] pub fn from_char(c: char) -> Self { - Scalar::Raw(c.into()) + Scalar::Int(c.into()) } #[inline] pub fn try_from_uint(i: impl Into, size: Size) -> Option { - ScalarInt::try_from_uint(i, size).map(Scalar::Raw) + ScalarInt::try_from_uint(i, size).map(Scalar::Int) } #[inline] @@ -254,22 +254,22 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn from_u8(i: u8) -> Self { - Scalar::Raw(i.into()) + Scalar::Int(i.into()) } #[inline] pub fn from_u16(i: u16) -> Self { - Scalar::Raw(i.into()) + Scalar::Int(i.into()) } #[inline] pub fn from_u32(i: u32) -> Self { - Scalar::Raw(i.into()) + Scalar::Int(i.into()) } #[inline] pub fn from_u64(i: u64) -> Self { - Scalar::Raw(i.into()) + Scalar::Int(i.into()) } #[inline] @@ -279,7 +279,7 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn try_from_int(i: impl Into, size: Size) -> Option { - ScalarInt::try_from_int(i, size).map(Scalar::Raw) + ScalarInt::try_from_int(i, size).map(Scalar::Int) } #[inline] @@ -316,12 +316,12 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn from_f32(f: Single) -> Self { - Scalar::Raw(f.into()) + Scalar::Int(f.into()) } #[inline] pub fn from_f64(f: Double) -> Self { - Scalar::Raw(f.into()) + Scalar::Int(f.into()) } /// This is very rarely the method you want! You should dispatch on the type @@ -336,7 +336,7 @@ impl<'tcx, Tag> Scalar { ) -> Result> { assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); match self { - Scalar::Raw(int) => Ok(int.assert_bits(target_size)), + Scalar::Int(int) => Ok(int.assert_bits(target_size)), Scalar::Ptr(ptr) => { assert_eq!(target_size, cx.data_layout().pointer_size); Err(ptr) @@ -350,7 +350,7 @@ impl<'tcx, Tag> Scalar { 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(int) => int.to_bits(target_size), + Scalar::Int(int) => int.to_bits(target_size), Scalar::Ptr(_) => throw_unsup!(ReadPointerAsBytes), } } @@ -364,14 +364,14 @@ impl<'tcx, Tag> Scalar { pub fn assert_ptr(self) -> Pointer { match self { Scalar::Ptr(p) => p, - Scalar::Raw { .. } => bug!("expected a Pointer but got Raw bits"), + Scalar::Int { .. } => bug!("expected a Pointer but got Raw bits"), } } /// Do not call this method! Dispatch based on the type instead. #[inline] pub fn is_bits(self) -> bool { - matches!(self, Scalar::Raw { .. }) + matches!(self, Scalar::Int { .. }) } /// Do not call this method! Dispatch based on the type instead. diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index db89a4ad4b64d..bf091201e1004 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1952,7 +1952,7 @@ impl<'tcx> Operand<'tcx> { .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e)) .size; let scalar_size = match val { - Scalar::Raw(int) => int.size(), + Scalar::Int(int) => int.size(), _ => panic!("Invalid scalar type {:?}", val), }; scalar_size == type_size diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 27ba6c9d49c52..8ff4adda606e2 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -982,27 +982,27 @@ pub trait PrettyPrinter<'tcx>: None => p!(""), }, // Bool - (Scalar::Raw(int), ty::Bool) if int == ScalarInt::FALSE => p!("false"), - (Scalar::Raw(int), ty::Bool) if int == ScalarInt::TRUE => p!("true"), + (Scalar::Int(int), ty::Bool) if int == ScalarInt::FALSE => p!("false"), + (Scalar::Int(int), ty::Bool) if int == ScalarInt::TRUE => p!("true"), // Float - (Scalar::Raw(int), ty::Float(ast::FloatTy::F32)) => { + (Scalar::Int(int), ty::Float(ast::FloatTy::F32)) => { p!(write("{}f32", Single::try_from(int).unwrap())) } - (Scalar::Raw(int), ty::Float(ast::FloatTy::F64)) => { + (Scalar::Int(int), ty::Float(ast::FloatTy::F64)) => { p!(write("{}f64", Double::try_from(int).unwrap())) } // Int - (Scalar::Raw(int), ty::Uint(_) | ty::Int(_)) => { + (Scalar::Int(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(int), ty::Char) if char::try_from(int).is_ok() => { + (Scalar::Int(int), ty::Char) if char::try_from(int).is_ok() => { p!(write("{:?}", char::try_from(int).unwrap())) } // Raw pointers - (Scalar::Raw(int), ty::RawPtr(_)) => { + (Scalar::Int(int), ty::RawPtr(_)) => { let data = int.assert_bits(self.tcx().data_layout.pointer_size); self = self.typed_value( |mut this| { @@ -1025,11 +1025,11 @@ pub trait PrettyPrinter<'tcx>: )?; } // For function type zsts just printing the path is enough - (Scalar::Raw(int), ty::FnDef(d, s)) if int == ScalarInt::ZST => { + (Scalar::Int(int), ty::FnDef(d, s)) if int == ScalarInt::ZST => { p!(print_value_path(*d, s)) } // Nontrivial types with scalar bit representation - (Scalar::Raw(int), _) => { + (Scalar::Int(int), _) => { let print = |mut this: Self| { if int.size() == Size::ZERO { write!(this, "transmute(())")?; diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index fce23abdfce30..a5edfbd9367aa 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -137,7 +137,7 @@ 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(int) => { + Scalar::Int(int) => { assert!(mplace.layout.is_zst()); assert_eq!( int.assert_bits(ecx.tcx.data_layout.pointer_size) @@ -162,7 +162,7 @@ pub(super) fn op_to_const<'tcx>( Scalar::Ptr(ptr) => { (ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(), ptr.offset.bytes()) } - Scalar::Raw { .. } => ( + Scalar::Int { .. } => ( ecx.tcx .intern_const_alloc(Allocation::from_byte_aligned_bytes(b"" as &[u8])), 0, diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index b734c724274af..5fe393bf43235 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -181,9 +181,9 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> bool { match (a, b) { // Comparisons between integers are always known. - (Scalar::Raw { .. }, Scalar::Raw { .. }) => a == b, + (Scalar::Int { .. }, Scalar::Int { .. }) => a == b, // Equality with integers can never be known for sure. - (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false, + (Scalar::Int { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Int { .. }) => false, // FIXME: return `true` for when both sides are the same pointer, *except* that // some things (like functions and vtables) do not have stable addresses // so we need to be careful around them (see e.g. #73722). @@ -194,11 +194,11 @@ 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::Int(_), Scalar::Int(_)) => 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. // Inequality with integers other than null can never be known for sure. - (Scalar::Raw(int), Scalar::Ptr(ptr)) | (Scalar::Ptr(ptr), Scalar::Raw(int)) => { + (Scalar::Int(int), Scalar::Ptr(ptr)) | (Scalar::Ptr(ptr), Scalar::Int(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 diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index bdb72297f0041..2fa73df2d60fd 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -212,7 +212,7 @@ impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> { pub fn to_const_int(self) -> ConstInt { assert!(self.layout.ty.is_integral()); let int = match self.to_scalar().expect("to_const_int doesn't work on scalar pairs") { - Scalar::Raw(int) => int, + Scalar::Int(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()) @@ -541,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(int) => Scalar::Raw(int), + Scalar::Int(int) => Scalar::Int(int), }) }; // Early-return cases. diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs index ceae436b18e53..3e10d0960a88a 100644 --- a/compiler/rustc_mir/src/interpret/place.rs +++ b/compiler/rustc_mir/src/interpret/place.rs @@ -721,7 +721,7 @@ where dest.layout.size, "Size mismatch when writing pointer" ), - Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::Raw(int))) => { + Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::Int(int))) => { assert_eq!(int.size(), dest.layout.size, "Size mismatch when writing bits") } Immediate::Scalar(ScalarMaybeUninit::Uninit) => {} // uninit can have any size diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs index 2ed27a6ed0a95..ea56080c75216 100644 --- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs +++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs @@ -40,7 +40,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { let bbs = &mut body.basic_blocks_mut(); let bb = &mut bbs[opt.bb_idx]; let new_value = match opt.branch_value_scalar { - Scalar::Raw(int) => { + Scalar::Int(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"); diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 5700492d6bbc7..8bee8417c51fa 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -630,7 +630,7 @@ pub fn write_allocations<'tcx>( ConstValue::Scalar(interpret::Scalar::Ptr(ptr)) => { Either::Left(Either::Left(std::iter::once(ptr.alloc_id))) } - ConstValue::Scalar(interpret::Scalar::Raw { .. }) => { + ConstValue::Scalar(interpret::Scalar::Int { .. }) => { Either::Left(Either::Right(std::iter::empty())) } ConstValue::ByRef { alloc, .. } | ConstValue::Slice { data: alloc, .. } => { diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index e8d470297ea6c..ac91fcf62937a 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -237,7 +237,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result { // only print integers - if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { .. })) = ct.val { + if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int { .. })) = ct.val { if ct.ty.is_integral() { return self.pretty_print_const(ct, true); } diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs index b54d2654579f7..c8bbc9ce2b028 100644 --- a/src/tools/clippy/clippy_lints/src/consts.rs +++ b/src/tools/clippy/clippy_lints/src/consts.rs @@ -503,7 +503,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { pub fn miri_to_const(result: &ty::Const<'_>) -> Option { use rustc_middle::mir::interpret::{ConstValue}; match result.val { - ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw(int))) => { + 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()))), From e5258e6143f9663d9bb0175bd3277602c6f2b8ad Mon Sep 17 00:00:00 2001 From: oli Date: Sun, 1 Nov 2020 16:58:16 +0000 Subject: [PATCH 08/26] Remove outdated FIXME --- compiler/rustc_middle/src/ty/consts/int.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 32e0eac00a741..043dd957b749f 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -113,7 +113,6 @@ impl std::fmt::Debug for ConstInt { } } -// FIXME: reuse in `super::int::ConstInt` and `Scalar::Bits` /// The raw bytes of a simple value. /// /// This is a packed struct in order to allow this type to be optimally embedded in enums From 1eb300ede104d8da439d308dd3193f4448ed442b Mon Sep 17 00:00:00 2001 From: oli Date: Sun, 1 Nov 2020 16:59:00 +0000 Subject: [PATCH 09/26] Unaligned reads are UB in Rust irrelevant on which platform we are --- compiler/rustc_middle/src/ty/consts/int.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 043dd957b749f..bdb6e4e966067 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -133,7 +133,7 @@ impl crate::ty::HashStable for ScalarInt { // Using a block `{self.data}` here to force a copy instead of using `self.data` // directly, because `hash_stable` takes `&self` and would thus borrow `self.data`. // Since `Self` is a packed struct, that would create a possibly unaligned reference, - // which is UB on a lot of platforms. + // which is UB. { self.data }.hash_stable(hcx, hasher); self.size.hash_stable(hcx, hasher); } @@ -174,7 +174,7 @@ impl ScalarInt { // directly, because `assert_eq` takes references to its arguments and formatting // arguments and would thus borrow `self.data`. Since `Self` // is a packed struct, that would create a possibly unaligned reference, which - // is UB on a lot of platforms. + // is UB. debug_assert_eq!( truncate(self.data, self.size()), { self.data }, @@ -348,7 +348,7 @@ impl fmt::LowerHex for ScalarInt { // directly, because `write!` takes references to its formatting arguments and // would thus borrow `self.data`. Since `Self` // is a packed struct, that would create a possibly unaligned reference, which - // is UB on a lot of platforms. + // is UB. write!(f, "{:01$x}", { self.data }, self.size as usize * 2) } } @@ -362,7 +362,7 @@ impl fmt::UpperHex for ScalarInt { // directly, because `write!` takes references to its formatting arguments and // would thus borrow `self.data`. Since `Self` // is a packed struct, that would create a possibly unaligned reference, which - // is UB on a lot of platforms. + // is UB. write!(f, "{:01$X}", { self.data }, self.size as usize * 2) } } From 3ef9dfdd425e061a71dd5ca168c2dfec03699754 Mon Sep 17 00:00:00 2001 From: oli Date: Sun, 1 Nov 2020 17:00:09 +0000 Subject: [PATCH 10/26] Update comment --- compiler/rustc_middle/src/ty/consts/int.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index bdb6e4e966067..4b842b75461e4 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -165,9 +165,8 @@ impl ScalarInt { } /// 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). + /// This is guaranteed by all constructors here, but having had this check saved us from + /// bugs many times in the past, so keeping it around is definitely worth it. #[inline(always)] fn check_data(self) { // Using a block `{self.data}` here to force a copy instead of using `self.data` From b8751c1fbb6489916a3fea9378e493710d2765ba Mon Sep 17 00:00:00 2001 From: oli Date: Sun, 1 Nov 2020 17:01:34 +0000 Subject: [PATCH 11/26] No need for a `zst` constructor method when we can have a constant --- compiler/rustc_middle/src/mir/interpret/value.rs | 2 +- compiler/rustc_middle/src/ty/consts/int.rs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index c0fff98dc55b2..d297482c1b69f 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -180,7 +180,7 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn zst() -> Self { - Scalar::Int(ScalarInt::zst()) + Scalar::Int(ScalarInt::ZST) } #[inline(always)] diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 4b842b75461e4..f9593c367b95c 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -183,11 +183,6 @@ impl ScalarInt { ); } - #[inline] - pub fn zst() -> Self { - Self::null(Size::ZERO) - } - #[inline] pub fn null(size: Size) -> Self { Self { data: 0, size: size.bytes() as u8 } From 8282d526e0dc7d59b4c939c2a4d66858ab0dfcc0 Mon Sep 17 00:00:00 2001 From: oli Date: Sun, 1 Nov 2020 17:04:13 +0000 Subject: [PATCH 12/26] Replace `Scalar::zst` with a `Scalar::ZST` constant --- compiler/rustc_middle/src/mir/interpret/value.rs | 5 +---- compiler/rustc_middle/src/ty/consts.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_mir/src/const_eval/eval_queries.rs | 2 +- compiler/rustc_mir/src/interpret/operand.rs | 6 +++--- 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index d297482c1b69f..2a879302d0d3b 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -178,10 +178,7 @@ impl<'tcx, Tag> Scalar { Scalar::Int(ScalarInt::null(cx.data_layout().pointer_size)) } - #[inline] - pub fn zst() -> Self { - Scalar::Int(ScalarInt::ZST) - } + pub const ZST: Self = Scalar::Int(ScalarInt::ZST); #[inline(always)] fn ptr_op( diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 64faacc1c0bc2..0af884a286d6e 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -132,7 +132,7 @@ impl<'tcx> Const<'tcx> { #[inline] /// Creates an interned zst constant. pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Self { - Self::from_scalar(tcx, Scalar::zst(), ty) + Self::from_scalar(tcx, Scalar::ZST, ty) } #[inline] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f6ea6743a0e04..216451f268f4e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -844,7 +844,7 @@ impl<'tcx> CommonConsts<'tcx> { CommonConsts { unit: mk_const(ty::Const { - val: ty::ConstKind::Value(ConstValue::Scalar(Scalar::zst())), + val: ty::ConstKind::Value(ConstValue::Scalar(Scalar::ZST)), ty: types.unit, }), } diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index a5edfbd9367aa..f1631d1b4401f 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -146,7 +146,7 @@ pub(super) fn op_to_const<'tcx>( "this MPlaceTy must come from a validated constant, thus we can assume the \ alignment is correct", ); - ConstValue::Scalar(Scalar::zst()) + ConstValue::Scalar(Scalar::ZST) } }; match immediate { diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 2fa73df2d60fd..55672a201eeff 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -259,7 +259,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } return Ok(Some(ImmTy { // zero-sized type - imm: Scalar::zst().into(), + imm: Scalar::ZST.into(), layout: mplace.layout, })); } @@ -358,7 +358,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let field_layout = op.layout.field(self, field)?; if field_layout.is_zst() { - let immediate = Scalar::zst().into(); + let immediate = Scalar::ZST.into(); return Ok(OpTy { op: Operand::Immediate(immediate), layout: field_layout }); } let offset = op.layout.fields.offset(field); @@ -443,7 +443,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = self.layout_of_local(frame, local, layout)?; let op = if layout.is_zst() { // Do not read from ZST, they might not be initialized - Operand::Immediate(Scalar::zst().into()) + Operand::Immediate(Scalar::ZST.into()) } else { M::access_local(&self, frame, local)? }; From d1074edb64723092e06ba5267b9482422e569b7b Mon Sep 17 00:00:00 2001 From: oli Date: Sun, 1 Nov 2020 17:14:09 +0000 Subject: [PATCH 13/26] catch conversion errors during `ptr_sized_op` --- compiler/rustc_middle/src/ty/consts/int.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index f9593c367b95c..ec84bff18cd9f 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -194,7 +194,7 @@ impl ScalarInt { f_int: impl FnOnce(u64) -> InterpResult<'tcx, u64>, ) -> InterpResult<'tcx, Self> { assert_eq!(u64::from(self.size), dl.pointer_size.bytes()); - Ok(Self { data: u128::from(f_int(u64::try_from(self.data).unwrap())?), size: self.size }) + Ok(Self::try_from_uint(f_int(u64::try_from(self.data).unwrap())?, self.size).unwrap()) } #[inline] From 0347ca7d02276c8f395bac553d7df400cc10548e Mon Sep 17 00:00:00 2001 From: oli Date: Sun, 1 Nov 2020 17:15:11 +0000 Subject: [PATCH 14/26] Explain why we forward to self-printing during self-printing --- compiler/rustc_middle/src/ty/consts/int.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index ec84bff18cd9f..838e9819b0fcd 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -194,7 +194,7 @@ impl ScalarInt { f_int: impl FnOnce(u64) -> InterpResult<'tcx, u64>, ) -> InterpResult<'tcx, Self> { assert_eq!(u64::from(self.size), dl.pointer_size.bytes()); - Ok(Self::try_from_uint(f_int(u64::try_from(self.data).unwrap())?, self.size).unwrap()) + Ok(Self::try_from_uint(f_int(u64::try_from(self.data).unwrap())?, self.size()).unwrap()) } #[inline] @@ -328,6 +328,7 @@ impl fmt::Debug for ScalarInt { self.check_data(); write!(f, "") } else { + // Dispatch to LowerHex below. write!(f, "0x{:x}", self) } } From f03b18b99b683c25a584344f73cdf9704d77b719 Mon Sep 17 00:00:00 2001 From: oli Date: Sun, 1 Nov 2020 17:17:04 +0000 Subject: [PATCH 15/26] Add `is_null` helper This is cheaper than creating a null-`ScalarInt` and comparing and then just throwing it away. --- compiler/rustc_middle/src/ty/consts/int.rs | 5 +++++ compiler/rustc_mir/src/const_eval/machine.rs | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 838e9819b0fcd..89d9ba2c0c34b 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -188,6 +188,11 @@ impl ScalarInt { Self { data: 0, size: size.bytes() as u8 } } + #[inline] + pub fn is_null(self) -> bool { + self.data == 0 + } + pub(crate) fn ptr_sized_op<'tcx>( self, dl: &TargetDataLayout, diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 5fe393bf43235..c72089ec55a99 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, ScalarInt, Ty}; +use rustc_middle::ty::{self, Ty}; use std::borrow::Borrow; use std::collections::hash_map::Entry; use std::hash::Hash; @@ -199,7 +199,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { // is in bounds, because if they are in bounds, the pointer can't be null. // Inequality with integers other than null can never be known for sure. (Scalar::Int(int), Scalar::Ptr(ptr)) | (Scalar::Ptr(ptr), Scalar::Int(int)) => { - int == ScalarInt::null(int.size()) && !self.memory.ptr_may_be_null(ptr) + int.is_null() && !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. From 500af76831e2babd8a1189eac2dffd82bc6db6ac Mon Sep 17 00:00:00 2001 From: oli Date: Sun, 1 Nov 2020 17:21:33 +0000 Subject: [PATCH 16/26] Add helper for getting an `int` out of a `Scalar` --- compiler/rustc_middle/src/mir/interpret/value.rs | 8 ++++++++ compiler/rustc_mir/src/interpret/operand.rs | 5 +---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 2a879302d0d3b..53bbbb8cddbbb 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -357,6 +357,14 @@ impl<'tcx, Tag> Scalar { self.to_bits(target_size).expect("expected Raw bits but got a Pointer") } + #[inline] + pub fn assert_int(self) -> ScalarInt { + match self { + Scalar::Ptr(_) => bug!("expected an int but got an abstract pointer"), + Scalar::Int(int) => int, + } + } + #[inline] pub fn assert_ptr(self) -> Pointer { match self { diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 55672a201eeff..8716d4d9ad7f0 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -211,10 +211,7 @@ impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> { #[inline] pub fn to_const_int(self) -> ConstInt { assert!(self.layout.ty.is_integral()); - let int = match self.to_scalar().expect("to_const_int doesn't work on scalar pairs") { - Scalar::Int(int) => int, - Scalar::Ptr(_) => bug!("to_const_int doesn't work on pointers"), - }; + let int = self.to_scalar().expect("to_const_int doesn't work on scalar pairs").assert_int(); ConstInt::new(int, self.layout.ty.is_signed(), self.layout.ty.is_ptr_sized_integral()) } } From dad0036cb4af6e641dbb85e5b5522070cfe8233d Mon Sep 17 00:00:00 2001 From: oli Date: Sun, 1 Nov 2020 17:30:33 +0000 Subject: [PATCH 17/26] Do not raise interp errors from the scalar int module --- .../rustc_middle/src/mir/interpret/mod.rs | 2 +- .../rustc_middle/src/mir/interpret/value.rs | 8 ++++- compiler/rustc_middle/src/ty/consts/int.rs | 33 +++++++++---------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index c94a882df0124..b5beb3babe239 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::($crate::err_ub!($($tt)*))? }; + ($($tt:tt)*) => { Err::(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 53bbbb8cddbbb..2830b0e43f501 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -347,7 +347,13 @@ impl<'tcx, Tag> Scalar { 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::Int(int) => int.to_bits(target_size), + Scalar::Int(int) => int.to_bits(target_size).map_err(|size| { + err_ub!(ScalarSizeMismatch { + target_size: target_size.bytes(), + data_size: size.bytes(), + }) + .into() + }), Scalar::Ptr(_) => throw_unsup!(ReadPointerAsBytes), } } diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 89d9ba2c0c34b..901b7571abb8f 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -1,5 +1,4 @@ -use crate::mir::interpret::{sign_extend, truncate, InterpErrorInfo, InterpResult}; -use crate::throw_ub; +use crate::mir::interpret::{sign_extend, truncate, InterpResult}; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -233,16 +232,14 @@ impl ScalarInt { } #[inline] - pub fn to_bits(self, target_size: Size) -> InterpResult<'static, u128> { + pub fn to_bits(self, target_size: Size) -> Result { 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), - }); + if target_size.bytes() == u64::from(self.size) { + self.check_data(); + Ok(self.data) + } else { + Err(self.size()) } - self.check_data(); - Ok(self.data) } } @@ -266,9 +263,9 @@ macro_rules! try_from { ($($ty:ty),*) => { $( impl TryFrom for $ty { - type Error = InterpErrorInfo<'static>; + type Error = Size; #[inline] - fn try_from(int: ScalarInt) -> InterpResult<'static, Self> { + fn try_from(int: ScalarInt) -> Result { int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>())).map(|u| u.try_into().unwrap()) } } @@ -287,9 +284,9 @@ impl From for ScalarInt { } impl TryFrom for char { - type Error = InterpErrorInfo<'static>; + type Error = Size; #[inline] - fn try_from(int: ScalarInt) -> InterpResult<'static, Self> { + fn try_from(int: ScalarInt) -> Result { int.to_bits(Size::from_bytes(std::mem::size_of::())) .map(|u| char::from_u32(u.try_into().unwrap()).unwrap()) } @@ -304,9 +301,9 @@ impl From for ScalarInt { } impl TryFrom for Single { - type Error = InterpErrorInfo<'static>; + type Error = Size; #[inline] - fn try_from(int: ScalarInt) -> InterpResult<'static, Self> { + fn try_from(int: ScalarInt) -> Result { int.to_bits(Size::from_bytes(4)).map(Self::from_bits) } } @@ -320,9 +317,9 @@ impl From for ScalarInt { } impl TryFrom for Double { - type Error = InterpErrorInfo<'static>; + type Error = Size; #[inline] - fn try_from(int: ScalarInt) -> InterpResult<'static, Self> { + fn try_from(int: ScalarInt) -> Result { int.to_bits(Size::from_bytes(8)).map(Self::from_bits) } } From 98b70c9ac09fbcace3ab1ba9f1154abc73ac1848 Mon Sep 17 00:00:00 2001 From: oli Date: Sun, 1 Nov 2020 17:32:51 +0000 Subject: [PATCH 18/26] Simplify `assert_bits` impl --- compiler/rustc_middle/src/ty/consts/int.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 901b7571abb8f..fd5f9d6ff1c9c 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -225,10 +225,9 @@ impl ScalarInt { #[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 + self.to_bits(target_size).unwrap_or_else(|size| { + bug!("int of size {}, but is {}", target_size.bytes(), size.bytes()) + }) } #[inline] From cb1cf6ae959f9b494a3d109dd84ebb49650da010 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 2 Nov 2020 12:52:52 +0100 Subject: [PATCH 19/26] Update compiler/rustc_middle/src/ty/consts/int.rs Co-authored-by: Ralf Jung --- compiler/rustc_middle/src/ty/consts/int.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index fd5f9d6ff1c9c..8308cfddb4385 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -226,7 +226,7 @@ impl ScalarInt { #[inline] pub fn assert_bits(self, target_size: Size) -> u128 { self.to_bits(target_size).unwrap_or_else(|size| { - bug!("int of size {}, but is {}", target_size.bytes(), size.bytes()) + bug!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes()) }) } From e67c768110f2cd55d6823defcbfca5651fe1f9f5 Mon Sep 17 00:00:00 2001 From: oli Date: Mon, 2 Nov 2020 11:54:06 +0000 Subject: [PATCH 20/26] Move ZST constant to the top of the impl block --- compiler/rustc_middle/src/mir/interpret/value.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 2830b0e43f501..a191dd1d705f7 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -162,6 +162,8 @@ impl Scalar<()> { } impl<'tcx, Tag> Scalar { + pub const ZST: Self = Scalar::Int(ScalarInt::ZST); + /// Erase the tag from the scalar, if any. /// /// Used by error reporting code to avoid having the error type depend on `Tag`. @@ -178,8 +180,6 @@ impl<'tcx, Tag> Scalar { Scalar::Int(ScalarInt::null(cx.data_layout().pointer_size)) } - pub const ZST: Self = Scalar::Int(ScalarInt::ZST); - #[inline(always)] fn ptr_op( self, From abacaf2aef26043ce09e3aee176a9587bb87eaf6 Mon Sep 17 00:00:00 2001 From: oli Date: Wed, 4 Nov 2020 13:41:58 +0000 Subject: [PATCH 21/26] `u128` truncation and sign extension are not just interpreter related --- compiler/rustc_codegen_cranelift/src/base.rs | 5 +-- .../src/debuginfo/metadata.rs | 3 +- compiler/rustc_lint/src/types.rs | 5 ++- .../rustc_middle/src/mir/interpret/mod.rs | 35 +------------------ .../rustc_middle/src/mir/interpret/value.rs | 6 ++-- compiler/rustc_middle/src/ty/consts/int.rs | 12 +++---- compiler/rustc_middle/src/ty/util.rs | 11 +++--- compiler/rustc_mir/src/interpret/cast.rs | 5 ++- .../rustc_mir/src/interpret/eval_context.rs | 8 ++--- compiler/rustc_mir/src/interpret/place.rs | 8 ++--- .../rustc_mir/src/transform/const_prop.rs | 9 +++-- .../src/build/matches/simplify.rs | 5 ++- compiler/rustc_mir_build/src/thir/constant.rs | 4 +-- .../src/thir/pattern/_match.rs | 4 +-- .../rustc_mir_build/src/thir/pattern/mod.rs | 6 ++-- compiler/rustc_symbol_mangling/src/v0.rs | 3 +- compiler/rustc_target/src/abi/mod.rs | 29 +++++++++++++++ src/librustdoc/clean/utils.rs | 4 +-- 18 files changed, 73 insertions(+), 89 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 2097f9d288705..bfe5514b6d3ea 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -585,10 +585,7 @@ fn codegen_stmt<'tcx>( .discriminant_for_variant(fx.tcx, *index) .unwrap(); let discr = if discr.ty.is_signed() { - rustc_middle::mir::interpret::sign_extend( - discr.val, - fx.layout_of(discr.ty).size, - ) + fx.layout_of(discr.ty).size.sign_extend(discr.val) } else { discr.val }; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index ef1ae807453f2..454d43fd4e7dc 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -29,7 +29,6 @@ use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::ich::NodeIdHashingMode; -use rustc_middle::mir::interpret::truncate; use rustc_middle::mir::{self, Field, GeneratorLayout}; use rustc_middle::ty::layout::{self, IntegerExt, PrimitiveExt, TyAndLayout}; use rustc_middle::ty::subst::GenericArgKind; @@ -1693,7 +1692,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { let value = (i.as_u32() as u128) .wrapping_sub(niche_variants.start().as_u32() as u128) .wrapping_add(niche_start); - let value = truncate(value, tag.value.size(cx)); + let value = tag.value.size(cx).truncate(value); // NOTE(eddyb) do *NOT* remove this assert, until // we pass the full 128-bit value to LLVM, otherwise // truncation will be silent and remain undetected. diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 428cd453dd5a2..467a3a425906f 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -6,7 +6,6 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{is_range_literal, ExprKind, Node}; use rustc_index::vec::Idx; -use rustc_middle::mir::interpret::{sign_extend, truncate}; use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable}; @@ -218,11 +217,11 @@ fn report_bin_hex_error( cx.struct_span_lint(OVERFLOWING_LITERALS, expr.span, |lint| { let (t, actually) = match ty { attr::IntType::SignedInt(t) => { - let actually = sign_extend(val, size) as i128; + let actually = size.sign_extend(val) as i128; (t.name_str(), actually.to_string()) } attr::IntType::UnsignedInt(t) => { - let actually = truncate(val, size); + let actually = size.truncate(val); (t.name_str(), actually.to_string()) } }; diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index b5beb3babe239..bcf85797313f2 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -110,7 +110,7 @@ use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_serialize::{Decodable, Encodable}; -use rustc_target::abi::{Endian, Size}; +use rustc_target::abi::Endian; use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; @@ -590,39 +590,6 @@ pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result u128 { - let size = size.bits(); - if size == 0 { - // Truncated until nothing is left. - return 0; - } - // Sign-extend it. - let shift = 128 - size; - // Shift the unsigned value to the left, then shift back to the right as signed - // (essentially fills with FF on the left). - (((value << shift) as i128) >> shift) as u128 -} - -/// Truncates `value` to `size` bits. -#[inline] -pub fn truncate(value: u128, size: Size) -> u128 { - let size = size.bits(); - if size == 0 { - // Truncated until nothing is left. - return 0; - } - let shift = 128 - size; - // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). - (value << shift) >> shift -} - /// Computes the unsigned absolute value without wrapping or panicking. #[inline] pub fn uabs(value: i64) -> u64 { diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index a191dd1d705f7..5e97862ecf2b6 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -10,7 +10,7 @@ use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; use crate::ty::{ParamEnv, ScalarInt, Ty, TyCtxt}; -use super::{sign_extend, AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; +use super::{AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; /// Represents the result of const evaluation via the `eval_to_allocation` query. #[derive(Clone, HashStable, TyEncodable, TyDecodable)] @@ -448,7 +448,7 @@ impl<'tcx, Tag> Scalar { fn to_signed_with_bit_width(self, bits: u64) -> InterpResult<'static, i128> { let sz = Size::from_bits(bits); let b = self.to_bits(sz)?; - Ok(sign_extend(b, sz) as i128) + Ok(sz.sign_extend(b) as i128) } /// Converts the scalar to produce an `i8`. Fails if the scalar is a pointer. @@ -479,7 +479,7 @@ impl<'tcx, Tag> Scalar { pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'static, i64> { let sz = cx.data_layout().pointer_size; let b = self.to_bits(sz)?; - let b = sign_extend(b, sz) as i128; + let b = sz.sign_extend(b) as i128; Ok(i64::try_from(b).unwrap()) } diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 8308cfddb4385..4ff88d1adaf8e 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -1,4 +1,4 @@ -use crate::mir::interpret::{sign_extend, truncate, InterpResult}; +use crate::mir::interpret::InterpResult; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -75,7 +75,7 @@ impl std::fmt::Debug for ConstInt { Ok(()) } } else { - let max = truncate(u128::MAX, Size::from_bytes(size)); + let max = Size::from_bytes(size).truncate(u128::MAX); if raw == max { match (size, is_ptr_sized_integral) { (_, true) => write!(fmt, "usize::MAX"), @@ -174,7 +174,7 @@ impl ScalarInt { // is a packed struct, that would create a possibly unaligned reference, which // is UB. debug_assert_eq!( - truncate(self.data, self.size()), + self.size().truncate(self.data), { self.data }, "Scalar value {:#x} exceeds size of {} bytes", { self.data }, @@ -204,7 +204,7 @@ impl ScalarInt { #[inline] pub fn try_from_uint(i: impl Into, size: Size) -> Option { let data = i.into(); - if truncate(data, size) == data { + if size.truncate(data) == data { Some(Self { data, size: size.bytes() as u8 }) } else { None @@ -215,8 +215,8 @@ impl ScalarInt { pub fn try_from_int(i: impl Into, size: Size) -> Option { 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 { + let truncated = size.truncate(i as u128); + if size.sign_extend(truncated) as i128 == i { Some(Self { data: truncated, size: size.bytes() as u8 }) } else { None diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 4a20e1c32f99e..5f117e19eca27 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -2,7 +2,6 @@ use crate::ich::NodeIdHashingMode; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::mir::interpret::{sign_extend, truncate}; use crate::ty::fold::TypeFolder; use crate::ty::layout::IntegerExt; use crate::ty::query::TyCtxtAt; @@ -38,7 +37,7 @@ impl<'tcx> fmt::Display for Discr<'tcx> { let size = ty::tls::with(|tcx| Integer::from_attr(&tcx, SignedInt(ity)).size()); let x = self.val; // sign extend the raw representation to be an i128 - let x = sign_extend(x, size) as i128; + let x = size.sign_extend(x) as i128; write!(fmt, "{}", x) } _ => write!(fmt, "{}", self.val), @@ -47,7 +46,7 @@ impl<'tcx> fmt::Display for Discr<'tcx> { } fn signed_min(size: Size) -> i128 { - sign_extend(1_u128 << (size.bits() - 1), size) as i128 + size.sign_extend(1_u128 << (size.bits() - 1)) as i128 } fn signed_max(size: Size) -> i128 { @@ -77,14 +76,14 @@ impl<'tcx> Discr<'tcx> { let (val, oflo) = if signed { let min = signed_min(size); let max = signed_max(size); - let val = sign_extend(self.val, size) as i128; + let val = size.sign_extend(self.val) as i128; assert!(n < (i128::MAX as u128)); let n = n as i128; let oflo = val > max - n; let val = if oflo { min + (n - (max - val) - 1) } else { val + n }; // zero the upper bits let val = val as u128; - let val = truncate(val, size); + let val = size.truncate(val); (val, oflo) } else { let max = unsigned_max(size); @@ -650,7 +649,7 @@ impl<'tcx> ty::TyS<'tcx> { let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); - let val = if signed { truncate(signed_min(size) as u128, size) } else { 0 }; + let val = if signed { size.truncate(signed_min(size) as u128) } else { 0 }; Some(val) } ty::Char => Some(0), diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs index affeae546b2aa..6d224bcc50b0f 100644 --- a/compiler/rustc_mir/src/interpret/cast.rs +++ b/compiler/rustc_mir/src/interpret/cast.rs @@ -13,8 +13,7 @@ use rustc_span::symbol::sym; use rustc_target::abi::{Integer, LayoutOf, Variants}; use super::{ - truncate, util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, - PlaceTy, + util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, }; impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { @@ -209,7 +208,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { RawPtr(_) => self.pointer_size(), _ => bug!(), }; - let v = truncate(v, size); + let v = size.truncate(v); Scalar::from_uint(v, size) } diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index ec1195d3703b4..08d8904ae1a5a 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -9,9 +9,7 @@ use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_middle::ich::StableHashingContext; use rustc_middle::mir; -use rustc_middle::mir::interpret::{ - sign_extend, truncate, GlobalId, InterpResult, Pointer, Scalar, -}; +use rustc_middle::mir::interpret::{GlobalId, InterpResult, Pointer, Scalar}; use rustc_middle::ty::layout::{self, TyAndLayout}; use rustc_middle::ty::{ self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, @@ -443,12 +441,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn sign_extend(&self, value: u128, ty: TyAndLayout<'_>) -> u128 { assert!(ty.abi.is_signed()); - sign_extend(value, ty.size) + ty.size.sign_extend(value) } #[inline(always)] pub fn truncate(&self, value: u128, ty: TyAndLayout<'_>) -> u128 { - truncate(value, ty.size) + ty.size.truncate(value) } #[inline] diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs index 3e10d0960a88a..a003380dda7e8 100644 --- a/compiler/rustc_mir/src/interpret/place.rs +++ b/compiler/rustc_mir/src/interpret/place.rs @@ -14,9 +14,9 @@ use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding}; use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants}; use super::{ - mir_assign_valid_types, truncate, AllocId, AllocMap, Allocation, AllocationExtra, ConstAlloc, - ImmTy, Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, - Pointer, PointerArithmetic, Scalar, ScalarMaybeUninit, + mir_assign_valid_types, AllocId, AllocMap, Allocation, AllocationExtra, ConstAlloc, ImmTy, + Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer, + PointerArithmetic, Scalar, ScalarMaybeUninit, }; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)] @@ -1073,7 +1073,7 @@ where // their computation, but the in-memory tag is the smallest possible // representation let size = tag_layout.value.size(self); - let tag_val = truncate(discr_val, size); + let tag_val = size.truncate(discr_val); let tag_dest = self.place_field(dest, tag_field)?; self.write_scalar(Scalar::from_uint(tag_val, size), tag_dest)?; diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index 620b9ac673a65..aeb9920c0e321 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -29,10 +29,9 @@ use rustc_trait_selection::traits; use crate::const_eval::ConstEvalErr; use crate::interpret::{ - self, compile_time_machine, truncate, AllocId, Allocation, ConstValue, CtfeValidationMode, - Frame, ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, Memory, - MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, - StackPopCleanup, + self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy, + Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, + Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup, }; use crate::transform::MirPass; @@ -746,7 +745,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } BinOp::BitOr => { - if arg_value == truncate(u128::MAX, const_arg.layout.size) + if arg_value == const_arg.layout.size.truncate(u128::MAX) || (const_arg.layout.ty.is_bool() && arg_value == 1) { this.ecx.write_immediate(*const_arg, dest)?; diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index e46274770be17..375f19f87559f 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -17,7 +17,6 @@ use crate::build::Builder; use crate::thir::{self, *}; use rustc_attr::{SignedInt, UnsignedInt}; use rustc_hir::RangeEnd; -use rustc_middle::mir::interpret::truncate; use rustc_middle::mir::Place; use rustc_middle::ty; use rustc_middle::ty::layout::IntegerExt; @@ -161,13 +160,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ty::Int(ity) => { let size = Integer::from_attr(&tcx, SignedInt(ity)).size(); - let max = truncate(u128::MAX, size); + let max = size.truncate(u128::MAX); let bias = 1u128 << (size.bits() - 1); (Some((0, max, size)), bias) } ty::Uint(uty) => { let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size(); - let max = truncate(u128::MAX, size); + let max = size.truncate(u128::MAX); (Some((0, max, size)), 0) } _ => (None, 0), diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index b71ff6e755749..dfe82317f48c6 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -1,6 +1,6 @@ use rustc_ast as ast; use rustc_middle::mir::interpret::{ - truncate, Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar, + Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar, }; use rustc_middle::ty::{self, ParamEnv, TyCtxt}; use rustc_span::symbol::Symbol; @@ -16,7 +16,7 @@ crate fn lit_to_const<'tcx>( let param_ty = ParamEnv::reveal_all().and(ty); let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size; trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); - let result = truncate(n, width); + let result = width.truncate(n); trace!("trunc result: {}", result); Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs index e0de1351ac33e..9e096f9ad6847 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs @@ -304,7 +304,7 @@ use rustc_arena::TypedArena; use rustc_attr::{SignedInt, UnsignedInt}; use rustc_hir::def_id::DefId; use rustc_hir::{HirId, RangeEnd}; -use rustc_middle::mir::interpret::{truncate, ConstValue}; +use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::Field; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; @@ -1608,7 +1608,7 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec { let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size(); - let max = truncate(u128::MAX, size); + let max = size.truncate(u128::MAX); vec![make_range(0, max)] } _ if cx.is_uninhabited(pcx.ty) => vec![], diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 3c746ac515393..db0ecd701bca4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -15,7 +15,7 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::RangeEnd; use rustc_index::vec::Idx; -use rustc_middle::mir::interpret::{get_slice_bytes, sign_extend, ConstValue}; +use rustc_middle::mir::interpret::{get_slice_bytes, ConstValue}; use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput}; use rustc_middle::mir::UserTypeProjection; use rustc_middle::mir::{BorrowKind, Field, Mutability}; @@ -1082,8 +1082,8 @@ crate fn compare_const_vals<'tcx>( use rustc_attr::SignedInt; use rustc_middle::ty::layout::IntegerExt; let size = rustc_target::abi::Integer::from_attr(&tcx, SignedInt(ity)).size(); - let a = sign_extend(a, size); - let b = sign_extend(b, size); + let a = size.sign_extend(a); + let b = size.sign_extend(b); Some((a as i128).cmp(&(b as i128))) } _ => Some(a.cmp(&b)), diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 1ff043ae91ffb..c28c2fecfbb43 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -4,7 +4,6 @@ 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::sign_extend; use rustc_middle::ty::print::{Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; @@ -527,7 +526,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { let param_env = ty::ParamEnv::reveal_all(); ct.try_eval_bits(self.tcx, param_env, ct.ty).and_then(|b| { let sz = self.tcx.layout_of(param_env.and(ct.ty)).ok()?.size; - let val = sign_extend(b, sz) as i128; + let val = sz.sign_extend(b) as i128; if val < 0 { neg = true; } diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 5c87a8f6b3d26..12cdd5c169acd 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -306,6 +306,35 @@ impl Size { let bytes = self.bytes().checked_mul(count)?; if bytes < dl.obj_size_bound() { Some(Size::from_bytes(bytes)) } else { None } } + + /// Truncates `value` to `self` bits and then sign-extend it to 128 bits + /// (i.e., if it is negative, fill with 1's on the left). + #[inline] + pub fn sign_extend(self, value: u128) -> u128 { + let size = self.bits(); + if size == 0 { + // Truncated until nothing is left. + return 0; + } + // Sign-extend it. + let shift = 128 - size; + // Shift the unsigned value to the left, then shift back to the right as signed + // (essentially fills with FF on the left). + (((value << shift) as i128) >> shift) as u128 + } + + /// Truncates `value` to `self` bits. + #[inline] + pub fn truncate(self, value: u128) -> u128 { + let size = self.bits(); + if size == 0 { + // Truncated until nothing is left. + return 0; + } + let shift = 128 - size; + // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). + (value << shift) >> shift + } } // Panicking addition, subtraction and multiplication for convenience. diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 167b06428e50c..f6258221e322d 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}; +use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, DefIdTree, Ty}; use rustc_span::symbol::{kw, sym, Symbol}; @@ -506,7 +506,7 @@ fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const 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; + let sign_extended_data = size.sign_extend(data) as i128; format!( "{}{}", From 2e5362542161d881c27ccf11aa4dbdc36ef431db Mon Sep 17 00:00:00 2001 From: oli Date: Wed, 4 Nov 2020 13:44:17 +0000 Subject: [PATCH 22/26] Document an `unwrap` --- compiler/rustc_middle/src/ty/consts/int.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 4ff88d1adaf8e..6ec0b2492b944 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -265,7 +265,10 @@ macro_rules! try_from { type Error = Size; #[inline] fn try_from(int: ScalarInt) -> Result { - int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>())).map(|u| u.try_into().unwrap()) + // The `unwrap` cannot fail because to_bits (if it succeeds) + // is guaranteed to return a value that fits into the size. + int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>())) + .map(|u| u.try_into().unwrap()) } } )* From 97bfff1f56748110417ce1a44e2046e2967c074a Mon Sep 17 00:00:00 2001 From: oli Date: Wed, 4 Nov 2020 13:55:29 +0000 Subject: [PATCH 23/26] Make `ScalarInt` entirely independent of MIR interpretation --- compiler/rustc_middle/src/ty/consts/int.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 6ec0b2492b944..126257a5b49ee 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -1,4 +1,3 @@ -use crate::mir::interpret::InterpResult; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -192,11 +191,11 @@ impl ScalarInt { self.data == 0 } - pub(crate) fn ptr_sized_op<'tcx>( + pub(crate) fn ptr_sized_op( self, dl: &TargetDataLayout, - f_int: impl FnOnce(u64) -> InterpResult<'tcx, u64>, - ) -> InterpResult<'tcx, Self> { + f_int: impl FnOnce(u64) -> Result, + ) -> Result { assert_eq!(u64::from(self.size), dl.pointer_size.bytes()); Ok(Self::try_from_uint(f_int(u64::try_from(self.data).unwrap())?, self.size()).unwrap()) } From 6e6c8a86e9f70b3be955716002d3af681039e7b8 Mon Sep 17 00:00:00 2001 From: oli Date: Wed, 4 Nov 2020 13:59:11 +0000 Subject: [PATCH 24/26] `u64::try_from` will now fail if `ScalarInt` isn't exactly 64 bits, thus we use `to_bits` with the correct size --- compiler/rustc_codegen_cranelift/src/value_and_place.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index a40686b193197..0000866c4f6a9 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -261,7 +261,7 @@ impl<'tcx> CValue<'tcx> { fx .bcx .ins() - .iconst(clif_ty, u64::try_from(const_val).expect("uint") as i64) + .iconst(clif_ty, const_val.to_bits(layout.size).unwrap() as i64) } ty::Float(FloatTy::F32) => { fx.bcx.ins().f32const(Ieee32::with_bits(u32::try_from(const_val).unwrap())) From 5f087f089f03c648527ac77a32bcb202c981bb57 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 4 Nov 2020 15:12:44 +0100 Subject: [PATCH 25/26] Update compiler/rustc_target/src/abi/mod.rs Co-authored-by: Ralf Jung --- compiler/rustc_target/src/abi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 12cdd5c169acd..55ace982d7228 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -319,7 +319,7 @@ impl Size { // Sign-extend it. let shift = 128 - size; // Shift the unsigned value to the left, then shift back to the right as signed - // (essentially fills with FF on the left). + // (essentially fills with sign bit on the left). (((value << shift) as i128) >> shift) as u128 } From 332750f9ebea6ff8a20b020772b60ccac637982e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 4 Nov 2020 15:13:06 +0100 Subject: [PATCH 26/26] Update compiler/rustc_target/src/abi/mod.rs Co-authored-by: Ralf Jung --- compiler/rustc_target/src/abi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 55ace982d7228..d3c31773c1ee7 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -307,7 +307,7 @@ impl Size { if bytes < dl.obj_size_bound() { Some(Size::from_bytes(bytes)) } else { None } } - /// Truncates `value` to `self` bits and then sign-extend it to 128 bits + /// Truncates `value` to `self` bits and then sign-extends it to 128 bits /// (i.e., if it is negative, fill with 1's on the left). #[inline] pub fn sign_extend(self, value: u128) -> u128 {