also allow visiting places and mplaces

This commit is contained in:
Ralf Jung 2018-10-31 19:52:10 +01:00
parent 7d7bd9b6c2
commit c8e471fac3

View File

@ -10,7 +10,7 @@ use rustc::mir::interpret::{
}; };
use super::{ use super::{
Machine, EvalContext, MPlaceTy, OpTy, Machine, EvalContext, MPlaceTy, PlaceTy, OpTy,
}; };
// A thing that we can project into, and that has a layout. // A thing that we can project into, and that has a layout.
@ -21,13 +21,16 @@ pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy
// Get this value's layout. // Get this value's layout.
fn layout(&self) -> TyLayout<'tcx>; fn layout(&self) -> TyLayout<'tcx>;
// Get the underlying `MPlaceTy`, or panic if there is no such thing. // Make this a `MPlaceTy`, or panic if that's not possible.
fn to_mem_place(self) -> MPlaceTy<'tcx, M::PointerTag>; fn force_allocation(
self,
ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>>;
// Create this from an `MPlaceTy` // Create this from an `MPlaceTy`.
fn from_mem_place(MPlaceTy<'tcx, M::PointerTag>) -> Self; fn from_mem_place(MPlaceTy<'tcx, M::PointerTag>) -> Self;
// Project to the n-th field // Project to the n-th field.
fn project_field( fn project_field(
self, self,
ectx: &mut EvalContext<'a, 'mir, 'tcx, M>, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
@ -45,8 +48,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
} }
#[inline(always)] #[inline(always)]
fn to_mem_place(self) -> MPlaceTy<'tcx, M::PointerTag> { fn force_allocation(
self.to_mem_place() self,
_ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
Ok(self.to_mem_place())
} }
#[inline(always)] #[inline(always)]
@ -63,6 +69,66 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
ectx.operand_field(self, field) ectx.operand_field(self, field)
} }
} }
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
for MPlaceTy<'tcx, M::PointerTag>
{
#[inline(always)]
fn layout(&self) -> TyLayout<'tcx> {
self.layout
}
#[inline(always)]
fn force_allocation(
self,
_ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
Ok(self)
}
#[inline(always)]
fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
mplace
}
#[inline(always)]
fn project_field(
self,
ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
field: u64,
) -> EvalResult<'tcx, Self> {
ectx.mplace_field(self, field)
}
}
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
for PlaceTy<'tcx, M::PointerTag>
{
#[inline(always)]
fn layout(&self) -> TyLayout<'tcx> {
self.layout
}
#[inline(always)]
fn force_allocation(
self,
ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
ectx.force_allocation(self)
}
#[inline(always)]
fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
mplace.into()
}
#[inline(always)]
fn project_field(
self,
ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
field: u64,
) -> EvalResult<'tcx, Self> {
ectx.place_field(self, field)
}
}
// 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<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: fmt::Debug { pub trait ValueVisitor<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: fmt::Debug {
@ -135,7 +201,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
// If it is a trait object, switch to the actual type that was used to create it. // If it is a trait object, switch to the actual type that was used to create it.
match v.layout().ty.sty { match v.layout().ty.sty {
ty::Dynamic(..) => { ty::Dynamic(..) => {
let dest = v.value().to_mem_place(); // immediate trait objects are not a thing // immediate trait objects are not a thing
let dest = v.value().force_allocation(self)?;
let inner = self.unpack_dyn_trait(dest)?.1; let inner = self.unpack_dyn_trait(dest)?.1;
// recurse with the inner type // recurse with the inner type
return v.with_field(Value::from_mem_place(inner), 0, |v| self.visit_value(v)); return v.with_field(Value::from_mem_place(inner), 0, |v| self.visit_value(v));
@ -201,7 +268,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
MPlaceTy::dangling(v.layout(), self) MPlaceTy::dangling(v.layout(), self)
} else { } else {
// non-ZST array/slice/str cannot be immediate // non-ZST array/slice/str cannot be immediate
v.value().to_mem_place() v.value().force_allocation(self)?
}; };
// Now iterate over it. // Now iterate over it.
for (i, field) in self.mplace_array_fields(mplace)?.enumerate() { for (i, field) in self.mplace_array_fields(mplace)?.enumerate() {