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 super::{
Machine, EvalContext, MPlaceTy, OpTy,
Machine, EvalContext, MPlaceTy, PlaceTy, OpTy,
};
// 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.
fn layout(&self) -> TyLayout<'tcx>;
// Get the underlying `MPlaceTy`, or panic if there is no such thing.
fn to_mem_place(self) -> MPlaceTy<'tcx, M::PointerTag>;
// Make this a `MPlaceTy`, or panic if that's not possible.
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;
// Project to the n-th field
// Project to the n-th field.
fn project_field(
self,
ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
@ -45,8 +48,11 @@ fn layout(&self) -> TyLayout<'tcx> {
}
#[inline(always)]
fn to_mem_place(self) -> MPlaceTy<'tcx, M::PointerTag> {
self.to_mem_place()
fn force_allocation(
self,
_ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
Ok(self.to_mem_place())
}
#[inline(always)]
@ -63,6 +69,66 @@ fn project_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.
pub trait ValueVisitor<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: fmt::Debug {
@ -135,7 +201,8 @@ pub fn visit_value<V: ValueVisitor<'a, 'mir, 'tcx, M>>(
// If it is a trait object, switch to the actual type that was used to create it.
match v.layout().ty.sty {
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;
// recurse with the inner type
return v.with_field(Value::from_mem_place(inner), 0, |v| self.visit_value(v));
@ -201,7 +268,7 @@ pub fn visit_value<V: ValueVisitor<'a, 'mir, 'tcx, M>>(
MPlaceTy::dangling(v.layout(), self)
} else {
// non-ZST array/slice/str cannot be immediate
v.value().to_mem_place()
v.value().force_allocation(self)?
};
// Now iterate over it.
for (i, field) in self.mplace_array_fields(mplace)?.enumerate() {