1
Fork 0

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:
bors 2023-07-26 13:06:25 +00:00
commit bd9785cce8
34 changed files with 406 additions and 374 deletions

View file

@ -58,7 +58,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
ecx.push_stack_frame( ecx.push_stack_frame(
cid.instance, cid.instance,
body, body,
&ret.into(), &ret.clone().into(),
StackPopCleanup::Root { cleanup: false }, 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. // Since evaluation had no errors, validate the resulting constant.
// This is a separate `try` block to provide more targeted error reporting. // This is a separate `try` block to provide more targeted error reporting.
let validation: Result<_, InterpErrorInfo<'_>> = try { let validation: Result<_, InterpErrorInfo<'_>> = try {
let mut ref_tracking = RefTracking::new(mplace); let mut ref_tracking = RefTracking::new(mplace.clone());
let mut inner = false; let mut inner = false;
while let Some((mplace, path)) = ref_tracking.todo.pop() { while let Some((mplace, path)) = ref_tracking.todo.pop() {
let mode = match tcx.static_mutability(cid.instance.def_id()) { let mode = match tcx.static_mutability(cid.instance.def_id()) {

View file

@ -216,7 +216,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
let mut msg_place = self.deref_operand(&args[0])?; let mut msg_place = self.deref_operand(&args[0])?;
while msg_place.layout.ty.is_ref() { 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)?); let msg = Symbol::intern(self.read_str(&msg_place)?);

View file

@ -5,7 +5,7 @@ use crate::const_eval::CanAccessStatics;
use crate::interpret::MPlaceTy; use crate::interpret::MPlaceTy;
use crate::interpret::{ use crate::interpret::{
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta, 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_middle::ty::{self, ScalarInt, Ty, TyCtxt};
use rustc_span::source_map::DUMMY_SP; use rustc_span::source_map::DUMMY_SP;
@ -21,7 +21,7 @@ fn branches<'tcx>(
) -> ValTreeCreationResult<'tcx> { ) -> ValTreeCreationResult<'tcx> {
let place = match variant { let place = match variant {
Some(variant) => ecx.project_downcast(place, variant).unwrap(), 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())))); let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32()))));
debug!(?place, ?variant); debug!(?place, ?variant);
@ -86,7 +86,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
Ok(ty::ValTree::zst()) Ok(ty::ValTree::zst())
} }
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { 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); return Err(ValTreeCreationError::Other);
}; };
let val = val.to_scalar(); 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::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
ty::Ref(_, _, _) => { 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); return Err(ValTreeCreationError::Other);
}; };
debug!(?derefd_place); 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") 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); return Err(ValTreeCreationError::Other);
}; };
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes) 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(..) => { ty::Ref(_, _, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
let mut place = match ty.kind() { let place = match ty.kind() {
ty::Ref(_, inner_ty, _) => { ty::Ref(_, inner_ty, _) => {
// Need to create a place for the pointee to fill for Refs // Need to create a place for the pointee to fill for Refs
create_pointee_place(&mut ecx, *inner_ty, valtree) create_pointee_place(&mut ecx, *inner_ty, valtree)
@ -289,8 +289,8 @@ pub fn valtree_to_const_value<'tcx>(
}; };
debug!(?place); debug!(?place);
valtree_into_mplace(&mut ecx, &mut place, valtree); valtree_into_mplace(&mut ecx, &place, valtree);
dump_place(&ecx, place.into()); dump_place(&ecx, &place);
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap(); intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
match ty.kind() { match ty.kind() {
@ -329,7 +329,7 @@ pub fn valtree_to_const_value<'tcx>(
#[instrument(skip(ecx), level = "debug")] #[instrument(skip(ecx), level = "debug")]
fn valtree_into_mplace<'tcx>( fn valtree_into_mplace<'tcx>(
ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>, ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
place: &mut MPlaceTy<'tcx>, place: &MPlaceTy<'tcx>,
valtree: ty::ValTree<'tcx>, valtree: ty::ValTree<'tcx>,
) { ) {
// This will match on valtree and write the value(s) corresponding to the ValTree // 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 => { ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
let scalar_int = valtree.unwrap_leaf(); let scalar_int = valtree.unwrap_leaf();
debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place); 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, _) => { 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); debug!(?pointee_place);
valtree_into_mplace(ecx, &mut pointee_place, valtree); valtree_into_mplace(ecx, &pointee_place, valtree);
dump_place(ecx, pointee_place.into()); dump_place(ecx, &pointee_place);
intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap(); intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap();
let imm = match inner_ty.kind() { let imm = match inner_ty.kind() {
@ -369,7 +369,7 @@ fn valtree_into_mplace<'tcx>(
}; };
debug!(?imm); 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(_) => { ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => {
let branches = valtree.unwrap_branch(); let branches = valtree.unwrap_branch();
@ -389,7 +389,7 @@ fn valtree_into_mplace<'tcx>(
Some(variant_idx), Some(variant_idx),
) )
} }
_ => (*place, branches, None), _ => (place.clone(), branches, None),
}; };
debug!(?place_adjusted, ?branches); debug!(?place_adjusted, ?branches);
@ -398,7 +398,7 @@ fn valtree_into_mplace<'tcx>(
for (i, inner_valtree) in branches.iter().enumerate() { for (i, inner_valtree) in branches.iter().enumerate() {
debug!(?i, ?inner_valtree); 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(), ty::Str | ty::Slice(_) => ecx.project_index(place, i as u64).unwrap(),
_ if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty()) _ if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty())
&& i == branches.len() - 1 => && i == branches.len() - 1 =>
@ -443,25 +443,25 @@ fn valtree_into_mplace<'tcx>(
}; };
debug!(?place_inner); debug!(?place_inner);
valtree_into_mplace(ecx, &mut place_inner, *inner_valtree); valtree_into_mplace(ecx, &place_inner, *inner_valtree);
dump_place(&ecx, place_inner.into()); dump_place(&ecx, &place_inner);
} }
debug!("dump of place_adjusted:"); debug!("dump of place_adjusted:");
dump_place(ecx, place_adjusted.into()); dump_place(ecx, &place_adjusted);
if let Some(variant_idx) = variant_idx { if let Some(variant_idx) = variant_idx {
// don't forget filling the place with the discriminant of the enum // 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:"); 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), _ => bug!("shouldn't have created a ValTree for {:?}", ty),
} }
} }
fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: PlaceTy<'tcx>) { fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>) {
trace!("{:?}", ecx.dump_place(*place)); trace!("{:?}", ecx.dump_place(Place::Ptr(**place)));
} }

View file

@ -56,7 +56,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} }
CastKind::FnPtrToPtr | CastKind::PtrToPtr => { 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)?; let res = self.ptr_to_ptr(&src, cast_ty)?;
self.write_immediate(res, dest)?; self.write_immediate(res, dest)?;
} }

View file

