From 51aa3f86a040599dad36a75c22fa0321f7de0741 Mon Sep 17 00:00:00 2001
From: b-naber <bn263@gmx.de>
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 fae22c28628f8..64a3b80988e33 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<S> 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<D> 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 31db66dc242f1..9c81a90529c26 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 <bn263@gmx.de>
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 6fd7f707e7e5d..dad6e5e34a6c8 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<VariantIdx>,
+) -> Option<ty::ValTree<'tcx>> {
+    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::<Option<Vec<_>>>()?)))
+}
+
+#[instrument(skip(ecx), level = "debug")]
 fn const_to_valtree_inner<'tcx>(
     ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
     place: &MPlaceTy<'tcx>,
 ) -> Option<ty::ValTree<'tcx>> {
-    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::<Option<Vec<_>>>()?),
-        ))
+    // We only want to use raw bytes in ValTrees for string slices or &[<integer_ty>]
+    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 9000567558b84..d271bf53eac0c 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<ImmTy<'tcx, M::PointerTag>>> {
@@ -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 b1784b12c6520..ad7620d83e677 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 <bn263@gmx.de>
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    | 128 ++++++++----------
 .../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, 64 insertions(+), 145 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 df809e8270195..e28e7d766161b 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 dad6e5e34a6c8..9b42910f99cea 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::<Option<Vec<_>>>()?)))
 }
 
+fn slice_branches<'tcx>(
+    ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
+    place: &MPlaceTy<'tcx>,
+    n: u64,
+) -> Option<ty::ValTree<'tcx>> {
+    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::<Option<Vec<_>>>()?)))
+}
+
 #[instrument(skip(ecx), level = "debug")]
 fn const_to_valtree_inner<'tcx>(
     ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
     place: &MPlaceTy<'tcx>,
 ) -> Option<ty::ValTree<'tcx>> {
-    // We only want to use raw bytes in ValTrees for string slices or &[<integer_ty>]
-    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.
-
-                    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
+        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);
+
+                            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 valtree = slice_branches(ecx, &derefd, len);
+                            debug!(?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));
 
-        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);
+                    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);
+                            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)
+                        }
+                        None => bug!("couldn't read immediate from {:?}", 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 d271bf53eac0c..3b9fab9db438e 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<Tag> {
 // as input for binary and cast operations.
 #[derive(Copy, Clone, Debug)]
 pub struct ImmTy<'tcx, Tag: Provenance = AllocId> {
-    imm: Immediate<Tag>,
+    pub(crate) imm: Immediate<Tag>,
     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 ad7620d83e677..b1784b12c6520 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 64a3b80988e33..195760c059081 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<S> 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<D> 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 9c81a90529c26..31db66dc242f1 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 <bn263@gmx.de>
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 9b42910f99cea..ee763f3b0b782 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 3b9fab9db438e..d820bd900a0d0 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<Tag> {
 // as input for binary and cast operations.
 #[derive(Copy, Clone, Debug)]
 pub struct ImmTy<'tcx, Tag: Provenance = AllocId> {
-    pub(crate) imm: Immediate<Tag>,
+    imm: Immediate<Tag>,
     pub layout: TyAndLayout<'tcx>,
 }
 

From 4b126b805bd51d2b7aa335cadd571a319ec0e224 Mon Sep 17 00:00:00 2001
From: b-naber <bn263@gmx.de>
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    | 49 +++++--------------
 .../rustc_const_eval/src/interpret/operand.rs |  2 +-
 .../rustc_const_eval/src/interpret/place.rs   |  2 +-
 3 files changed, 14 insertions(+), 39 deletions(-)

diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index ee763f3b0b782..541462a26d5ec 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 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
-                        }
-                    }
+                    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);
+
+                    valtree
                 }
                 _ => {
-                    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);
+                    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 d820bd900a0d0..9000567558b84 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<ImmTy<'tcx, M::PointerTag>>> {
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index b1784b12c6520..85f3f3d53d6b7 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 <bn263@gmx.de>
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 541462a26d5ec..80270f825630f 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::<Option<Vec<_>>>()?)))
@@ -83,17 +84,13 @@ fn branches<'tcx>(
 fn slice_branches<'tcx>(
     ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
     place: &MPlaceTy<'tcx>,
-    n: u64,
 ) -> Option<ty::ValTree<'tcx>> {
-    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::<Option<Vec<_>>>()?)))
 }
 
@@ -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);
-
-                    valtree
-                }
-                _ => {
-                    let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e));
-                    debug!(?derefd_place);
+        ty::Ref(_, _, _)  => {
+            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() {