From 51aa3f86a040599dad36a75c22fa0321f7de0741 Mon Sep 17 00:00:00 2001 From: b-naber Date: Tue, 29 Mar 2022 11:18:40 +0200 Subject: [PATCH 1/6] Add type for slices in ValTrees --- .../rustc_middle/src/ty/consts/valtree.rs | 30 ++++++++++++++++++- compiler/rustc_middle/src/ty/mod.rs | 2 +- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index fae22c28628..64a3b80988e 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -1,5 +1,7 @@ use super::ScalarInt; -use rustc_macros::HashStable; +use crate::ty::codec::TyDecoder; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; +use rustc_serialize::{Decodable, Encodable, Encoder}; #[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)] #[derive(HashStable)] @@ -20,6 +22,7 @@ pub enum ValTree<'tcx> { /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values /// of these types have the same representation. Leaf(ScalarInt), + SliceOrStr(ValSlice<'tcx>), /// 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 @@ -32,3 +35,28 @@ impl<'tcx> ValTree<'tcx> { Self::Branch(&[]) } } + +#[derive(Copy, Clone, Debug, HashStable, Hash, Eq, PartialEq, PartialOrd, Ord)] +pub struct ValSlice<'tcx> { + pub bytes: &'tcx [u8], +} + +impl<'tcx, S: Encoder> Encodable for ValSlice<'tcx> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_usize(self.bytes.len())?; + s.emit_raw_bytes(self.bytes)?; + + Ok(()) + } +} + +impl<'tcx, D: TyDecoder<'tcx>> Decodable for ValSlice<'tcx> { + fn decode(d: &mut D) -> Self { + let tcx = d.tcx(); + let len = d.read_usize(); + let bytes_raw = d.read_raw_bytes(len); + let bytes = tcx.arena.alloc_slice(&bytes_raw[..]); + + ValSlice { bytes } + } +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 31db66dc242..9c81a90529c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -62,7 +62,7 @@ pub use self::closure::{ CAPTURE_STRUCT_LOCAL, }; pub use self::consts::{ - Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, Unevaluated, ValTree, + Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, Unevaluated, ValSlice, ValTree, }; pub use self::context::{ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, From fcc4d8ce98ef61586fccfb7efae7563788453b73 Mon Sep 17 00:00:00 2001 From: b-naber Date: Tue, 29 Mar 2022 11:38:08 +0200 Subject: [PATCH 2/6] include refs in valtree creation --- .../rustc_const_eval/src/const_eval/mod.rs | 138 ++++++++++++++---- .../rustc_const_eval/src/interpret/operand.rs | 37 ++++- .../rustc_const_eval/src/interpret/place.rs | 12 ++ 3 files changed, 158 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 6fd7f707e7e..dad6e5e34a6 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -6,9 +6,10 @@ use rustc_hir::Mutability; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::{ mir::{self, interpret::ConstAlloc}, - ty::ScalarInt, + ty::{ScalarInt, Ty}, }; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; +use rustc_target::abi::VariantIdx; use crate::interpret::{ intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy, @@ -55,28 +56,43 @@ pub(crate) fn const_to_valtree<'tcx>( const_to_valtree_inner(&ecx, &place) } +#[instrument(skip(ecx), level = "debug")] +fn branches<'tcx>( + ecx: &CompileTimeEvalContext<'tcx, 'tcx>, + place: &MPlaceTy<'tcx>, + n: usize, + variant: Option, +) -> Option> { + 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())))); + debug!(?place, ?variant); + + let fields = (0..n).map(|i| { + 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(branches.collect::>>()?))) +} + +#[instrument(skip(ecx), level = "debug")] 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) - }); - // 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(branches.collect::>>()?), - )) + // We only want to use raw bytes in ValTrees for string slices or &[] + let use_bytes_for_ref = |ty: Ty<'tcx>| -> bool { + match ty.kind() { + ty::Str | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Bool => true, + _ => false, + } }; + match place.layout.ty.kind() { ty::FnDef(..) => Some(ty::ValTree::zst()), ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { @@ -90,7 +106,82 @@ fn const_to_valtree_inner<'tcx>( // 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"), + + ty::Ref(_, ref_ty, _) if place.layout.ty.is_slice() => { + match ecx.try_read_immediate_from_mplace(&place) { + Ok(Some(imm)) => { + // `imm` is a ScalarPair. We try to get the underlying bytes behind that + // fat pointer for string slices and slices of integer types. For any other + // slice types we use `branches` to recursively construct the Valtree. + + if use_bytes_for_ref(*ref_ty) { + let (alloc, range) = ecx.get_alloc_from_imm_scalar_pair(imm); + let alloc_bytes = match alloc.get_bytes(&ecx.tcx, range) { + Ok(bytes) => bytes, + Err(_e) => return None, + }; + debug!(?alloc_bytes); + + let bytes = ecx.tcx.arena.alloc_slice(alloc_bytes); + let len = bytes.len(); + debug!(?bytes, ?len); + + let slice = ty::ValSlice { bytes}; + + Some(ty::ValTree::SliceOrStr(slice)) + } else { + let derefd = ecx.deref_operand(&imm.into()).expect(&format!("couldnt deref {:?}", imm)); + debug!("derefd: {:?}", derefd); + + let derefd_imm = match ecx.try_read_immediate_from_mplace(&derefd) { + Ok(Some(imm)) => imm, + _ => return None, + }; + debug!(?derefd_imm); + + let tcx = ecx.tcx.tcx; + let scalar_len= derefd.meta.unwrap_meta(); + let len = match scalar_len { + Scalar::Int(int) => { + int.try_to_machine_usize(tcx).expect(&format!("Expected a valid ScalarInt in {:?}", scalar_len)) + } + _ => bug!("expected a ScalarInt in meta data for {:?}", place), + }; + debug!(?len); + + let valtree = branches(ecx, place, len.try_into().expect("BLA"), None); + debug!(?valtree); + + valtree + } + } + _ => { + None + } + } + } + + ty::Ref(_, inner_ty, _) => { + debug!("Ref with inner_ty: {:?}", inner_ty); + let imm = ecx.try_read_immediate_from_mplace(&place).unwrap_or_else(|e| bug!("couldnt read immediate from {:?}, error: {:?}", place, e)); + match imm { + Some(imm) => { + debug!(?imm); + + let derefd_place = ecx.deref_mplace(place).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e)); + debug!(?derefd_place); + + const_to_valtree_inner(ecx, &derefd_place) + } + None => None, + } + } + ty::Str => { + bug!("ty::Str should have been handled in ty::Ref branch that uses raw bytes"); + } + ty::Slice(_) => { + bug!("should have been handled in the Ref arm"); + } // 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 @@ -98,11 +189,8 @@ fn const_to_valtree_inner<'tcx>( // but it is unclear if this is useful. ty::Dynamic(..) => None, - 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::Tuple(substs) => branches(ecx, place, substs.len(), None), + ty::Array(_, len) => branches(ecx, place, usize::try_from(len.eval_usize(ecx.tcx.tcx, ecx.param_env)).unwrap(), None), ty::Adt(def, _) => { if def.variants().is_empty() { @@ -111,7 +199,7 @@ fn const_to_valtree_inner<'tcx>( let variant = ecx.read_discriminant(&place.into()).unwrap().1; - branches(def.variant(variant).fields.len(), def.is_enum().then_some(variant)) + branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant)) } ty::Never diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 9000567558b..d271bf53eac 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -14,9 +14,9 @@ use rustc_target::abi::{Abi, HasDataLayout, Size, TagEncoding}; use rustc_target::abi::{VariantIdx, Variants}; use super::{ - alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, GlobalId, - InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, Provenance, - Scalar, ScalarMaybeUninit, + alloc_range, from_known_layout, mir_assign_valid_types, AllocId, AllocRange, Allocation, + ConstValue, GlobalId, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, + Pointer, Provenance, Scalar, ScalarMaybeUninit, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -248,7 +248,7 @@ impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> { impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`. /// Returns `None` if the layout does not permit loading this as a value. - fn try_read_immediate_from_mplace( + pub(crate) fn try_read_immediate_from_mplace( &self, mplace: &MPlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, Option>> { @@ -777,3 +777,32 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }) } } + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx, PointerTag = AllocId>> InterpCx<'mir, 'tcx, M> { + pub fn get_alloc_from_imm_scalar_pair( + &self, + imm: ImmTy<'tcx, M::PointerTag>, + ) -> (&Allocation, AllocRange) { + match imm.imm { + Immediate::ScalarPair(a, b) => { + // We know `offset` is relative to the allocation, so we can use `into_parts`. + let (data, start) = match self.scalar_to_ptr(a.check_init().unwrap()).into_parts() { + (Some(alloc_id), offset) => { + (self.tcx.global_alloc(alloc_id).unwrap_memory(), offset.bytes()) + } + (None, _offset) => ( + self.tcx.intern_const_alloc(Allocation::from_bytes_byte_aligned_immutable( + b"" as &[u8], + )), + 0, + ), + }; + let len = b.to_machine_usize(self).unwrap(); + let size = Size::from_bytes(len); + let start = Size::from_bytes(start); + (data.inner(), AllocRange { start, size }) + } + _ => bug!("{:?} not a ScalarPair", imm), + } + } +} diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index b1784b12c65..ad7620d83e6 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -305,6 +305,18 @@ where Ok(mplace) } + #[instrument(skip(self), level = "debug")] + pub fn deref_mplace( + &self, + src: &MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + let val = self.try_read_immediate_from_mplace(src)?; + let mplace = self.ref_to_mplace(&val.unwrap())?; + self.check_mplace_access(mplace, CheckInAllocMsg::DerefTest)?; + + Ok(mplace) + } + #[inline] pub(super) fn get_alloc( &self, From 82217a6587da07433c901a8b3ea0765acf288860 Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 8 Apr 2022 13:09:24 +0200 Subject: [PATCH 3/6] create leafs for slices --- .../src/const_eval/eval_queries.rs | 2 + .../rustc_const_eval/src/const_eval/mod.rs | 126 ++++++++---------- .../rustc_const_eval/src/interpret/operand.rs | 37 +---- .../rustc_const_eval/src/interpret/place.rs | 12 -- .../rustc_middle/src/ty/consts/valtree.rs | 28 ---- compiler/rustc_middle/src/ty/mod.rs | 2 +- 6 files changed, 63 insertions(+), 144 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index df809e82701..e28e7d76616 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -188,6 +188,7 @@ pub(super) fn op_to_const<'tcx>( } } +#[instrument(skip(tcx), level = "debug")] fn turn_into_const_value<'tcx>( tcx: TyCtxt<'tcx>, constant: ConstAlloc<'tcx>, @@ -206,6 +207,7 @@ fn turn_into_const_value<'tcx>( !is_static || cid.promoted.is_some(), "the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead" ); + // Turn this into a proper constant. op_to_const(&ecx, &mplace.into()) } diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index dad6e5e34a6..9b42910f99c 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -6,14 +6,14 @@ use rustc_hir::Mutability; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::{ mir::{self, interpret::ConstAlloc}, - ty::{ScalarInt, Ty}, + ty::ScalarInt, }; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; use rustc_target::abi::VariantIdx; use crate::interpret::{ - intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy, - MemPlaceMeta, Scalar, + intern_const_alloc_recursive, ConstValue, Immediate, InternKind, InterpCx, InterpResult, + MPlaceTy, MemPlaceMeta, Scalar, }; mod error; @@ -80,19 +80,28 @@ fn branches<'tcx>( Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::>>()?))) } +fn slice_branches<'tcx>( + ecx: &CompileTimeEvalContext<'tcx, 'tcx>, + place: &MPlaceTy<'tcx>, + n: u64, +) -> Option> { + let elems = (0..n).map(|i| { + let place_elem = ecx.mplace_index(place, i).unwrap(); + const_to_valtree_inner(ecx, &place_elem) + }); + + // Need `len` for the ValTree -> ConstValue conversion + let len = Some(Some(ty::ValTree::Leaf(ScalarInt::from(n)))); + let branches = len.into_iter().chain(elems); + + Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::>>()?))) +} + #[instrument(skip(ecx), level = "debug")] fn const_to_valtree_inner<'tcx>( ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>, ) -> Option> { - // We only want to use raw bytes in ValTrees for string slices or &[] - let use_bytes_for_ref = |ty: Ty<'tcx>| -> bool { - match ty.kind() { - ty::Str | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Bool => true, - _ => false, - } - }; - match place.layout.ty.kind() { ty::FnDef(..) => Some(ty::ValTree::zst()), ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { @@ -107,75 +116,52 @@ fn const_to_valtree_inner<'tcx>( // agree with runtime equality tests. ty::FnPtr(_) | ty::RawPtr(_) => None, - ty::Ref(_, ref_ty, _) if place.layout.ty.is_slice() => { - match ecx.try_read_immediate_from_mplace(&place) { - Ok(Some(imm)) => { - // `imm` is a ScalarPair. We try to get the underlying bytes behind that - // fat pointer for string slices and slices of integer types. For any other - // slice types we use `branches` to recursively construct the Valtree. + ty::Ref(_, inner_ty, _) => { + match inner_ty.kind() { + ty::Slice(_) | ty::Str => { + match ecx.try_read_immediate_from_mplace(&place) { + Ok(Some(imm)) => { + let mplace_ref = ecx.ref_to_mplace(&imm).unwrap(); + let derefd = ecx.deref_operand(&place.into()).expect(&format!("couldnt deref {:?}", imm)); + debug!(?mplace_ref, ?derefd); - if use_bytes_for_ref(*ref_ty) { - let (alloc, range) = ecx.get_alloc_from_imm_scalar_pair(imm); - let alloc_bytes = match alloc.get_bytes(&ecx.tcx, range) { - Ok(bytes) => bytes, - Err(_e) => return None, - }; - debug!(?alloc_bytes); + let len = match imm.imm { + Immediate::ScalarPair(_, b) => { + let len = b.to_machine_usize(&ecx.tcx.tcx).unwrap(); + len + } + _ => bug!("expected ScalarPair for &[T] or &str"), + }; + debug!(?len); - let bytes = ecx.tcx.arena.alloc_slice(alloc_bytes); - let len = bytes.len(); - debug!(?bytes, ?len); + let valtree = slice_branches(ecx, &derefd, len); + debug!(?valtree); - let slice = ty::ValSlice { bytes}; - - Some(ty::ValTree::SliceOrStr(slice)) - } else { - let derefd = ecx.deref_operand(&imm.into()).expect(&format!("couldnt deref {:?}", imm)); - debug!("derefd: {:?}", derefd); - - let derefd_imm = match ecx.try_read_immediate_from_mplace(&derefd) { - Ok(Some(imm)) => imm, - _ => return None, - }; - debug!(?derefd_imm); - - let tcx = ecx.tcx.tcx; - let scalar_len= derefd.meta.unwrap_meta(); - let len = match scalar_len { - Scalar::Int(int) => { - int.try_to_machine_usize(tcx).expect(&format!("Expected a valid ScalarInt in {:?}", scalar_len)) - } - _ => bug!("expected a ScalarInt in meta data for {:?}", place), - }; - debug!(?len); - - let valtree = branches(ecx, place, len.try_into().expect("BLA"), None); - debug!(?valtree); - - valtree + valtree + } + _ => { + None + } } } _ => { - None + let imm = ecx.try_read_immediate_from_mplace(&place).unwrap_or_else(|e| bug!("couldnt read immediate from {:?}, error: {:?}", place, e)); + + match imm { + Some(imm) => { + debug!(?imm); + + let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e)); + debug!(?derefd_place); + + const_to_valtree_inner(ecx, &derefd_place) + } + None => bug!("couldn't read immediate from {:?}", place), + } } } } - ty::Ref(_, inner_ty, _) => { - debug!("Ref with inner_ty: {:?}", inner_ty); - let imm = ecx.try_read_immediate_from_mplace(&place).unwrap_or_else(|e| bug!("couldnt read immediate from {:?}, error: {:?}", place, e)); - match imm { - Some(imm) => { - debug!(?imm); - - let derefd_place = ecx.deref_mplace(place).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e)); - debug!(?derefd_place); - - const_to_valtree_inner(ecx, &derefd_place) - } - None => None, - } - } ty::Str => { bug!("ty::Str should have been handled in ty::Ref branch that uses raw bytes"); } diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index d271bf53eac..3b9fab9db43 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -14,9 +14,9 @@ use rustc_target::abi::{Abi, HasDataLayout, Size, TagEncoding}; use rustc_target::abi::{VariantIdx, Variants}; use super::{ - alloc_range, from_known_layout, mir_assign_valid_types, AllocId, AllocRange, Allocation, - ConstValue, GlobalId, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, - Pointer, Provenance, Scalar, ScalarMaybeUninit, + alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, GlobalId, + InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, Provenance, + Scalar, ScalarMaybeUninit, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -98,7 +98,7 @@ impl<'tcx, Tag: Provenance> Immediate { // as input for binary and cast operations. #[derive(Copy, Clone, Debug)] pub struct ImmTy<'tcx, Tag: Provenance = AllocId> { - imm: Immediate, + pub(crate) imm: Immediate, pub layout: TyAndLayout<'tcx>, } @@ -777,32 +777,3 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }) } } - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx, PointerTag = AllocId>> InterpCx<'mir, 'tcx, M> { - pub fn get_alloc_from_imm_scalar_pair( - &self, - imm: ImmTy<'tcx, M::PointerTag>, - ) -> (&Allocation, AllocRange) { - match imm.imm { - Immediate::ScalarPair(a, b) => { - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (data, start) = match self.scalar_to_ptr(a.check_init().unwrap()).into_parts() { - (Some(alloc_id), offset) => { - (self.tcx.global_alloc(alloc_id).unwrap_memory(), offset.bytes()) - } - (None, _offset) => ( - self.tcx.intern_const_alloc(Allocation::from_bytes_byte_aligned_immutable( - b"" as &[u8], - )), - 0, - ), - }; - let len = b.to_machine_usize(self).unwrap(); - let size = Size::from_bytes(len); - let start = Size::from_bytes(start); - (data.inner(), AllocRange { start, size }) - } - _ => bug!("{:?} not a ScalarPair", imm), - } - } -} diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index ad7620d83e6..b1784b12c65 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -305,18 +305,6 @@ where Ok(mplace) } - #[instrument(skip(self), level = "debug")] - pub fn deref_mplace( - &self, - src: &MPlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - let val = self.try_read_immediate_from_mplace(src)?; - let mplace = self.ref_to_mplace(&val.unwrap())?; - self.check_mplace_access(mplace, CheckInAllocMsg::DerefTest)?; - - Ok(mplace) - } - #[inline] pub(super) fn get_alloc( &self, diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 64a3b80988e..195760c0590 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -1,7 +1,5 @@ use super::ScalarInt; -use crate::ty::codec::TyDecoder; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; -use rustc_serialize::{Decodable, Encodable, Encoder}; #[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)] #[derive(HashStable)] @@ -22,7 +20,6 @@ pub enum ValTree<'tcx> { /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values /// of these types have the same representation. Leaf(ScalarInt), - SliceOrStr(ValSlice<'tcx>), /// 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 @@ -35,28 +32,3 @@ impl<'tcx> ValTree<'tcx> { Self::Branch(&[]) } } - -#[derive(Copy, Clone, Debug, HashStable, Hash, Eq, PartialEq, PartialOrd, Ord)] -pub struct ValSlice<'tcx> { - pub bytes: &'tcx [u8], -} - -impl<'tcx, S: Encoder> Encodable for ValSlice<'tcx> { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_usize(self.bytes.len())?; - s.emit_raw_bytes(self.bytes)?; - - Ok(()) - } -} - -impl<'tcx, D: TyDecoder<'tcx>> Decodable for ValSlice<'tcx> { - fn decode(d: &mut D) -> Self { - let tcx = d.tcx(); - let len = d.read_usize(); - let bytes_raw = d.read_raw_bytes(len); - let bytes = tcx.arena.alloc_slice(&bytes_raw[..]); - - ValSlice { bytes } - } -} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9c81a90529c..31db66dc242 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -62,7 +62,7 @@ pub use self::closure::{ CAPTURE_STRUCT_LOCAL, }; pub use self::consts::{ - Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, Unevaluated, ValSlice, ValTree, + Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, Unevaluated, ValTree, }; pub use self::context::{ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, From 8a5273bc995d5ac457eaf70bf3d10c1513277234 Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 8 Apr 2022 17:13:45 +0200 Subject: [PATCH 4/6] use deref on ImmTy --- compiler/rustc_const_eval/src/const_eval/mod.rs | 5 ++--- compiler/rustc_const_eval/src/interpret/operand.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 9b42910f99c..ee763f3b0b7 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -121,11 +121,10 @@ fn const_to_valtree_inner<'tcx>( ty::Slice(_) | ty::Str => { match ecx.try_read_immediate_from_mplace(&place) { Ok(Some(imm)) => { - let mplace_ref = ecx.ref_to_mplace(&imm).unwrap(); let derefd = ecx.deref_operand(&place.into()).expect(&format!("couldnt deref {:?}", imm)); - debug!(?mplace_ref, ?derefd); + debug!(?derefd); - let len = match imm.imm { + let len = match *imm { Immediate::ScalarPair(_, b) => { let len = b.to_machine_usize(&ecx.tcx.tcx).unwrap(); len diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 3b9fab9db43..d820bd900a0 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -98,7 +98,7 @@ impl<'tcx, Tag: Provenance> Immediate { // as input for binary and cast operations. #[derive(Copy, Clone, Debug)] pub struct ImmTy<'tcx, Tag: Provenance = AllocId> { - pub(crate) imm: Immediate, + imm: Immediate, pub layout: TyAndLayout<'tcx>, } From 4b126b805bd51d2b7aa335cadd571a319ec0e224 Mon Sep 17 00:00:00 2001 From: b-naber Date: Tue, 12 Apr 2022 16:08:59 +0200 Subject: [PATCH 5/6] use len on mplace instead of reading immediate, remove dead code --- .../rustc_const_eval/src/const_eval/mod.rs | 47 +++++-------------- .../rustc_const_eval/src/interpret/operand.rs | 2 +- .../rustc_const_eval/src/interpret/place.rs | 2 +- 3 files changed, 13 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index ee763f3b0b7..541462a26d5 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -12,8 +12,8 @@ use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; use rustc_target::abi::VariantIdx; use crate::interpret::{ - intern_const_alloc_recursive, ConstValue, Immediate, InternKind, InterpCx, InterpResult, - MPlaceTy, MemPlaceMeta, Scalar, + intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy, + MemPlaceMeta, Scalar, }; mod error; @@ -119,44 +119,19 @@ fn const_to_valtree_inner<'tcx>( ty::Ref(_, inner_ty, _) => { match inner_ty.kind() { ty::Slice(_) | ty::Str => { - match ecx.try_read_immediate_from_mplace(&place) { - Ok(Some(imm)) => { - let derefd = ecx.deref_operand(&place.into()).expect(&format!("couldnt deref {:?}", imm)); - debug!(?derefd); + let derefd = ecx.deref_operand(&place.into()).unwrap(); + debug!(?derefd); + let len = derefd.len(&ecx.tcx.tcx).unwrap(); + let valtree = slice_branches(ecx, &derefd, len); + debug!(?valtree); - let len = match *imm { - Immediate::ScalarPair(_, b) => { - let len = b.to_machine_usize(&ecx.tcx.tcx).unwrap(); - len - } - _ => bug!("expected ScalarPair for &[T] or &str"), - }; - debug!(?len); - - let valtree = slice_branches(ecx, &derefd, len); - debug!(?valtree); - - valtree - } - _ => { - None - } - } + valtree } _ => { - let imm = ecx.try_read_immediate_from_mplace(&place).unwrap_or_else(|e| bug!("couldnt read immediate from {:?}, error: {:?}", place, e)); + let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e)); + debug!(?derefd_place); - match imm { - Some(imm) => { - debug!(?imm); - - let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e)); - debug!(?derefd_place); - - const_to_valtree_inner(ecx, &derefd_place) - } - None => bug!("couldn't read immediate from {:?}", place), - } + const_to_valtree_inner(ecx, &derefd_place) } } } diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index d820bd900a0..9000567558b 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -248,7 +248,7 @@ impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> { impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`. /// Returns `None` if the layout does not permit loading this as a value. - pub(crate) fn try_read_immediate_from_mplace( + fn try_read_immediate_from_mplace( &self, mplace: &MPlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, Option>> { diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index b1784b12c65..85f3f3d53d6 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -191,7 +191,7 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { } #[inline] - pub(super) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { + pub(crate) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { if self.layout.is_unsized() { // We need to consult `meta` metadata match self.layout.ty.kind() { From d8205cd3fe3cda6ebbcff40c8d173f8e05a375be Mon Sep 17 00:00:00 2001 From: b-naber Date: Thu, 14 Apr 2022 21:56:27 +0200 Subject: [PATCH 6/6] handle arrays and slices uniformly in valtree creation --- .../rustc_const_eval/src/const_eval/mod.rs | 44 ++++++------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 541462a26d5..80270f82563 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -3,6 +3,7 @@ use std::convert::TryFrom; use rustc_hir::Mutability; +use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::{ mir::{self, interpret::ConstAlloc}, @@ -74,7 +75,7 @@ fn branches<'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 + // For enums, we prepend 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(branches.collect::>>()?))) @@ -83,17 +84,13 @@ fn branches<'tcx>( fn slice_branches<'tcx>( ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>, - n: u64, ) -> Option> { - let elems = (0..n).map(|i| { + let n = place.len(&ecx.tcx()).expect(&format!("expected to use len of place {:?}", place)); + let branches = (0..n).map(|i| { let place_elem = ecx.mplace_index(place, i).unwrap(); const_to_valtree_inner(ecx, &place_elem) }); - // Need `len` for the ValTree -> ConstValue conversion - let len = Some(Some(ty::ValTree::Leaf(ScalarInt::from(n)))); - let branches = len.into_iter().chain(elems); - Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::>>()?))) } @@ -116,33 +113,19 @@ fn const_to_valtree_inner<'tcx>( // agree with runtime equality tests. ty::FnPtr(_) | ty::RawPtr(_) => None, - ty::Ref(_, inner_ty, _) => { - match inner_ty.kind() { - ty::Slice(_) | ty::Str => { - let derefd = ecx.deref_operand(&place.into()).unwrap(); - debug!(?derefd); - let len = derefd.len(&ecx.tcx.tcx).unwrap(); - let valtree = slice_branches(ecx, &derefd, len); - debug!(?valtree); + ty::Ref(_, _, _) => { + let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e)); + debug!(?derefd_place); - valtree - } - _ => { - let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e)); - debug!(?derefd_place); - - const_to_valtree_inner(ecx, &derefd_place) - } - } + const_to_valtree_inner(ecx, &derefd_place) } - ty::Str => { - bug!("ty::Str should have been handled in ty::Ref branch that uses raw bytes"); - } - ty::Slice(_) => { - bug!("should have been handled in the Ref arm"); - } + ty::Str | ty::Slice(_) | ty::Array(_, _) => { + let valtree = slice_branches(ecx, place); + debug!(?valtree); + valtree + } // 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 // hypothetically be able to allow `dyn StructuralEq` trait objects in the future, @@ -150,7 +133,6 @@ fn const_to_valtree_inner<'tcx>( ty::Dynamic(..) => None, ty::Tuple(substs) => branches(ecx, place, substs.len(), None), - ty::Array(_, len) => branches(ecx, place, usize::try_from(len.eval_usize(ecx.tcx.tcx, ecx.param_env)).unwrap(), None), ty::Adt(def, _) => { if def.variants().is_empty() {