@ -5,7 +5,7 @@ use rustc_middle::{mir, ty};
use rustc_target::abi::{self, TagEncoding}; use rustc_target::abi::{self, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants}; 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> { impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Writes the discriminant of the given variant. /// 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( pub fn write_discriminant(
&mut self, &mut self,
variant_index: VariantIdx, variant_index: VariantIdx,
dest: &PlaceTy<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
// Layout computation excludes uninhabited variants from consideration // Layout computation excludes uninhabited variants from consideration
// therefore there's no way to represent those variants in the given layout. // 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. // discriminant, so we cannot do anything here.
// When evaluating we will always error before even getting here, but ConstProp 'executes' // When evaluating we will always error before even getting here, but ConstProp 'executes'
// dead code, so we cannot ICE here. // 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)) throw_ub!(UninhabitedEnumVariantWritten(variant_index))
} }
match dest.layout.variants { match dest.layout().variants {
abi::Variants::Single { index } => { abi::Variants::Single { index } => {
assert_eq!(index, variant_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 // No need to validate that the discriminant here because the
// `TyAndLayout::for_variant()` call earlier already checks the variant is valid. // `TyAndLayout::for_variant()` call earlier already checks the variant is valid.
let discr_val = let discr_val = dest
dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val; .layout()
.ty
.discriminant_for_variant(*self.tcx, variant_index)
.unwrap()
.val;
// raw discriminants for enums are isize or bigger during // raw discriminants for enums are isize or bigger during
// their computation, but the in-memory tag is the smallest possible // 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")] #[instrument(skip(self), level = "trace")]
pub fn read_discriminant( pub fn read_discriminant(
&self, &self,
op: &OpTy<'tcx, M::Provenance>, op: &impl Readable<'tcx, M::Provenance>,
) -> InterpResult<'tcx, VariantIdx> { ) -> 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. // 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); trace!("discriminant type: {:?}", discr_layout.ty);
// We use "discriminant" to refer to the value associated with a particular enum variant. // 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. // 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 // 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`). // 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 } => { Variants::Single { index } => {
// Do some extra checks on enums. // 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. // Hilariously, `Single` is used even for 0-variant enums.
// (See https://github.com/rust-lang/rust/issues/89765). // (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)) throw_ub!(UninhabitedEnumVariantRead(index))
} }
// For consisteny with `write_discriminant`, and to make sure that // For consisteny with `write_discriminant`, and to make sure that
// `project_downcast` cannot fail due to strange layouts, we declare immediate UB // `project_downcast` cannot fail due to strange layouts, we declare immediate UB
// for uninhabited variants. // 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)) 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(); self.cast_from_int_like(scalar, tag_val.layout, discr_layout.ty).unwrap();
let discr_bits = discr_val.assert_bits(discr_layout.size); let discr_bits = discr_val.assert_bits(discr_layout.size);
// Convert discriminant to variant index, and catch invalid discriminants. // Convert discriminant to variant index, and catch invalid discriminants.
let index = match *op.layout.ty.kind() { let index = match *ty.kind() {
ty::Adt(adt, _) => { ty::Adt(adt, _) => {
adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits) 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) .checked_add(variant_index_relative)
.expect("overflow computing absolute variant idx"), .expect("overflow computing absolute variant idx"),
); );
let variants = op let variants =
.layout ty.ty_adt_def().expect("tagged layout for non adt").variants();
.ty
.ty_adt_def()
.expect("tagged layout for non adt")
.variants();
assert!(variant_index < variants.next_index()); assert!(variant_index < variants.next_index());
variant_index variant_index
} else { } 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. // 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)) throw_ub!(UninhabitedEnumVariantRead(index))
} }
Ok(index) Ok(index)

View file

@ -170,7 +170,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
let tcx = self.ecx.tcx; let tcx = self.ecx.tcx;
let ty = mplace.layout.ty; let ty = mplace.layout.ty;
if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() { 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)?; let mplace = self.ecx.ref_to_mplace(&value)?;
assert_eq!(mplace.layout.ty, referenced_ty); assert_eq!(mplace.layout.ty, referenced_ty);
// Handle trait object vtables. // Handle trait object vtables.
@ -358,7 +358,7 @@ pub fn intern_const_alloc_recursive<
Some(ret.layout.ty), 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() { while let Some(((mplace, mode), _)) = ref_tracking.todo.pop() {
let res = InternVisitor { let res = InternVisitor {
@ -464,7 +464,7 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>>
) -> InterpResult<'tcx, ()>, ) -> InterpResult<'tcx, ()>,
) -> InterpResult<'tcx, ConstAllocation<'tcx>> { ) -> InterpResult<'tcx, ConstAllocation<'tcx>> {
let dest = self.allocate(layout, MemoryKind::Stack)?; 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; let mut alloc = self.memory.alloc_map.remove(&dest.ptr.provenance.unwrap()).unwrap().1;
alloc.mutability = Mutability::Not; alloc.mutability = Mutability::Not;
Ok(self.tcx.mk_const_alloc(alloc)) Ok(self.tcx.mk_const_alloc(alloc))

View file

@ -226,7 +226,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} }
sym::discriminant_value => { sym::discriminant_value => {
let place = self.deref_operand(&args[0])?; 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)?; let discr = self.discriminant_for_variant(place.layout, variant)?;
self.write_scalar(discr, dest)?; self.write_scalar(discr, dest)?;
} }
@ -432,7 +432,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} else { } else {
self.project_index(&input, i)?.into() 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 => { sym::simd_extract => {
@ -445,7 +445,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
input_len input_len
); );
self.copy_op( self.copy_op(
&self.project_index(&input, index)?.into(), &self.project_index(&input, index)?,
dest, dest,
/*allow_transmute*/ false, /*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>, count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
nonoverlapping: bool, nonoverlapping: bool,
) -> InterpResult<'tcx> { ) -> 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 layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
let (size, align) = (layout.size, layout.align.abi); let (size, align) = (layout.size, layout.align.abi);
// `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max), // `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 src = self.read_pointer(src)?;
let dst = self.read_pointer(&dst)?; let dst = self.read_pointer(dst)?;
self.mem_copy(src, align, dst, align, size, nonoverlapping) 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> { ) -> InterpResult<'tcx> {
let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?; let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?;
let dst = self.read_pointer(&dst)?; let dst = self.read_pointer(dst)?;
let byte = self.read_scalar(&byte)?.to_u8()?; let byte = self.read_scalar(byte)?.to_u8()?;
let count = self.read_target_usize(&count)?; let count = self.read_target_usize(count)?;
// `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max), // `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. // but no actual allocation can be big enough for the difference to be noticeable.

View file

@ -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(); let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
// Initialize fields. // 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"); .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"); .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"); .expect("writing to memory we just allocated cannot fail");
location location

View file

@ -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::intern::{intern_const_alloc_recursive, InternKind};
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump}; pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
pub use self::operand::{ImmTy, Immediate, OpTy, Operand}; pub use self::operand::{ImmTy, Immediate, OpTy, Operand, Readable};
pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy}; pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy, Writeable};
pub use self::projection::Projectable; pub use self::projection::Projectable;
pub use self::terminator::FnArg; pub use self::terminator::FnArg;
pub use self::validity::{CtfeValidationMode, RefTracking}; pub use self::validity::{CtfeValidationMode, RefTracking};

View file

@ -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> { impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
#[inline(always)] #[inline(always)]
fn from(val: ImmTy<'tcx, Prov>) -> Self { 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> { impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
#[inline] #[inline]
pub fn from_scalar(val: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self { 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)] #[inline(always)]
fn layout(&self) -> TyAndLayout<'tcx> { fn layout(&self) -> TyAndLayout<'tcx> {
self.layout self.layout
} }
fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>( fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self, &self,
_ecx: &InterpCx<'mir, 'tcx, M>, _ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> { ) -> 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)) 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, &self,
_ecx: &InterpCx<'mir, 'tcx, M>, _ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { ) -> 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> impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> {
for OpTy<'tcx, Prov>
{
#[inline(always)] #[inline(always)]
fn layout(&self) -> TyAndLayout<'tcx> { fn layout(&self) -> TyAndLayout<'tcx> {
self.layout self.layout
} }
fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>( fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self, &self,
_ecx: &InterpCx<'mir, 'tcx, M>, _ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> { ) -> 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, &self,
_ecx: &InterpCx<'mir, 'tcx, M>, _ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { ) -> 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> { impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`. /// 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. /// 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. /// ConstProp needs it, though.
pub fn read_immediate_raw( pub fn read_immediate_raw(
&self, &self,
src: &OpTy<'tcx, M::Provenance>, src: &impl Readable<'tcx, M::Provenance>,
) -> InterpResult<'tcx, Either<MPlaceTy<'tcx, M::Provenance>, ImmTy<'tcx, M::Provenance>>> { ) -> InterpResult<'tcx, Either<MPlaceTy<'tcx, M::Provenance>, ImmTy<'tcx, M::Provenance>>> {
Ok(match src.as_mplace_or_imm() { Ok(match src.as_mplace_or_imm() {
Left(ref mplace) => { Left(ref mplace) => {
if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? { if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? {
Right(val) Right(val)
} else { } else {
Left(*mplace) Left(mplace.clone())
} }
} }
Right(val) => Right(val), Right(val) => Right(val),
@ -494,14 +489,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
#[inline(always)] #[inline(always)]
pub fn read_immediate( pub fn read_immediate(
&self, &self,
op: &OpTy<'tcx, M::Provenance>, op: &impl Readable<'tcx, M::Provenance>,
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
if !matches!( if !matches!(
op.layout.abi, op.layout().abi,
Abi::Scalar(abi::Scalar::Initialized { .. }) Abi::Scalar(abi::Scalar::Initialized { .. })
| Abi::ScalarPair(abi::Scalar::Initialized { .. }, 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(); let imm = self.read_immediate_raw(op)?.right().unwrap();
if matches!(*imm, Immediate::Uninit) { 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 /// Read a scalar from a place
pub fn read_scalar( pub fn read_scalar(
&self, &self,
op: &OpTy<'tcx, M::Provenance>, op: &impl Readable<'tcx, M::Provenance>,
) -> InterpResult<'tcx, Scalar<M::Provenance>> { ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
Ok(self.read_immediate(op)?.to_scalar()) 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. /// Read a pointer from a place.
pub fn read_pointer( pub fn read_pointer(
&self, &self,
op: &OpTy<'tcx, M::Provenance>, op: &impl Readable<'tcx, M::Provenance>,
) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> { ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
self.read_scalar(op)?.to_pointer(self) self.read_scalar(op)?.to_pointer(self)
} }
/// Read a pointer-sized unsigned integer from a place. /// 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) self.read_scalar(op)?.to_target_usize(self)
} }
/// Read a pointer-sized signed integer from a place. /// 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) self.read_scalar(op)?.to_target_isize(self)
} }

View file

@ -18,7 +18,7 @@ use rustc_target::abi::{self, Abi, Align, FieldIdx, HasDataLayout, Size, FIRST_V
use super::{ use super::{
alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckInAllocMsg, alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckInAllocMsg,
ConstAlloc, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, OpTy, Operand, 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)] #[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. /// 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> { pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
mplace: MemPlace<Prov>, mplace: MemPlace<Prov>,
pub layout: TyAndLayout<'tcx>, pub layout: TyAndLayout<'tcx>,
@ -92,6 +92,14 @@ pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
pub align: Align, 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)] #[derive(Copy, Clone, Debug)]
pub enum Place<Prov: Provenance = AllocId> { pub enum Place<Prov: Provenance = AllocId> {
/// A place referring to a value allocated in the `Memory` system. /// 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> { impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> {
#[inline(always)] #[inline(always)]
fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { 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> { impl<Prov: Provenance> MemPlace<Prov> {
#[inline(always)] #[inline(always)]
pub fn from_ptr(ptr: Pointer<Option<Prov>>) -> Self { 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> impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
for MPlaceTy<'tcx, Prov>
{
#[inline(always)] #[inline(always)]
fn layout(&self) -> TyAndLayout<'tcx> { fn layout(&self) -> TyAndLayout<'tcx> {
self.layout self.layout
} }
fn meta<M: Machine<'mir, 'tcx, Provenance = Prov>>( fn meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self, &self,
_ecx: &InterpCx<'mir, 'tcx, M>, _ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> { ) -> 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, &self,
_ecx: &InterpCx<'mir, 'tcx, M>, _ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { ) -> 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> pub trait Writeable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> {
for PlaceTy<'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)] #[inline(always)]
fn layout(&self) -> TyAndLayout<'tcx> { fn as_mplace_or_local(
self.layout &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, &self,
ecx: &InterpCx<'mir, 'tcx, M>, ecx: &mut InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>> { ) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>> {
ecx.place_meta(self) 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, &self,
offset: Size, _ecx: &mut InterpCx<'mir, 'tcx, M>,
meta: MemPlaceMeta<Prov>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>> {
layout: TyAndLayout<'tcx>, Ok(self.clone())
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)
} }
} }
@ -412,7 +442,7 @@ where
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
pub fn deref_operand( pub fn deref_operand(
&self, &self,
src: &OpTy<'tcx, M::Provenance>, src: &impl Readable<'tcx, M::Provenance>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
let val = self.read_immediate(src)?; let val = self.read_immediate(src)?;
trace!("deref to {} on {:?}", val.layout.ty, *val); trace!("deref to {} on {:?}", val.layout.ty, *val);
@ -422,7 +452,7 @@ where
} }
let mplace = self.ref_to_mplace(&val)?; let mplace = self.ref_to_mplace(&val)?;
self.check_mplace(mplace)?; self.check_mplace(&mplace)?;
Ok(mplace) Ok(mplace)
} }
@ -453,7 +483,7 @@ where
} }
/// Check if this mplace is dereferenceable and sufficiently aligned. /// 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 let (size, _align) = self
.size_and_align_of_mplace(&mplace)? .size_and_align_of_mplace(&mplace)?
.unwrap_or((mplace.layout.size, mplace.layout.align.abi)); .unwrap_or((mplace.layout.size, mplace.layout.align.abi));
@ -537,13 +567,13 @@ where
pub fn write_immediate( pub fn write_immediate(
&mut self, &mut self,
src: Immediate<M::Provenance>, src: Immediate<M::Provenance>,
dest: &PlaceTy<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
self.write_immediate_no_validate(src, dest)?; 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! // 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(()) Ok(())
@ -554,7 +584,7 @@ where
pub fn write_scalar( pub fn write_scalar(
&mut self, &mut self,
val: impl Into<Scalar<M::Provenance>>, val: impl Into<Scalar<M::Provenance>>,
dest: &PlaceTy<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
self.write_immediate(Immediate::Scalar(val.into()), dest) self.write_immediate(Immediate::Scalar(val.into()), dest)
} }
@ -564,7 +594,7 @@ where
pub fn write_pointer( pub fn write_pointer(
&mut self, &mut self,
ptr: impl Into<Pointer<Option<M::Provenance>>>, ptr: impl Into<Pointer<Option<M::Provenance>>>,
dest: &PlaceTy<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
self.write_scalar(Scalar::from_maybe_pointer(ptr.into(), self), dest) self.write_scalar(Scalar::from_maybe_pointer(ptr.into(), self), dest)
} }
@ -575,20 +605,19 @@ where
fn write_immediate_no_validate( fn write_immediate_no_validate(
&mut self, &mut self,
src: Immediate<M::Provenance>, src: Immediate<M::Provenance>,
dest: &PlaceTy<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
assert!(dest.layout.is_sized(), "Cannot write unsized immediate data"); assert!(dest.layout().is_sized(), "Cannot write unsized immediate data");
trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
// See if we can avoid an allocation. This is the counterpart to `read_immediate_raw`, // See if we can avoid an allocation. This is the counterpart to `read_immediate_raw`,
// but not factored as a separate function. // but not factored as a separate function.
let mplace = match dest.place { let mplace = match dest.as_mplace_or_local() {
Place::Local { frame, local, offset } => { Right((frame, local, offset, align, layout)) => {
if offset.is_some() { if offset.is_some() {
// This has been projected to a part of this local. We could have complicated // 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 // logic to still keep this local as an `Operand`... but it's much easier to
// just fall back to the indirect path. // just fall back to the indirect path.
*self.force_allocation(dest)? dest.force_mplace(self)?
} else { } else {
match M::access_local_mut(self, frame, local)? { match M::access_local_mut(self, frame, local)? {
Operand::Immediate(local_val) => { Operand::Immediate(local_val) => {
@ -623,16 +652,16 @@ where
} }
Operand::Indirect(mplace) => { Operand::Indirect(mplace) => {
// The local is in memory, go on below. // 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. // 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. /// 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() { let mplace = match dest.as_mplace_or_local() {
Left(mplace) => mplace, Left(mplace) => mplace,
Right((frame, local, offset)) => { Right((frame, local, offset, align, layout)) => {
if offset.is_some() { if offset.is_some() {
// This has been projected to a part of this local. We could have complicated // 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 // logic to still keep this local as an `Operand`... but it's much easier to
// just fall back to the indirect path. // just fall back to the indirect path.
// FIXME: share the logic with `write_immediate_no_validate`. // FIXME: share the logic with `write_immediate_no_validate`.
self.force_allocation(dest)? dest.force_mplace(self)?
} else { } else {
match M::access_local_mut(self, frame, local)? { match M::access_local_mut(self, frame, local)? {
Operand::Immediate(local) => { Operand::Immediate(local) => {
@ -714,7 +746,7 @@ where
} }
Operand::Indirect(mplace) => { Operand::Indirect(mplace) => {
// The local is in memory, go on below. // 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")] #[instrument(skip(self), level = "debug")]
pub fn copy_op( pub fn copy_op(
&mut self, &mut self,
src: &OpTy<'tcx, M::Provenance>, src: &impl Readable<'tcx, M::Provenance>,
dest: &PlaceTy<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>,
allow_transmute: bool, allow_transmute: bool,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
self.copy_op_no_validate(src, dest, allow_transmute)?; 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! // 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(()) Ok(())
@ -755,20 +787,20 @@ where
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn copy_op_no_validate( fn copy_op_no_validate(
&mut self, &mut self,
src: &OpTy<'tcx, M::Provenance>, src: &impl Readable<'tcx, M::Provenance>,
dest: &PlaceTy<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>,
allow_transmute: bool, allow_transmute: bool,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
// We do NOT compare the types for equality, because well-typed code can // 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. // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
let layout_compat = 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 { if !allow_transmute && !layout_compat {
span_bug!( span_bug!(
self.cur_span(), self.cur_span(),
"type mismatch when copying!\nsrc: {:?},\ndest: {:?}", "type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
src.layout.ty, src.layout().ty,
dest.layout.ty, dest.layout().ty,
); );
} }
@ -781,13 +813,13 @@ where
// actually sized, due to a trivially false where-clause // actually sized, due to a trivially false where-clause
// predicate like `where Self: Sized` with `Self = dyn Trait`. // predicate like `where Self: Sized` with `Self = dyn Trait`.
// See #102553 for an example of such a predicate. // See #102553 for an example of such a predicate.
if src.layout.is_unsized() { if src.layout().is_unsized() {
throw_inval!(SizeOfUnsizedType(src.layout.ty)); throw_inval!(SizeOfUnsizedType(src.layout().ty));
} }
if dest.layout.is_unsized() { if dest.layout().is_unsized() {
throw_inval!(SizeOfUnsizedType(dest.layout.ty)); 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. // Yay, we got a value that we can write directly.
return if layout_compat { return if layout_compat {
self.write_immediate_no_validate(*src_val, dest) 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 // 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 // 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*. // 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( self.write_immediate_to_mplace_no_validate(
*src_val, *src_val,
src.layout, src.layout(),
dest_mem.align, dest_mem.align,
*dest_mem, *dest_mem,
) )
@ -808,9 +840,9 @@ where
Left(mplace) => mplace, Left(mplace) => mplace,
}; };
// Slow path, this does not fit into an immediate. Just memcpy. // 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 { let Some((dest_size, _)) = self.size_and_align_of_mplace(&dest)? else {
span_bug!(self.cur_span(), "copy_op needs (dynamically) sized values") span_bug!(self.cur_span(), "copy_op needs (dynamically) sized values")
}; };
@ -928,7 +960,7 @@ where
operands: &IndexSlice<FieldIdx, mir::Operand<'tcx>>, operands: &IndexSlice<FieldIdx, mir::Operand<'tcx>>,
dest: &PlaceTy<'tcx, M::Provenance>, dest: &PlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
self.write_uninit(&dest)?; self.write_uninit(dest)?;
let (variant_index, variant_dest, active_field_index) = match *kind { let (variant_index, variant_dest, active_field_index) = match *kind {
mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => { mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => {
let variant_dest = self.project_downcast(dest, variant_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))?; let op = self.eval_operand(operand, Some(field_dest.layout))?;
self.copy_op(&op, &field_dest, /*allow_transmute*/ false)?; 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( pub fn raw_const_to_mplace(
@ -983,7 +1015,7 @@ where
/// Turn a `dyn* Trait` type into an value with the actual dynamic type. /// Turn a `dyn* Trait` type into an value with the actual dynamic type.
/// Also returns the vtable. /// 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, &self,
val: &P, val: &P,
) -> InterpResult<'tcx, (P, Pointer<Option<M::Provenance>>)> { ) -> InterpResult<'tcx, (P, Pointer<Option<M::Provenance>>)> {

View file

@ -16,21 +16,20 @@ use rustc_target::abi::HasDataLayout;
use rustc_target::abi::Size; use rustc_target::abi::Size;
use rustc_target::abi::{self, VariantIdx}; use rustc_target::abi::{self, VariantIdx};
use super::MPlaceTy; use super::{InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar};
use super::{InterpCx, InterpResult, Machine, MemPlaceMeta, OpTy, Provenance, Scalar};
/// A thing that we can project into, and that has a layout. /// 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. /// Get the layout.
fn layout(&self) -> TyAndLayout<'tcx>; fn layout(&self) -> TyAndLayout<'tcx>;
/// Get the metadata of a wide value. /// 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, &self,
ecx: &InterpCx<'mir, 'tcx, M>, ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>>; ) -> InterpResult<'tcx, MemPlaceMeta<M::Provenance>>;
fn len<M: Machine<'mir, 'tcx, Provenance = Prov>>( fn len<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self, &self,
ecx: &InterpCx<'mir, 'tcx, M>, ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, u64> { ) -> 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 /// Convert this to an `OpTy`. This might be an irreversible transformation, but is useful for
/// reading from this thing. /// reading from this thing.
fn to_op<M: Machine<'mir, 'tcx, Provenance = Prov>>( fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
&self, &self,
ecx: &InterpCx<'mir, 'tcx, M>, ecx: &InterpCx<'mir, 'tcx, M>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>; ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>;
@ -85,7 +84,7 @@ where
/// ///
/// This also works for arrays, but then the `usize` index type is restricting. /// This also works for arrays, but then the `usize` index type is restricting.
/// For indexing into arrays, use `mplace_index`. /// 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, &self,
base: &P, base: &P,
field: usize, field: usize,
@ -128,7 +127,7 @@ where
} }
/// Downcasting to an enum variant. /// 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, &self,
base: &P, base: &P,
variant: VariantIdx, variant: VariantIdx,
@ -149,7 +148,7 @@ where
} }
/// Compute the offset and field layout for accessing the given index. /// 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, &self,
base: &P, base: &P,
index: u64, index: u64,
@ -178,7 +177,7 @@ where
base.offset(offset, field_layout, self) 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, &self,
base: &P, base: &P,
offset: u64, offset: u64,
@ -204,7 +203,7 @@ where
/// Iterates over all fields of an array. Much more efficient than doing the /// Iterates over all fields of an array. Much more efficient than doing the
/// same by repeatedly calling `operand_index`. /// 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, &self,
base: &'a P, base: &'a P,
) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, P>> + 'a> ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, P>> + 'a>
@ -224,7 +223,7 @@ where
} }
/// Subslicing /// Subslicing
fn project_subslice<P: Projectable<'mir, 'tcx, M::Provenance>>( fn project_subslice<P: Projectable<'tcx, M::Provenance>>(
&self, &self,
base: &P, base: &P,
from: u64, from: u64,
@ -284,9 +283,7 @@ where
#[instrument(skip(self), level = "trace")] #[instrument(skip(self), level = "trace")]
pub fn project<P>(&self, base: &P, proj_elem: mir::PlaceElem<'tcx>) -> InterpResult<'tcx, P> pub fn project<P>(&self, base: &P, proj_elem: mir::PlaceElem<'tcx>) -> InterpResult<'tcx, P>
where where
P: Projectable<'mir, 'tcx, M::Provenance> P: Projectable<'tcx, M::Provenance> + From<MPlaceTy<'tcx, M::Provenance>> + std::fmt::Debug,
+ From<MPlaceTy<'tcx, M::Provenance>>
+ std::fmt::Debug,
{ {
use rustc_middle::mir::ProjectionElem::*; use rustc_middle::mir::ProjectionElem::*;
Ok(match proj_elem { Ok(match proj_elem {

View file

@ -198,7 +198,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} else { } else {
// Write the src to the first element. // Write the src to the first element.
let first = self.project_index(&dest, 0)?; 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 // This is performance-sensitive code for big static/const arrays! So we
// avoid writing each operand individually and instead just make many copies // avoid writing each operand individually and instead just make many copies

View file

@ -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 // Ensure the return place is aligned and dereferenceable, and protect it for
// in-place return value passing. // in-place return value passing.
if let Either::Left(mplace) = destination.as_mplace_or_local() { if let Either::Left(mplace) = destination.as_mplace_or_local() {
self.check_mplace(mplace)?; self.check_mplace(&mplace)?;
} else { } else {
// Nothing to do for locals, they are always properly allocated and aligned. // Nothing to do for locals, they are always properly allocated and aligned.
} }

View file

@ -136,19 +136,19 @@ pub struct RefTracking<T, PATH = ()> {
pub todo: Vec<(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 { pub fn empty() -> Self {
RefTracking { seen: FxHashSet::default(), todo: vec![] } RefTracking { seen: FxHashSet::default(), todo: vec![] }
} }
pub fn new(op: T) -> Self { pub fn new(op: T) -> Self {
let mut ref_tracking_for_consts = 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.seen.insert(op);
ref_tracking_for_consts ref_tracking_for_consts
} }
pub fn track(&mut self, op: T, path: impl FnOnce() -> PATH) { 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); trace!("Recursing below ptr {:#?}", op);
let path = path(); let path = path();
// Remember to come back to this later. // Remember to come back to this later.

View file

@ -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. /// 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 { pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
type V: Projectable<'mir, 'tcx, M::Provenance> type V: Projectable<'tcx, M::Provenance> + From<MPlaceTy<'tcx, M::Provenance>>;
+ From<MPlaceTy<'tcx, M::Provenance>>
+ std::fmt::Debug;
/// The visitor must have an `InterpCx` in it. /// The visitor must have an `InterpCx` in it.
fn ecx(&self) -> &InterpCx<'mir, 'tcx, M>; fn ecx(&self) -> &InterpCx<'mir, 'tcx, M>;

View file

@ -494,7 +494,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
trace!("assertion on {:?} should be {:?}", value, expected); trace!("assertion on {:?} should be {:?}", value, expected);
let expected = Scalar::from_bool(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 { if expected != value_const {
// Poison all places this operand references so that further code // 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 } => { TerminatorKind::SwitchInt { ref discr, ref targets } => {
if let Some(ref value) = self.eval_operand(&discr, location) 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) = value_const.try_to_int()
&& let Ok(constant) = constant.to_bits(constant.size()) && let Ok(constant) = constant.to_bits(constant.size())
{ {

View file

@ -472,7 +472,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
// This is fine with StackedBorrow and race checks because they don't concern metadata on // This is fine with StackedBorrow and race checks because they don't concern metadata on
// the *value* (including the associated provenance if this is an AtomicPtr) at this location. // the *value* (including the associated provenance if this is an AtomicPtr) at this location.
// Only metadata on the location itself is used. // Only metadata on the location itself is used.
let scalar = this.allow_data_races_ref(move |this| this.read_scalar(&place.into()))?; let scalar = this.allow_data_races_ref(move |this| this.read_scalar(place))?;
this.validate_overlapping_atomic(place)?; this.validate_overlapping_atomic(place)?;
this.buffered_atomic_read(place, atomic, scalar, || { this.buffered_atomic_read(place, atomic, scalar, || {
this.validate_atomic_load(place, atomic) this.validate_atomic_load(place, atomic)
@ -490,7 +490,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
this.atomic_access_check(dest)?; this.atomic_access_check(dest)?;
this.validate_overlapping_atomic(dest)?; this.validate_overlapping_atomic(dest)?;
this.allow_data_races_mut(move |this| this.write_scalar(val, &dest.into()))?; this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?;
this.validate_atomic_store(dest, atomic)?; this.validate_atomic_store(dest, atomic)?;
// FIXME: it's not possible to get the value before write_scalar. A read_scalar will cause // FIXME: it's not possible to get the value before write_scalar. A read_scalar will cause
// side effects from a read the program did not perform. So we have to initialise // side effects from a read the program did not perform. So we have to initialise
@ -513,12 +513,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
this.atomic_access_check(place)?; this.atomic_access_check(place)?;
this.validate_overlapping_atomic(place)?; this.validate_overlapping_atomic(place)?;
let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; let old = this.allow_data_races_mut(|this| this.read_immediate(place))?;
// Atomics wrap around on overflow. // Atomics wrap around on overflow.
let val = this.binary_op(op, &old, rhs)?; let val = this.binary_op(op, &old, rhs)?;
let val = if neg { this.unary_op(mir::UnOp::Not, &val)? } else { val }; let val = if neg { this.unary_op(mir::UnOp::Not, &val)? } else { val };
this.allow_data_races_mut(|this| this.write_immediate(*val, &place.into()))?; this.allow_data_races_mut(|this| this.write_immediate(*val, place))?;
this.validate_atomic_rmw(place, atomic)?; this.validate_atomic_rmw(place, atomic)?;
@ -538,8 +538,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
this.atomic_access_check(place)?; this.atomic_access_check(place)?;
this.validate_overlapping_atomic(place)?; this.validate_overlapping_atomic(place)?;
let old = this.allow_data_races_mut(|this| this.read_scalar(&place.into()))?; let old = this.allow_data_races_mut(|this| this.read_scalar(place))?;
this.allow_data_races_mut(|this| this.write_scalar(new, &place.into()))?; this.allow_data_races_mut(|this| this.write_scalar(new, place))?;
this.validate_atomic_rmw(place, atomic)?; this.validate_atomic_rmw(place, atomic)?;
@ -560,7 +560,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
this.atomic_access_check(place)?; this.atomic_access_check(place)?;
this.validate_overlapping_atomic(place)?; this.validate_overlapping_atomic(place)?;
let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; let old = this.allow_data_races_mut(|this| this.read_immediate(place))?;
let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?; let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?;
let new_val = if min { let new_val = if min {
@ -569,7 +569,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
if lt { &rhs } else { &old } if lt { &rhs } else { &old }
}; };
this.allow_data_races_mut(|this| this.write_immediate(**new_val, &place.into()))?; this.allow_data_races_mut(|this| this.write_immediate(**new_val, place))?;
this.validate_atomic_rmw(place, atomic)?; this.validate_atomic_rmw(place, atomic)?;
@ -603,7 +603,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
// to read with the failure ordering and if successful then try again with the success // to read with the failure ordering and if successful then try again with the success
// read ordering and write in the success case. // read ordering and write in the success case.
// Read as immediate for the sake of `binary_op()` // Read as immediate for the sake of `binary_op()`
let old = this.allow_data_races_mut(|this| this.read_immediate(&(place.into())))?; let old = this.allow_data_races_mut(|this| this.read_immediate(place))?;
// `binary_op` will bail if either of them is not a scalar. // `binary_op` will bail if either of them is not a scalar.
let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?; let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?;
// If the operation would succeed, but is "weak", fail some portion // If the operation would succeed, but is "weak", fail some portion
@ -621,7 +621,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
// if successful, perform a full rw-atomic validation // if successful, perform a full rw-atomic validation
// otherwise treat this as an atomic load with the fail ordering. // otherwise treat this as an atomic load with the fail ordering.
if cmpxchg_success { if cmpxchg_success {
this.allow_data_races_mut(|this| this.write_scalar(new, &place.into()))?; this.allow_data_races_mut(|this| this.write_scalar(new, place))?;
this.validate_atomic_rmw(place, success)?; this.validate_atomic_rmw(place, success)?;
this.buffered_atomic_rmw(new, place, success, old.to_scalar())?; this.buffered_atomic_rmw(new, place, success, old.to_scalar())?;
} else { } else {

View file

@ -834,7 +834,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
if let Some(thread_info_place) = thread { if let Some(thread_info_place) = thread {
this.write_scalar( this.write_scalar(
Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size), Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size),
&thread_info_place.into(), &thread_info_place,
)?; )?;
} }

View file

@ -246,7 +246,7 @@ impl MainThreadState {
this.machine.main_fn_ret_place.unwrap().ptr, this.machine.main_fn_ret_place.unwrap().ptr,
this.machine.layouts.isize, this.machine.layouts.isize,
); );
let exit_code = this.read_target_isize(&ret_place.into())?; let exit_code = this.read_target_isize(&ret_place)?;
// Need to call this ourselves since we are not going to return to the scheduler // Need to call this ourselves since we are not going to return to the scheduler
// loop, and we want the main thread TLS to not show up as memory leaks. // loop, and we want the main thread TLS to not show up as memory leaks.
this.terminate_active_thread()?; this.terminate_active_thread()?;
@ -321,7 +321,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?;
for (idx, arg) in argvs.into_iter().enumerate() { for (idx, arg) in argvs.into_iter().enumerate() {
let place = ecx.project_field(&argvs_place, idx)?; let place = ecx.project_field(&argvs_place, idx)?;
ecx.write_immediate(arg, &place.into())?; ecx.write_immediate(arg, &place)?;
} }
ecx.mark_immutable(&argvs_place); ecx.mark_immutable(&argvs_place);
// A pointer to that place is the 3rd argument for main. // A pointer to that place is the 3rd argument for main.
@ -330,7 +330,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
{ {
let argc_place = let argc_place =
ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?;
ecx.write_scalar(argc, &argc_place.into())?; ecx.write_scalar(argc, &argc_place)?;
ecx.mark_immutable(&argc_place); ecx.mark_immutable(&argc_place);
ecx.machine.argc = Some(*argc_place); ecx.machine.argc = Some(*argc_place);
@ -338,7 +338,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
ecx.layout_of(Ty::new_imm_ptr(tcx, tcx.types.unit))?, ecx.layout_of(Ty::new_imm_ptr(tcx, tcx.types.unit))?,
MiriMemoryKind::Machine.into(), MiriMemoryKind::Machine.into(),
)?; )?;
ecx.write_immediate(argv, &argv_place.into())?; ecx.write_immediate(argv, &argv_place)?;
ecx.mark_immutable(&argv_place); ecx.mark_immutable(&argv_place);
ecx.machine.argv = Some(*argv_place); ecx.machine.argv = Some(*argv_place);
} }
@ -355,7 +355,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
// Store the UTF-16 string. We just allocated so we know the bounds are fine. // Store the UTF-16 string. We just allocated so we know the bounds are fine.
for (idx, &c) in cmd_utf16.iter().enumerate() { for (idx, &c) in cmd_utf16.iter().enumerate() {
let place = ecx.project_field(&cmd_place, idx)?; let place = ecx.project_field(&cmd_place, idx)?;
ecx.write_scalar(Scalar::from_u16(c), &place.into())?; ecx.write_scalar(Scalar::from_u16(c), &place)?;
} }
ecx.mark_immutable(&cmd_place); ecx.mark_immutable(&cmd_place);
} }

View file

@ -166,7 +166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let const_val = this.eval_global(cid, None).unwrap_or_else(|err| { let const_val = this.eval_global(cid, None).unwrap_or_else(|err| {
panic!("failed to evaluate required Rust item: {path:?}\n{err:?}") panic!("failed to evaluate required Rust item: {path:?}\n{err:?}")
}); });
this.read_scalar(&const_val.into()) this.read_scalar(&const_val)
.unwrap_or_else(|err| panic!("failed to read required Rust item: {path:?}\n{err:?}")) .unwrap_or_else(|err| panic!("failed to read required Rust item: {path:?}\n{err:?}"))
} }
@ -231,7 +231,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} }
/// Project to the given *named* field (which must be a struct or union type). /// Project to the given *named* field (which must be a struct or union type).
fn project_field_named<P: Projectable<'mir, 'tcx, Provenance>>( fn project_field_named<P: Projectable<'tcx, Provenance>>(
&self, &self,
base: &P, base: &P,
name: &str, name: &str,
@ -252,13 +252,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn write_int( fn write_int(
&mut self, &mut self,
i: impl Into<i128>, i: impl Into<i128>,
dest: &PlaceTy<'tcx, Provenance>, dest: &impl Writeable<'tcx, Provenance>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
assert!(dest.layout.abi.is_scalar(), "write_int on non-scalar type {}", dest.layout.ty); assert!(dest.layout().abi.is_scalar(), "write_int on non-scalar type {}", dest.layout().ty);
let val = if dest.layout.abi.is_signed() { let val = if dest.layout().abi.is_signed() {
Scalar::from_int(i, dest.layout.size) Scalar::from_int(i, dest.layout().size)
} else { } else {
Scalar::from_uint(u64::try_from(i.into()).unwrap(), dest.layout.size) Scalar::from_uint(u64::try_from(i.into()).unwrap(), dest.layout().size)
}; };
self.eval_context_mut().write_scalar(val, dest) self.eval_context_mut().write_scalar(val, dest)
} }
@ -267,12 +267,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn write_int_fields( fn write_int_fields(
&mut self, &mut self,
values: &[i128], values: &[i128],
dest: &MPlaceTy<'tcx, Provenance>, dest: &impl Writeable<'tcx, Provenance>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
for (idx, &val) in values.iter().enumerate() { for (idx, &val) in values.iter().enumerate() {
let field = this.project_field(dest, idx)?; let field = this.project_field(dest, idx)?;
this.write_int(val, &field.into())?; this.write_int(val, &field)?;
} }
Ok(()) Ok(())
} }
@ -281,18 +281,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn write_int_fields_named( fn write_int_fields_named(
&mut self, &mut self,
values: &[(&str, i128)], values: &[(&str, i128)],
dest: &MPlaceTy<'tcx, Provenance>, dest: &impl Writeable<'tcx, Provenance>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
for &(name, val) in values.iter() { for &(name, val) in values.iter() {
let field = this.project_field_named(dest, name)?; let field = this.project_field_named(dest, name)?;
this.write_int(val, &field.into())?; this.write_int(val, &field)?;
} }
Ok(()) Ok(())
} }
/// Write a 0 of the appropriate size to `dest`. /// Write a 0 of the appropriate size to `dest`.
fn write_null(&mut self, dest: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { fn write_null(&mut self, dest: &impl Writeable<'tcx, Provenance>) -> InterpResult<'tcx> {
self.write_int(0, dest) self.write_int(0, dest)
} }
@ -600,14 +600,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// necessary. /// necessary.
fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
if let Some(errno_place) = this.active_thread_ref().last_error { if let Some(errno_place) = this.active_thread_ref().last_error.as_ref() {
Ok(errno_place) Ok(errno_place.clone())
} else { } else {
// Allocate new place, set initial value to 0. // Allocate new place, set initial value to 0.
let errno_layout = this.machine.layouts.u32; let errno_layout = this.machine.layouts.u32;
let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into())?; let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into())?;
this.write_scalar(Scalar::from_u32(0), &errno_place.into())?; this.write_scalar(Scalar::from_u32(0), &errno_place)?;
this.active_thread_mut().last_error = Some(errno_place); this.active_thread_mut().last_error = Some(errno_place.clone());
Ok(errno_place) Ok(errno_place)
} }
} }
@ -616,14 +616,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn set_last_error(&mut self, scalar: Scalar<Provenance>) -> InterpResult<'tcx> { fn set_last_error(&mut self, scalar: Scalar<Provenance>) -> InterpResult<'tcx> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
let errno_place = this.last_error_place()?; let errno_place = this.last_error_place()?;
this.write_scalar(scalar, &errno_place.into()) this.write_scalar(scalar, &errno_place)
} }
/// Gets the last error variable. /// Gets the last error variable.
fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar<Provenance>> { fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
let errno_place = this.last_error_place()?; let errno_place = this.last_error_place()?;
this.read_scalar(&errno_place.into()) this.read_scalar(&errno_place)
} }
/// This function tries to produce the most similar OS error from the `std::io::ErrorKind` /// This function tries to produce the most similar OS error from the `std::io::ErrorKind`
@ -725,7 +725,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let mplace = MPlaceTy::from_aligned_ptr(ptr, layout); let mplace = MPlaceTy::from_aligned_ptr(ptr, layout);
this.check_mplace(mplace)?; this.check_mplace(&mplace)?;
Ok(mplace) Ok(mplace)
} }
@ -772,7 +772,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
) -> InterpResult<'tcx, Scalar<Provenance>> { ) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_ref(); let this = self.eval_context_ref();
let value_place = this.deref_operand_and_offset(op, offset, base_layout, value_layout)?; let value_place = this.deref_operand_and_offset(op, offset, base_layout, value_layout)?;
this.read_scalar(&value_place.into()) this.read_scalar(&value_place)
} }
fn write_scalar_at_offset( fn write_scalar_at_offset(
@ -785,7 +785,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
) -> InterpResult<'tcx, ()> { ) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
let value_place = this.deref_operand_and_offset(op, offset, base_layout, value_layout)?; let value_place = this.deref_operand_and_offset(op, offset, base_layout, value_layout)?;
this.write_scalar(value, &value_place.into()) this.write_scalar(value, &value_place)
} }
/// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None` /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None`
@ -797,10 +797,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
) -> InterpResult<'tcx, Option<Duration>> { ) -> InterpResult<'tcx, Option<Duration>> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
let seconds_place = this.project_field(tp, 0)?; let seconds_place = this.project_field(tp, 0)?;
let seconds_scalar = this.read_scalar(&seconds_place.into())?; let seconds_scalar = this.read_scalar(&seconds_place)?;
let seconds = seconds_scalar.to_target_isize(this)?; let seconds = seconds_scalar.to_target_isize(this)?;
let nanoseconds_place = this.project_field(tp, 1)?; let nanoseconds_place = this.project_field(tp, 1)?;
let nanoseconds_scalar = this.read_scalar(&nanoseconds_place.into())?; let nanoseconds_scalar = this.read_scalar(&nanoseconds_place)?;
let nanoseconds = nanoseconds_scalar.to_target_isize(this)?; let nanoseconds = nanoseconds_scalar.to_target_isize(this)?;
Ok(try { Ok(try {

View file

@ -651,7 +651,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
val: ImmTy<'tcx, Provenance>, val: ImmTy<'tcx, Provenance>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?; let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?;
this.write_immediate(*val, &place.into())?; this.write_immediate(*val, &place)?;
Self::add_extern_static(this, name, place.ptr); Self::add_extern_static(this, name, place.ptr);
Ok(()) Ok(())
} }
@ -668,7 +668,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
Self::add_extern_static( Self::add_extern_static(
this, this,
"environ", "environ",
this.machine.env_vars.environ.unwrap().ptr, this.machine.env_vars.environ.as_ref().unwrap().ptr,
); );
// A couple zero-initialized pointer-sized extern statics. // A couple zero-initialized pointer-sized extern statics.
// Most of them are for weak symbols, which we all set to null (indicating that the // Most of them are for weak symbols, which we all set to null (indicating that the
@ -685,7 +685,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
Self::add_extern_static( Self::add_extern_static(
this, this,
"environ", "environ",
this.machine.env_vars.environ.unwrap().ptr, this.machine.env_vars.environ.as_ref().unwrap().ptr,
); );
} }
"android" => { "android" => {

View file

@ -85,7 +85,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
for (i, ptr) in ptrs.into_iter().enumerate() { for (i, ptr) in ptrs.into_iter().enumerate() {
let place = this.project_index(&alloc, i as u64)?; let place = this.project_index(&alloc, i as u64)?;
this.write_pointer(ptr, &place.into())?; this.write_pointer(ptr, &place)?;
} }
this.write_immediate( this.write_immediate(
@ -106,7 +106,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let op_place = buf_place.offset(offset, ptr_layout, this)?; let op_place = buf_place.offset(offset, ptr_layout, this)?;
this.write_pointer(ptr, &op_place.into())?; this.write_pointer(ptr, &op_place)?;
} }
} }
_ => throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags), _ => throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags),
@ -196,33 +196,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_immediate( this.write_immediate(
name_alloc.to_ref(this), name_alloc.to_ref(this),
&this.project_field(&dest, 0)?.into(), &this.project_field(&dest, 0)?,
)?; )?;
this.write_immediate( this.write_immediate(
filename_alloc.to_ref(this), filename_alloc.to_ref(this),
&this.project_field(&dest, 1)?.into(), &this.project_field(&dest, 1)?,
)?; )?;
} }
1 => { 1 => {
this.write_scalar( this.write_scalar(
Scalar::from_target_usize(name.len().try_into().unwrap(), this), Scalar::from_target_usize(name.len().try_into().unwrap(), this),
&this.project_field(&dest, 0)?.into(), &this.project_field(&dest, 0)?,
)?; )?;
this.write_scalar( this.write_scalar(
Scalar::from_target_usize(filename.len().try_into().unwrap(), this), Scalar::from_target_usize(filename.len().try_into().unwrap(), this),
&this.project_field(&dest, 1)?.into(), &this.project_field(&dest, 1)?,
)?; )?;
} }
_ => throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags), _ => throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags),
} }
this.write_scalar(Scalar::from_u32(lineno), &this.project_field(&dest, 2)?.into())?; this.write_scalar(Scalar::from_u32(lineno), &this.project_field(&dest, 2)?)?;
this.write_scalar(Scalar::from_u32(colno), &this.project_field(&dest, 3)?.into())?; this.write_scalar(Scalar::from_u32(colno), &this.project_field(&dest, 3)?)?;
// Support a 4-field struct for now - this is deprecated // Support a 4-field struct for now - this is deprecated
// and slated for removal. // and slated for removal.
if num_fields == 5 { if num_fields == 5 {
this.write_pointer(fn_ptr, &this.project_field(&dest, 4)?.into())?; this.write_pointer(fn_ptr, &this.project_field(&dest, 4)?)?;
} }
Ok(()) Ok(())

