Auto merge of #97019 - b-naber:transition-to-valtrees-pt1, r=oli-obk
Transition to valtrees pt1 Compartmentalising https://github.com/rust-lang/rust/pull/96591 as much as possible. r? `@oli-obk`
This commit is contained in:
commit
cd282d7f75
27 changed files with 541 additions and 245 deletions
|
@ -135,7 +135,7 @@ pub(super) fn op_to_const<'tcx>(
|
|||
} else {
|
||||
// It is guaranteed that any non-slice scalar pair is actually ByRef here.
|
||||
// When we come back from raw const eval, we are always by-ref. The only way our op here is
|
||||
// by-val is if we are in destructure_const, i.e., if this is (a field of) something that we
|
||||
// by-val is if we are in destructure_mir_constant, i.e., if this is (a field of) something that we
|
||||
// "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or
|
||||
// structs containing such.
|
||||
op.try_as_mplace()
|
||||
|
|
|
@ -4,6 +4,7 @@ use std::convert::TryFrom;
|
|||
|
||||
use rustc_hir::Mutability;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
|
||||
|
||||
|
@ -22,7 +23,7 @@ pub use error::*;
|
|||
pub use eval_queries::*;
|
||||
pub use fn_queries::*;
|
||||
pub use machine::*;
|
||||
pub(crate) use valtrees::{const_to_valtree, valtree_to_const_value};
|
||||
pub(crate) use valtrees::{const_to_valtree_inner, valtree_to_const_value};
|
||||
|
||||
pub(crate) fn const_caller_location(
|
||||
tcx: TyCtxt<'_>,
|
||||
|
@ -38,6 +39,57 @@ pub(crate) fn const_caller_location(
|
|||
ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr, &tcx))
|
||||
}
|
||||
|
||||
// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
|
||||
const VALTREE_MAX_NODES: usize = 1000;
|
||||
|
||||
pub(crate) enum ValTreeCreationError {
|
||||
NodesOverflow,
|
||||
NonSupportedType,
|
||||
Other,
|
||||
}
|
||||
pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>;
|
||||
|
||||
/// Evaluates a constant and turns it into a type-level constant value.
|
||||
pub(crate) fn eval_to_valtree<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
cid: GlobalId<'tcx>,
|
||||
) -> EvalToValTreeResult<'tcx> {
|
||||
let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?;
|
||||
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(const_alloc).unwrap();
|
||||
debug!(?place);
|
||||
|
||||
let mut num_nodes = 0;
|
||||
let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes);
|
||||
|
||||
match valtree_result {
|
||||
Ok(valtree) => Ok(Some(valtree)),
|
||||
Err(err) => {
|
||||
let did = cid.instance.def_id();
|
||||
let s = cid.display(tcx);
|
||||
match err {
|
||||
ValTreeCreationError::NodesOverflow => {
|
||||
let msg = format!("maximum number of nodes exceeded in constant {}", &s);
|
||||
let mut diag = match tcx.hir().span_if_local(did) {
|
||||
Some(span) => tcx.sess.struct_span_err(span, &msg),
|
||||
None => tcx.sess.struct_err(&msg),
|
||||
};
|
||||
diag.emit();
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
ValTreeCreationError::NonSupportedType | ValTreeCreationError::Other => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This function should never fail for validated constants. However, it is also invoked from the
|
||||
/// pretty printer which might attempt to format invalid constants and in that case it might fail.
|
||||
pub(crate) fn try_destructure_const<'tcx>(
|
||||
|
@ -48,7 +100,6 @@ pub(crate) fn try_destructure_const<'tcx>(
|
|||
trace!("destructure_const: {:?}", val);
|
||||
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
|
||||
let op = ecx.const_to_op(val, None)?;
|
||||
|
||||
// We go to `usize` as we cannot allocate anything bigger anyway.
|
||||
let (field_count, variant, down) = match val.ty().kind() {
|
||||
ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
|
||||
|
@ -64,7 +115,6 @@ pub(crate) fn try_destructure_const<'tcx>(
|
|||
ty::Tuple(substs) => (substs.len(), None, op),
|
||||
_ => bug!("cannot destructure constant {:?}", val),
|
||||
};
|
||||
|
||||
let fields = (0..field_count)
|
||||
.map(|i| {
|
||||
let field_op = ecx.operand_field(&down, i)?;
|
||||
|
@ -73,10 +123,46 @@ pub(crate) fn try_destructure_const<'tcx>(
|
|||
})
|
||||
.collect::<InterpResult<'tcx, Vec<_>>>()?;
|
||||
let fields = tcx.arena.alloc_from_iter(fields);
|
||||
|
||||
Ok(mir::DestructuredConst { variant, fields })
|
||||
}
|
||||
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
pub(crate) fn try_destructure_mir_constant<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
val: mir::ConstantKind<'tcx>,
|
||||
) -> InterpResult<'tcx, mir::DestructuredMirConstant<'tcx>> {
|
||||
trace!("destructure_mir_constant: {:?}", val);
|
||||
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
|
||||
let op = ecx.mir_const_to_op(&val, None)?;
|
||||
|
||||
// We go to `usize` as we cannot allocate anything bigger anyway.
|
||||
let (field_count, variant, down) = match val.ty().kind() {
|
||||
ty::Array(_, len) => (len.eval_usize(tcx, param_env) as usize, None, op),
|
||||
ty::Adt(def, _) if def.variants().is_empty() => {
|
||||
throw_ub!(Unreachable)
|
||||
}
|
||||
ty::Adt(def, _) => {
|
||||
let variant = ecx.read_discriminant(&op).unwrap().1;
|
||||
let down = ecx.operand_downcast(&op, variant).unwrap();
|
||||
(def.variants()[variant].fields.len(), Some(variant), down)
|
||||
}
|
||||
ty::Tuple(substs) => (substs.len(), None, op),
|
||||
_ => bug!("cannot destructure mir constant {:?}", val),
|
||||
};
|
||||
|
||||
let fields_iter = (0..field_count)
|
||||
.map(|i| {
|
||||
let field_op = ecx.operand_field(&down, i)?;
|
||||
let val = op_to_const(&ecx, &field_op);
|
||||
Ok(mir::ConstantKind::Val(val, field_op.layout.ty))
|
||||
})
|
||||
.collect::<InterpResult<'tcx, Vec<_>>>()?;
|
||||
let fields = tcx.arena.alloc_from_iter(fields_iter);
|
||||
|
||||
Ok(mir::DestructuredMirConstant { variant, fields })
|
||||
}
|
||||
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
pub(crate) fn deref_const<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -113,3 +199,39 @@ pub(crate) fn deref_const<'tcx>(
|
|||
|
||||
tcx.mk_const(ty::ConstS { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty })
|
||||
}
|
||||
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
pub(crate) fn deref_mir_constant<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
val: mir::ConstantKind<'tcx>,
|
||||
) -> mir::ConstantKind<'tcx> {
|
||||
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
|
||||
let op = ecx.mir_const_to_op(&val, None).unwrap();
|
||||
let mplace = ecx.deref_operand(&op).unwrap();
|
||||
if let Some(alloc_id) = mplace.ptr.provenance {
|
||||
assert_eq!(
|
||||
tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().0.0.mutability,
|
||||
Mutability::Not,
|
||||
"deref_const cannot be used with mutable allocations as \
|
||||
that could allow pattern matching to observe mutable statics",
|
||||
);
|
||||
}
|
||||
|
||||
let ty = match mplace.meta {
|
||||
MemPlaceMeta::None => mplace.layout.ty,
|
||||
MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace),
|
||||
// In case of unsized types, figure out the real type behind.
|
||||
MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() {
|
||||
ty::Str => bug!("there's no sized equivalent of a `str`"),
|
||||
ty::Slice(elem_ty) => tcx.mk_array(*elem_ty, scalar.to_machine_usize(&tcx).unwrap()),
|
||||
_ => bug!(
|
||||
"type {} should not have metadata, but had {:?}",
|
||||
mplace.layout.ty,
|
||||
mplace.meta
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
mir::ConstantKind::Val(op_to_const(&ecx, &mplace.into()), ty)
|
||||
}
|
||||
|
|
|
@ -1,33 +1,16 @@
|
|||
use super::eval_queries::{mk_eval_cx, op_to_const};
|
||||
use super::machine::CompileTimeEvalContext;
|
||||
use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
|
||||
use crate::interpret::{
|
||||
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
|
||||
MemoryKind, PlaceTy, Scalar, ScalarMaybeUninit,
|
||||
};
|
||||
use rustc_middle::mir::interpret::ConstAlloc;
|
||||
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
use rustc_target::abi::{Align, VariantIdx};
|
||||
|
||||
use crate::interpret::MPlaceTy;
|
||||
use crate::interpret::Value;
|
||||
|
||||
/// Convert an evaluated constant to a type level constant
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
pub(crate) fn const_to_valtree<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
raw: ConstAlloc<'tcx>,
|
||||
) -> Option<ty::ValTree<'tcx>> {
|
||||
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)
|
||||
}
|
||||
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
|
||||
|
||||
#[instrument(skip(ecx), level = "debug")]
|
||||
fn branches<'tcx>(
|
||||
|
@ -35,7 +18,8 @@ fn branches<'tcx>(
|
|||
place: &MPlaceTy<'tcx>,
|
||||
n: usize,
|
||||
variant: Option<VariantIdx>,
|
||||
) -> Option<ty::ValTree<'tcx>> {
|
||||
num_nodes: &mut usize,
|
||||
) -> ValTreeCreationResult<'tcx> {
|
||||
let place = match variant {
|
||||
Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(),
|
||||
None => *place,
|
||||
|
@ -43,82 +27,116 @@ fn branches<'tcx>(
|
|||
let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32()))));
|
||||
debug!(?place, ?variant);
|
||||
|
||||
let fields = (0..n).map(|i| {
|
||||
let mut fields = Vec::with_capacity(n);
|
||||
for i in 0..n {
|
||||
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
|
||||
let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?;
|
||||
fields.push(Some(valtree));
|
||||
}
|
||||
|
||||
// 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<_>>>()?)))
|
||||
let branches = variant
|
||||
.into_iter()
|
||||
.chain(fields.into_iter())
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.expect("should have already checked for errors in ValTree creation");
|
||||
|
||||
// Have to account for ZSTs here
|
||||
if branches.len() == 0 {
|
||||
*num_nodes += 1;
|
||||
}
|
||||
|
||||
Ok(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches)))
|
||||
}
|
||||
|
||||
#[instrument(skip(ecx), level = "debug")]
|
||||
fn slice_branches<'tcx>(
|
||||
ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
|
||||
place: &MPlaceTy<'tcx>,
|
||||
) -> Option<ty::ValTree<'tcx>> {
|
||||
num_nodes: &mut usize,
|
||||
) -> ValTreeCreationResult<'tcx> {
|
||||
let n = place
|
||||
.len(&ecx.tcx.tcx)
|
||||
.unwrap_or_else(|_| panic!("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<_>>>()?)))
|
||||
let mut elems = Vec::with_capacity(n as usize);
|
||||
for i in 0..n {
|
||||
let place_elem = ecx.mplace_index(place, i).unwrap();
|
||||
let valtree = const_to_valtree_inner(ecx, &place_elem, num_nodes)?;
|
||||
elems.push(valtree);
|
||||
}
|
||||
|
||||
Ok(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(elems)))
|
||||
}
|
||||
|
||||
#[instrument(skip(ecx), level = "debug")]
|
||||
fn const_to_valtree_inner<'tcx>(
|
||||
pub(crate) 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()),
|
||||
num_nodes: &mut usize,
|
||||
) -> ValTreeCreationResult<'tcx> {
|
||||
if *num_nodes >= VALTREE_MAX_NODES {
|
||||
return Err(ValTreeCreationError::NodesOverflow);
|
||||
}
|
||||
|
||||
let ty = place.layout.ty;
|
||||
debug!("ty kind: {:?}", ty.kind());
|
||||
|
||||
match ty.kind() {
|
||||
ty::FnDef(..) => {
|
||||
*num_nodes += 1;
|
||||
Ok(ty::ValTree::zst())
|
||||
}
|
||||
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
|
||||
let val = ecx.read_immediate(&place.into()).unwrap();
|
||||
let Ok(val) = ecx.read_immediate(&place.into()) else {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
};
|
||||
let val = val.to_scalar().unwrap();
|
||||
Some(ty::ValTree::Leaf(val.assert_int()))
|
||||
*num_nodes += 1;
|
||||
|
||||
Ok(ty::ValTree::Leaf(val.assert_int()))
|
||||
}
|
||||
|
||||
// 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::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
|
||||
|
||||
ty::Ref(_, _, _) => {
|
||||
let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e));
|
||||
let Ok(derefd_place)= ecx.deref_operand(&place.into()) else {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
};
|
||||
debug!(?derefd_place);
|
||||
|
||||
const_to_valtree_inner(ecx, &derefd_place)
|
||||
const_to_valtree_inner(ecx, &derefd_place, num_nodes)
|
||||
}
|
||||
|
||||
ty::Str | ty::Slice(_) | ty::Array(_, _) => {
|
||||
let valtree = slice_branches(ecx, place);
|
||||
debug!(?valtree);
|
||||
|
||||
valtree
|
||||
slice_branches(ecx, place, num_nodes)
|
||||
}
|
||||
// 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::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType),
|
||||
|
||||
ty::Tuple(substs) => branches(ecx, place, substs.len(), None),
|
||||
ty::Tuple(elem_tys) => {
|
||||
branches(ecx, place, elem_tys.len(), None, num_nodes)
|
||||
}
|
||||
|
||||
ty::Adt(def, _) => {
|
||||
if def.is_union() {
|
||||
return None
|
||||
return Err(ValTreeCreationError::NonSupportedType);
|
||||
} else if def.variants().is_empty() {
|
||||
bug!("uninhabited types should have errored and never gotten converted to valtree")
|
||||
}
|
||||
|
||||
let variant = ecx.read_discriminant(&place.into()).unwrap().1;
|
||||
|
||||
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant))
|
||||
let Ok((_, variant)) = ecx.read_discriminant(&place.into()) else {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
};
|
||||
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)
|
||||
}
|
||||
|
||||
ty::Never
|
||||
|
@ -136,7 +154,7 @@ fn const_to_valtree_inner<'tcx>(
|
|||
// FIXME(oli-obk): we can probably encode closures just like structs
|
||||
| ty::Closure(..)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(..) => None,
|
||||
| ty::GeneratorWitness(..) => Err(ValTreeCreationError::NonSupportedType),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,8 +243,11 @@ fn create_pointee_place<'tcx>(
|
|||
.unwrap();
|
||||
debug!(?ptr);
|
||||
|
||||
let mut place = MPlaceTy::from_aligned_ptr(ptr.into(), layout);
|
||||
place.meta = MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64));
|
||||
let place = MPlaceTy::from_aligned_ptr_with_meta(
|
||||
ptr.into(),
|
||||
layout,
|
||||
MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64)),
|
||||
);
|
||||
debug!(?place);
|
||||
|
||||
place
|
||||
|
@ -237,11 +258,11 @@ fn create_pointee_place<'tcx>(
|
|||
|
||||
/// Converts a `ValTree` to a `ConstValue`, which is needed after mir
|
||||
/// construction has finished.
|
||||
// FIXME Merge `valtree_to_const_value` and `fill_place_recursively` into one function
|
||||
// FIXME Merge `valtree_to_const_value` and `valtree_into_mplace` into one function
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
pub fn valtree_to_const_value<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
ty: Ty<'tcx>,
|
||||
valtree: ty::ValTree<'tcx>,
|
||||
) -> ConstValue<'tcx> {
|
||||
// Basic idea: We directly construct `Scalar` values from trivial `ValTree`s
|
||||
|
@ -251,8 +272,8 @@ pub fn valtree_to_const_value<'tcx>(
|
|||
// create inner `MPlace`s which are filled recursively.
|
||||
// FIXME Does this need an example?
|
||||
|
||||
let (param_env, ty) = param_env_ty.into_parts();
|
||||
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
|
||||
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::empty(), false);
|
||||
let param_env_ty = ty::ParamEnv::empty().and(ty);
|
||||
|
||||
match ty.kind() {
|
||||
ty::FnDef(..) => {
|
||||
|
@ -275,7 +296,7 @@ pub fn valtree_to_const_value<'tcx>(
|
|||
};
|
||||
debug!(?place);
|
||||
|
||||
fill_place_recursively(&mut ecx, &mut place, valtree);
|
||||
valtree_into_mplace(&mut ecx, &mut place, valtree);
|
||||
dump_place(&ecx, place.into());
|
||||
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
|
||||
|
||||
|
@ -317,7 +338,7 @@ pub fn valtree_to_const_value<'tcx>(
|
|||
|
||||
// FIXME Needs a better/correct name
|
||||
#[instrument(skip(ecx), level = "debug")]
|
||||
fn fill_place_recursively<'tcx>(
|
||||
fn valtree_into_mplace<'tcx>(
|
||||
ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
|
||||
place: &mut MPlaceTy<'tcx>,
|
||||
valtree: ty::ValTree<'tcx>,
|
||||
|
@ -349,7 +370,7 @@ fn fill_place_recursively<'tcx>(
|
|||
let mut pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
|
||||
debug!(?pointee_place);
|
||||
|
||||
fill_place_recursively(ecx, &mut pointee_place, valtree);
|
||||
valtree_into_mplace(ecx, &mut pointee_place, valtree);
|
||||
dump_place(ecx, pointee_place.into());
|
||||
intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap();
|
||||
|
||||
|
@ -437,7 +458,7 @@ fn fill_place_recursively<'tcx>(
|
|||
};
|
||||
|
||||
debug!(?place_inner);
|
||||
fill_place_recursively(ecx, &mut place_inner, *inner_valtree);
|
||||
valtree_into_mplace(ecx, &mut place_inner, *inner_valtree);
|
||||
dump_place(&ecx, place_inner.into());
|
||||
}
|
||||
|
||||
|
|
|
@ -115,12 +115,6 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for MPlaceTy<'tcx, Tag> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Tag: Provenance> std::ops::DerefMut for MPlaceTy<'tcx, Tag> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.mplace
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
|
||||
#[inline(always)]
|
||||
fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
|
||||
|
@ -196,6 +190,18 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
|
|||
MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align.abi), layout }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_aligned_ptr_with_meta(
|
||||
ptr: Pointer<Option<Tag>>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
meta: MemPlaceMeta<Tag>,
|
||||
) -> Self {
|
||||
let mut mplace = MemPlace::from_ptr(ptr, layout.align.abi);
|
||||
mplace.meta = meta;
|
||||
|
||||
MPlaceTy { mplace, layout }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
|
||||
if self.layout.is_unsized() {
|
||||
|
@ -495,7 +501,7 @@ where
|
|||
|
||||
/// Project into an mplace
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub(crate) fn mplace_projection(
|
||||
pub(super) fn mplace_projection(
|
||||
&self,
|
||||
base: &MPlaceTy<'tcx, M::PointerTag>,
|
||||
proj_elem: mir::PlaceElem<'tcx>,
|
||||
|
|
|
@ -34,26 +34,32 @@ pub mod transform;
|
|||
pub mod util;
|
||||
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::ParamEnv;
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
const_eval::provide(providers);
|
||||
providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
|
||||
providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
|
||||
providers.const_caller_location = const_eval::const_caller_location;
|
||||
providers.try_destructure_const = |tcx, param_env_and_value| {
|
||||
let (param_env, value) = param_env_and_value.into_parts();
|
||||
const_eval::try_destructure_const(tcx, param_env, value).ok()
|
||||
providers.try_destructure_const = |tcx, param_env_and_val| {
|
||||
let (param_env, c) = param_env_and_val.into_parts();
|
||||
const_eval::try_destructure_const(tcx, param_env, c).ok()
|
||||
};
|
||||
providers.const_to_valtree = |tcx, param_env_and_value| {
|
||||
providers.eval_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)
|
||||
const_eval::eval_to_valtree(tcx, param_env, raw)
|
||||
};
|
||||
providers.valtree_to_const_val = |tcx, (ty, valtree)| {
|
||||
const_eval::valtree_to_const_value(tcx, ParamEnv::empty().and(ty), valtree)
|
||||
providers.try_destructure_mir_constant = |tcx, param_env_and_value| {
|
||||
let (param_env, value) = param_env_and_value.into_parts();
|
||||
const_eval::try_destructure_mir_constant(tcx, param_env, value).ok()
|
||||
};
|
||||
providers.valtree_to_const_val =
|
||||
|tcx, (ty, valtree)| const_eval::valtree_to_const_value(tcx, ty, valtree);
|
||||
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)
|
||||
};
|
||||
providers.deref_mir_constant = |tcx, param_env_and_value| {
|
||||
let (param_env, value) = param_env_and_value.into_parts();
|
||||
const_eval::deref_mir_constant(tcx, param_env, value)
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue