From a4fbac163e7291b052fa5ec64f14cc0a52932ff4 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 22 Feb 2021 14:09:24 +0000 Subject: [PATCH 01/27] Implement valtree valtree is a version of constants that is inherently safe to be used within types. This is in contrast to ty::Const which can have different representations of the same value. These representation differences can show up in hashing or equality comparisons, breaking type equality of otherwise equal types. valtrees do not have this problem. --- .../rustc_middle/src/mir/interpret/value.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 8 ++ compiler/rustc_middle/src/ty/consts.rs | 2 + .../rustc_middle/src/ty/consts/valtree.rs | 15 +++ compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/query/mod.rs | 2 +- compiler/rustc_mir/src/const_eval/mod.rs | 92 ++++++++++++++++++- compiler/rustc_mir/src/interpret/place.rs | 2 +- compiler/rustc_mir/src/lib.rs | 4 + compiler/rustc_query_impl/src/keys.rs | 9 ++ 10 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 compiler/rustc_middle/src/ty/consts/valtree.rs diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index a07ccd4d2b5..ba9b285e8e6 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -13,7 +13,7 @@ use crate::ty::{ParamEnv, ScalarInt, Ty, TyCtxt}; use super::{AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; /// Represents the result of const evaluation via the `eval_to_allocation` query. -#[derive(Clone, HashStable, TyEncodable, TyDecodable, Debug)] +#[derive(Copy, Clone, HashStable, TyEncodable, TyDecodable, Debug, Hash, Eq, PartialEq)] pub struct ConstAlloc<'tcx> { // the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory` // (so you can use `AllocMap::unwrap_memory`). diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b03b26d6460..b0c066fb42f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -785,6 +785,14 @@ rustc_queries! { cache_on_disk_if { true } } + /// Convert an evaluated constant to a type level constant or + /// return `None` if that is not possible. + query const_to_valtree( + key: ty::ParamEnvAnd<'tcx, ConstAlloc<'tcx>> + ) -> Option { + desc { "destructure constant" } + } + /// Destructure a constant ADT or array into its variant index and its /// field values. query destructure_const( diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index e7b2c9efd63..622f8e8ff6c 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -10,9 +10,11 @@ use rustc_macros::HashStable; mod int; mod kind; +mod valtree; pub use int::*; pub use kind::*; +pub use valtree::*; /// Typed constant value. #[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)] diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs new file mode 100644 index 00000000000..9b42023f054 --- /dev/null +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -0,0 +1,15 @@ +use super::ScalarInt; +use rustc_macros::HashStable; + +#[derive(Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)] +#[derive(HashStable)] +pub enum ValTree { + Leaf(ScalarInt), + Branch(Vec), +} + +impl ValTree { + pub fn zst() -> Self { + Self::Branch(Vec::new()) + } +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f5aef108927..5bbf7b35d3d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -55,7 +55,7 @@ pub use rustc_type_ir::*; pub use self::binding::BindingMode; pub use self::binding::BindingMode::*; -pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt}; +pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt, ValTree}; pub use self::context::{ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt, diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index 51a214bc07b..48e777f7158 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -14,8 +14,8 @@ use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLife use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; use crate::mir::interpret::GlobalId; +use crate::mir::interpret::{ConstAlloc, LitToConstError, LitToConstInput}; use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult}; -use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index a4e1cd2faa3..fbd2d5d78a7 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -3,12 +3,15 @@ use std::convert::TryFrom; use rustc_hir::Mutability; -use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::{ + mir::{self, interpret::ConstAlloc}, + ty::ScalarInt, +}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; use crate::interpret::{ - intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MemPlaceMeta, Scalar, + intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MPlaceTy, MemPlaceMeta, Scalar, }; mod error; @@ -35,6 +38,91 @@ pub(crate) fn const_caller_location( ConstValue::Scalar(loc_place.ptr) } +/// Convert an evaluated constant to a type level constant +pub(crate) fn const_to_valtree<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + raw: ConstAlloc<'tcx>, +) -> Option { + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); + let place = ecx.raw_const_to_mplace(raw).unwrap(); + const_to_valtree_inner(&ecx, &place) +} + +fn const_to_valtree_inner<'tcx>( + ecx: &CompileTimeEvalContext<'tcx, 'tcx>, + place: &MPlaceTy<'tcx>, +) -> Option { + let branches = |n, variant| { + let place = match variant { + Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(), + None => *place, + }; + let variant = + variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32())))); + let fields = (0..n).map(|i| { + let field = ecx.mplace_field(&place, i).unwrap(); + const_to_valtree_inner(ecx, &field) + }); + Some(ty::ValTree::Branch(variant.into_iter().chain(fields).collect::>()?)) + }; + match place.layout.ty.kind() { + ty::FnDef(..) => Some(ty::ValTree::zst()), + ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { + let val = ecx.read_immediate(&place.into()).unwrap(); + let val = val.to_scalar().unwrap(); + Some(ty::ValTree::Leaf(val.assert_int())) + } + + // Raw pointers are not allowed in type level constants, as raw pointers cannot be treated + // like references. If we looked behind the raw pointer, we may be breaking the meaning of + // the raw pointer. Equality on raw pointers is performed on the pointer and not on the pointee, + // and we cannot guarantee any kind of pointer stability in the type system. + // Technically we could allow function pointers, but they are not guaranteed to be the + // same as the function pointers at runtime. + ty::FnPtr(_) | ty::RawPtr(_) => None, + ty::Ref(..) => unimplemented!("need to use deref_const"), + + ty::Dynamic(..) => unimplemented!( + "for trait objects we must look at the vtable and figure out the real type" + ), + + ty::Slice(_) | ty::Str => { + unimplemented!("need to find the backing data of the slice/str and recurse on that") + } + ty::Tuple(substs) => branches(substs.len(), None), + ty::Array(_, len) => branches(usize::try_from(len.eval_usize(ecx.tcx.tcx, ecx.param_env)).unwrap(), None), + + ty::Adt(def, _) => { + if def.variants.is_empty() { + // Uninhabited + return None; + } + + let variant = ecx.read_discriminant(&place.into()).unwrap().1; + + branches(def.variants[variant].fields.len(), Some(variant)) + } + + ty::Never + | ty::Error(_) + | ty::Foreign(..) + | ty::Infer(ty::FreshIntTy(_)) + | ty::Infer(ty::FreshFloatTy(_)) + | ty::Projection(..) + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(..) + // FIXME(oli-obk): we could look behind opaque types + | ty::Opaque(..) + | ty::Infer(_) + // FIXME(oli-obk): we can probably encode closures just like structs + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) => None, + } +} + /// This function uses `unwrap` copiously, because an already validated constant /// must have valid fields and can thus never fail outside of compiler bugs. However, it is /// invoked from the pretty printer, where it can receive enums with no variants and e.g. diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs index 7ba79e6f759..699b531f501 100644 --- a/compiler/rustc_mir/src/interpret/place.rs +++ b/compiler/rustc_mir/src/interpret/place.rs @@ -531,7 +531,7 @@ where base.offset(from_offset, meta, layout, self) } - pub(super) fn mplace_downcast( + pub(crate) fn mplace_downcast( &self, base: &MPlaceTy<'tcx, M::PointerTag>, variant: VariantIdx, diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 93c17057590..194bc74c0fb 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -63,6 +63,10 @@ pub fn provide(providers: &mut Providers) { let (param_env, value) = param_env_and_value.into_parts(); const_eval::destructure_const(tcx, param_env, value) }; + providers.const_to_valtree = |tcx, param_env_and_value| { + let (param_env, raw) = param_env_and_value.into_parts(); + const_eval::const_to_valtree(tcx, param_env, raw) + }; providers.deref_const = |tcx, param_env_and_value| { let (param_env, value) = param_env_and_value.into_parts(); const_eval::deref_const(tcx, param_env, value) diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index 1ae5bf12cab..e467f419863 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -228,6 +228,15 @@ impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) { } } +impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl<'tcx> Key for ty::PolyTraitRef<'tcx> { fn query_crate(&self) -> CrateNum { self.def_id().krate From 0fe4f38769ff5654cb24a9b84ce69b4cdce46e64 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 22 Feb 2021 14:34:23 +0000 Subject: [PATCH 02/27] Intern valtree field vector --- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/codec.rs | 10 ++++++++++ compiler/rustc_middle/src/ty/consts/valtree.rs | 10 +++++----- compiler/rustc_mir/src/const_eval/mod.rs | 10 +++++++--- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b0c066fb42f..49ab1084e58 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -789,7 +789,7 @@ rustc_queries! { /// return `None` if that is not possible. query const_to_valtree( key: ty::ParamEnvAnd<'tcx, ConstAlloc<'tcx>> - ) -> Option { + ) -> Option> { desc { "destructure constant" } } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 73ad87a9ef2..f796534c2e1 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -333,6 +333,16 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::Const<'tcx> { } } +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] { + fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { + Ok(decoder.tcx().arena.alloc_from_iter( + (0..decoder.read_usize()?) + .map(|_| Decodable::decode(decoder)) + .collect::, _>>()?, + )) + } +} + impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for Allocation { fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?)) diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 9b42023f054..6c8eea8c768 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -1,15 +1,15 @@ use super::ScalarInt; use rustc_macros::HashStable; -#[derive(Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)] #[derive(HashStable)] -pub enum ValTree { +pub enum ValTree<'tcx> { Leaf(ScalarInt), - Branch(Vec), + Branch(&'tcx [ValTree<'tcx>]), } -impl ValTree { +impl ValTree<'tcx> { pub fn zst() -> Self { - Self::Branch(Vec::new()) + Self::Branch(&[]) } } diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index fbd2d5d78a7..5e77cc9daf3 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -43,7 +43,7 @@ pub(crate) fn const_to_valtree<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, raw: ConstAlloc<'tcx>, -) -> Option { +) -> Option> { let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); let place = ecx.raw_const_to_mplace(raw).unwrap(); const_to_valtree_inner(&ecx, &place) @@ -52,7 +52,7 @@ pub(crate) fn const_to_valtree<'tcx>( fn const_to_valtree_inner<'tcx>( ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>, -) -> Option { +) -> Option> { let branches = |n, variant| { let place = match variant { Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(), @@ -64,7 +64,11 @@ fn const_to_valtree_inner<'tcx>( let field = ecx.mplace_field(&place, i).unwrap(); const_to_valtree_inner(ecx, &field) }); - Some(ty::ValTree::Branch(variant.into_iter().chain(fields).collect::>()?)) + Some(ty::ValTree::Branch( + ecx.tcx + .arena + .alloc_from_iter(variant.into_iter().chain(fields).collect::>>()?), + )) }; match place.layout.ty.kind() { ty::FnDef(..) => Some(ty::ValTree::zst()), From 858216cabf9cd1521e55c675502426bdd5262c73 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 23 Feb 2021 10:16:24 +0000 Subject: [PATCH 03/27] Add fallible Scalar to ScalarInt conversion method --- .../rustc_middle/src/mir/interpret/value.rs | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index ba9b285e8e6..3dd905b35b2 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -346,16 +346,13 @@ impl<'tcx, Tag> Scalar { #[inline] 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).map_err(|size| { - err_ub!(ScalarSizeMismatch { - target_size: target_size.bytes(), - data_size: size.bytes(), - }) - .into() - }), - Scalar::Ptr(_) => throw_unsup!(ReadPointerAsBytes), - } + self.to_int()?.to_bits(target_size).map_err(|size| { + err_ub!(ScalarSizeMismatch { + target_size: target_size.bytes(), + data_size: size.bytes(), + }) + .into() + }) } #[inline(always)] @@ -364,13 +361,18 @@ impl<'tcx, Tag> Scalar { } #[inline] - pub fn assert_int(self) -> ScalarInt { + pub fn to_int(self) -> InterpResult<'tcx, ScalarInt> { match self { - Scalar::Ptr(_) => bug!("expected an int but got an abstract pointer"), - Scalar::Int(int) => int, + Scalar::Ptr(_) => throw_unsup!(ReadPointerAsBytes), + Scalar::Int(int) => Ok(int), } } + #[inline] + pub fn assert_int(self) -> ScalarInt { + self.to_int().expect("expected an int but got an abstract pointer") + } + #[inline] pub fn assert_ptr(self) -> Pointer { match self { From 09f7f915327b8877ea6025e71dc028ffdbd2369c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 23 Feb 2021 14:11:29 +0000 Subject: [PATCH 04/27] Add convenience conversion methods for ScalarInt --- .../rustc_middle/src/mir/interpret/value.rs | 31 ++++++++++++++----- compiler/rustc_middle/src/ty/consts/int.rs | 19 ++++++++++++ compiler/rustc_middle/src/ty/consts/kind.rs | 13 ++++++-- 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 3dd905b35b2..c7b1005fffc 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -1,4 +1,4 @@ -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::fmt; use rustc_apfloat::{ @@ -56,20 +56,20 @@ impl<'tcx> ConstValue<'tcx> { } } + pub fn try_to_scalar_int(&self) -> Option { + self.try_to_scalar()?.to_int().ok() + } + pub fn try_to_bits(&self, size: Size) -> Option { - self.try_to_scalar()?.to_bits(size).ok() + self.try_to_scalar_int()?.to_bits(size).ok() } pub fn try_to_bool(&self) -> Option { - match self.try_to_bits(Size::from_bytes(1))? { - 0 => Some(false), - 1 => Some(true), - _ => None, - } + self.try_to_scalar_int()?.try_into().ok() } pub fn try_to_machine_usize(&self, tcx: TyCtxt<'tcx>) -> Option { - Some(self.try_to_bits(tcx.data_layout.pointer_size)? as u64) + self.try_to_scalar_int()?.try_to_machine_usize(tcx).ok() } pub fn try_to_bits_for_ty( @@ -505,6 +505,21 @@ impl From> for Scalar { } } +impl TryFrom for ScalarInt { + type Error = super::InterpErrorInfo<'static>; + #[inline] + fn try_from(scalar: Scalar) -> InterpResult<'static, Self> { + scalar.to_int() + } +} + +impl From for Scalar { + #[inline(always)] + fn from(ptr: ScalarInt) -> Self { + Scalar::Int(ptr) + } +} + #[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, HashStable, Hash)] pub enum ScalarMaybeUninit { Scalar(Scalar), diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 63e95f25bb7..8ed8ea6a0bc 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -5,6 +5,8 @@ use rustc_target::abi::{Size, TargetDataLayout}; use std::convert::{TryFrom, TryInto}; use std::fmt; +use crate::ty::TyCtxt; + #[derive(Copy, Clone)] /// A type for representing any integer. Only used for printing. pub struct ConstInt { @@ -239,6 +241,11 @@ impl ScalarInt { Err(self.size()) } } + + #[inline] + pub fn try_to_machine_usize(&self, tcx: TyCtxt<'tcx>) -> Result { + Ok(self.to_bits(tcx.data_layout.pointer_size)? as u64) + } } macro_rules! from { @@ -277,6 +284,18 @@ macro_rules! try_from { from!(u8, u16, u32, u64, u128, bool); try_from!(u8, u16, u32, u64, u128); +impl TryFrom for bool { + type Error = Size; + #[inline] + fn try_from(int: ScalarInt) -> Result { + int.to_bits(Size::from_bytes(1)).and_then(|u| match u { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(Size::from_bytes(1)), + }) + } +} + impl From for ScalarInt { #[inline] fn from(c: char) -> Self { diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 98c215407a8..5a6f219a413 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -1,3 +1,5 @@ +use std::convert::TryInto; + use crate::mir::interpret::ConstValue; use crate::mir::interpret::Scalar; use crate::mir::Promoted; @@ -9,6 +11,8 @@ use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_target::abi::Size; +use super::ScalarInt; + /// Represents a constant in Rust. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] #[derive(HashStable)] @@ -51,14 +55,19 @@ impl<'tcx> ConstKind<'tcx> { self.try_to_value()?.try_to_scalar() } + #[inline] + pub fn try_to_scalar_int(self) -> Option { + self.try_to_value()?.try_to_scalar()?.to_int().ok() + } + #[inline] pub fn try_to_bits(self, size: Size) -> Option { - self.try_to_value()?.try_to_bits(size) + self.try_to_scalar_int()?.to_bits(size).ok() } #[inline] pub fn try_to_bool(self) -> Option { - self.try_to_value()?.try_to_bool() + self.try_to_scalar_int()?.try_into().ok() } #[inline] From 019dba0cebac1944c74644ba7365490ef3a8c753 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 2 Mar 2021 11:22:37 +0000 Subject: [PATCH 05/27] Resolve a FIXME around type equality checks in Relate for constants --- compiler/rustc_middle/src/ty/relate.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index f21545447b2..fef8be57344 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -498,12 +498,15 @@ pub fn super_relate_consts>( debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); let tcx = relation.tcx(); - let eagerly_eval = |x: &'tcx ty::Const<'tcx>| x.eval(tcx, relation.param_env()).val; + // FIXME(oli-obk): once const generics can have generic types, this assertion + // will likely get triggered. Move to `normalize_erasing_regions` at that point. + assert_eq!( + tcx.erase_regions(a.ty), + tcx.erase_regions(b.ty), + "cannot relate constants of different types" + ); - // FIXME(eddyb) doesn't look like everything below checks that `a.ty == b.ty`. - // We could probably always assert it early, as const generic parameters - // are not allowed to depend on other generic parameters, i.e. are concrete. - // (although there could be normalization differences) + let eagerly_eval = |x: &'tcx ty::Const<'tcx>| x.eval(tcx, relation.param_env()).val; // Currently, the values that can be unified are primitive types, // and those that derive both `PartialEq` and `Eq`, corresponding @@ -524,7 +527,7 @@ pub fn super_relate_consts>( } (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => { let new_val = match (a_val, b_val) { - (ConstValue::Scalar(a_val), ConstValue::Scalar(b_val)) if a.ty == b.ty => { + (ConstValue::Scalar(a_val), ConstValue::Scalar(b_val)) => { if a_val == b_val { Ok(ConstValue::Scalar(a_val)) } else if let ty::FnPtr(_) = a.ty.kind() { From 4d917faa9905432a4ca18fdab29d3d8b951b7d97 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 2 Mar 2021 11:38:03 +0000 Subject: [PATCH 06/27] Reduce destructuring and re-interning where possible --- compiler/rustc_middle/src/ty/relate.rs | 33 ++++++++++++++------------ 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index fef8be57344..503a421beac 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -506,18 +506,21 @@ pub fn super_relate_consts>( "cannot relate constants of different types" ); - let eagerly_eval = |x: &'tcx ty::Const<'tcx>| x.eval(tcx, relation.param_env()).val; + let eagerly_eval = |x: &'tcx ty::Const<'tcx>| x.eval(tcx, relation.param_env()); + let a = eagerly_eval(a); + let b = eagerly_eval(b); // Currently, the values that can be unified are primitive types, // and those that derive both `PartialEq` and `Eq`, corresponding // to structural-match types. - let new_const_val = match (eagerly_eval(a), eagerly_eval(b)) { + match (a.val, b.val) { (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { // The caller should handle these cases! bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b) } - (ty::ConstKind::Error(d), _) | (_, ty::ConstKind::Error(d)) => Ok(ty::ConstKind::Error(d)), + (ty::ConstKind::Error(_), _) => Ok(a), + (_, ty::ConstKind::Error(_)) => Ok(b), (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => { return Ok(a); @@ -526,15 +529,15 @@ pub fn super_relate_consts>( return Ok(a); } (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => { - let new_val = match (a_val, b_val) { + match (a_val, b_val) { (ConstValue::Scalar(a_val), ConstValue::Scalar(b_val)) => { if a_val == b_val { - Ok(ConstValue::Scalar(a_val)) + Ok(a) } else if let ty::FnPtr(_) = a.ty.kind() { let a_instance = tcx.global_alloc(a_val.assert_ptr().alloc_id).unwrap_fn(); let b_instance = tcx.global_alloc(b_val.assert_ptr().alloc_id).unwrap_fn(); if a_instance == b_instance { - Ok(ConstValue::Scalar(a_val)) + Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) } @@ -547,7 +550,7 @@ pub fn super_relate_consts>( let a_bytes = get_slice_bytes(&tcx, a_val); let b_bytes = get_slice_bytes(&tcx, b_val); if a_bytes == b_bytes { - Ok(a_val) + Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) } @@ -567,7 +570,7 @@ pub fn super_relate_consts>( relation.consts(a_field, b_field)?; } - Ok(a_val) + Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) } @@ -585,9 +588,7 @@ pub fn super_relate_consts>( } _ => Err(TypeError::ConstMismatch(expected_found(relation, a, b))), - }; - - new_val.map(ty::ConstKind::Value) + } } ( @@ -595,7 +596,7 @@ pub fn super_relate_consts>( ty::ConstKind::Unevaluated(b_def, b_substs, None), ) if tcx.features().const_evaluatable_checked && !relation.visit_ct_substs() => { if tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) { - Ok(a.val) + Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) } @@ -610,11 +611,13 @@ pub fn super_relate_consts>( ) if a_def == b_def && a_promoted == b_promoted => { let substs = relation.relate_with_variance(ty::Variance::Invariant, a_substs, b_substs)?; - Ok(ty::ConstKind::Unevaluated(a_def, substs, a_promoted)) + Ok(tcx.mk_const(ty::Const { + val: ty::ConstKind::Unevaluated(a_def, substs, a_promoted), + ty: a.ty, + })) } _ => Err(TypeError::ConstMismatch(expected_found(relation, a, b))), - }; - new_const_val.map(|val| tcx.mk_const(ty::Const { val, ty: a.ty })) + } } impl<'tcx> Relate<'tcx> for &'tcx ty::List>> { From 5e8a89b2e5a036688d12eb6da4a1b97cadb6949f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 2 Mar 2021 12:13:17 +0000 Subject: [PATCH 07/27] Reduce the duplication in the relation logic for constants --- compiler/rustc_middle/src/ty/relate.rs | 110 ++++++++++--------------- 1 file changed, 44 insertions(+), 66 deletions(-) diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 503a421beac..8814a334fbb 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -4,13 +4,12 @@ //! types or regions but can be other things. Examples of type relations are //! subtyping, type equality, etc. -use crate::mir::interpret::{get_slice_bytes, ConstValue}; +use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar}; use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_hir as ast; use rustc_hir::def_id::DefId; -use rustc_span::DUMMY_SP; use rustc_target::spec::abi; use std::iter; @@ -513,81 +512,63 @@ pub fn super_relate_consts>( // Currently, the values that can be unified are primitive types, // and those that derive both `PartialEq` and `Eq`, corresponding // to structural-match types. - match (a.val, b.val) { + let is_match = match (a.val, b.val) { (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { // The caller should handle these cases! bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b) } - (ty::ConstKind::Error(_), _) => Ok(a), - (_, ty::ConstKind::Error(_)) => Ok(b), + (ty::ConstKind::Error(_), _) => return Ok(a), + (_, ty::ConstKind::Error(_)) => return Ok(b), - (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => { - return Ok(a); - } - (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) if p1 == p2 => { - return Ok(a); - } + (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) => a_p.index == b_p.index, + (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2, (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => { match (a_val, b_val) { - (ConstValue::Scalar(a_val), ConstValue::Scalar(b_val)) => { - if a_val == b_val { - Ok(a) - } else if let ty::FnPtr(_) = a.ty.kind() { - let a_instance = tcx.global_alloc(a_val.assert_ptr().alloc_id).unwrap_fn(); - let b_instance = tcx.global_alloc(b_val.assert_ptr().alloc_id).unwrap_fn(); - if a_instance == b_instance { - Ok(a) - } else { - Err(TypeError::ConstMismatch(expected_found(relation, a, b))) + ( + ConstValue::Scalar(Scalar::Int(a_val)), + ConstValue::Scalar(Scalar::Int(b_val)), + ) => a_val == b_val, + ( + ConstValue::Scalar(Scalar::Ptr(a_val)), + ConstValue::Scalar(Scalar::Ptr(b_val)), + ) => { + a_val == b_val + || match ( + tcx.global_alloc(a_val.alloc_id), + tcx.global_alloc(b_val.alloc_id), + ) { + ( + GlobalAlloc::Function(a_instance), + GlobalAlloc::Function(b_instance), + ) => a_instance == b_instance, + _ => false, } - } else { - Err(TypeError::ConstMismatch(expected_found(relation, a, b))) - } } (ConstValue::Slice { .. }, ConstValue::Slice { .. }) => { - let a_bytes = get_slice_bytes(&tcx, a_val); - let b_bytes = get_slice_bytes(&tcx, b_val); - if a_bytes == b_bytes { - Ok(a) - } else { - Err(TypeError::ConstMismatch(expected_found(relation, a, b))) - } + get_slice_bytes(&tcx, a_val) == get_slice_bytes(&tcx, b_val) } (ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => { - match a.ty.kind() { - ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { - let a_destructured = tcx.destructure_const(relation.param_env().and(a)); - let b_destructured = tcx.destructure_const(relation.param_env().and(b)); + let a_destructured = tcx.destructure_const(relation.param_env().and(a)); + let b_destructured = tcx.destructure_const(relation.param_env().and(b)); - // Both the variant and each field have to be equal. - if a_destructured.variant == b_destructured.variant { - for (a_field, b_field) in - a_destructured.fields.iter().zip(b_destructured.fields.iter()) - { - relation.consts(a_field, b_field)?; - } + // Both the variant and each field have to be equal. + if a_destructured.variant == b_destructured.variant { + for (a_field, b_field) in + a_destructured.fields.iter().zip(b_destructured.fields.iter()) + { + relation.consts(a_field, b_field)?; + } - Ok(a) - } else { - Err(TypeError::ConstMismatch(expected_found(relation, a, b))) - } - } - // FIXME(const_generics): There are probably some `TyKind`s - // which should be handled here. - _ => { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!("unexpected consts: a: {:?}, b: {:?}", a, b), - ); - Err(TypeError::ConstMismatch(expected_found(relation, a, b))) - } + true + } else { + false } } - _ => Err(TypeError::ConstMismatch(expected_found(relation, a, b))), + _ => false, } } @@ -595,11 +576,7 @@ pub fn super_relate_consts>( ty::ConstKind::Unevaluated(a_def, a_substs, None), ty::ConstKind::Unevaluated(b_def, b_substs, None), ) if tcx.features().const_evaluatable_checked && !relation.visit_ct_substs() => { - if tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) { - Ok(a) - } else { - Err(TypeError::ConstMismatch(expected_found(relation, a, b))) - } + tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) } // While this is slightly incorrect, it shouldn't matter for `min_const_generics` @@ -611,13 +588,14 @@ pub fn super_relate_consts>( ) if a_def == b_def && a_promoted == b_promoted => { let substs = relation.relate_with_variance(ty::Variance::Invariant, a_substs, b_substs)?; - Ok(tcx.mk_const(ty::Const { + return Ok(tcx.mk_const(ty::Const { val: ty::ConstKind::Unevaluated(a_def, substs, a_promoted), ty: a.ty, - })) + })); } - _ => Err(TypeError::ConstMismatch(expected_found(relation, a, b))), - } + _ => false, + }; + if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) } } impl<'tcx> Relate<'tcx> for &'tcx ty::List>> { From b729cc9d6129c11c1cd71a61f6eb745dd98531c6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 2 Mar 2021 12:21:10 +0000 Subject: [PATCH 08/27] Pull out ConstValue relating into its own function --- compiler/rustc_middle/src/ty/relate.rs | 97 ++++++++++++++------------ 1 file changed, 51 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 8814a334fbb..436ca4c0578 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -524,52 +524,7 @@ pub fn super_relate_consts>( (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) => a_p.index == b_p.index, (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2, (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => { - match (a_val, b_val) { - ( - ConstValue::Scalar(Scalar::Int(a_val)), - ConstValue::Scalar(Scalar::Int(b_val)), - ) => a_val == b_val, - ( - ConstValue::Scalar(Scalar::Ptr(a_val)), - ConstValue::Scalar(Scalar::Ptr(b_val)), - ) => { - a_val == b_val - || match ( - tcx.global_alloc(a_val.alloc_id), - tcx.global_alloc(b_val.alloc_id), - ) { - ( - GlobalAlloc::Function(a_instance), - GlobalAlloc::Function(b_instance), - ) => a_instance == b_instance, - _ => false, - } - } - - (ConstValue::Slice { .. }, ConstValue::Slice { .. }) => { - get_slice_bytes(&tcx, a_val) == get_slice_bytes(&tcx, b_val) - } - - (ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => { - let a_destructured = tcx.destructure_const(relation.param_env().and(a)); - let b_destructured = tcx.destructure_const(relation.param_env().and(b)); - - // Both the variant and each field have to be equal. - if a_destructured.variant == b_destructured.variant { - for (a_field, b_field) in - a_destructured.fields.iter().zip(b_destructured.fields.iter()) - { - relation.consts(a_field, b_field)?; - } - - true - } else { - false - } - } - - _ => false, - } + check_const_value_eq(relation, a_val, b_val, a, b)? } ( @@ -598,6 +553,56 @@ pub fn super_relate_consts>( if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) } } +fn check_const_value_eq>( + relation: &mut R, + a_val: ConstValue<'tcx>, + b_val: ConstValue<'tcx>, + // FIXME(oli-obk): these arguments should go away with valtrees + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, + // FIXME(oli-obk): this should just be `bool` with valtrees +) -> RelateResult<'tcx, bool> { + let tcx = relation.tcx(); + Ok(match (a_val, b_val) { + (ConstValue::Scalar(Scalar::Int(a_val)), ConstValue::Scalar(Scalar::Int(b_val))) => { + a_val == b_val + } + (ConstValue::Scalar(Scalar::Ptr(a_val)), ConstValue::Scalar(Scalar::Ptr(b_val))) => { + a_val == b_val + || match (tcx.global_alloc(a_val.alloc_id), tcx.global_alloc(b_val.alloc_id)) { + (GlobalAlloc::Function(a_instance), GlobalAlloc::Function(b_instance)) => { + a_instance == b_instance + } + _ => false, + } + } + + (ConstValue::Slice { .. }, ConstValue::Slice { .. }) => { + get_slice_bytes(&tcx, a_val) == get_slice_bytes(&tcx, b_val) + } + + (ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => { + let a_destructured = tcx.destructure_const(relation.param_env().and(a)); + let b_destructured = tcx.destructure_const(relation.param_env().and(b)); + + // Both the variant and each field have to be equal. + if a_destructured.variant == b_destructured.variant { + for (a_field, b_field) in + a_destructured.fields.iter().zip(b_destructured.fields.iter()) + { + relation.consts(a_field, b_field)?; + } + + true + } else { + false + } + } + + _ => false, + }) +} + impl<'tcx> Relate<'tcx> for &'tcx ty::List>> { fn relate>( relation: &mut R, From 0bb367e070ec19786d563b4a6bda605e84ed694c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 2 Mar 2021 14:54:10 +0000 Subject: [PATCH 09/27] Split pretty printer logic for scalar int and scalar ptr Value trees won't have scalar ptr at all, so we need a scalar int printing method anyway. This way we'll be able to share that method between all const representations. --- compiler/rustc_middle/src/ty/print/pretty.rs | 137 +++++++++++-------- 1 file changed, 79 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 53c164d44b3..7946d170064 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -956,32 +956,40 @@ pub trait PrettyPrinter<'tcx>: } fn pretty_print_const_scalar( - mut self, + self, scalar: Scalar, ty: Ty<'tcx>, print_ty: bool, + ) -> Result { + match scalar { + Scalar::Ptr(ptr) => self.pretty_print_const_scalar_ptr(ptr, ty, print_ty), + Scalar::Int(int) => self.pretty_print_const_scalar_int(int, ty, print_ty), + } + } + + fn pretty_print_const_scalar_ptr( + mut self, + ptr: Pointer, + ty: Ty<'tcx>, + print_ty: bool, ) -> Result { define_scoped_cx!(self); - match (scalar, &ty.kind()) { + match ty.kind() { // Byte strings (&[u8; N]) - ( - Scalar::Ptr(ptr), - ty::Ref( - _, - ty::TyS { - kind: - ty::Array( - ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. }, - ty::Const { - val: ty::ConstKind::Value(ConstValue::Scalar(int)), - .. - }, - ), - .. - }, - _, - ), + ty::Ref( + _, + ty::TyS { + kind: + ty::Array( + ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. }, + ty::Const { + val: ty::ConstKind::Value(ConstValue::Scalar(int)), .. + }, + ), + .. + }, + _, ) => match self.tcx().get_global_alloc(ptr.alloc_id) { Some(GlobalAlloc::Memory(alloc)) => { let bytes = int.assert_bits(self.tcx().data_layout.pointer_size); @@ -997,39 +1005,7 @@ pub trait PrettyPrinter<'tcx>: Some(GlobalAlloc::Function(_)) => p!(""), None => p!(""), }, - // Bool - (Scalar::Int(int), ty::Bool) if int == ScalarInt::FALSE => p!("false"), - (Scalar::Int(int), ty::Bool) if int == ScalarInt::TRUE => p!("true"), - // Float - (Scalar::Int(int), ty::Float(ty::FloatTy::F32)) => { - p!(write("{}f32", Single::try_from(int).unwrap())) - } - (Scalar::Int(int), ty::Float(ty::FloatTy::F64)) => { - p!(write("{}f64", Double::try_from(int).unwrap())) - } - // 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::Int(int), ty::Char) if char::try_from(int).is_ok() => { - p!(write("{:?}", char::try_from(int).unwrap())) - } - // Raw pointers - (Scalar::Int(int), ty::RawPtr(_) | ty::FnPtr(_)) => { - let data = int.assert_bits(self.tcx().data_layout.pointer_size); - self = self.typed_value( - |mut this| { - write!(this, "0x{:x}", data)?; - Ok(this) - }, - |this| this.print_type(ty), - " as ", - )?; - } - (Scalar::Ptr(ptr), ty::FnPtr(_)) => { + ty::FnPtr(_) => { // FIXME: We should probably have a helper method to share code with the "Byte strings" // printing above (which also has to handle pointers to all sorts of things). match self.tcx().get_global_alloc(ptr.alloc_id) { @@ -1043,12 +1019,61 @@ pub trait PrettyPrinter<'tcx>: _ => self = self.pretty_print_const_pointer(ptr, ty, print_ty)?, } } + // Any pointer values not covered by a branch above + _ => { + self = self.pretty_print_const_pointer(ptr, ty, print_ty)?; + } + } + Ok(self) + } + + fn pretty_print_const_scalar_int( + mut self, + int: ScalarInt, + ty: Ty<'tcx>, + print_ty: bool, + ) -> Result { + define_scoped_cx!(self); + + match ty.kind() { + // Bool + ty::Bool if int == ScalarInt::FALSE => p!("false"), + ty::Bool if int == ScalarInt::TRUE => p!("true"), + // Float + ty::Float(ty::FloatTy::F32) => { + p!(write("{}f32", Single::try_from(int).unwrap())) + } + ty::Float(ty::FloatTy::F64) => { + p!(write("{}f64", Double::try_from(int).unwrap())) + } + // 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 + ty::Char if char::try_from(int).is_ok() => { + p!(write("{:?}", char::try_from(int).unwrap())) + } + // Raw pointers + ty::RawPtr(_) | ty::FnPtr(_) => { + let data = int.assert_bits(self.tcx().data_layout.pointer_size); + self = self.typed_value( + |mut this| { + write!(this, "0x{:x}", data)?; + Ok(this) + }, + |this| this.print_type(ty), + " as ", + )?; + } // For function type zsts just printing the path is enough - (Scalar::Int(int), ty::FnDef(d, s)) if int == ScalarInt::ZST => { + ty::FnDef(d, s) if int == ScalarInt::ZST => { p!(print_value_path(*d, s)) } // Nontrivial types with scalar bit representation - (Scalar::Int(int), _) => { + _ => { let print = |mut this: Self| { if int.size() == Size::ZERO { write!(this, "transmute(())")?; @@ -1063,10 +1088,6 @@ pub trait PrettyPrinter<'tcx>: print(self)? }; } - // Any pointer values not covered by a branch above - (Scalar::Ptr(p), _) => { - self = self.pretty_print_const_pointer(p, ty, print_ty)?; - } } Ok(self) } From d5eec653c0d0b445efa0aaf186e47baa24994f62 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 8 Mar 2021 14:09:22 +0000 Subject: [PATCH 10/27] Use the explicit error constant instead of fake dummies --- compiler/rustc_mir_build/src/thir/cx/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index fe8a58c0088..c0433604f8c 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -68,11 +68,11 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { // FIXME(#31407) this is only necessary because float parsing is buggy self.tcx.sess.span_err(sp, "could not evaluate float literal (see issue #31407)"); // create a dummy value and continue compiling - Const::from_bits(self.tcx, 0, self.param_env.and(ty)) + self.tcx.const_error(ty) } Err(LitToConstError::Reported) => { // create a dummy value and continue compiling - Const::from_bits(self.tcx, 0, self.param_env.and(ty)) + self.tcx.const_error(ty) } Err(LitToConstError::TypeError) => bug!("const_eval_literal: had type error"), } From 914df2a493a0f14e1b74db8618016c4de2feedce Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 8 Mar 2021 14:14:11 +0000 Subject: [PATCH 11/27] Add `ty` helper function for mir constants This is in preparation of the `literal` field becoming an enum that distinguishes between type level constants and runtime constants --- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 10 +++------- compiler/rustc_codegen_ssa/src/mir/constant.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/debuginfo.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 3 +++ 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 289629d9215..272356841fd 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -231,7 +231,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { let check = match terminator.kind { mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. } => { - match *c.literal.ty.kind() { + match *c.ty().kind() { ty::FnDef(did, _) => Some((did, args)), _ => None, } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index a8dda100763..fc4fc08bb0a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -635,12 +635,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if i == 2 && intrinsic.as_str().starts_with("simd_shuffle") { if let mir::Operand::Constant(constant) = arg { let c = self.eval_mir_constant(constant); - let (llval, ty) = self.simd_shuffle_indices( - &bx, - constant.span, - constant.literal.ty, - c, - ); + let (llval, ty) = + self.simd_shuffle_indices(&bx, constant.span, constant.ty(), c); return OperandRef { val: Immediate(llval), layout: bx.layout_of(ty), @@ -830,7 +826,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let const_value = self .eval_mir_constant(constant) .unwrap_or_else(|_| span_bug!(span, "asm const cannot be resolved")); - let ty = constant.literal.ty; + let ty = constant.ty(); let size = bx.layout_of(ty).size; let scalar = match const_value { ConstValue::Scalar(s) => s, diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index b79a221a0e7..114f6a4032a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -16,7 +16,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { constant: &mir::Constant<'tcx>, ) -> Result, ErrorHandled> { let val = self.eval_mir_constant(constant)?; - let ty = self.monomorphize(constant.literal.ty); + let ty = self.monomorphize(constant.ty()); Ok(OperandRef::from_const(bx, val, ty)) } diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index ea59e183118..a3f20abc82d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -372,7 +372,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (var_ty, var_kind) } mir::VarDebugInfoContents::Const(c) => { - let ty = self.monomorphize(c.literal.ty); + let ty = self.monomorphize(c.ty()); (ty, VariableKind::LocalVariable) } }; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index f6952667494..44794628e46 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2421,6 +2421,9 @@ impl Constant<'tcx> { _ => None, } } + pub fn ty(&self) -> Ty<'tcx> { + self.literal.ty + } } /// A collection of projections into user types. From 3ecde6f5db72c0a99824ec91f57411442026141d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 8 Mar 2021 15:01:53 +0000 Subject: [PATCH 12/27] Directly intern allocations so that we can write a `Lift` impl for them --- compiler/rustc_middle/src/ty/context.rs | 35 ++++++++++++++++++++----- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e1d79248171..7fbd75ca165 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -94,6 +94,8 @@ pub struct CtxtInterners<'tcx> { projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, const_: InternedSet<'tcx, Const<'tcx>>, + /// Const allocations. + allocation: InternedSet<'tcx, Allocation>, } impl<'tcx> CtxtInterners<'tcx> { @@ -111,6 +113,7 @@ impl<'tcx> CtxtInterners<'tcx> { projs: Default::default(), place_elems: Default::default(), const_: Default::default(), + allocation: Default::default(), } } @@ -1013,9 +1016,6 @@ pub struct GlobalCtxt<'tcx> { /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes const_stability_interner: ShardedHashMap<&'tcx attr::ConstStability, ()>, - /// Stores the value of constants (and deduplicates the actual memory) - allocation_interner: ShardedHashMap<&'tcx Allocation, ()>, - /// Stores memory for globals (statics/consts). pub(crate) alloc_map: Lock>, @@ -1058,7 +1058,10 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn intern_const_alloc(self, alloc: Allocation) -> &'tcx Allocation { - self.allocation_interner.intern(alloc, |alloc| self.arena.alloc(alloc)) + self.interners + .allocation + .intern(alloc, |alloc| Interned(self.interners.arena.alloc(alloc))) + .0 } /// Allocates a read-only byte or string literal for `mir::interpret`. @@ -1174,7 +1177,6 @@ impl<'tcx> TyCtxt<'tcx> { layout_interner: Default::default(), stability_interner: Default::default(), const_stability_interner: Default::default(), - allocation_interner: Default::default(), alloc_map: Lock::new(interpret::AllocMap::new()), output_filenames: Arc::new(output_filenames.clone()), } @@ -1610,6 +1612,7 @@ macro_rules! nop_list_lift { nop_lift! {type_; Ty<'a> => Ty<'tcx>} nop_lift! {region; Region<'a> => Region<'tcx>} nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>} +nop_lift! {allocation; &'a Allocation => &'tcx Allocation} nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>} nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>} @@ -1900,7 +1903,7 @@ impl<'tcx> TyCtxt<'tcx> { "Const Stability interner: #{}", self.0.const_stability_interner.len() )?; - writeln!(fmt, "Allocation interner: #{}", self.0.allocation_interner.len())?; + writeln!(fmt, "Allocation interner: #{}", self.0.interners.allocation.len())?; writeln!(fmt, "Layout interner: #{}", self.0.layout_interner.len())?; Ok(()) @@ -2001,6 +2004,26 @@ impl<'tcx> Borrow> for Interned<'tcx, Const<'tcx>> { } } +impl<'tcx> Borrow for Interned<'tcx, Allocation> { + fn borrow<'a>(&'a self) -> &'a Allocation { + &self.0 + } +} + +impl<'tcx> PartialEq for Interned<'tcx, Allocation> { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl<'tcx> Eq for Interned<'tcx, Allocation> {} + +impl<'tcx> Hash for Interned<'tcx, Allocation> { + fn hash(&self, s: &mut H) { + self.0.hash(s) + } +} + macro_rules! direct_interners { ($($name:ident: $method:ident($ty:ty),)+) => { $(impl<'tcx> PartialEq for Interned<'tcx, $ty> { From 3127a9c60f267c862d2b0f1250c28f38891b94aa Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 8 Mar 2021 16:18:03 +0000 Subject: [PATCH 13/27] Prepare mir::Constant for ty::Const only supporting valtrees --- .../rustc_codegen_cranelift/src/constant.rs | 30 ++-- .../src/intrinsics/llvm.rs | 6 +- .../src/intrinsics/simd.rs | 8 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- .../rustc_codegen_ssa/src/mir/constant.rs | 7 +- .../rustc_middle/src/mir/interpret/value.rs | 18 +++ compiler/rustc_middle/src/mir/mod.rs | 133 ++++++++++++++++-- compiler/rustc_middle/src/mir/tcx.rs | 2 +- .../rustc_middle/src/mir/type_foldable.rs | 17 +++ compiler/rustc_middle/src/mir/visit.rs | 5 +- .../src/borrow_check/diagnostics/mod.rs | 4 +- .../src/borrow_check/type_check/mod.rs | 23 ++- .../rustc_mir/src/interpret/eval_context.rs | 2 +- compiler/rustc_mir/src/interpret/operand.rs | 52 ++++--- .../rustc_mir/src/monomorphize/collector.rs | 2 +- compiler/rustc_mir/src/shim.rs | 8 +- .../src/transform/check_consts/qualifs.rs | 34 ++--- .../rustc_mir/src/transform/const_prop.rs | 52 ++++--- .../src/transform/elaborate_drops.rs | 2 +- compiler/rustc_mir/src/transform/generator.rs | 2 +- compiler/rustc_mir/src/transform/inline.rs | 9 +- .../rustc_mir/src/transform/instcombine.rs | 7 +- .../src/transform/lower_intrinsics.rs | 2 +- .../rustc_mir/src/transform/match_branches.rs | 4 +- .../rustc_mir/src/transform/promote_consts.rs | 36 ++--- .../src/transform/required_consts.rs | 8 +- .../rustc_mir/src/transform/rustc_peek.rs | 2 +- .../transform/simplify_comparison_integral.rs | 4 +- .../rustc_mir/src/util/elaborate_drops.rs | 2 +- compiler/rustc_mir/src/util/find_self_call.rs | 4 +- compiler/rustc_mir/src/util/pretty.rs | 9 +- compiler/rustc_mir_build/src/build/cfg.rs | 2 +- .../src/build/expr/as_constant.rs | 8 +- .../src/build/expr/as_rvalue.rs | 2 +- .../rustc_mir_build/src/build/expr/into.rs | 4 +- .../rustc_mir_build/src/build/matches/test.rs | 2 +- compiler/rustc_mir_build/src/build/misc.rs | 3 +- .../src/traits/const_evaluatable.rs | 5 +- 38 files changed, 369 insertions(+), 153 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index b0639cf9e15..23ad5267c56 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -8,7 +8,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{ read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Pointer, Scalar, }; -use rustc_middle::ty::{Const, ConstKind}; +use rustc_middle::ty::ConstKind; use cranelift_codegen::ir::GlobalValueData; use cranelift_module::*; @@ -39,7 +39,10 @@ impl ConstantCx { pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool { let mut all_constants_ok = true; for constant in &fx.mir.required_consts { - let const_ = fx.monomorphize(constant.literal); + let const_ = match fx.monomorphize(constant.literal) { + ConstantSource::Ty(ct) => ct, + ConstantSource::Val(..) => continue, + }; match const_.val { ConstKind::Value(_) => {} ConstKind::Unevaluated(def, ref substs, promoted) => { @@ -113,19 +116,17 @@ pub(crate) fn codegen_constant<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, constant: &Constant<'tcx>, ) -> CValue<'tcx> { - let const_ = fx.monomorphize(constant.literal); + let const_ = match fx.monomorphize(constant.literal) { + ConstantSource::Ty(ct) => ct, + ConstantSource::Val(val, ty) => return codegen_const_value(fx, val, ty), + }; let const_val = match const_.val { ConstKind::Value(const_val) => const_val, ConstKind::Unevaluated(def, ref substs, promoted) if fx.tcx.is_static(def.did) => { assert!(substs.is_empty()); assert!(promoted.is_none()); - return codegen_static_ref( - fx, - def.did, - fx.layout_of(fx.monomorphize(&constant.literal.ty)), - ) - .to_cvalue(fx); + return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty)).to_cvalue(fx); } ConstKind::Unevaluated(def, ref substs, promoted) => { match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), def, substs, promoted, None) { @@ -422,11 +423,14 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant pub(crate) fn mir_operand_get_const_val<'tcx>( fx: &FunctionCx<'_, '_, 'tcx>, operand: &Operand<'tcx>, -) -> Option<&'tcx Const<'tcx>> { +) -> Option> { match operand { Operand::Copy(_) | Operand::Move(_) => None, - Operand::Constant(const_) => { - Some(fx.monomorphize(const_.literal).eval(fx.tcx, ParamEnv::reveal_all())) - } + Operand::Constant(const_) => match const_.literal { + ConstantSource::Ty(const_) => { + fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val.try_to_value() + } + ConstantSource::Val(val, _) => Some(val), + }, } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index 0692da397eb..83c91f789cd 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -53,7 +53,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( }; llvm.x86.sse2.cmp.ps | llvm.x86.sse2.cmp.pd, (c x, c y, o kind) { let kind_const = crate::constant::mir_operand_get_const_val(fx, kind).expect("llvm.x86.sse2.cmp.* kind not const"); - let flt_cc = match kind_const.val.try_to_bits(Size::from_bytes(1)).unwrap_or_else(|| panic!("kind not scalar: {:?}", kind_const)) { + let flt_cc = match kind_const.try_to_bits(Size::from_bytes(1)).unwrap_or_else(|| panic!("kind not scalar: {:?}", kind_const)) { 0 => FloatCC::Equal, 1 => FloatCC::LessThan, 2 => FloatCC::LessThanOrEqual, @@ -84,7 +84,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( llvm.x86.sse2.psrli.d, (c a, o imm8) { let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const"); simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| { - let res_lane = match imm8.val.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) { + let res_lane = match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) { imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), _ => fx.bcx.ins().iconst(types::I32, 0), }; @@ -94,7 +94,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( llvm.x86.sse2.pslli.d, (c a, o imm8) { let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const"); simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| { - let res_lane = match imm8.val.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) { + let res_lane = match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) { imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), _ => fx.bcx.ins().iconst(types::I32, 0), }; diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 1f8eeb1e714..d17136080fe 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -85,8 +85,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( use rustc_middle::mir::interpret::*; let idx_const = crate::constant::mir_operand_get_const_val(fx, idx).expect("simd_shuffle* idx not const"); - let idx_bytes = match idx_const.val { - ty::ConstKind::Value(ConstValue::ByRef { alloc, offset }) => { + let idx_bytes = match idx_const { + ConstValue::ByRef { alloc, offset } => { let ptr = Pointer::new(AllocId(0 /* dummy */), offset); let size = Size::from_bytes(4 * u64::from(ret_lane_count) /* size_of([u32; ret_lane_count]) */); alloc.get_bytes(fx, ptr, size).unwrap() @@ -130,7 +130,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ); }; - let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); + let idx = idx_const.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx); if idx >= lane_count.into() { fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count)); @@ -159,7 +159,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( return; }; - let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); + let idx = idx_const.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx); if idx >= lane_count.into() { fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count)); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index fc4fc08bb0a..04225ddd36f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -860,7 +860,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::InlineAsmOperand::SymFn { ref value } => { let literal = self.monomorphize(value.literal); - if let ty::FnDef(def_id, substs) = *literal.ty.kind() { + if let ty::FnDef(def_id, substs) = *literal.ty().kind() { let instance = ty::Instance::resolve_for_fn_ptr( bx.tcx(), ty::ParamEnv::reveal_all(), diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 114f6a4032a..d73e2325a8b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -24,7 +24,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &self, constant: &mir::Constant<'tcx>, ) -> Result, ErrorHandled> { - match self.monomorphize(constant.literal).val { + let ct = self.monomorphize(constant.literal); + let ct = match ct { + mir::ConstantSource::Ty(ct) => ct, + mir::ConstantSource::Val(val, _) => return Ok(val), + }; + match ct.val { ty::ConstKind::Unevaluated(def, substs, promoted) => self .cx .tcx() diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index c7b1005fffc..cddcc7d576a 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -47,7 +47,25 @@ pub enum ConstValue<'tcx> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(ConstValue<'_>, 32); +impl From for ConstValue<'tcx> { + fn from(s: Scalar) -> Self { + Self::Scalar(s) + } +} + impl<'tcx> ConstValue<'tcx> { + pub fn lift<'lifted>(self, tcx: TyCtxt<'lifted>) -> Option> { + Some(match self { + ConstValue::Scalar(s) => ConstValue::Scalar(s), + ConstValue::Slice { data, start, end } => { + ConstValue::Slice { data: tcx.lift(data)?, start, end } + } + ConstValue::ByRef { alloc, offset } => { + ConstValue::ByRef { alloc: tcx.lift(alloc)?, offset } + } + }) + } + #[inline] pub fn try_to_scalar(&self) -> Option { match *self { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 44794628e46..20ba82a8e86 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -11,12 +11,12 @@ use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::{self, List, Ty, TyCtxt}; -use crate::ty::{AdtDef, InstanceDef, Region, UserTypeAnnotationIndex}; +use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::{self, GeneratorKind}; -use rustc_target::abi::VariantIdx; +use rustc_target::abi::{Size, VariantIdx}; use polonius_engine::Atom; pub use rustc_ast::Mutability; @@ -30,6 +30,7 @@ use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; use rustc_target::asm::InlineAsmRegOrRegClass; use std::borrow::Cow; +use std::convert::TryInto; use std::fmt::{self, Debug, Display, Formatter, Write}; use std::ops::{ControlFlow, Index, IndexMut}; use std::slice; @@ -2032,7 +2033,7 @@ impl<'tcx> Operand<'tcx> { Operand::Constant(box Constant { span, user_ty: None, - literal: ty::Const::zero_sized(tcx, ty), + literal: ConstantSource::Ty(ty::Const::zero_sized(tcx, ty)), }) } @@ -2063,7 +2064,7 @@ impl<'tcx> Operand<'tcx> { Operand::Constant(box Constant { span, user_ty: None, - literal: ty::Const::from_scalar(tcx, val, ty), + literal: ConstantSource::Val(val.into(), ty), }) } @@ -2405,12 +2406,21 @@ pub struct Constant<'tcx> { /// Needed for NLL to impose user-given type constraints. pub user_ty: Option, - pub literal: &'tcx ty::Const<'tcx>, + pub literal: ConstantSource<'tcx>, +} + +#[derive(Clone, Copy, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable, Debug)] +pub enum ConstantSource<'tcx> { + /// This constant came from the type system + Ty(&'tcx ty::Const<'tcx>), + /// This constant cannot go back into the type system, as it represents + /// something the type system cannot handle (e.g. pointers). + Val(interpret::ConstValue<'tcx>, Ty<'tcx>), } impl Constant<'tcx> { pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option { - match self.literal.val.try_to_scalar() { + match self.literal.const_for_ty()?.val.try_to_scalar() { Some(Scalar::Ptr(ptr)) => match tcx.global_alloc(ptr.alloc_id) { GlobalAlloc::Static(def_id) => { assert!(!tcx.is_thread_local_static(def_id)); @@ -2422,7 +2432,92 @@ impl Constant<'tcx> { } } pub fn ty(&self) -> Ty<'tcx> { - self.literal.ty + self.literal.ty() + } +} + +impl From<&'tcx ty::Const<'tcx>> for ConstantSource<'tcx> { + fn from(ct: &'tcx ty::Const<'tcx>) -> Self { + Self::Ty(ct) + } +} + +impl ConstantSource<'tcx> { + /// Returns `None` if the constant is not trivially safe for use in the type system. + pub fn const_for_ty(&self) -> Option<&'tcx ty::Const<'tcx>> { + match self { + ConstantSource::Ty(c) => Some(c), + ConstantSource::Val(..) => None, + } + } + + pub fn ty(&self) -> Ty<'tcx> { + match self { + ConstantSource::Ty(c) => c.ty, + ConstantSource::Val(_, ty) => ty, + } + } + + #[inline] + pub fn try_to_value(self) -> Option> { + match self { + ConstantSource::Ty(c) => c.val.try_to_value(), + ConstantSource::Val(val, _) => Some(val), + } + } + + #[inline] + pub fn try_to_scalar(self) -> Option { + self.try_to_value()?.try_to_scalar() + } + + #[inline] + pub fn try_to_scalar_int(self) -> Option { + self.try_to_value()?.try_to_scalar()?.to_int().ok() + } + + #[inline] + pub fn try_to_bits(self, size: Size) -> Option { + self.try_to_scalar_int()?.to_bits(size).ok() + } + + #[inline] + pub fn try_to_bool(self) -> Option { + self.try_to_scalar_int()?.try_into().ok() + } + + #[inline] + pub fn try_eval_bits( + &self, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + ) -> Option { + match self { + Self::Ty(ct) => ct.try_eval_bits(tcx, param_env, ty), + Self::Val(val, t) => { + assert_eq!(*t, ty); + let size = + tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; + val.try_to_bits(size) + } + } + } + + #[inline] + pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option { + match self { + Self::Ty(ct) => ct.try_eval_bool(tcx, param_env), + Self::Val(val, _) => val.try_to_bool(), + } + } + + #[inline] + pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option { + match self { + Self::Ty(ct) => ct.try_eval_usize(tcx, param_env), + Self::Val(val, _) => val.try_to_machine_usize(tcx), + } } } @@ -2609,11 +2704,14 @@ impl<'tcx> Debug for Constant<'tcx> { impl<'tcx> Display for Constant<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - match self.literal.ty.kind() { + match self.ty().kind() { ty::FnDef(..) => {} _ => write!(fmt, "const ")?, } - pretty_print_const(self.literal, fmt, true) + match self.literal { + ConstantSource::Ty(c) => pretty_print_const(c, fmt, true), + ConstantSource::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true), + } } } @@ -2632,6 +2730,23 @@ fn pretty_print_const( }) } +fn pretty_print_const_value( + val: interpret::ConstValue<'tcx>, + ty: Ty<'tcx>, + fmt: &mut Formatter<'_>, + print_types: bool, +) -> fmt::Result { + use crate::ty::print::PrettyPrinter; + ty::tls::with(|tcx| { + let val = val.lift(tcx).unwrap(); + let ty = tcx.lift(ty).unwrap(); + let mut cx = FmtPrinter::new(tcx, fmt, Namespace::ValueNS); + cx.print_alloc_ids = true; + cx.pretty_print_const_value(val, ty, print_types)?; + Ok(()) + }) +} + impl<'tcx> graph::DirectedGraph for Body<'tcx> { type Node = BasicBlock; } diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 3961fd938be..6e819145976 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -227,7 +227,7 @@ impl<'tcx> Operand<'tcx> { { match self { &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, - &Operand::Constant(ref c) => c.literal.ty, + &Operand::Constant(ref c) => c.literal.ty(), } } } diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 6fabddbd149..4ad69a2cb98 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -343,5 +343,22 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.literal.visit_with(visitor) + // FIXME: should this be visiting the `user_ty`, too? + } +} + +impl<'tcx> TypeFoldable<'tcx> for ConstantSource<'tcx> { + fn super_fold_with>(self, folder: &mut F) -> Self { + match self { + ConstantSource::Ty(c) => ConstantSource::Ty(c.fold_with(folder)), + ConstantSource::Val(v, t) => ConstantSource::Val(v, t.fold_with(folder)), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { + match *self { + ConstantSource::Ty(c) => c.visit_with(visitor), + ConstantSource::Val(_, t) => t.visit_with(visitor), + } } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 4e81612c0b9..9015e771864 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -871,7 +871,10 @@ macro_rules! make_mir_visitor { self.visit_span(span); drop(user_ty); // no visit method for this - self.visit_const(literal, location); + match literal { + ConstantSource::Ty(ct) => self.visit_const(ct, location), + ConstantSource::Val(_, t) => self.visit_ty(t, TyContext::Location(location)), + } } fn super_span(&mut self, _span: & $($mutability)? Span) { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 04ea3cbd8b6..bc15b3972c9 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -81,12 +81,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let terminator = self.body[location.block].terminator(); debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator); if let TerminatorKind::Call { - func: Operand::Constant(box Constant { literal: ty::Const { ty: const_ty, .. }, .. }), + func: Operand::Constant(box Constant { literal, .. }), args, .. } = &terminator.kind { - if let ty::FnDef(id, _) = *const_ty.kind() { + if let ty::FnDef(id, _) = *literal.ty().kind() { debug!("add_moved_or_invoked_closure_note: id={:?}", id); if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() { let closure = match args.first() { diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index ab7e75bf4f1..d744db064b6 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -282,7 +282,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); - let ty = self.sanitize_type(constant, constant.literal.ty); + let ty = self.sanitize_type(constant, constant.literal.ty()); self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { let live_region_vid = @@ -296,7 +296,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { if let Some(annotation_index) = constant.user_ty { if let Err(terr) = self.cx.relate_type_and_user_type( - constant.literal.ty, + constant.literal.ty(), ty::Variance::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![] }, location.to_locations(), @@ -308,13 +308,22 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { constant, "bad constant user type {:?} vs {:?}: {:?}", annotation, - constant.literal.ty, + constant.literal.ty(), terr, ); } } else { let tcx = self.tcx(); - if let ty::ConstKind::Unevaluated(def, substs, promoted) = constant.literal.val { + let maybe_uneval = match constant.literal { + ConstantSource::Ty(ct) => match ct.val { + ty::ConstKind::Unevaluated(def, substs, promoted) => { + Some((def, substs, promoted)) + } + _ => None, + }, + _ => None, + }; + if let Some((def, substs, promoted)) = maybe_uneval { if let Some(promoted) = promoted { let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, promoted: &Body<'tcx>, @@ -349,7 +358,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { location.to_locations(), ConstraintCategory::Boring, self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( - constant.literal.ty, + constant.literal.ty(), def.did, UserSubsts { substs, user_self_ty: None }, )), @@ -367,7 +376,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { let unnormalized_ty = tcx.type_of(static_def_id); let locations = location.to_locations(); let normalized_ty = self.cx.normalize(unnormalized_ty, locations); - let literal_ty = constant.literal.ty.builtin_deref(true).unwrap().ty; + let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty; if let Err(terr) = self.cx.eq_types( normalized_ty, @@ -379,7 +388,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } } - if let ty::FnDef(def_id, substs) = *constant.literal.ty.kind() { + if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() { let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); self.cx.normalize_and_prove_instantiated_predicates( instantiated_predicates, diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 6b796eb3721..149a9f81ea0 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -689,7 +689,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let span = const_.span; let const_ = self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal); - self.const_to_op(const_, None).map_err(|err| { + self.mir_const_to_op(&const_, None).map_err(|err| { // If there was an error, set the span of the current frame to this constant. // Avoiding doing this when evaluation succeeds. self.frame_mut().loc = Err(span); diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 2c4aba19e4a..69ab2abaf27 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -532,7 +532,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // * During ConstProp, with `TooGeneric` or since the `requried_consts` were not all // checked yet. // * During CTFE, since promoteds in `const`/`static` initializer bodies can fail. - self.const_to_op(val, layout)? + + self.mir_const_to_op(&val, layout)? } }; trace!("{:?}: {:?}", mir_op, *op); @@ -556,28 +557,45 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { val: &ty::Const<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + match val.val { + ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), + ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)), + ty::ConstKind::Unevaluated(def, substs, promoted) => { + let instance = self.resolve(def, substs)?; + Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into()) + } + ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { + span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) + } + ty::ConstKind::Value(val_val) => self.const_val_to_op(val_val, val.ty, layout), + } + } + + crate fn mir_const_to_op( + &self, + val: &mir::ConstantSource<'tcx>, + layout: Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + match val { + mir::ConstantSource::Ty(ct) => self.const_to_op(ct, layout), + mir::ConstantSource::Val(val, ty) => self.const_val_to_op(*val, ty, None), + } + } + + crate fn const_val_to_op( + &self, + val_val: ConstValue<'tcx>, + ty: Ty<'tcx>, + layout: Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + // Other cases need layout. let tag_scalar = |scalar| -> InterpResult<'tcx, _> { Ok(match scalar { Scalar::Ptr(ptr) => Scalar::Ptr(self.global_base_pointer(ptr)?), Scalar::Int(int) => Scalar::Int(int), }) }; - // Early-return cases. - let val_val = match val.val { - ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), - ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)), - ty::ConstKind::Unevaluated(def, substs, promoted) => { - let instance = self.resolve(def, substs)?; - return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into()); - } - ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { - span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) - } - ty::ConstKind::Value(val_val) => val_val, - }; - // Other cases need layout. - let layout = - from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(val.ty))?; + let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?; let op = match val_val { ConstValue::ByRef { alloc, offset } => { let id = self.tcx.create_memory_alloc(alloc); diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index 20cb989196a..911224d8c1f 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -684,7 +684,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { for op in operands { match *op { mir::InlineAsmOperand::SymFn { ref value } => { - let fn_ty = self.monomorphize(value.literal.ty); + let fn_ty = self.monomorphize(value.literal.ty()); visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output); } mir::InlineAsmOperand::SymStatic { def_id } => { diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs index 0dbd7ce7f1d..796d024771d 100644 --- a/compiler/rustc_mir/src/shim.rs +++ b/compiler/rustc_mir/src/shim.rs @@ -421,7 +421,7 @@ impl CloneShimBuilder<'tcx> { let func = Operand::Constant(box Constant { span: self.span, user_ty: None, - literal: ty::Const::zero_sized(tcx, func_ty), + literal: ty::Const::zero_sized(tcx, func_ty).into(), }); let ref_loc = self.make_place( @@ -478,7 +478,7 @@ impl CloneShimBuilder<'tcx> { box Constant { span: self.span, user_ty: None, - literal: ty::Const::from_usize(self.tcx, value), + literal: ty::Const::from_usize(self.tcx, value).into(), } } @@ -509,7 +509,7 @@ impl CloneShimBuilder<'tcx> { Rvalue::Use(Operand::Constant(box Constant { span: self.span, user_ty: None, - literal: len, + literal: len.into(), })), ))), ]; @@ -768,7 +768,7 @@ fn build_call_shim<'tcx>( Operand::Constant(box Constant { span, user_ty: None, - literal: ty::Const::zero_sized(tcx, ty), + literal: ty::Const::zero_sized(tcx, ty).into(), }), rcvr.into_iter().collect::>(), ) diff --git a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs index 13d7166b4b5..748f65cba22 100644 --- a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs @@ -246,25 +246,27 @@ where }; // Check the qualifs of the value of `const` items. - if let ty::ConstKind::Unevaluated(def, _, promoted) = constant.literal.val { - assert!(promoted.is_none()); - // Don't peek inside trait associated constants. - if cx.tcx.trait_of_item(def.did).is_none() { - let qualifs = if let Some((did, param_did)) = def.as_const_arg() { - cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did)) - } else { - cx.tcx.at(constant.span).mir_const_qualif(def.did) - }; + if let Some(ct) = constant.literal.const_for_ty() { + if let ty::ConstKind::Unevaluated(def, _, promoted) = ct.val { + assert!(promoted.is_none()); + // Don't peek inside trait associated constants. + if cx.tcx.trait_of_item(def.did).is_none() { + let qualifs = if let Some((did, param_did)) = def.as_const_arg() { + cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did)) + } else { + cx.tcx.at(constant.span).mir_const_qualif(def.did) + }; - if !Q::in_qualifs(&qualifs) { - return false; + if !Q::in_qualifs(&qualifs) { + return false; + } + + // Just in case the type is more specific than + // the definition, e.g., impl associated const + // with type parameters, take it into account. } - - // Just in case the type is more specific than - // the definition, e.g., impl associated const - // with type parameters, take it into account. } } // Otherwise use the qualifs of the type. - Q::in_any_value_of_ty(cx, constant.literal.ty) + Q::in_any_value_of_ty(cx, constant.literal.ty()) } diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index 9d03b1b027e..0d5c8953bc6 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -13,9 +13,9 @@ use rustc_middle::mir::visit::{ MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, }; use rustc_middle::mir::{ - AssertKind, BasicBlock, BinOp, Body, ClearCrossCrate, Constant, Local, LocalDecl, LocalKind, - Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, - StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, + AssertKind, BasicBlock, BinOp, Body, ClearCrossCrate, Constant, ConstantSource, Local, + LocalDecl, LocalKind, Location, Operand, Place, Rvalue, SourceInfo, SourceScope, + SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, }; use rustc_middle::ty::layout::{HasTyCtxt, LayoutError, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; @@ -482,18 +482,21 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } - match self.ecx.const_to_op(c.literal, None) { + match self.ecx.mir_const_to_op(&c.literal, None) { Ok(op) => Some(op), Err(error) => { let tcx = self.ecx.tcx.at(c.span); let err = ConstEvalErr::new(&self.ecx, error, Some(c.span)); if let Some(lint_root) = self.lint_root(source_info) { - let lint_only = match c.literal.val { - // Promoteds must lint and not error as the user didn't ask for them - ConstKind::Unevaluated(_, _, Some(_)) => true, - // Out of backwards compatibility we cannot report hard errors in unused - // generic functions using associated constants of the generic parameters. - _ => c.literal.needs_subst(), + let lint_only = match c.literal { + ConstantSource::Ty(ct) => match ct.val { + // Promoteds must lint and not error as the user didn't ask for them + ConstKind::Unevaluated(_, _, Some(_)) => true, + // Out of backwards compatibility we cannot report hard errors in unused + // generic functions using associated constants of the generic parameters. + _ => c.literal.needs_subst(), + }, + ConstantSource::Val(_, ty) => ty.needs_subst(), }; if lint_only { // Out of backwards compatibility we cannot report hard errors in unused @@ -803,7 +806,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Operand::Constant(Box::new(Constant { span, user_ty: None, - literal: ty::Const::from_scalar(self.tcx, scalar, ty), + literal: ty::Const::from_scalar(self.tcx, scalar, ty).into(), })) } @@ -814,9 +817,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { source_info: SourceInfo, ) { if let Rvalue::Use(Operand::Constant(c)) = rval { - if !matches!(c.literal.val, ConstKind::Unevaluated(..)) { - trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c); - return; + match c.literal { + ConstantSource::Ty(c) if matches!(c.val, ConstKind::Unevaluated(..)) => {} + _ => { + trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c); + return; + } } } @@ -883,13 +889,17 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { *rval = Rvalue::Use(Operand::Constant(Box::new(Constant { span: source_info.span, user_ty: None, - literal: self.ecx.tcx.mk_const(ty::Const { - ty, - val: ty::ConstKind::Value(ConstValue::ByRef { - alloc, - offset: Size::ZERO, - }), - }), + literal: self + .ecx + .tcx + .mk_const(ty::Const { + ty, + val: ty::ConstKind::Value(ConstValue::ByRef { + alloc, + offset: Size::ZERO, + }), + }) + .into(), }))); } } diff --git a/compiler/rustc_mir/src/transform/elaborate_drops.rs b/compiler/rustc_mir/src/transform/elaborate_drops.rs index 3d435f6d0e7..c0fcfb620ff 100644 --- a/compiler/rustc_mir/src/transform/elaborate_drops.rs +++ b/compiler/rustc_mir/src/transform/elaborate_drops.rs @@ -471,7 +471,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { Rvalue::Use(Operand::Constant(Box::new(Constant { span, user_ty: None, - literal: ty::Const::from_bool(self.tcx, val), + literal: ty::Const::from_bool(self.tcx, val).into(), }))) } diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs index f299b6ecc28..c85e9b9b932 100644 --- a/compiler/rustc_mir/src/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -989,7 +989,7 @@ fn insert_panic_block<'tcx>( cond: Operand::Constant(box Constant { span: body.span, user_ty: None, - literal: ty::Const::from_bool(tcx, false), + literal: ty::Const::from_bool(tcx, false).into(), }), expected: true, msg: message, diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index cf85503b3d5..dd06daecd5d 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -416,7 +416,7 @@ impl Inliner<'tcx> { TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => { if let ty::FnDef(def_id, substs) = - *callsite.callee.subst_mir(self.tcx, &f.literal.ty).kind() + *callsite.callee.subst_mir(self.tcx, &f.literal.ty()).kind() { let substs = self.tcx.normalize_erasing_regions(self.param_env, substs); if let Ok(Some(instance)) = @@ -637,8 +637,11 @@ impl Inliner<'tcx> { // `required_consts`, here we may not only have `ConstKind::Unevaluated` // because we are calling `subst_and_normalize_erasing_regions`. caller_body.required_consts.extend( - callee_body.required_consts.iter().copied().filter(|&constant| { - matches!(constant.literal.val, ConstKind::Unevaluated(_, _, _)) + callee_body.required_consts.iter().copied().filter(|&ct| { + match ct.literal.const_for_ty() { + Some(ct) => matches!(ct.val, ConstKind::Unevaluated(_, _, _)), + None => true, + } }), ); } diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs index bad82fe893e..7aaf0224164 100644 --- a/compiler/rustc_mir/src/transform/instcombine.rs +++ b/compiler/rustc_mir/src/transform/instcombine.rs @@ -79,7 +79,7 @@ impl<'tcx, 'a> InstCombineContext<'tcx, 'a> { fn try_eval_bool(&self, a: &Operand<'_>) -> Option { let a = a.constant()?; - if a.literal.ty.is_bool() { a.literal.val.try_to_bool() } else { None } + if a.literal.ty().is_bool() { a.literal.try_to_bool() } else { None } } /// Transform "&(*a)" ==> "a". @@ -110,12 +110,13 @@ impl<'tcx, 'a> InstCombineContext<'tcx, 'a> { fn combine_len(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) { if let Rvalue::Len(ref place) = *rvalue { let place_ty = place.ty(self.local_decls, self.tcx).ty; - if let ty::Array(_, len) = place_ty.kind() { + if let ty::Array(_, len) = *place_ty.kind() { if !self.should_combine(source_info, rvalue) { return; } - let constant = Constant { span: source_info.span, literal: len, user_ty: None }; + let constant = + Constant { span: source_info.span, literal: len.into(), user_ty: None }; *rvalue = Rvalue::Use(Operand::Constant(box constant)); } } diff --git a/compiler/rustc_mir/src/transform/lower_intrinsics.rs b/compiler/rustc_mir/src/transform/lower_intrinsics.rs index d6a73360616..e6ee474285e 100644 --- a/compiler/rustc_mir/src/transform/lower_intrinsics.rs +++ b/compiler/rustc_mir/src/transform/lower_intrinsics.rs @@ -33,7 +33,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { Rvalue::Use(Operand::Constant(box Constant { span: terminator.source_info.span, user_ty: None, - literal: ty::Const::zero_sized(tcx, tcx.types.unit), + literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(), })), )), }); diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index 15c2c3a160f..d04a7011ab0 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -93,8 +93,8 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))), StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), ) if lhs_f == lhs_s - && f_c.literal.ty.is_bool() - && s_c.literal.ty.is_bool() + && f_c.literal.ty().is_bool() + && s_c.literal.ty().is_bool() && f_c.literal.try_eval_bool(tcx, param_env).is_some() && s_c.literal.try_eval_bool(tcx, param_env).is_some() => {} diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index f60570483ce..7db790cf32b 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -921,7 +921,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let unit = Rvalue::Use(Operand::Constant(box Constant { span: statement.source_info.span, user_ty: None, - literal: ty::Const::zero_sized(self.tcx, self.tcx.types.unit), + literal: ty::Const::zero_sized(self.tcx, self.tcx.types.unit).into(), })); mem::replace(rhs, unit) }, @@ -998,20 +998,22 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { Operand::Constant(Box::new(Constant { span, user_ty: None, - literal: tcx.mk_const(ty::Const { - ty, - val: ty::ConstKind::Unevaluated( - def, - InternalSubsts::for_item(tcx, def.did, |param, _| { - if let ty::GenericParamDefKind::Lifetime = param.kind { - tcx.lifetimes.re_erased.into() - } else { - tcx.mk_param_from_def(param) - } - }), - Some(promoted_id), - ), - }), + literal: tcx + .mk_const(ty::Const { + ty, + val: ty::ConstKind::Unevaluated( + def, + InternalSubsts::for_item(tcx, def.did, |param, _| { + if let ty::GenericParamDefKind::Lifetime = param.kind { + tcx.lifetimes.re_erased.into() + } else { + tcx.mk_param_from_def(param) + } + }), + Some(promoted_id), + ), + }) + .into(), })) }; let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); @@ -1250,8 +1252,8 @@ crate fn is_const_fn_in_array_repeat_expression<'tcx>( if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) = &block.terminator { - if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func { - if let ty::FnDef(def_id, _) = *ty.kind() { + if let Operand::Constant(box Constant { literal, .. }) = func { + if let ty::FnDef(def_id, _) = *literal.ty().kind() { if let Some((destination_place, _)) = destination { if destination_place == place { if is_const_fn(ccx.tcx, def_id) { diff --git a/compiler/rustc_mir/src/transform/required_consts.rs b/compiler/rustc_mir/src/transform/required_consts.rs index a63ab30a68f..2b518bd3a48 100644 --- a/compiler/rustc_mir/src/transform/required_consts.rs +++ b/compiler/rustc_mir/src/transform/required_consts.rs @@ -14,10 +14,10 @@ impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for RequiredConstsVisitor<'a, 'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) { - let const_kind = constant.literal.val; - - if let ConstKind::Unevaluated(_, _, _) = const_kind { - self.required_consts.push(*constant); + if let Some(ct) = constant.literal.const_for_ty() { + if let ConstKind::Unevaluated(_, _, _) = ct.val { + self.required_consts.push(*constant); + } } } } diff --git a/compiler/rustc_mir/src/transform/rustc_peek.rs b/compiler/rustc_mir/src/transform/rustc_peek.rs index 7598be4e4a1..a6b8f20f6d4 100644 --- a/compiler/rustc_mir/src/transform/rustc_peek.rs +++ b/compiler/rustc_mir/src/transform/rustc_peek.rs @@ -205,7 +205,7 @@ impl PeekCall { if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } = &terminator.kind { - if let ty::FnDef(def_id, substs) = *func.literal.ty.kind() { + if let ty::FnDef(def_id, substs) = *func.literal.ty().kind() { let sig = tcx.fn_sig(def_id); let name = tcx.item_name(def_id); if sig.abi() != Abi::RustIntrinsic || name != sym::rustc_peek { diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs index 32df40ebf9e..9f473f3bae5 100644 --- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs +++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs @@ -205,12 +205,12 @@ fn find_branch_value_info<'tcx>( match (left, right) { (Constant(branch_value), Copy(to_switch_on) | Move(to_switch_on)) | (Copy(to_switch_on) | Move(to_switch_on), Constant(branch_value)) => { - let branch_value_ty = branch_value.literal.ty; + let branch_value_ty = branch_value.literal.ty(); // we only want to apply this optimization if we are matching on integrals (and chars), as it is not possible to switch on floats if !branch_value_ty.is_integral() && !branch_value_ty.is_char() { return None; }; - let branch_value_scalar = branch_value.literal.val.try_to_scalar()?; + let branch_value_scalar = branch_value.literal.try_to_scalar()?; Some((branch_value_scalar, branch_value_ty, *to_switch_on)) } _ => None, diff --git a/compiler/rustc_mir/src/util/elaborate_drops.rs b/compiler/rustc_mir/src/util/elaborate_drops.rs index b22dadcd7d2..e9190d7ebef 100644 --- a/compiler/rustc_mir/src/util/elaborate_drops.rs +++ b/compiler/rustc_mir/src/util/elaborate_drops.rs @@ -1035,7 +1035,7 @@ where Operand::Constant(box Constant { span: self.source_info.span, user_ty: None, - literal: ty::Const::from_usize(self.tcx(), val.into()), + literal: ty::Const::from_usize(self.tcx(), val.into()).into(), }) } diff --git a/compiler/rustc_mir/src/util/find_self_call.rs b/compiler/rustc_mir/src/util/find_self_call.rs index 5b146eeb87c..ddda98d1616 100644 --- a/compiler/rustc_mir/src/util/find_self_call.rs +++ b/compiler/rustc_mir/src/util/find_self_call.rs @@ -17,8 +17,8 @@ pub fn find_self_call<'tcx>( &body[block].terminator { debug!("find_self_call: func={:?}", func); - if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func { - if let ty::FnDef(def_id, substs) = *ty.kind() { + if let Operand::Constant(box Constant { literal, .. }) = func { + if let ty::FnDef(def_id, substs) = *literal.ty().kind() { if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = tcx.opt_associated_item(def_id) { diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 247a0beccaf..8e38a87a8f4 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -439,7 +439,7 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); let Constant { span, user_ty, literal } = constant; - match literal.ty.kind() { + match literal.ty().kind() { ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char => {} // Unit type ty::Tuple(tys) if tys.is_empty() => {} @@ -449,7 +449,12 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { if let Some(user_ty) = user_ty { self.push(&format!("+ user_ty: {:?}", user_ty)); } - self.push(&format!("+ literal: {:?}", literal)); + match literal { + ConstantSource::Ty(literal) => self.push(&format!("+ literal: {:?}", literal)), + ConstantSource::Val(val, ty) => { + self.push(&format!("+ literal: {:?}, {}", val, ty)) + } + } } } } diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs index 42e2b242d77..e562e52f841 100644 --- a/compiler/rustc_mir_build/src/build/cfg.rs +++ b/compiler/rustc_mir_build/src/build/cfg.rs @@ -68,7 +68,7 @@ impl<'tcx> CFG<'tcx> { Rvalue::Use(Operand::Constant(box Constant { span: source_info.span, user_ty: None, - literal: ty::Const::zero_sized(tcx, tcx.types.unit), + literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(), })), ); } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 727aedb0ef8..c8f9993def3 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -11,7 +11,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn as_constant(&mut self, expr: &Expr<'_, 'tcx>) -> Constant<'tcx> { let this = self; let Expr { ty, temp_lifetime: _, span, ref kind } = *expr; - match kind { + match *kind { ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value), ExprKind::Literal { literal, user_ty, const_id: _ } => { let user_ty = user_ty.map(|user_ty| { @@ -22,11 +22,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) }); assert_eq!(literal.ty, ty); - Constant { span, user_ty, literal } + Constant { span, user_ty, literal: literal.into() } } - ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal }, + ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal: literal.into() }, ExprKind::ConstBlock { value } => { - Constant { span: span, user_ty: None, literal: value } + Constant { span: span, user_ty: None, literal: value.into() } } _ => span_bug!(span, "expression is not a valid constant {:?}", kind), } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index d73e5eef70c..65531b60818 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -219,7 +219,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::Use(Operand::Constant(box Constant { span: expr_span, user_ty: None, - literal: ty::Const::zero_sized(this.tcx, this.tcx.types.unit), + literal: ty::Const::zero_sized(this.tcx, this.tcx.types.unit).into(), }))) } ExprKind::Yield { .. } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 47f75825fb6..1dc6506e30d 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span: expr_span, user_ty: None, - literal: ty::Const::from_bool(this.tcx, true), + literal: ty::Const::from_bool(this.tcx, true).into(), }, ); @@ -157,7 +157,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span: expr_span, user_ty: None, - literal: ty::Const::from_bool(this.tcx, false), + literal: ty::Const::from_bool(this.tcx, false).into(), }, ); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 48abaa8d35f..7f26c0e5d76 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -429,7 +429,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Need to experiment. user_ty: None, - literal: method, + literal: method.into(), }), args: vec![val, expect], destination: Some((eq_result, eq_block)), diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs index 62c217a12aa..a1126d1c3d5 100644 --- a/compiler/rustc_mir_build/src/build/misc.rs +++ b/compiler/rustc_mir_build/src/build/misc.rs @@ -30,6 +30,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span: Span, literal: &'tcx ty::Const<'tcx>, ) -> Operand<'tcx> { + let literal = literal.into(); let constant = box Constant { span, user_ty: None, literal }; Operand::Constant(constant) } @@ -57,7 +58,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span: source_info.span, user_ty: None, - literal: ty::Const::from_usize(self.tcx, value), + literal: ty::Const::from_usize(self.tcx, value).into(), }, ); temp diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index f4983dd7531..5ace45e4c7c 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -377,7 +377,10 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let local = self.place_to_local(span, p)?; Ok(self.locals[local]) } - mir::Operand::Constant(ct) => Ok(self.add_node(Node::Leaf(ct.literal), span)), + mir::Operand::Constant(ct) => match ct.literal { + mir::ConstantSource::Ty(ct) => Ok(self.add_node(Node::Leaf(ct), span)), + mir::ConstantSource::Val(..) => self.error(Some(span), "unsupported constant")?, + }, } } From 20f737966ec350e3cdc3b4193f2d000ad321d10e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 10 Mar 2021 11:45:22 +0000 Subject: [PATCH 14/27] Replace a custom lift method with a Lift impl --- compiler/rustc_middle/src/mir/interpret/value.rs | 9 ++++++--- compiler/rustc_middle/src/mir/mod.rs | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index cddcc7d576a..515aabd59bc 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -8,7 +8,7 @@ use rustc_apfloat::{ use rustc_macros::HashStable; use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; -use crate::ty::{ParamEnv, ScalarInt, Ty, TyCtxt}; +use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt}; use super::{AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; @@ -53,8 +53,9 @@ impl From for ConstValue<'tcx> { } } -impl<'tcx> ConstValue<'tcx> { - pub fn lift<'lifted>(self, tcx: TyCtxt<'lifted>) -> Option> { +impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> { + type Lifted = ConstValue<'tcx>; + fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option> { Some(match self { ConstValue::Scalar(s) => ConstValue::Scalar(s), ConstValue::Slice { data, start, end } => { @@ -65,7 +66,9 @@ impl<'tcx> ConstValue<'tcx> { } }) } +} +impl<'tcx> ConstValue<'tcx> { #[inline] pub fn try_to_scalar(&self) -> Option { match *self { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 20ba82a8e86..481d02fccf5 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2738,7 +2738,7 @@ fn pretty_print_const_value( ) -> fmt::Result { use crate::ty::print::PrettyPrinter; ty::tls::with(|tcx| { - let val = val.lift(tcx).unwrap(); + let val = tcx.lift(val).unwrap(); let ty = tcx.lift(ty).unwrap(); let mut cx = FmtPrinter::new(tcx, fmt, Namespace::ValueNS); cx.print_alloc_ids = true; From 6ca1d871948cc8fb9831f7f4d2e898bbef557e93 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 12 Mar 2021 12:59:37 +0000 Subject: [PATCH 15/27] Visit `mir::Constant::user_ty` for completeness. It's not necessary yet, but it may become necessary with things like lazy normalization. --- compiler/rustc_middle/src/mir/type_foldable.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 4ad69a2cb98..44bedd75553 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -342,8 +342,8 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { } } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { - self.literal.visit_with(visitor) - // FIXME: should this be visiting the `user_ty`, too? + self.literal.visit_with(visitor)?; + self.user_ty.visit_with(visitor) } } From c51749af6e8b42540f0493c7be47df332686d64a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 12 Mar 2021 13:00:16 +0000 Subject: [PATCH 16/27] We won't support trait object constants in type level constants for the forseeable future --- compiler/rustc_mir/src/const_eval/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index 5e77cc9daf3..ca165f2c8cb 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -87,9 +87,11 @@ fn const_to_valtree_inner<'tcx>( ty::FnPtr(_) | ty::RawPtr(_) => None, ty::Ref(..) => unimplemented!("need to use deref_const"), - ty::Dynamic(..) => unimplemented!( - "for trait objects we must look at the vtable and figure out the real type" - ), + // Trait objects are not allowed in type level constants, as we have no concept for + // resolving their backing type, even if we can do that at const eval time. We may want to consider + // adding a `ValTree::DownCast(Ty<'tcx>, Box)` in the future, but I don't even know the + // questions such a concept would open up, so an RFC would probably be good for this. + ty::Dynamic(..) => None, ty::Slice(_) | ty::Str => { unimplemented!("need to find the backing data of the slice/str and recurse on that") From 11ddd2251061bd84408c6e098588c41f4f51370b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 12 Mar 2021 13:46:39 +0000 Subject: [PATCH 17/27] Run rustfmt --- compiler/rustc_mir_build/src/build/expr/as_constant.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index c8f9993def3..57f56e2d092 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -24,7 +24,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { assert_eq!(literal.ty, ty); Constant { span, user_ty, literal: literal.into() } } - ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal: literal.into() }, + ExprKind::StaticRef { literal, .. } => { + Constant { span, user_ty: None, literal: literal.into() } + } ExprKind::ConstBlock { value } => { Constant { span: span, user_ty: None, literal: value.into() } } From c30c1be1e69a0cf37855b611fa0921e41e04016f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 15 Mar 2021 11:23:44 +0000 Subject: [PATCH 18/27] s/ConstantSource/ConstantKind/ --- .../rustc_codegen_cranelift/src/constant.rs | 12 ++++---- .../rustc_codegen_ssa/src/mir/constant.rs | 4 +-- .../rustc_middle/src/mir/interpret/value.rs | 8 ------ compiler/rustc_middle/src/mir/mod.rs | 28 +++++++++---------- .../rustc_middle/src/mir/type_foldable.rs | 10 +++---- compiler/rustc_middle/src/mir/visit.rs | 4 +-- .../src/borrow_check/type_check/mod.rs | 2 +- compiler/rustc_mir/src/interpret/operand.rs | 6 ++-- .../rustc_mir/src/transform/const_prop.rs | 12 ++++---- compiler/rustc_mir/src/util/pretty.rs | 4 +-- .../src/traits/const_evaluatable.rs | 4 +-- 11 files changed, 43 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 23ad5267c56..9d93370b7d0 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -40,8 +40,8 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool { let mut all_constants_ok = true; for constant in &fx.mir.required_consts { let const_ = match fx.monomorphize(constant.literal) { - ConstantSource::Ty(ct) => ct, - ConstantSource::Val(..) => continue, + ConstantKind::Ty(ct) => ct, + ConstantKind::Val(..) => continue, }; match const_.val { ConstKind::Value(_) => {} @@ -117,8 +117,8 @@ pub(crate) fn codegen_constant<'tcx>( constant: &Constant<'tcx>, ) -> CValue<'tcx> { let const_ = match fx.monomorphize(constant.literal) { - ConstantSource::Ty(ct) => ct, - ConstantSource::Val(val, ty) => return codegen_const_value(fx, val, ty), + ConstantKind::Ty(ct) => ct, + ConstantKind::Val(val, ty) => return codegen_const_value(fx, val, ty), }; let const_val = match const_.val { ConstKind::Value(const_val) => const_val, @@ -427,10 +427,10 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( match operand { Operand::Copy(_) | Operand::Move(_) => None, Operand::Constant(const_) => match const_.literal { - ConstantSource::Ty(const_) => { + ConstantKind::Ty(const_) => { fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val.try_to_value() } - ConstantSource::Val(val, _) => Some(val), + ConstantKind::Val(val, _) => Some(val), }, } } diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index d73e2325a8b..aa41acc3578 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -26,8 +26,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Result, ErrorHandled> { let ct = self.monomorphize(constant.literal); let ct = match ct { - mir::ConstantSource::Ty(ct) => ct, - mir::ConstantSource::Val(val, _) => return Ok(val), + mir::ConstantKind::Ty(ct) => ct, + mir::ConstantKind::Val(val, _) => return Ok(val), }; match ct.val { ty::ConstKind::Unevaluated(def, substs, promoted) => self diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 515aabd59bc..44810a9b2e6 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -381,14 +381,6 @@ impl<'tcx, Tag> Scalar { self.to_bits(target_size).expect("expected Raw bits but got a Pointer") } - #[inline] - pub fn to_int(self) -> InterpResult<'tcx, ScalarInt> { - match self { - Scalar::Ptr(_) => throw_unsup!(ReadPointerAsBytes), - Scalar::Int(int) => Ok(int), - } - } - #[inline] pub fn assert_int(self) -> ScalarInt { self.to_int().expect("expected an int but got an abstract pointer") diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 481d02fccf5..0ba0429b4e2 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2033,7 +2033,7 @@ impl<'tcx> Operand<'tcx> { Operand::Constant(box Constant { span, user_ty: None, - literal: ConstantSource::Ty(ty::Const::zero_sized(tcx, ty)), + literal: ConstantKind::Ty(ty::Const::zero_sized(tcx, ty)), }) } @@ -2064,7 +2064,7 @@ impl<'tcx> Operand<'tcx> { Operand::Constant(box Constant { span, user_ty: None, - literal: ConstantSource::Val(val.into(), ty), + literal: ConstantKind::Val(val.into(), ty), }) } @@ -2406,11 +2406,11 @@ pub struct Constant<'tcx> { /// Needed for NLL to impose user-given type constraints. pub user_ty: Option, - pub literal: ConstantSource<'tcx>, + pub literal: ConstantKind<'tcx>, } #[derive(Clone, Copy, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable, Debug)] -pub enum ConstantSource<'tcx> { +pub enum ConstantKind<'tcx> { /// This constant came from the type system Ty(&'tcx ty::Const<'tcx>), /// This constant cannot go back into the type system, as it represents @@ -2436,33 +2436,33 @@ impl Constant<'tcx> { } } -impl From<&'tcx ty::Const<'tcx>> for ConstantSource<'tcx> { +impl From<&'tcx ty::Const<'tcx>> for ConstantKind<'tcx> { fn from(ct: &'tcx ty::Const<'tcx>) -> Self { Self::Ty(ct) } } -impl ConstantSource<'tcx> { +impl ConstantKind<'tcx> { /// Returns `None` if the constant is not trivially safe for use in the type system. pub fn const_for_ty(&self) -> Option<&'tcx ty::Const<'tcx>> { match self { - ConstantSource::Ty(c) => Some(c), - ConstantSource::Val(..) => None, + ConstantKind::Ty(c) => Some(c), + ConstantKind::Val(..) => None, } } pub fn ty(&self) -> Ty<'tcx> { match self { - ConstantSource::Ty(c) => c.ty, - ConstantSource::Val(_, ty) => ty, + ConstantKind::Ty(c) => c.ty, + ConstantKind::Val(_, ty) => ty, } } #[inline] pub fn try_to_value(self) -> Option> { match self { - ConstantSource::Ty(c) => c.val.try_to_value(), - ConstantSource::Val(val, _) => Some(val), + ConstantKind::Ty(c) => c.val.try_to_value(), + ConstantKind::Val(val, _) => Some(val), } } @@ -2709,8 +2709,8 @@ impl<'tcx> Display for Constant<'tcx> { _ => write!(fmt, "const ")?, } match self.literal { - ConstantSource::Ty(c) => pretty_print_const(c, fmt, true), - ConstantSource::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true), + ConstantKind::Ty(c) => pretty_print_const(c, fmt, true), + ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true), } } } diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 44bedd75553..cb599277270 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -347,18 +347,18 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ConstantSource<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> { fn super_fold_with>(self, folder: &mut F) -> Self { match self { - ConstantSource::Ty(c) => ConstantSource::Ty(c.fold_with(folder)), - ConstantSource::Val(v, t) => ConstantSource::Val(v, t.fold_with(folder)), + ConstantKind::Ty(c) => ConstantKind::Ty(c.fold_with(folder)), + ConstantKind::Val(v, t) => ConstantKind::Val(v, t.fold_with(folder)), } } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { match *self { - ConstantSource::Ty(c) => c.visit_with(visitor), - ConstantSource::Val(_, t) => t.visit_with(visitor), + ConstantKind::Ty(c) => c.visit_with(visitor), + ConstantKind::Val(_, t) => t.visit_with(visitor), } } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 9015e771864..be248ccabda 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -872,8 +872,8 @@ macro_rules! make_mir_visitor { self.visit_span(span); drop(user_ty); // no visit method for this match literal { - ConstantSource::Ty(ct) => self.visit_const(ct, location), - ConstantSource::Val(_, t) => self.visit_ty(t, TyContext::Location(location)), + ConstantKind::Ty(ct) => self.visit_const(ct, location), + ConstantKind::Val(_, t) => self.visit_ty(t, TyContext::Location(location)), } } diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index d744db064b6..cce1549cb29 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -315,7 +315,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } else { let tcx = self.tcx(); let maybe_uneval = match constant.literal { - ConstantSource::Ty(ct) => match ct.val { + ConstantKind::Ty(ct) => match ct.val { ty::ConstKind::Unevaluated(def, substs, promoted) => { Some((def, substs, promoted)) } diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 69ab2abaf27..28933493a21 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -573,12 +573,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { crate fn mir_const_to_op( &self, - val: &mir::ConstantSource<'tcx>, + val: &mir::ConstantKind<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { match val { - mir::ConstantSource::Ty(ct) => self.const_to_op(ct, layout), - mir::ConstantSource::Val(val, ty) => self.const_val_to_op(*val, ty, None), + mir::ConstantKind::Ty(ct) => self.const_to_op(ct, layout), + mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, ty, None), } } diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index 0d5c8953bc6..cc8669d9705 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -13,9 +13,9 @@ use rustc_middle::mir::visit::{ MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, }; use rustc_middle::mir::{ - AssertKind, BasicBlock, BinOp, Body, ClearCrossCrate, Constant, ConstantSource, Local, - LocalDecl, LocalKind, Location, Operand, Place, Rvalue, SourceInfo, SourceScope, - SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, + AssertKind, BasicBlock, BinOp, Body, ClearCrossCrate, Constant, ConstantKind, Local, LocalDecl, + LocalKind, Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, + Statement, StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, }; use rustc_middle::ty::layout::{HasTyCtxt, LayoutError, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; @@ -489,14 +489,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let err = ConstEvalErr::new(&self.ecx, error, Some(c.span)); if let Some(lint_root) = self.lint_root(source_info) { let lint_only = match c.literal { - ConstantSource::Ty(ct) => match ct.val { + ConstantKind::Ty(ct) => match ct.val { // Promoteds must lint and not error as the user didn't ask for them ConstKind::Unevaluated(_, _, Some(_)) => true, // Out of backwards compatibility we cannot report hard errors in unused // generic functions using associated constants of the generic parameters. _ => c.literal.needs_subst(), }, - ConstantSource::Val(_, ty) => ty.needs_subst(), + ConstantKind::Val(_, ty) => ty.needs_subst(), }; if lint_only { // Out of backwards compatibility we cannot report hard errors in unused @@ -818,7 +818,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ) { if let Rvalue::Use(Operand::Constant(c)) = rval { match c.literal { - ConstantSource::Ty(c) if matches!(c.val, ConstKind::Unevaluated(..)) => {} + ConstantKind::Ty(c) if matches!(c.val, ConstKind::Unevaluated(..)) => {} _ => { trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c); return; diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 8e38a87a8f4..1bf010ffca7 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -450,8 +450,8 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { self.push(&format!("+ user_ty: {:?}", user_ty)); } match literal { - ConstantSource::Ty(literal) => self.push(&format!("+ literal: {:?}", literal)), - ConstantSource::Val(val, ty) => { + ConstantKind::Ty(literal) => self.push(&format!("+ literal: {:?}", literal)), + ConstantKind::Val(val, ty) => { self.push(&format!("+ literal: {:?}, {}", val, ty)) } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 5ace45e4c7c..670527fb3f0 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -378,8 +378,8 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { Ok(self.locals[local]) } mir::Operand::Constant(ct) => match ct.literal { - mir::ConstantSource::Ty(ct) => Ok(self.add_node(Node::Leaf(ct), span)), - mir::ConstantSource::Val(..) => self.error(Some(span), "unsupported constant")?, + mir::ConstantKind::Ty(ct) => Ok(self.add_node(Node::Leaf(ct), span)), + mir::ConstantKind::Val(..) => self.error(Some(span), "unsupported constant")?, }, } } From bc8641a4877a15d4a3184c079e8548029d02d524 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 15 Mar 2021 11:31:01 +0000 Subject: [PATCH 19/27] Document valtree --- compiler/rustc_middle/src/ty/consts/valtree.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 6c8eea8c768..fbe4c657323 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -3,8 +3,26 @@ use rustc_macros::HashStable; #[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)] #[derive(HashStable)] +/// This datastructure is used to represent the value of constants used in the type system. +/// +/// We explicitly choose a different datastructure from the way values are processed within +/// CTFE, as in the type system equal values must also have equal representation. +/// Since CTFE uses `AllocId` to represent pointers, it often happens that two different +/// `AllocId`s point to equal values. So we may end up with different representations for +/// two constants whose value is `&42`. Furthermore any kind of struct that has padding will +/// have arbitrary values within that padding, even if the values of the struct are the same. +/// +/// `ValTree` does not have this problem with representation, as it only contains integers or +/// lists of values of itself. pub enum ValTree<'tcx> { + /// ZSTs, integers, `bool`, `char` are represented as scalars. + /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values + /// of these types have the same representation. Leaf(ScalarInt), + /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by + /// listing their fields' values in order. + /// Enums are represented by storing their discriminant as a field, followed by all + /// the fields of the variant. Branch(&'tcx [ValTree<'tcx>]), } From f646c1e43445f5edff741c8572cb7d52bdb97ce1 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 15 Mar 2021 11:52:00 +0000 Subject: [PATCH 20/27] Explain why we do not allow const_to_valtree to read from statics --- compiler/rustc_mir/src/const_eval/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index ca165f2c8cb..4086c18c3d2 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -44,7 +44,12 @@ pub(crate) fn const_to_valtree<'tcx>( param_env: ty::ParamEnv<'tcx>, raw: ConstAlloc<'tcx>, ) -> Option> { - let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); + let ecx = mk_eval_cx( + tcx, DUMMY_SP, param_env, + // It is absolutely crucial for soundness that + // we do not read from static items or other mutable memory. + false, + ); let place = ecx.raw_const_to_mplace(raw).unwrap(); const_to_valtree_inner(&ecx, &place) } From c01c49430c8e5a2b5aa7db777f49bd3a18525d0b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 15 Mar 2021 11:52:26 +0000 Subject: [PATCH 21/27] Explain how we encode enums at the encoding site --- compiler/rustc_mir/src/const_eval/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index 4086c18c3d2..218b1dadebd 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -69,10 +69,11 @@ fn const_to_valtree_inner<'tcx>( let field = ecx.mplace_field(&place, i).unwrap(); const_to_valtree_inner(ecx, &field) }); + // For enums, we preped their variant index before the variant's fields so we can figure out + // the variant again when just seeing a valtree. + let branches = variant.into_iter().chain(fields); Some(ty::ValTree::Branch( - ecx.tcx - .arena - .alloc_from_iter(variant.into_iter().chain(fields).collect::>>()?), + ecx.tcx.arena.alloc_from_iter(branches.collect::>>()?), )) }; match place.layout.ty.kind() { From 0dd5a1b622f1ba1ca702e079b2ce2ab5b513e2be Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 15 Mar 2021 11:53:37 +0000 Subject: [PATCH 22/27] Explain pointer and dyn Trait handling in const_to_valtree --- compiler/rustc_mir/src/const_eval/mod.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index 218b1dadebd..c45c29ccdcf 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -84,19 +84,18 @@ fn const_to_valtree_inner<'tcx>( Some(ty::ValTree::Leaf(val.assert_int())) } - // Raw pointers are not allowed in type level constants, as raw pointers cannot be treated - // like references. If we looked behind the raw pointer, we may be breaking the meaning of - // the raw pointer. Equality on raw pointers is performed on the pointer and not on the pointee, - // and we cannot guarantee any kind of pointer stability in the type system. + // Raw pointers are not allowed in type level constants, as raw pointers compare equal if + // their addresses are equal. Since we cannot guarantee any kind of pointer stability in + // the type system. // Technically we could allow function pointers, but they are not guaranteed to be the // same as the function pointers at runtime. ty::FnPtr(_) | ty::RawPtr(_) => None, ty::Ref(..) => unimplemented!("need to use deref_const"), // Trait objects are not allowed in type level constants, as we have no concept for - // resolving their backing type, even if we can do that at const eval time. We may want to consider - // adding a `ValTree::DownCast(Ty<'tcx>, Box)` in the future, but I don't even know the - // questions such a concept would open up, so an RFC would probably be good for this. + // resolving their backing type, even if we can do that at const eval time. We may + // hypothetically be able to allow `dyn StructuralEq` trait objects in the future, + // but it is unclear if this is useful. ty::Dynamic(..) => None, ty::Slice(_) | ty::Str => { @@ -107,8 +106,7 @@ fn const_to_valtree_inner<'tcx>( ty::Adt(def, _) => { if def.variants.is_empty() { - // Uninhabited - return None; + bug!("uninhabited types should have errored and never gotten converted to valtree") } let variant = ecx.read_discriminant(&place.into()).unwrap().1; From 9f407ae5ee53a0c1e2ec12ee1087c8f58e5f0ac0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 15 Mar 2021 12:06:07 +0000 Subject: [PATCH 23/27] Do not expose fallible `to_int` operation on `Scalar`. Any use of it has been shown to be a bug in the past. --- .../rustc_middle/src/mir/interpret/value.rs | 32 +++++++++---------- compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/ty/consts/kind.rs | 2 +- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 44810a9b2e6..5172dfd041a 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -78,7 +78,7 @@ impl<'tcx> ConstValue<'tcx> { } pub fn try_to_scalar_int(&self) -> Option { - self.try_to_scalar()?.to_int().ok() + Some(self.try_to_scalar()?.assert_int()) } pub fn try_to_bits(&self, size: Size) -> Option { @@ -367,13 +367,16 @@ impl<'tcx, Tag> Scalar { #[inline] 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"); - self.to_int()?.to_bits(target_size).map_err(|size| { - err_ub!(ScalarSizeMismatch { - target_size: target_size.bytes(), - data_size: size.bytes(), - }) - .into() - }) + match self { + 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), + } } #[inline(always)] @@ -383,7 +386,10 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn assert_int(self) -> ScalarInt { - self.to_int().expect("expected an int but got an abstract pointer") + match self { + Scalar::Ptr(_) => bug!("expected an int but got an abstract pointer"), + Scalar::Int(int) => int, + } } #[inline] @@ -518,14 +524,6 @@ impl From> for Scalar { } } -impl TryFrom for ScalarInt { - type Error = super::InterpErrorInfo<'static>; - #[inline] - fn try_from(scalar: Scalar) -> InterpResult<'static, Self> { - scalar.to_int() - } -} - impl From for Scalar { #[inline(always)] fn from(ptr: ScalarInt) -> Self { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 0ba0429b4e2..90fda9ec91c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2473,7 +2473,7 @@ impl ConstantKind<'tcx> { #[inline] pub fn try_to_scalar_int(self) -> Option { - self.try_to_value()?.try_to_scalar()?.to_int().ok() + Some(self.try_to_value()?.try_to_scalar()?.assert_int()) } #[inline] diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 5a6f219a413..43e22ce8f87 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -57,7 +57,7 @@ impl<'tcx> ConstKind<'tcx> { #[inline] pub fn try_to_scalar_int(self) -> Option { - self.try_to_value()?.try_to_scalar()?.to_int().ok() + Some(self.try_to_value()?.try_to_scalar()?.assert_int()) } #[inline] From 1ffd21a15c19121e46f931f44e8442e4a31df236 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 15 Mar 2021 12:19:29 +0000 Subject: [PATCH 24/27] Pacify tidy --- compiler/rustc_middle/src/ty/consts/valtree.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index fbe4c657323..97e7dd6507b 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -11,7 +11,7 @@ use rustc_macros::HashStable; /// `AllocId`s point to equal values. So we may end up with different representations for /// two constants whose value is `&42`. Furthermore any kind of struct that has padding will /// have arbitrary values within that padding, even if the values of the struct are the same. -/// +/// /// `ValTree` does not have this problem with representation, as it only contains integers or /// lists of values of itself. pub enum ValTree<'tcx> { From f0997fa1e85d305afef2b5b4e74c4a9b1a043ec2 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 16 Mar 2021 18:26:09 +0100 Subject: [PATCH 25/27] Update compiler/rustc_mir/src/const_eval/mod.rs Co-authored-by: Ralf Jung --- compiler/rustc_mir/src/const_eval/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index c45c29ccdcf..77531ae2c5f 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -84,11 +84,10 @@ fn const_to_valtree_inner<'tcx>( Some(ty::ValTree::Leaf(val.assert_int())) } - // Raw pointers are not allowed in type level constants, as raw pointers compare equal if - // their addresses are equal. Since we cannot guarantee any kind of pointer stability in - // the type system. - // Technically we could allow function pointers, but they are not guaranteed to be the - // same as the function pointers at runtime. + // Raw pointers are not allowed in type level constants, as we cannot properly test them for + // equality at compile-time (see `ptr_guaranteed_eq`/`_ne`). + // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to + // agree with runtime equality tests. ty::FnPtr(_) | ty::RawPtr(_) => None, ty::Ref(..) => unimplemented!("need to use deref_const"), From 5b9bd903c08cb8bfe453e71f8d2d393bcc43819f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 16 Mar 2021 18:31:25 +0100 Subject: [PATCH 26/27] Update compiler/rustc_middle/src/ty/consts/valtree.rs Co-authored-by: Ralf Jung --- compiler/rustc_middle/src/ty/consts/valtree.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 97e7dd6507b..46be9cec7ab 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -6,7 +6,8 @@ use rustc_macros::HashStable; /// This datastructure is used to represent the value of constants used in the type system. /// /// We explicitly choose a different datastructure from the way values are processed within -/// CTFE, as in the type system equal values must also have equal representation. +/// CTFE, as in the type system equal values (according to their `PartialEq`) must also have +/// equal representation (`==` on the rustc data structure, e.g. `ValTree`) and vice versa. /// Since CTFE uses `AllocId` to represent pointers, it often happens that two different /// `AllocId`s point to equal values. So we may end up with different representations for /// two constants whose value is `&42`. Furthermore any kind of struct that has padding will From c4d564c7808334bf08bcbad700f4a4a93a99be14 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 16 Mar 2021 18:31:33 +0100 Subject: [PATCH 27/27] Update compiler/rustc_middle/src/ty/consts/valtree.rs Co-authored-by: Ralf Jung --- compiler/rustc_middle/src/ty/consts/valtree.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 46be9cec7ab..f1b78c87632 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -14,7 +14,7 @@ use rustc_macros::HashStable; /// have arbitrary values within that padding, even if the values of the struct are the same. /// /// `ValTree` does not have this problem with representation, as it only contains integers or -/// lists of values of itself. +/// lists of (nested) `ValTree`. pub enum ValTree<'tcx> { /// ZSTs, integers, `bool`, `char` are represented as scalars. /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values