View file

@ -87,8 +87,8 @@ impl<'tcx> EnvVars<'tcx> {
ecx.deallocate_ptr(ptr, None, MiriMemoryKind::Runtime.into())?; ecx.deallocate_ptr(ptr, None, MiriMemoryKind::Runtime.into())?;
} }
// Deallocate environ var list. // Deallocate environ var list.
let environ = ecx.machine.env_vars.environ.unwrap(); let environ = ecx.machine.env_vars.environ.as_ref().unwrap();
let old_vars_ptr = ecx.read_pointer(&environ.into())?; let old_vars_ptr = ecx.read_pointer(environ)?;
ecx.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; ecx.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?;
Ok(()) Ok(())
} }
@ -431,8 +431,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn update_environ(&mut self) -> InterpResult<'tcx> { fn update_environ(&mut self) -> InterpResult<'tcx> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
// Deallocate the old environ list, if any. // Deallocate the old environ list, if any.
if let Some(environ) = this.machine.env_vars.environ { if let Some(environ) = this.machine.env_vars.environ.as_ref() {
let old_vars_ptr = this.read_pointer(&environ.into())?; let old_vars_ptr = this.read_pointer(environ)?;
this.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; this.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?;
} else { } else {
// No `environ` allocated yet, let's do that. // No `environ` allocated yet, let's do that.
@ -457,9 +457,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?; let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?;
for (idx, var) in vars.into_iter().enumerate() { for (idx, var) in vars.into_iter().enumerate() {
let place = this.project_field(&vars_place, idx)?; let place = this.project_field(&vars_place, idx)?;
this.write_pointer(var, &place.into())?; this.write_pointer(var, &place)?;
} }
this.write_pointer(vars_place.ptr, &this.machine.env_vars.environ.unwrap().into())?; this.write_pointer(vars_place.ptr, &this.machine.env_vars.environ.clone().unwrap())?;
Ok(()) Ok(())
} }

