Auto merge of #114071 - RalfJung:interpret-generic-read-write, r=oli-obk
interpret: make read/write methods generic Instead of always having to call `into()` to convert things to `PlaceTy`/`OpTy`, make the relevant methods generic. This also means that when we read from an `MPlaceTy`, we avoid creating an intermediate `PlaceTy`. This makes it feasible to remove the `Copy` from `MPlaceTy`. All the other `*Ty` interpreter types already had their `Copy` removed a while ago so this is only consistent. (And in fact we had one function that accidentally took `MPlaceTy` instead of `&MPlaceTy`.)
This commit is contained in:
commit
bd9785cce8
34 changed files with 406 additions and 374 deletions
|
@ -58,7 +58,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
|
|||
ecx.push_stack_frame(
|
||||
cid.instance,
|
||||
body,
|
||||
&ret.into(),
|
||||
&ret.clone().into(),
|
||||
StackPopCleanup::Root { cleanup: false },
|
||||
)?;
|
||||
|
||||
|
@ -356,7 +356,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
|||
// Since evaluation had no errors, validate the resulting constant.
|
||||
// This is a separate `try` block to provide more targeted error reporting.
|
||||
let validation: Result<_, InterpErrorInfo<'_>> = try {
|
||||
let mut ref_tracking = RefTracking::new(mplace);
|
||||
let mut ref_tracking = RefTracking::new(mplace.clone());
|
||||
let mut inner = false;
|
||||
while let Some((mplace, path)) = ref_tracking.todo.pop() {
|
||||
let mode = match tcx.static_mutability(cid.instance.def_id()) {
|
||||
|
|
|
@ -216,7 +216,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
|||
|
||||
let mut msg_place = self.deref_operand(&args[0])?;
|
||||
while msg_place.layout.ty.is_ref() {
|
||||
msg_place = self.deref_operand(&msg_place.into())?;
|
||||
msg_place = self.deref_operand(&msg_place)?;
|
||||
}
|
||||
|
||||
let msg = Symbol::intern(self.read_str(&msg_place)?);
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::const_eval::CanAccessStatics;
|
|||
use crate::interpret::MPlaceTy;
|
||||
use crate::interpret::{
|
||||
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
|
||||
MemoryKind, PlaceTy, Projectable, Scalar,
|
||||
MemoryKind, Place, Projectable, Scalar,
|
||||
};
|
||||
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
|
@ -21,7 +21,7 @@ fn branches<'tcx>(
|
|||
) -> ValTreeCreationResult<'tcx> {
|
||||
let place = match variant {
|
||||
Some(variant) => ecx.project_downcast(place, variant).unwrap(),
|
||||
None => *place,
|
||||
None => place.clone(),
|
||||
};
|
||||
let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32()))));
|
||||
debug!(?place, ?variant);
|
||||
|
@ -86,7 +86,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
|
|||
Ok(ty::ValTree::zst())
|
||||
}
|
||||
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
|
||||
let Ok(val) = ecx.read_immediate(&place.into()) else {
|
||||
let Ok(val) = ecx.read_immediate(place) else {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
};
|
||||
let val = val.to_scalar();
|
||||
|
@ -102,7 +102,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
|
|||
ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
|
||||
|
||||
ty::Ref(_, _, _) => {
|
||||
let Ok(derefd_place)= ecx.deref_operand(&place.into()) else {
|
||||
let Ok(derefd_place)= ecx.deref_operand(place) else {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
};
|
||||
debug!(?derefd_place);
|
||||
|
@ -130,7 +130,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
|
|||
bug!("uninhabited types should have errored and never gotten converted to valtree")
|
||||
}
|
||||
|
||||
let Ok(variant) = ecx.read_discriminant(&place.into()) else {
|
||||
let Ok(variant) = ecx.read_discriminant(place) else {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
};
|
||||
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)
|
||||
|
@ -280,7 +280,7 @@ pub fn valtree_to_const_value<'tcx>(
|
|||
),
|
||||
},
|
||||
ty::Ref(_, _, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
|
||||
let mut place = match ty.kind() {
|
||||
let place = match ty.kind() {
|
||||
ty::Ref(_, inner_ty, _) => {
|
||||
// Need to create a place for the pointee to fill for Refs
|
||||
create_pointee_place(&mut ecx, *inner_ty, valtree)
|
||||
|
@ -289,8 +289,8 @@ pub fn valtree_to_const_value<'tcx>(
|
|||
};
|
||||
debug!(?place);
|
||||
|
||||
valtree_into_mplace(&mut ecx, &mut place, valtree);
|
||||
dump_place(&ecx, place.into());
|
||||
valtree_into_mplace(&mut ecx, &place, valtree);
|
||||
dump_place(&ecx, &place);
|
||||
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
|
||||
|
||||
match ty.kind() {
|
||||
|
@ -329,7 +329,7 @@ pub fn valtree_to_const_value<'tcx>(
|
|||
#[instrument(skip(ecx), level = "debug")]
|
||||
fn valtree_into_mplace<'tcx>(
|
||||
ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
|
||||
place: &mut MPlaceTy<'tcx>,
|
||||
place: &MPlaceTy<'tcx>,
|
||||
valtree: ty::ValTree<'tcx>,
|
||||
) {
|
||||
// This will match on valtree and write the value(s) corresponding to the ValTree
|
||||
|
@ -345,14 +345,14 @@ fn valtree_into_mplace<'tcx>(
|
|||
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
|
||||
let scalar_int = valtree.unwrap_leaf();
|
||||
debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place);
|
||||
ecx.write_immediate(Immediate::Scalar(scalar_int.into()), &place.into()).unwrap();
|
||||
ecx.write_immediate(Immediate::Scalar(scalar_int.into()), place).unwrap();
|
||||
}
|
||||
ty::Ref(_, inner_ty, _) => {
|
||||
let mut pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
|
||||
let pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
|
||||
debug!(?pointee_place);
|
||||
|
||||
valtree_into_mplace(ecx, &mut pointee_place, valtree);
|
||||
dump_place(ecx, pointee_place.into());
|
||||
valtree_into_mplace(ecx, &pointee_place, valtree);
|
||||
dump_place(ecx, &pointee_place);
|
||||
intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap();
|
||||
|
||||
let imm = match inner_ty.kind() {
|
||||
|
@ -369,7 +369,7 @@ fn valtree_into_mplace<'tcx>(
|
|||
};
|
||||
debug!(?imm);
|
||||
|
||||
ecx.write_immediate(imm, &place.into()).unwrap();
|
||||
ecx.write_immediate(imm, place).unwrap();
|
||||
}
|
||||
ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => {
|
||||
let branches = valtree.unwrap_branch();
|
||||
|
@ -389,7 +389,7 @@ fn valtree_into_mplace<'tcx>(
|
|||
Some(variant_idx),
|
||||
)
|
||||
}
|
||||
_ => (*place, branches, None),
|
||||
_ => (place.clone(), branches, None),
|
||||
};
|
||||
debug!(?place_adjusted, ?branches);
|
||||
|
||||
|
@ -398,7 +398,7 @@ fn valtree_into_mplace<'tcx>(
|
|||
for (i, inner_valtree) in branches.iter().enumerate() {
|
||||
debug!(?i, ?inner_valtree);
|
||||
|
||||
let mut place_inner = match ty.kind() {
|
||||
let place_inner = match ty.kind() {
|
||||
ty::Str | ty::Slice(_) => ecx.project_index(place, i as u64).unwrap(),
|
||||
_ if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty())
|
||||
&& i == branches.len() - 1 =>
|
||||
|
@ -443,25 +443,25 @@ fn valtree_into_mplace<'tcx>(
|
|||
};
|
||||
|
||||
debug!(?place_inner);
|
||||
valtree_into_mplace(ecx, &mut place_inner, *inner_valtree);
|
||||
dump_place(&ecx, place_inner.into());
|
||||
valtree_into_mplace(ecx, &place_inner, *inner_valtree);
|
||||
dump_place(&ecx, &place_inner);
|
||||
}
|
||||
|
||||
debug!("dump of place_adjusted:");
|
||||
dump_place(ecx, place_adjusted.into());
|
||||
dump_place(ecx, &place_adjusted);
|
||||
|
||||
if let Some(variant_idx) = variant_idx {
|
||||
// don't forget filling the place with the discriminant of the enum
|
||||
ecx.write_discriminant(variant_idx, &place.into()).unwrap();
|
||||
ecx.write_discriminant(variant_idx, place).unwrap();
|
||||
}
|
||||
|
||||
debug!("dump of place after writing discriminant:");
|
||||
dump_place(ecx, place.into());
|
||||
dump_place(ecx, place);
|
||||
}
|
||||
_ => bug!("shouldn't have created a ValTree for {:?}", ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: PlaceTy<'tcx>) {
|
||||
trace!("{:?}", ecx.dump_place(*place));
|
||||
fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>) {
|
||||
trace!("{:?}", ecx.dump_place(Place::Ptr(**place)));
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
|
||||
CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
|
||||
let src = self.read_immediate(&src)?;
|
||||
let src = self.read_immediate(src)?;
|
||||
let res = self.ptr_to_ptr(&src, cast_ty)?;
|
||||
self.write_immediate(res, dest)?;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use rustc_middle::{mir, ty};
|
|||
use rustc_target::abi::{self, TagEncoding};
|
||||
use rustc_target::abi::{VariantIdx, Variants};
|
||||
|
||||
use super::{ImmTy, InterpCx, InterpResult, Machine, OpTy, PlaceTy, Scalar};
|
||||
use super::{ImmTy, InterpCx, InterpResult, Machine, Readable, Scalar, Writeable};
|
||||
|
||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
/// Writes the discriminant of the given variant.
|
||||
|
@ -13,7 +13,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
pub fn write_discriminant(
|
||||
&mut self,
|
||||
variant_index: VariantIdx,
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
dest: &impl Writeable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Layout computation excludes uninhabited variants from consideration
|
||||
// therefore there's no way to represent those variants in the given layout.
|
||||
|
@ -21,11 +21,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// discriminant, so we cannot do anything here.
|
||||
// When evaluating we will always error before even getting here, but ConstProp 'executes'
|
||||
// dead code, so we cannot ICE here.
|
||||
if dest.layout.for_variant(self, variant_index).abi.is_uninhabited() {
|
||||
if dest.layout().for_variant(self, variant_index).abi.is_uninhabited() {
|
||||
throw_ub!(UninhabitedEnumVariantWritten(variant_index))
|
||||
}
|
||||
|
||||
match dest.layout.variants {
|
||||
match dest.layout().variants {
|
||||
abi::Variants::Single { index } => {
|
||||
assert_eq!(index, variant_index);
|
||||
}
|
||||
|
@ -38,8 +38,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// No need to validate that the discriminant here because the
|
||||
// `TyAndLayout::for_variant()` call earlier already checks the variant is valid.
|
||||
|
||||
let discr_val =
|
||||
dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val;
|
||||
let discr_val = dest
|
||||
.layout()
|
||||
.ty
|
||||
.discriminant_for_variant(*self.tcx, variant_index)
|
||||
.unwrap()
|
||||
.val;
|
||||
|
||||
// raw discriminants for enums are isize or bigger during
|
||||
// their computation, but the in-memory tag is the smallest possible
|
||||
|
@ -92,11 +96,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
#[instrument(skip(self), level = "trace")]
|
||||
pub fn read_discriminant(
|
||||
&self,
|
||||
op: &OpTy<'tcx, M::Provenance>,
|
||||
op: &impl Readable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, VariantIdx> {
|
||||
trace!("read_discriminant_value {:#?}", op.layout);
|
||||
let ty = op.layout().ty;
|
||||
trace!("read_discriminant_value {:#?}", op.layout());
|
||||
// Get type and layout of the discriminant.
|
||||
let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?;
|
||||
let discr_layout = self.layout_of(ty.discriminant_ty(*self.tcx))?;
|
||||
trace!("discriminant type: {:?}", discr_layout.ty);
|
||||
|
||||
// We use "discriminant" to refer to the value associated with a particular enum variant.
|
||||
|
@ -104,20 +109,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// declared list of variants -- they can differ with explicitly assigned discriminants.
|
||||
// We use "tag" to refer to how the discriminant is encoded in memory, which can be either
|
||||
// straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
|
||||
let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants {
|
||||
let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout().variants {
|
||||
Variants::Single { index } => {
|
||||
// Do some extra checks on enums.
|
||||
if op.layout.ty.is_enum() {
|
||||
if ty.is_enum() {
|
||||
// Hilariously, `Single` is used even for 0-variant enums.
|
||||
// (See https://github.com/rust-lang/rust/issues/89765).
|
||||
if matches!(op.layout.ty.kind(), ty::Adt(def, ..) if def.variants().is_empty())
|
||||
{
|
||||
if matches!(ty.kind(), ty::Adt(def, ..) if def.variants().is_empty()) {
|
||||
throw_ub!(UninhabitedEnumVariantRead(index))
|
||||
}
|
||||
// For consisteny with `write_discriminant`, and to make sure that
|
||||
// `project_downcast` cannot fail due to strange layouts, we declare immediate UB
|
||||
// for uninhabited variants.
|
||||
if op.layout.for_variant(self, index).abi.is_uninhabited() {
|
||||
if op.layout().for_variant(self, index).abi.is_uninhabited() {
|
||||
throw_ub!(UninhabitedEnumVariantRead(index))
|
||||
}
|
||||
}
|
||||
|
@ -163,7 +167,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
self.cast_from_int_like(scalar, tag_val.layout, discr_layout.ty).unwrap();
|
||||
let discr_bits = discr_val.assert_bits(discr_layout.size);
|
||||
// Convert discriminant to variant index, and catch invalid discriminants.
|
||||
let index = match *op.layout.ty.kind() {
|
||||
let index = match *ty.kind() {
|
||||
ty::Adt(adt, _) => {
|
||||
adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits)
|
||||
}
|
||||
|
@ -217,12 +221,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
.checked_add(variant_index_relative)
|
||||
.expect("overflow computing absolute variant idx"),
|
||||
);
|
||||
let variants = op
|
||||
.layout
|
||||
.ty
|
||||
.ty_adt_def()
|
||||
.expect("tagged layout for non adt")
|
||||
.variants();
|
||||
let variants =
|
||||
ty.ty_adt_def().expect("tagged layout for non adt").variants();
|
||||
assert!(variant_index < variants.next_index());
|
||||
variant_index
|
||||
} else {
|
||||
|
@ -237,7 +237,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
};
|
||||
// For consisteny with `write_discriminant`, and to make sure that `project_downcast` cannot fail due to strange layouts, we declare immediate UB for uninhabited variants.
|
||||
if op.layout.for_variant(self, index).abi.is_uninhabited() {
|
||||
if op.layout().for_variant(self, index).abi.is_uninhabited() {
|
||||
throw_ub!(UninhabitedEnumVariantRead(index))
|
||||
}
|
||||
Ok(index)
|
||||
|
|
|
@ -170,7 +170,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
|
|||
let tcx = self.ecx.tcx;
|
||||
let ty = mplace.layout.ty;
|
||||
if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() {
|
||||
let value = self.ecx.read_immediate(&mplace.into())?;
|
||||
let value = self.ecx.read_immediate(mplace)?;
|
||||
let mplace = self.ecx.ref_to_mplace(&value)?;
|
||||
assert_eq!(mplace.layout.ty, referenced_ty);
|
||||
// Handle trait object vtables.
|
||||
|
@ -358,7 +358,7 @@ pub fn intern_const_alloc_recursive<
|
|||
Some(ret.layout.ty),
|
||||
);
|
||||
|
||||
ref_tracking.track((*ret, base_intern_mode), || ());
|
||||
ref_tracking.track((ret.clone(), base_intern_mode), || ());
|
||||
|
||||
while let Some(((mplace, mode), _)) = ref_tracking.todo.pop() {
|
||||
let res = InternVisitor {
|
||||
|
@ -464,7 +464,7 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>>
|
|||
) -> InterpResult<'tcx, ()>,
|
||||
) -> InterpResult<'tcx, ConstAllocation<'tcx>> {
|
||||
let dest = self.allocate(layout, MemoryKind::Stack)?;
|
||||
f(self, &dest.into())?;
|
||||
f(self, &dest.clone().into())?;
|
||||
let mut alloc = self.memory.alloc_map.remove(&dest.ptr.provenance.unwrap()).unwrap().1;
|
||||
alloc.mutability = Mutability::Not;
|
||||
Ok(self.tcx.mk_const_alloc(alloc))
|
||||
|
|
|
@ -226,7 +226,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
sym::discriminant_value => {
|
||||
let place = self.deref_operand(&args[0])?;
|
||||
let variant = self.read_discriminant(&place.into())?;
|
||||
let variant = self.read_discriminant(&place)?;
|
||||
let discr = self.discriminant_for_variant(place.layout, variant)?;
|
||||
self.write_scalar(discr, dest)?;
|
||||
}
|
||||
|
@ -432,7 +432,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
} else {
|
||||
self.project_index(&input, i)?.into()
|
||||
};
|
||||
self.copy_op(&value, &place.into(), /*allow_transmute*/ false)?;
|
||||
self.copy_op(&value, &place, /*allow_transmute*/ false)?;
|
||||
}
|
||||
}
|
||||
sym::simd_extract => {
|
||||
|
@ -445,7 +445,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
input_len
|
||||
);
|
||||
self.copy_op(
|
||||
&self.project_index(&input, index)?.into(),
|
||||
&self.project_index(&input, index)?,
|
||||
dest,
|
||||
/*allow_transmute*/ false,
|
||||
)?;
|
||||
|
@ -610,7 +610,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
|
||||
nonoverlapping: bool,
|
||||
) -> InterpResult<'tcx> {
|
||||
let count = self.read_target_usize(&count)?;
|
||||
let count = self.read_target_usize(count)?;
|
||||
let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
|
||||
let (size, align) = (layout.size, layout.align.abi);
|
||||
// `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max),
|
||||
|
@ -622,8 +622,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
)
|
||||
})?;
|
||||
|
||||
let src = self.read_pointer(&src)?;
|
||||
let dst = self.read_pointer(&dst)?;
|
||||
let src = self.read_pointer(src)?;
|
||||
let dst = self.read_pointer(dst)?;
|
||||
|
||||
self.mem_copy(src, align, dst, align, size, nonoverlapping)
|
||||
}
|
||||
|
@ -636,9 +636,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
) -> InterpResult<'tcx> {
|
||||
let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?;
|
||||
|
||||
let dst = self.read_pointer(&dst)?;
|
||||
let byte = self.read_scalar(&byte)?.to_u8()?;
|
||||
let count = self.read_target_usize(&count)?;
|
||||
let dst = self.read_pointer(dst)?;
|
||||
let byte = self.read_scalar(byte)?.to_u8()?;
|
||||
let count = self.read_target_usize(count)?;
|
||||
|
||||
// `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max),
|
||||
// but no actual allocation can be big enough for the difference to be noticeable.
|
||||
|
|
|
@ -101,11 +101,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
|
||||
|
||||
// Initialize fields.
|
||||
self.write_immediate(file.to_ref(self), &self.project_field(&location, 0).unwrap().into())
|
||||
self.write_immediate(file.to_ref(self), &self.project_field(&location, 0).unwrap())
|
||||
.expect("writing to memory we just allocated cannot fail");
|
||||
self.write_scalar(line, &self.project_field(&location, 1).unwrap().into())
|
||||
self.write_scalar(line, &self.project_field(&location, 1).unwrap())
|
||||
.expect("writing to memory we just allocated cannot fail");
|
||||
self.write_scalar(col, &self.project_field(&location, 2).unwrap().into())
|
||||
self.write_scalar(col, &self.project_field(&location, 2).unwrap())
|
||||
.expect("writing to memory we just allocated cannot fail");
|
||||
|
||||
location
|
||||
|
|
|
@ -24,8 +24,8 @@ pub use self::eval_context::{Frame, FrameInfo, InterpCx, LocalState, LocalValue,
|
|||
pub use self::intern::{intern_const_alloc_recursive, InternKind};
|
||||
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
|
||||
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
|
||||
pub use self::operand::{ImmTy, Immediate, OpTy, Operand};
|
||||
pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy};
|
||||
pub use self::operand::{ImmTy, Immediate, OpTy, Operand, Readable};
|
||||
pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy, Writeable};
|
||||
pub use self::projection::Projectable;
|
||||
pub use self::terminator::FnArg;
|
||||
pub use self::validity::{CtfeValidationMode, RefTracking};
|
||||
|
|
|
@ -180,20 +180,6 @@ impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance> From<&'_ MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn from(mplace: &MPlaceTy<'tcx, Prov>) -> Self {
|
||||
OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance> From<&'_ mut MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn from(mplace: &mut MPlaceTy<'tcx, Prov>) -> Self {
|
||||
OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn from(val: ImmTy<'tcx, Prov>) -> Self {
|
||||
|
@ -201,20 +187,6 @@ impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance> From<&'_ ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn from(val: &ImmTy<'tcx, Prov>) -> Self {
|
||||
OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance> From<&'_ mut ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn from(val: &mut ImmTy<'tcx, Prov>) -> Self {
|
||||
OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
|
||||
#[inline]
|
||||
pub fn from_scalar(val: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self {
|
||||
|
@ -312,13 +284,13 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir, Prov: Provenance> Projectable<'mir, 'tcx, Prov> for ImmTy<'tcx, Prov> {
|
||||
impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn layout(&self) -> TyAndLayout<'tcx> {
|
||||
self.layout
|
||||
}
|
||||
|
||||
fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
_ecx: &InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
|
||||
|
@ -337,11 +309,11 @@ impl<'mir, 'tcx: 'mir, Prov: Provenance> Projectable<'mir, 'tcx, Prov> for ImmTy
|
|||
Ok(self.offset_(offset, layout, cx))
|
||||
}
|
||||
|
||||
fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
_ecx: &InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||
Ok(self.into())
|
||||
Ok(self.clone().into())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -362,15 +334,13 @@ impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
|
||||
for OpTy<'tcx, Prov>
|
||||
{
|
||||
impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn layout(&self) -> TyAndLayout<'tcx> {
|
||||
self.layout
|
||||
}
|
||||
|
||||
fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
_ecx: &InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
|
||||
|
@ -394,7 +364,7 @@ impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
|
|||
}
|
||||
}
|
||||
|
||||
fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
_ecx: &InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||
|
@ -402,6 +372,31 @@ impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Readable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> {
|
||||
fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>>;
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance + 'static> Readable<'tcx, Prov> for OpTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> {
|
||||
self.as_mplace_or_imm()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance + 'static> Readable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> {
|
||||
Left(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance> Readable<'tcx, Prov> for ImmTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> {
|
||||
Right(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -474,14 +469,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
/// ConstProp needs it, though.
|
||||
pub fn read_immediate_raw(
|
||||
&self,
|
||||
src: &OpTy<'tcx, M::Provenance>,
|
||||
src: &impl Readable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, Either<MPlaceTy<'tcx, M::Provenance>, ImmTy<'tcx, M::Provenance>>> {
|
||||
Ok(match src.as_mplace_or_imm() {
|
||||
Left(ref mplace) => {
|
||||
if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? {
|
||||
Right(val)
|
||||
} else {
|
||||
Left(*mplace)
|
||||
Left(mplace.clone())
|
||||
}
|
||||
}
|
||||
Right(val) => Right(val),
|
||||
|
@ -494,14 +489,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
#[inline(always)]
|
||||
pub fn read_immediate(
|
||||
&self,
|
||||
op: &OpTy<'tcx, M::Provenance>,
|
||||
op: &impl Readable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||
if !matches!(
|
||||
op.layout.abi,
|
||||
op.layout().abi,
|
||||
Abi::Scalar(abi::Scalar::Initialized { .. })
|
||||
| Abi::ScalarPair(abi::Scalar::Initialized { .. }, abi::Scalar::Initialized { .. })
|
||||
) {
|
||||
span_bug!(self.cur_span(), "primitive read not possible for type: {:?}", op.layout.ty);
|
||||
span_bug!(
|
||||
self.cur_span(),
|
||||
"primitive read not possible for type: {:?}",
|
||||
op.layout().ty
|
||||
);
|
||||
}
|
||||
let imm = self.read_immediate_raw(op)?.right().unwrap();
|
||||
if matches!(*imm, Immediate::Uninit) {
|
||||
|
@ -513,7 +512,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
/// Read a scalar from a place
|
||||
pub fn read_scalar(
|
||||
&self,
|
||||
op: &OpTy<'tcx, M::Provenance>,
|
||||
op: &impl Readable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, Scalar<M::Provenance>> {
|
||||
Ok(self.read_immediate(op)?.to_scalar())
|
||||
}
|
||||
|
@ -524,16 +523,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
/// Read a pointer from a place.
|
||||
pub fn read_pointer(
|
||||
&self,
|
||||
op: &OpTy<'tcx, M::Provenance>,
|
||||
op: &impl Readable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
|
||||
self.read_scalar(op)?.to_pointer(self)
|
||||
}
|
||||
/// Read a pointer-sized unsigned integer from a place.
|
||||
pub fn read_target_usize(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx, u64> {
|
||||
pub fn read_target_usize(
|
||||
&self,
|
||||
op: &impl Readable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, u64> {
|
||||
self.read_scalar(op)?.to_target_usize(self)
|
||||
}
|
||||
/// Read a pointer-sized signed integer from a place.
|
||||
pub fn read_target_isize(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx, i64> {
|
||||
pub fn read_target_isize(
|
||||
&self,
|
||||
op: &impl Readable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, i64> {
|
||||
self.read_scalar(op)?.to_target_isize(self)
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ use rustc_target::abi::{self, Abi, Align, FieldIdx, HasDataLayout, Size, FIRST_V
|
|||
use super::{
|
||||
alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckInAllocMsg,
|
||||
ConstAlloc, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, OpTy, Operand,
|
||||
Pointer, Projectable, Provenance, Scalar,
|
||||
Pointer, Projectable, Provenance, Readable, Scalar,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
|
||||
|
@ -81,7 +81,7 @@ pub struct MemPlace<Prov: Provenance = AllocId> {
|
|||
}
|
||||
|
||||
/// A MemPlace with its layout. Constructing it is only possible in this module.
|
||||
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
|
||||
#[derive(Clone, Hash, Eq, PartialEq, Debug)]
|
||||
pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
|
||||
mplace: MemPlace<Prov>,
|
||||
pub layout: TyAndLayout<'tcx>,
|
||||
|
@ -92,6 +92,14 @@ pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
|
|||
pub align: Align,
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance> std::ops::Deref for MPlaceTy<'tcx, Prov> {
|
||||
type Target = MemPlace<Prov>;
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &MemPlace<Prov> {
|
||||
&self.mplace
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Place<Prov: Provenance = AllocId> {
|
||||
/// A place referring to a value allocated in the `Memory` system.
|
||||
|
@ -125,14 +133,6 @@ impl<'tcx, Prov: Provenance> std::ops::Deref for PlaceTy<'tcx, Prov> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance> std::ops::Deref for MPlaceTy<'tcx, Prov> {
|
||||
type Target = MemPlace<Prov>;
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &MemPlace<Prov> {
|
||||
&self.mplace
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self {
|
||||
|
@ -140,20 +140,6 @@ impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov>
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance> From<&'_ MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn from(mplace: &MPlaceTy<'tcx, Prov>) -> Self {
|
||||
PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance> From<&'_ mut MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn from(mplace: &mut MPlaceTy<'tcx, Prov>) -> Self {
|
||||
PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prov: Provenance> MemPlace<Prov> {
|
||||
#[inline(always)]
|
||||
pub fn from_ptr(ptr: Pointer<Option<Prov>>) -> Self {
|
||||
|
@ -229,15 +215,13 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
|
||||
for MPlaceTy<'tcx, Prov>
|
||||
{
|
||||
impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn layout(&self) -> TyAndLayout<'tcx> {
|
||||
self.layout
|
||||
}
|
||||
|
||||
fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
_ecx: &InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
|
||||
|
@ -258,11 +242,59 @@ impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
|
|||
})
|
||||
}
|
||||
|
||||
fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
_ecx: &InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||
Ok(self.into())
|
||||
Ok(self.clone().into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn layout(&self) -> TyAndLayout<'tcx> {
|
||||
self.layout
|
||||
}
|
||||
|
||||
fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
ecx: &InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
|
||||
ecx.place_meta(self)
|
||||
}
|
||||
|
||||
fn offset_with_meta(
|
||||
&self,
|
||||
offset: Size,
|
||||
meta: MemPlaceMeta<Prov>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
cx: &impl HasDataLayout,
|
||||
) -> InterpResult<'tcx, Self> {
|
||||
Ok(match self.as_mplace_or_local() {
|
||||
Left(mplace) => mplace.offset_with_meta(offset, meta, layout, cx)?.into(),
|
||||
Right((frame, local, old_offset)) => {
|
||||
assert_matches!(meta, MemPlaceMeta::None); // we couldn't store it anyway...
|
||||
let new_offset = cx
|
||||
.data_layout()
|
||||
.offset(old_offset.unwrap_or(Size::ZERO).bytes(), offset.bytes())?;
|
||||
PlaceTy {
|
||||
place: Place::Local {
|
||||
frame,
|
||||
local,
|
||||
offset: Some(Size::from_bytes(new_offset)),
|
||||
},
|
||||
align: self.align.restrict_for_offset(offset),
|
||||
layout,
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
ecx: &InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||
ecx.place_to_op(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,53 +346,51 @@ impl<'tcx, Prov: Provenance + 'static> PlaceTy<'tcx, Prov> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir, Prov: Provenance + 'static> Projectable<'mir, 'tcx, Prov>
|
||||
for PlaceTy<'tcx, Prov>
|
||||
{
|
||||
pub trait Writeable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> {
|
||||
fn as_mplace_or_local(
|
||||
&self,
|
||||
) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, Align, TyAndLayout<'tcx>)>;
|
||||
|
||||
fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
ecx: &mut InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>>;
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance + 'static> Writeable<'tcx, Prov> for PlaceTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn layout(&self) -> TyAndLayout<'tcx> {
|
||||
self.layout
|
||||
fn as_mplace_or_local(
|
||||
&self,
|
||||
) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, Align, TyAndLayout<'tcx>)>
|
||||
{
|
||||
self.as_mplace_or_local()
|
||||
.map_right(|(frame, local, offset)| (frame, local, offset, self.align, self.layout))
|
||||
}
|
||||
|
||||
fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
#[inline(always)]
|
||||
fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
ecx: &InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> {
|
||||
ecx.place_meta(self)
|
||||
ecx: &mut InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>> {
|
||||
ecx.force_allocation(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance + 'static> Writeable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
fn as_mplace_or_local(
|
||||
&self,
|
||||
) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, Align, TyAndLayout<'tcx>)>
|
||||
{
|
||||
Left(self.clone())
|
||||
}
|
||||
|
||||
fn offset_with_meta(
|
||||
#[inline(always)]
|
||||
fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
offset: Size,
|
||||
meta: MemPlaceMeta<Prov>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
cx: &impl HasDataLayout,
|
||||
) -> InterpResult<'tcx, Self> {
|
||||
Ok(match self.as_mplace_or_local() {
|
||||
Left(mplace) => mplace.offset_with_meta(offset, meta, layout, cx)?.into(),
|
||||
Right((frame, local, old_offset)) => {
|
||||
assert_matches!(meta, MemPlaceMeta::None); // we couldn't store it anyway...
|
||||
let new_offset = cx
|
||||
.data_layout()
|
||||
.offset(old_offset.unwrap_or(Size::ZERO).bytes(), offset.bytes())?;
|
||||
PlaceTy {
|
||||
place: Place::Local {
|
||||
frame,
|
||||
local,
|
||||
offset: Some(Size::from_bytes(new_offset)),
|
||||
},
|
||||
align: self.align.restrict_for_offset(offset),
|
||||
layout,
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
ecx: &InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||
ecx.place_to_op(self)
|
||||
_ecx: &mut InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>> {
|
||||
Ok(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,7 +442,7 @@ where
|
|||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn deref_operand(
|
||||
&self,
|
||||
src: &OpTy<'tcx, M::Provenance>,
|
||||
src: &impl Readable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
|
||||
let val = self.read_immediate(src)?;
|
||||
trace!("deref to {} on {:?}", val.layout.ty, *val);
|
||||
|
@ -422,7 +452,7 @@ where
|
|||
}
|
||||
|
||||
let mplace = self.ref_to_mplace(&val)?;
|
||||
self.check_mplace(mplace)?;
|
||||
self.check_mplace(&mplace)?;
|
||||
Ok(mplace)
|
||||
}
|
||||
|
||||
|
@ -453,7 +483,7 @@ where
|
|||
}
|
||||
|
||||
/// Check if this mplace is dereferenceable and sufficiently aligned.
|
||||
pub fn check_mplace(&self, mplace: MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
|
||||
pub fn check_mplace(&self, mplace: &MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
|
||||
let (size, _align) = self
|
||||
.size_and_align_of_mplace(&mplace)?
|
||||
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
|
||||
|
@ -537,13 +567,13 @@ where
|
|||
pub fn write_immediate(
|
||||
&mut self,
|
||||
src: Immediate<M::Provenance>,
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
dest: &impl Writeable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
self.write_immediate_no_validate(src, dest)?;
|
||||
|
||||
if M::enforce_validity(self, dest.layout) {
|
||||
if M::enforce_validity(self, dest.layout()) {
|
||||
// Data got changed, better make sure it matches the type!
|
||||
self.validate_operand(&self.place_to_op(dest)?)?;
|
||||
self.validate_operand(&dest.to_op(self)?)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -554,7 +584,7 @@ where
|
|||
pub fn write_scalar(
|
||||
&mut self,
|
||||
val: impl Into<Scalar<M::Provenance>>,
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
dest: &impl Writeable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
self.write_immediate(Immediate::Scalar(val.into()), dest)
|
||||
}
|
||||
|
@ -564,7 +594,7 @@ where
|
|||
pub fn write_pointer(
|
||||
&mut self,
|
||||
ptr: impl Into<Pointer<Option<M::Provenance>>>,
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
dest: &impl Writeable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
self.write_scalar(Scalar::from_maybe_pointer(ptr.into(), self), dest)
|
||||
}
|
||||
|
@ -575,20 +605,19 @@ where
|
|||
fn write_immediate_no_validate(
|
||||
&mut self,
|
||||
src: Immediate<M::Provenance>,
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
dest: &impl Writeable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
assert!(dest.layout.is_sized(), "Cannot write unsized immediate data");
|
||||
trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
|
||||
assert!(dest.layout().is_sized(), "Cannot write unsized immediate data");
|
||||
|
||||
// See if we can avoid an allocation. This is the counterpart to `read_immediate_raw`,
|
||||
// but not factored as a separate function.
|
||||
let mplace = match dest.place {
|
||||
Place::Local { frame, local, offset } => {
|
||||
let mplace = match dest.as_mplace_or_local() {
|
||||
Right((frame, local, offset, align, layout)) => {
|
||||
if offset.is_some() {
|
||||
// This has been projected to a part of this local. We could have complicated
|
||||
// logic to still keep this local as an `Operand`... but it's much easier to
|
||||
// just fall back to the indirect path.
|
||||
*self.force_allocation(dest)?
|
||||
dest.force_mplace(self)?
|
||||
} else {
|
||||
match M::access_local_mut(self, frame, local)? {
|
||||
Operand::Immediate(local_val) => {
|
||||
|
@ -623,16 +652,16 @@ where
|
|||
}
|
||||
Operand::Indirect(mplace) => {
|
||||
// The local is in memory, go on below.
|
||||
*mplace
|
||||
MPlaceTy { mplace: *mplace, align, layout }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Place::Ptr(mplace) => mplace, // already referring to memory
|
||||
Left(mplace) => mplace, // already referring to memory
|
||||
};
|
||||
|
||||
// This is already in memory, write there.
|
||||
self.write_immediate_to_mplace_no_validate(src, dest.layout, dest.align, mplace)
|
||||
self.write_immediate_to_mplace_no_validate(src, mplace.layout, mplace.align, mplace.mplace)
|
||||
}
|
||||
|
||||
/// Write an immediate to memory.
|
||||
|
@ -696,16 +725,19 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
|
||||
pub fn write_uninit(
|
||||
&mut self,
|
||||
dest: &impl Writeable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let mplace = match dest.as_mplace_or_local() {
|
||||
Left(mplace) => mplace,
|
||||
Right((frame, local, offset)) => {
|
||||
Right((frame, local, offset, align, layout)) => {
|
||||
if offset.is_some() {
|
||||
// This has been projected to a part of this local. We could have complicated
|
||||
// logic to still keep this local as an `Operand`... but it's much easier to
|
||||
// just fall back to the indirect path.
|
||||
// FIXME: share the logic with `write_immediate_no_validate`.
|
||||
self.force_allocation(dest)?
|
||||
dest.force_mplace(self)?
|
||||
} else {
|
||||
match M::access_local_mut(self, frame, local)? {
|
||||
Operand::Immediate(local) => {
|
||||
|
@ -714,7 +746,7 @@ where
|
|||
}
|
||||
Operand::Indirect(mplace) => {
|
||||
// The local is in memory, go on below.
|
||||
MPlaceTy { mplace: *mplace, layout: dest.layout, align: dest.align }
|
||||
MPlaceTy { mplace: *mplace, layout, align }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -734,15 +766,15 @@ where
|
|||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn copy_op(
|
||||
&mut self,
|
||||
src: &OpTy<'tcx, M::Provenance>,
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
src: &impl Readable<'tcx, M::Provenance>,
|
||||
dest: &impl Writeable<'tcx, M::Provenance>,
|
||||
allow_transmute: bool,
|
||||
) -> InterpResult<'tcx> {
|
||||
self.copy_op_no_validate(src, dest, allow_transmute)?;
|
||||
|
||||
if M::enforce_validity(self, dest.layout) {
|
||||
if M::enforce_validity(self, dest.layout()) {
|
||||
// Data got changed, better make sure it matches the type!
|
||||
self.validate_operand(&self.place_to_op(dest)?)?;
|
||||
self.validate_operand(&dest.to_op(self)?)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -755,20 +787,20 @@ where
|
|||
#[instrument(skip(self), level = "debug")]
|
||||
fn copy_op_no_validate(
|
||||
&mut self,
|
||||
src: &OpTy<'tcx, M::Provenance>,
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
src: &impl Readable<'tcx, M::Provenance>,
|
||||
dest: &impl Writeable<'tcx, M::Provenance>,
|
||||
allow_transmute: bool,
|
||||
) -> InterpResult<'tcx> {
|
||||
// We do NOT compare the types for equality, because well-typed code can
|
||||
// actually "transmute" `&mut T` to `&T` in an assignment without a cast.
|
||||
let layout_compat =
|
||||
mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout);
|
||||
mir_assign_valid_types(*self.tcx, self.param_env, src.layout(), dest.layout());
|
||||
if !allow_transmute && !layout_compat {
|
||||
span_bug!(
|
||||
self.cur_span(),
|
||||
"type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
|
||||
src.layout.ty,
|
||||
dest.layout.ty,
|
||||
src.layout().ty,
|
||||
dest.layout().ty,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -781,13 +813,13 @@ where
|
|||
// actually sized, due to a trivially false where-clause
|
||||
// predicate like `where Self: Sized` with `Self = dyn Trait`.
|
||||
// See #102553 for an example of such a predicate.
|
||||
if src.layout.is_unsized() {
|
||||
throw_inval!(SizeOfUnsizedType(src.layout.ty));
|
||||
if src.layout().is_unsized() {
|
||||
throw_inval!(SizeOfUnsizedType(src.layout().ty));
|
||||
}
|
||||
if dest.layout.is_unsized() {
|
||||
throw_inval!(SizeOfUnsizedType(dest.layout.ty));
|
||||
if dest.layout().is_unsized() {
|
||||
throw_inval!(SizeOfUnsizedType(dest.layout().ty));
|
||||
}
|
||||
assert_eq!(src.layout.size, dest.layout.size);
|
||||
assert_eq!(src.layout().size, dest.layout().size);
|
||||
// Yay, we got a value that we can write directly.
|
||||
return if layout_compat {
|
||||
self.write_immediate_no_validate(*src_val, dest)
|
||||
|
@ -796,10 +828,10 @@ where
|
|||
// loaded using the offsets defined by `src.layout`. When we put this back into
|
||||
// the destination, we have to use the same offsets! So (a) we make sure we
|
||||
// write back to memory, and (b) we use `dest` *with the source layout*.
|
||||
let dest_mem = self.force_allocation(dest)?;
|
||||
let dest_mem = dest.force_mplace(self)?;
|
||||
self.write_immediate_to_mplace_no_validate(
|
||||
*src_val,
|
||||
src.layout,
|
||||
src.layout(),
|
||||
dest_mem.align,
|
||||
*dest_mem,
|
||||
)
|
||||
|
@ -808,9 +840,9 @@ where
|
|||
Left(mplace) => mplace,
|
||||
};
|
||||
// Slow path, this does not fit into an immediate. Just memcpy.
|
||||
trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
|
||||
trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout().ty);
|
||||
|
||||
let dest = self.force_allocation(&dest)?;
|
||||
let dest = dest.force_mplace(self)?;
|
||||
let Some((dest_size, _)) = self.size_and_align_of_mplace(&dest)? else {
|
||||
span_bug!(self.cur_span(), "copy_op needs (dynamically) sized values")
|
||||
};
|
||||
|
@ -928,7 +960,7 @@ where
|
|||
operands: &IndexSlice<FieldIdx, mir::Operand<'tcx>>,
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
self.write_uninit(&dest)?;
|
||||
self.write_uninit(dest)?;
|
||||
let (variant_index, variant_dest, active_field_index) = match *kind {
|
||||
mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => {
|
||||
let variant_dest = self.project_downcast(dest, variant_index)?;
|
||||
|
@ -945,7 +977,7 @@ where
|
|||
let op = self.eval_operand(operand, Some(field_dest.layout))?;
|
||||
self.copy_op(&op, &field_dest, /*allow_transmute*/ false)?;
|
||||
}
|
||||
self.write_discriminant(variant_index, &dest)
|
||||
self.write_discriminant(variant_index, dest)
|
||||
}
|
||||
|
||||
pub fn raw_const_to_mplace(
|
||||
|
@ -983,7 +1015,7 @@ where
|
|||
|
||||
/// Turn a `dyn* Trait` type into an value with the actual dynamic type.
|
||||
/// Also returns the vtable.
|
||||
pub(super) fn unpack_dyn_star<P: Projectable<'mir, 'tcx, M::Provenance>>(
|
||||
pub(super) fn unpack_dyn_star<P: Projectable<'tcx, M::Provenance>>(
|
||||
&self,
|
||||
val: &P,
|
||||
) -> InterpResult<'tcx, (P, Pointer<Option<M::Provenance>>)> {
|
||||
|
|
|
@ -16,21 +16,20 @@ use rustc_target::abi::HasDataLayout;
|
|||
use rustc_target::abi::Size;
|
||||
use rustc_target::abi::{self, VariantIdx};
|
||||
|
||||
use super::MPlaceTy;
|
||||
use super::{InterpCx, InterpResult, Machine, MemPlaceMeta, OpTy, Provenance, Scalar};
|
||||
use super::{InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar};
|
||||
|
||||
/// A thing that we can project into, and that has a layout.
|
||||
pub trait Projectable<'mir, 'tcx: 'mir, Prov: Provenance>: Sized {
|
||||
pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug {
|
||||
/// Get the layout.
|
||||
fn layout(&self) -> TyAndLayout<'tcx>;
|
||||
|
||||
/// Get the metadata of a wide value.
|
||||
fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
ecx: &InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>>;
|
||||
|
||||
fn len<M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
fn len<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
ecx: &InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, u64> {
|
||||
|
@ -67,7 +66,7 @@ pub trait Projectable<'mir, 'tcx: 'mir, Prov: Provenance>: Sized {
|
|||
|
||||
/// Convert this to an `OpTy`. This might be an irreversible transformation, but is useful for
|
||||
/// reading from this thing.
|
||||
fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
|
||||
&self,
|
||||
ecx: &InterpCx<'mir, 'tcx, M>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>;
|
||||
|
@ -85,7 +84,7 @@ where
|
|||
///
|
||||
/// This also works for arrays, but then the `usize` index type is restricting.
|
||||
/// For indexing into arrays, use `mplace_index`.
|
||||
pub fn project_field<P: Projectable<'mir, 'tcx, M::Provenance>>(
|
||||
pub fn project_field<P: Projectable<'tcx, M::Provenance>>(
|
||||
&self,
|
||||
base: &P,
|
||||
field: usize,
|
||||
|
@ -128,7 +127,7 @@ where
|
|||
}
|
||||
|
||||
/// Downcasting to an enum variant.
|
||||
pub fn project_downcast<P: Projectable<'mir, 'tcx, M::Provenance>>(
|
||||
pub fn project_downcast<P: Projectable<'tcx, M::Provenance>>(
|
||||
&self,
|
||||
base: &P,
|
||||
variant: VariantIdx,
|
||||
|
@ -149,7 +148,7 @@ where
|
|||
}
|
||||
|
||||
/// Compute the offset and field layout for accessing the given index.
|
||||
pub fn project_index<P: Projectable<'mir, 'tcx, M::Provenance>>(
|
||||
pub fn project_index<P: Projectable<'tcx, M::Provenance>>(
|
||||
&self,
|
||||
base: &P,
|
||||
index: u64,
|
||||
|
@ -178,7 +177,7 @@ where
|
|||
base.offset(offset, field_layout, self)
|
||||
}
|
||||
|
||||
fn project_constant_index<P: Projectable<'mir, 'tcx, M::Provenance>>(
|
||||
fn project_constant_index<P: Projectable<'tcx, M::Provenance>>(
|
||||
&self,
|
||||
base: &P,
|
||||
offset: u64,
|
||||
|
@ -204,7 +203,7 @@ where
|
|||
|
||||
/// Iterates over all fields of an array. Much more efficient than doing the
|
||||
/// same by repeatedly calling `operand_index`.
|
||||
pub fn project_array_fields<'a, P: Projectable<'mir, 'tcx, M::Provenance>>(
|
||||
pub fn project_array_fields<'a, P: Projectable<'tcx, M::Provenance>>(
|
||||
&self,
|
||||
base: &'a P,
|
||||
) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, P>> + 'a>
|
||||
|
@ -224,7 +223,7 @@ where
|
|||
}
|
||||
|
||||
/// Subslicing
|
||||
fn project_subslice<P: Projectable<'mir, 'tcx, M::Provenance>>(
|
||||
fn project_subslice<P: Projectable<'tcx, M::Provenance>>(
|
||||
&self,
|
||||
base: &P,
|
||||
from: u64,
|
||||
|
@ -284,9 +283,7 @@ where
|
|||
#[instrument(skip(self), level = "trace")]
|
||||
pub fn project<P>(&self, base: &P, proj_elem: mir::PlaceElem<'tcx>) -> InterpResult<'tcx, P>
|
||||
where
|
||||
P: Projectable<'mir, 'tcx, M::Provenance>
|
||||
+ From<MPlaceTy<'tcx, M::Provenance>>
|
||||
+ std::fmt::Debug,
|
||||
P: Projectable<'tcx, M::Provenance> + From<MPlaceTy<'tcx, M::Provenance>> + std::fmt::Debug,
|
||||
{
|
||||
use rustc_middle::mir::ProjectionElem::*;
|
||||
Ok(match proj_elem {
|
||||
|
|
|
@ -198,7 +198,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
} else {
|
||||
// Write the src to the first element.
|
||||
let first = self.project_index(&dest, 0)?;
|
||||
self.copy_op(&src, &first.into(), /*allow_transmute*/ false)?;
|
||||
self.copy_op(&src, &first, /*allow_transmute*/ false)?;
|
||||
|
||||
// This is performance-sensitive code for big static/const arrays! So we
|
||||
// avoid writing each operand individually and instead just make many copies
|
||||
|
|
|
@ -634,7 +634,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// Ensure the return place is aligned and dereferenceable, and protect it for
|
||||
// in-place return value passing.
|
||||
if let Either::Left(mplace) = destination.as_mplace_or_local() {
|
||||
self.check_mplace(mplace)?;
|
||||
self.check_mplace(&mplace)?;
|
||||
} else {
|
||||
// Nothing to do for locals, they are always properly allocated and aligned.
|
||||
}
|
||||
|
|
|
@ -136,19 +136,19 @@ pub struct RefTracking<T, PATH = ()> {
|
|||
pub todo: Vec<(T, PATH)>,
|
||||
}
|
||||
|
||||
impl<T: Copy + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH> {
|
||||
impl<T: Clone + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH> {
|
||||
pub fn empty() -> Self {
|
||||
RefTracking { seen: FxHashSet::default(), todo: vec![] }
|
||||
}
|
||||
pub fn new(op: T) -> Self {
|
||||
let mut ref_tracking_for_consts =
|
||||
RefTracking { seen: FxHashSet::default(), todo: vec![(op, PATH::default())] };
|
||||
RefTracking { seen: FxHashSet::default(), todo: vec![(op.clone(), PATH::default())] };
|
||||
ref_tracking_for_consts.seen.insert(op);
|
||||
ref_tracking_for_consts
|
||||
}
|
||||
|
||||
pub fn track(&mut self, op: T, path: impl FnOnce() -> PATH) {
|
||||
if self.seen.insert(op) {
|
||||
if self.seen.insert(op.clone()) {
|
||||
trace!("Recursing below ptr {:#?}", op);
|
||||
let path = path();
|
||||
// Remember to come back to this later.
|
||||
|
|
|
@ -13,9 +13,7 @@ use super::{InterpCx, MPlaceTy, Machine, Projectable};
|
|||
|
||||
/// How to traverse a value and what to do when we are at the leaves.
|
||||
pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
|
||||
type V: Projectable<'mir, 'tcx, M::Provenance>
|
||||
+ From<MPlaceTy<'tcx, M::Provenance>>
|
||||
+ std::fmt::Debug;
|
||||
type V: Projectable<'tcx, M::Provenance> + From<MPlaceTy<'tcx, M::Provenance>>;
|
||||
|
||||
/// The visitor must have an `InterpCx` in it.
|
||||
fn ecx(&self) -> &InterpCx<'mir, 'tcx, M>;
|
||||
|
|
|
@ -494,7 +494,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
trace!("assertion on {:?} should be {:?}", value, expected);
|
||||
|
||||
let expected = Scalar::from_bool(expected);
|
||||
let value_const = self.use_ecx(location, |this| this.ecx.read_scalar(&value))?;
|
||||
let value_const = self.use_ecx(location, |this| this.ecx.read_scalar(value))?;
|
||||
|
||||
if expected != value_const {
|
||||
// Poison all places this operand references so that further code
|
||||
|
@ -664,7 +664,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
|||
}
|
||||
TerminatorKind::SwitchInt { ref discr, ref targets } => {
|
||||
if let Some(ref value) = self.eval_operand(&discr, location)
|
||||
&& let Some(value_const) = self.use_ecx(location, |this| this.ecx.read_scalar(&value))
|
||||
&& let Some(value_const) = self.use_ecx(location, |this| this.ecx.read_scalar(value))
|
||||
&& let Ok(constant) = value_const.try_to_int()
|
||||
&& let Ok(constant) = constant.to_bits(constant.size())
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue