diff options
| author | Dylan DPC <99973273+Dylan-DPC@users.noreply.github.com> | 2022-04-16 19:42:03 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-04-16 19:42:03 +0200 |
| commit | 1dc672a766832287f2f998a1cdde76ea74cd480d (patch) | |
| tree | 2022a3f97f940e941e72e5f233ae70cbd9273a13 /compiler/rustc_const_eval/src | |
| parent | 3dced8029843ac9cfdeaa11400dec99d331a2779 (diff) | |
| parent | d8205cd3fe3cda6ebbcff40c8d173f8e05a375be (diff) | |
| download | rust-1dc672a766832287f2f998a1cdde76ea74cd480d.tar.gz rust-1dc672a766832287f2f998a1cdde76ea74cd480d.zip | |
Rollup merge of #95426 - b-naber:valtrees-slice, r=RalfJung,oli-obk
Include Refs in Valtree Creation This adds references to `const_to_valtree`, which isn't used in the compiler yet, but after the previous changes we made to the thir and mir representations and this change we should be able to finally introduce them in the next PR. I wasn't able to properly test this code, except indirectly by including a call of `const_to_valtree` in the code that currently creates constants (`turn_into_const_value`). r? `@lcnr` cc `@oli-obk` `@RalfJung`
Diffstat (limited to 'compiler/rustc_const_eval/src')
| -rw-r--r-- | compiler/rustc_const_eval/src/const_eval/eval_queries.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/const_eval/mod.rs | 80 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/place.rs | 2 |
3 files changed, 58 insertions, 26 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 498b2f1b081..7cca6178ab2 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 6fd7f707e7e..80270f82563 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -3,12 +3,14 @@ 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}, 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, @@ -55,28 +57,48 @@ pub(crate) fn const_to_valtree<'tcx>( const_to_valtree_inner(&ecx, &place) } -fn const_to_valtree_inner<'tcx>( +#[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 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<_>>>()?), - )) + 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 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<_>>>()?))) +} + +fn slice_branches<'tcx>( + ecx: &CompileTimeEvalContext<'tcx, 'tcx>, + place: &MPlaceTy<'tcx>, +) -> Option<ty::ValTree<'tcx>> { + 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) + }); + + 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>> { match place.layout.ty.kind() { ty::FnDef(..) => Some(ty::ValTree::zst()), ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { @@ -90,19 +112,27 @@ 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(_, _, _) => { + 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) + } + + 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, // 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::Adt(def, _) => { if def.variants().is_empty() { @@ -111,7 +141,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/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 8dc74035d61..31da4522a1f 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() { |