View file

@ -97,12 +97,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"volatile_load" => { "volatile_load" => {
let [place] = check_arg_count(args)?; let [place] = check_arg_count(args)?;
let place = this.deref_operand(place)?; let place = this.deref_operand(place)?;
this.copy_op(&place.into(), dest, /*allow_transmute*/ false)?; this.copy_op(&place, dest, /*allow_transmute*/ false)?;
} }
"volatile_store" => { "volatile_store" => {
let [place, dest] = check_arg_count(args)?; let [place, dest] = check_arg_count(args)?;
let place = this.deref_operand(place)?; let place = this.deref_operand(place)?;
this.copy_op(dest, &place.into(), /*allow_transmute*/ false)?; this.copy_op(dest, &place, /*allow_transmute*/ false)?;
} }
"write_bytes" | "volatile_set_memory" => { "write_bytes" | "volatile_set_memory" => {

View file

@ -57,7 +57,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}; };
for i in 0..dest_len { for i in 0..dest_len {
let op = this.read_immediate(&this.project_index(&op, i)?.into())?; let op = this.read_immediate(&this.project_index(&op, i)?)?;
let dest = this.project_index(&dest, i)?; let dest = this.project_index(&dest, i)?;
let val = match which { let val = match which {
Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar(), Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar(),
@ -104,7 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} }
}; };
this.write_scalar(val, &dest.into())?; this.write_scalar(val, &dest)?;
} }
} }
#[rustfmt::skip] #[rustfmt::skip]
@ -172,8 +172,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}; };
for i in 0..dest_len { for i in 0..dest_len {
let left = this.read_immediate(&this.project_index(&left, i)?.into())?; let left = this.read_immediate(&this.project_index(&left, i)?)?;
let right = this.read_immediate(&this.project_index(&right, i)?.into())?; let right = this.read_immediate(&this.project_index(&right, i)?)?;
let dest = this.project_index(&dest, i)?; let dest = this.project_index(&dest, i)?;
let val = match which { let val = match which {
Op::MirOp(mir_op) => { Op::MirOp(mir_op) => {
@ -217,7 +217,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fmin_op(&left, &right)? fmin_op(&left, &right)?
} }
}; };
this.write_scalar(val, &dest.into())?; this.write_scalar(val, &dest)?;
} }
} }
"fma" => { "fma" => {
@ -232,9 +232,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
assert_eq!(dest_len, c_len); assert_eq!(dest_len, c_len);
for i in 0..dest_len { for i in 0..dest_len {
let a = this.read_scalar(&this.project_index(&a, i)?.into())?; let a = this.read_scalar(&this.project_index(&a, i)?)?;
let b = this.read_scalar(&this.project_index(&b, i)?.into())?; let b = this.read_scalar(&this.project_index(&b, i)?)?;
let c = this.read_scalar(&this.project_index(&c, i)?.into())?; let c = this.read_scalar(&this.project_index(&c, i)?)?;
let dest = this.project_index(&dest, i)?; let dest = this.project_index(&dest, i)?;
// Works for f32 and f64. // Works for f32 and f64.
@ -258,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
Scalar::from_u64(res.to_bits()) Scalar::from_u64(res.to_bits())
} }
}; };
this.write_scalar(val, &dest.into())?; this.write_scalar(val, &dest)?;
} }
} }
#[rustfmt::skip] #[rustfmt::skip]
@ -295,13 +295,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}; };
// Initialize with first lane, then proceed with the rest. // Initialize with first lane, then proceed with the rest.
let mut res = this.read_immediate(&this.project_index(&op, 0)?.into())?; let mut res = this.read_immediate(&this.project_index(&op, 0)?)?;
if matches!(which, Op::MirOpBool(_)) { if matches!(which, Op::MirOpBool(_)) {
// Convert to `bool` scalar. // Convert to `bool` scalar.
res = imm_from_bool(simd_element_to_bool(res)?); res = imm_from_bool(simd_element_to_bool(res)?);
} }
for i in 1..op_len { for i in 1..op_len {
let op = this.read_immediate(&this.project_index(&op, i)?.into())?; let op = this.read_immediate(&this.project_index(&op, i)?)?;
res = match which { res = match which {
Op::MirOp(mir_op) => { Op::MirOp(mir_op) => {
this.binary_op(mir_op, &res, &op)? this.binary_op(mir_op, &res, &op)?
@ -355,7 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let mut res = init; let mut res = init;
for i in 0..op_len { for i in 0..op_len {
let op = this.read_immediate(&this.project_index(&op, i)?.into())?; let op = this.read_immediate(&this.project_index(&op, i)?)?;
res = this.binary_op(mir_op, &res, &op)?; res = this.binary_op(mir_op, &res, &op)?;
} }
this.write_immediate(*res, dest)?; this.write_immediate(*res, dest)?;
@ -372,13 +372,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
assert_eq!(dest_len, no_len); assert_eq!(dest_len, no_len);
for i in 0..dest_len { for i in 0..dest_len {
let mask = this.read_immediate(&this.project_index(&mask, i)?.into())?; let mask = this.read_immediate(&this.project_index(&mask, i)?)?;
let yes = this.read_immediate(&this.project_index(&yes, i)?.into())?; let yes = this.read_immediate(&this.project_index(&yes, i)?)?;
let no = this.read_immediate(&this.project_index(&no, i)?.into())?; let no = this.read_immediate(&this.project_index(&no, i)?)?;
let dest = this.project_index(&dest, i)?; let dest = this.project_index(&dest, i)?;
let val = if simd_element_to_bool(mask)? { yes } else { no }; let val = if simd_element_to_bool(mask)? { yes } else { no };
this.write_immediate(*val, &dest.into())?; this.write_immediate(*val, &dest)?;
} }
} }
"select_bitmask" => { "select_bitmask" => {
@ -403,12 +403,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
& 1u64 & 1u64
.checked_shl(simd_bitmask_index(i, dest_len, this.data_layout().endian)) .checked_shl(simd_bitmask_index(i, dest_len, this.data_layout().endian))
.unwrap(); .unwrap();
let yes = this.read_immediate(&this.project_index(&yes, i.into())?.into())?; let yes = this.read_immediate(&this.project_index(&yes, i.into())?)?;
let no = this.read_immediate(&this.project_index(&no, i.into())?.into())?; let no = this.read_immediate(&this.project_index(&no, i.into())?)?;
let dest = this.project_index(&dest, i.into())?; let dest = this.project_index(&dest, i.into())?;
let val = if mask != 0 { yes } else { no }; let val = if mask != 0 { yes } else { no };
this.write_immediate(*val, &dest.into())?; this.write_immediate(*val, &dest)?;
} }
for i in dest_len..bitmask_len { for i in dest_len..bitmask_len {
// If the mask is "padded", ensure that padding is all-zero. // If the mask is "padded", ensure that padding is all-zero.
@ -435,7 +435,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let from_exposed_cast = intrinsic_name == "from_exposed_addr"; let from_exposed_cast = intrinsic_name == "from_exposed_addr";
for i in 0..dest_len { for i in 0..dest_len {
let op = this.read_immediate(&this.project_index(&op, i)?.into())?; let op = this.read_immediate(&this.project_index(&op, i)?)?;
let dest = this.project_index(&dest, i)?; let dest = this.project_index(&dest, i)?;
let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) { let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) {
@ -472,7 +472,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
to_ty = dest.layout.ty, to_ty = dest.layout.ty,
), ),
}; };
this.write_immediate(val, &dest.into())?; this.write_immediate(val, &dest)?;
} }
} }
"shuffle" => { "shuffle" => {
@ -503,17 +503,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let dest = this.project_index(&dest, i)?; let dest = this.project_index(&dest, i)?;
let val = if src_index < left_len { let val = if src_index < left_len {
this.read_immediate(&this.project_index(&left, src_index)?.into())? this.read_immediate(&this.project_index(&left, src_index)?)?
} else if src_index < left_len.checked_add(right_len).unwrap() { } else if src_index < left_len.checked_add(right_len).unwrap() {
let right_idx = src_index.checked_sub(left_len).unwrap(); let right_idx = src_index.checked_sub(left_len).unwrap();
this.read_immediate(&this.project_index(&right, right_idx)?.into())? this.read_immediate(&this.project_index(&right, right_idx)?)?
} else { } else {
span_bug!( span_bug!(
this.cur_span(), this.cur_span(),
"simd_shuffle index {src_index} is out of bounds for 2 vectors of size {left_len}", "simd_shuffle index {src_index} is out of bounds for 2 vectors of size {left_len}",
); );
}; };
this.write_immediate(*val, &dest.into())?; this.write_immediate(*val, &dest)?;
} }
} }
"gather" => { "gather" => {
@ -528,18 +528,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
assert_eq!(dest_len, mask_len); assert_eq!(dest_len, mask_len);
for i in 0..dest_len { for i in 0..dest_len {
let passthru = this.read_immediate(&this.project_index(&passthru, i)?.into())?; let passthru = this.read_immediate(&this.project_index(&passthru, i)?)?;
let ptr = this.read_immediate(&this.project_index(&ptrs, i)?.into())?; let ptr = this.read_immediate(&this.project_index(&ptrs, i)?)?;
let mask = this.read_immediate(&this.project_index(&mask, i)?.into())?; let mask = this.read_immediate(&this.project_index(&mask, i)?)?;
let dest = this.project_index(&dest, i)?; let dest = this.project_index(&dest, i)?;
let val = if simd_element_to_bool(mask)? { let val = if simd_element_to_bool(mask)? {
let place = this.deref_operand(&ptr.into())?; let place = this.deref_operand(&ptr)?;
this.read_immediate(&place.into())? this.read_immediate(&place)?
} else { } else {
passthru passthru
}; };
this.write_immediate(*val, &dest.into())?; this.write_immediate(*val, &dest)?;
} }
} }
"scatter" => { "scatter" => {
@ -552,13 +552,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
assert_eq!(ptrs_len, mask_len); assert_eq!(ptrs_len, mask_len);
for i in 0..ptrs_len { for i in 0..ptrs_len {
let value = this.read_immediate(&this.project_index(&value, i)?.into())?; let value = this.read_immediate(&this.project_index(&value, i)?)?;
let ptr = this.read_immediate(&this.project_index(&ptrs, i)?.into())?; let ptr = this.read_immediate(&this.project_index(&ptrs, i)?)?;
let mask = this.read_immediate(&this.project_index(&mask, i)?.into())?; let mask = this.read_immediate(&this.project_index(&mask, i)?)?;
if simd_element_to_bool(mask)? { if simd_element_to_bool(mask)? {
let place = this.deref_operand(&ptr.into())?; let place = this.deref_operand(&ptr)?;
this.write_immediate(*value, &place.into())?; this.write_immediate(*value, &place)?;
} }
} }
} }
@ -578,7 +578,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let mut res = 0u64; let mut res = 0u64;
for i in 0..op_len { for i in 0..op_len {
let op = this.read_immediate(&this.project_index(&op, i.into())?.into())?; let op = this.read_immediate(&this.project_index(&op, i.into())?)?;
if simd_element_to_bool(op)? { if simd_element_to_bool(op)? {
res |= 1u64 res |= 1u64
.checked_shl(simd_bitmask_index(i, op_len, this.data_layout().endian)) .checked_shl(simd_bitmask_index(i, op_len, this.data_layout().endian))
@ -588,7 +588,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// We have to force the place type to be an int so that we can write `res` into it. // We have to force the place type to be an int so that we can write `res` into it.
let mut dest = this.force_allocation(dest)?; let mut dest = this.force_allocation(dest)?;
dest.layout = this.machine.layouts.uint(dest.layout.size).unwrap(); dest.layout = this.machine.layouts.uint(dest.layout.size).unwrap();
this.write_int(res, &dest.into())?; this.write_int(res, &dest)?;
} }
name => throw_unsup_format!("unimplemented intrinsic: `simd_{name}`"), name => throw_unsup_format!("unimplemented intrinsic: `simd_{name}`"),

View file

@ -158,7 +158,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
})?; })?;
this.write_scalar( this.write_scalar(
Scalar::from_i64(qpc), Scalar::from_i64(qpc),
&this.deref_operand(lpPerformanceCount_op)?.into(), &this.deref_operand(lpPerformanceCount_op)?,
)?; )?;
Ok(Scalar::from_i32(-1)) // return non-zero on success Ok(Scalar::from_i32(-1)) // return non-zero on success
} }
@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// and thus 10^9 counts per second. // and thus 10^9 counts per second.
this.write_scalar( this.write_scalar(
Scalar::from_i64(1_000_000_000), Scalar::from_i64(1_000_000_000),
&this.deref_operand_as(lpFrequency_op, this.machine.layouts.u64)?.into(), &this.deref_operand_as(lpFrequency_op, this.machine.layouts.u64)?,
)?; )?;
Ok(Scalar::from_i32(-1)) // Return non-zero on success Ok(Scalar::from_i32(-1)) // Return non-zero on success
} }

