mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-26 14:43:24 +00:00
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`
This commit is contained in:
commit
1dc672a766
@ -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())
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
#[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 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>> {
|
||||
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<_>>>()?),
|
||||
))
|
||||
};
|
||||
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
|
||||
|
@ -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() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::ScalarInt;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[derive(HashStable)]
|
||||
|
Loading…
Reference in New Issue
Block a user