View file

@ -201,14 +201,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_int(einval, dest)?; this.write_int(einval, dest)?;
} else { } else {
if size == 0 { if size == 0 {
this.write_null(&ret.into())?; this.write_null(&ret)?;
} else { } else {
let ptr = this.allocate_ptr( let ptr = this.allocate_ptr(
Size::from_bytes(size), Size::from_bytes(size),
Align::from_bytes(align).unwrap(), Align::from_bytes(align).unwrap(),
MiriMemoryKind::C.into(), MiriMemoryKind::C.into(),
)?; )?;
this.write_pointer(ptr, &ret.into())?; this.write_pointer(ptr, &ret)?;
} }
this.write_null(dest)?; this.write_null(dest)?;
} }
@ -293,7 +293,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Create key and write it into the memory where `key_ptr` wants it. // Create key and write it into the memory where `key_ptr` wants it.
let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?; let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?;
this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place.into())?; this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place)?;
// Return success (`0`). // Return success (`0`).
this.write_null(dest)?; this.write_null(dest)?;
@ -508,7 +508,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let [_attr, guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let [_attr, guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let guard_size = this.deref_operand(guard_size)?; let guard_size = this.deref_operand(guard_size)?;
let guard_size_layout = this.libc_ty_layout("size_t"); let guard_size_layout = this.libc_ty_layout("size_t");
this.write_scalar(Scalar::from_uint(this.machine.page_size, guard_size_layout.size), &guard_size.into())?; this.write_scalar(Scalar::from_uint(this.machine.page_size, guard_size_layout.size), &guard_size)?;
// Return success (`0`). // Return success (`0`).
this.write_null(dest)?; this.write_null(dest)?;
@ -538,11 +538,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_scalar( this.write_scalar(
Scalar::from_uint(this.machine.stack_addr, this.pointer_size()), Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
&addr_place.into(), &addr_place,
)?; )?;
this.write_scalar( this.write_scalar(
Scalar::from_uint(this.machine.stack_size, this.pointer_size()), Scalar::from_uint(this.machine.stack_size, this.pointer_size()),
&size_place.into(), &size_place,
)?; )?;
// Return success (`0`). // Return success (`0`).
@ -587,20 +587,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Reset all fields to `uninit` to make sure nobody reads them. // Reset all fields to `uninit` to make sure nobody reads them.
// (This is a std-only shim so we are okay with such hacks.) // (This is a std-only shim so we are okay with such hacks.)
this.write_uninit(&pwd.into())?; this.write_uninit(&pwd)?;
// We only set the home_dir field. // We only set the home_dir field.
#[allow(deprecated)] #[allow(deprecated)]
let home_dir = std::env::home_dir().unwrap(); let home_dir = std::env::home_dir().unwrap();
let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?; let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
let pw_dir = this.project_field_named(&pwd, "pw_dir")?; let pw_dir = this.project_field_named(&pwd, "pw_dir")?;
this.write_pointer(buf, &pw_dir.into())?; this.write_pointer(buf, &pw_dir)?;
if written { if written {
this.write_pointer(pwd.ptr, &result.into())?; this.write_pointer(pwd.ptr, &result)?;
this.write_null(dest)?; this.write_null(dest)?;
} else { } else {
this.write_null(&result.into())?; this.write_null(&result)?;
this.write_scalar(this.eval_libc("ERANGE"), dest)?; this.write_scalar(this.eval_libc("ERANGE"), dest)?;
} }
} }

View file

@ -1457,13 +1457,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
)?; )?;
let result_place = this.deref_operand(result_op)?; let result_place = this.deref_operand(result_op)?;
this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?; this.write_scalar(this.read_scalar(entry_op)?, &result_place)?;
0 0
} }
None => { None => {
// end of stream: return 0, assign *result=NULL // end of stream: return 0, assign *result=NULL
this.write_null(&this.deref_operand(result_op)?.into())?; this.write_null(&this.deref_operand(result_op)?)?;
0 0
} }
Some(Err(e)) => Some(Err(e)) =>

View file

@ -74,9 +74,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let event = this.deref_operand_as(event, this.libc_ty_layout("epoll_event"))?; let event = this.deref_operand_as(event, this.libc_ty_layout("epoll_event"))?;
let events = this.project_field(&event, 0)?; let events = this.project_field(&event, 0)?;
let events = this.read_scalar(&events.into())?.to_u32()?; let events = this.read_scalar(&events)?.to_u32()?;
let data = this.project_field(&event, 1)?; let data = this.project_field(&event, 1)?;
let data = this.read_scalar(&data.into())?; let data = this.read_scalar(&data)?;
let event = EpollEvent { events, data }; let event = EpollEvent { events, data };
if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) {
@ -248,8 +248,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let sv1 = fh.insert_fd(Box::new(SocketPair)); let sv1 = fh.insert_fd(Box::new(SocketPair));
let sv1 = ScalarInt::try_from_int(sv1, sv.layout.size).unwrap(); let sv1 = ScalarInt::try_from_int(sv1, sv.layout.size).unwrap();
this.write_scalar(sv0, &sv.into())?; this.write_scalar(sv0, &sv)?;
this.write_scalar(sv1, &sv.offset(sv.layout.size, sv.layout, this)?.into())?; this.write_scalar(sv1, &sv.offset(sv.layout.size, sv.layout, this)?)?;
Ok(Scalar::from_i32(0)) Ok(Scalar::from_i32(0))
} }

View file

@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"_NSGetEnviron" => { "_NSGetEnviron" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
this.write_pointer( this.write_pointer(
this.machine.env_vars.environ.expect("machine must be initialized").ptr, this.machine.env_vars.environ.as_ref().expect("machine must be initialized").ptr,
dest, dest,
)?; )?;
} }
@ -133,7 +133,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let (written, size_needed) = this.write_path_to_c_str( let (written, size_needed) = this.write_path_to_c_str(
&path, &path,
buf_ptr, buf_ptr,
this.read_scalar(&bufsize.into())?.to_u32()?.into(), this.read_scalar(&bufsize)?.to_u32()?.into(),
)?; )?;
if written { if written {
@ -141,7 +141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} else { } else {
this.write_scalar( this.write_scalar(
Scalar::from_u32(size_needed.try_into().unwrap()), Scalar::from_u32(size_needed.try_into().unwrap()),
&bufsize.into(), &bufsize,
)?; )?;
this.write_int(-1, dest)?; this.write_int(-1, dest)?;
} }

View file

@ -346,7 +346,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// This can always be revisited to have some external state to catch double-destroys // This can always be revisited to have some external state to catch double-destroys
// but not complain about the above code. See https://github.com/rust-lang/miri/pull/1933 // but not complain about the above code. See https://github.com/rust-lang/miri/pull/1933
this.write_uninit( this.write_uninit(
&this.deref_operand_as(attr_op, this.libc_ty_layout("pthread_mutexattr_t"))?.into(), &this.deref_operand_as(attr_op, this.libc_ty_layout("pthread_mutexattr_t"))?,
)?; )?;
Ok(0) Ok(0)
@ -500,7 +500,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// This might lead to false positives, see comment in pthread_mutexattr_destroy // This might lead to false positives, see comment in pthread_mutexattr_destroy
this.write_uninit( this.write_uninit(
&this.deref_operand_as(mutex_op, this.libc_ty_layout("pthread_mutex_t"))?.into(), &this.deref_operand_as(mutex_op, this.libc_ty_layout("pthread_mutex_t"))?,
)?; )?;
// FIXME: delete interpreter state associated with this mutex. // FIXME: delete interpreter state associated with this mutex.
@ -625,7 +625,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// This might lead to false positives, see comment in pthread_mutexattr_destroy // This might lead to false positives, see comment in pthread_mutexattr_destroy
this.write_uninit( this.write_uninit(
&this.deref_operand_as(rwlock_op, this.libc_ty_layout("pthread_rwlock_t"))?.into(), &this.deref_operand_as(rwlock_op, this.libc_ty_layout("pthread_rwlock_t"))?,
)?; )?;
// FIXME: delete interpreter state associated with this rwlock. // FIXME: delete interpreter state associated with this rwlock.
@ -675,7 +675,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
let clock_id = condattr_get_clock_id(this, attr_op)?; let clock_id = condattr_get_clock_id(this, attr_op)?;
this.write_scalar(Scalar::from_i32(clock_id), &this.deref_operand(clk_id_op)?.into())?; this.write_scalar(Scalar::from_i32(clock_id), &this.deref_operand(clk_id_op)?)?;
Ok(Scalar::from_i32(0)) Ok(Scalar::from_i32(0))
} }
@ -691,7 +691,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// This might lead to false positives, see comment in pthread_mutexattr_destroy // This might lead to false positives, see comment in pthread_mutexattr_destroy
this.write_uninit( this.write_uninit(
&this.deref_operand_as(attr_op, this.libc_ty_layout("pthread_condattr_t"))?.into(), &this.deref_operand_as(attr_op, this.libc_ty_layout("pthread_condattr_t"))?,
)?; )?;
Ok(0) Ok(0)
@ -868,7 +868,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// This might lead to false positives, see comment in pthread_mutexattr_destroy // This might lead to false positives, see comment in pthread_mutexattr_destroy
this.write_uninit( this.write_uninit(
&this.deref_operand_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?.into(), &this.deref_operand_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?,
)?; )?;
// FIXME: delete interpreter state associated with this condvar. // FIXME: delete interpreter state associated with this condvar.

View file

@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.project_field_named(&io_status_block, "Information")?; this.project_field_named(&io_status_block, "Information")?;
this.write_scalar( this.write_scalar(
Scalar::from_target_usize(n.into(), this), Scalar::from_target_usize(n.into(), this),
&io_status_information.into(), &io_status_information,
)?; )?;
} }
// Return whether this was a success. >= 0 is success. // Return whether this was a success. >= 0 is success.

View file

@ -323,7 +323,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let layout = this.machine.layouts.uint(size).unwrap(); let layout = this.machine.layouts.uint(size).unwrap();
let futex_val = this let futex_val = this
.read_scalar_atomic(&MPlaceTy::from_aligned_ptr(ptr, layout), AtomicReadOrd::Relaxed)?; .read_scalar_atomic(&MPlaceTy::from_aligned_ptr(ptr, layout), AtomicReadOrd::Relaxed)?;
let compare_val = this.read_scalar(&MPlaceTy::from_aligned_ptr(compare, layout).into())?; let compare_val = this.read_scalar(&MPlaceTy::from_aligned_ptr(compare, layout))?;
if futex_val == compare_val { if futex_val == compare_val {
// If the values are the same, we have to block. // If the values are the same, we have to block.