make ValueVisitor mut-polymorphic

This commit is contained in:
Ralf Jung 2018-11-02 14:06:43 +01:00
parent 7565b5ac67
commit 873041009d
3 changed files with 192 additions and 221 deletions

View File

@ -535,7 +535,7 @@ fn validate_const<'a, 'tcx>(
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
let cid = key.value;
let mut ecx = mk_eval_cx(tcx, cid.instance, key.param_env).unwrap();
let ecx = mk_eval_cx(tcx, cid.instance, key.param_env).unwrap();
let val = (|| {
let op = ecx.const_to_op(constant)?;
let mut ref_tracking = RefTracking::new(op);

View File

@ -129,7 +129,7 @@ struct ValidityVisitor<'rt, 'a: 'rt, 'mir: 'rt, 'tcx: 'a+'rt+'mir, M: Machine<'a
path: Vec<PathElem>,
ref_tracking: Option<&'rt mut RefTracking<'tcx, M::PointerTag>>,
const_mode: bool,
ecx: &'rt mut EvalContext<'a, 'mir, 'tcx, M>,
ecx: &'rt EvalContext<'a, 'mir, 'tcx, M>,
}
impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ValidityVisitor<'rt, 'a, 'mir, 'tcx, M> {
@ -188,8 +188,8 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
type V = OpTy<'tcx, M::PointerTag>;
#[inline(always)]
fn ecx(&mut self) -> &mut EvalContext<'a, 'mir, 'tcx, M> {
&mut self.ecx
fn ecx(&self) -> &EvalContext<'a, 'mir, 'tcx, M> {
&self.ecx
}
#[inline]
@ -557,7 +557,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
/// This also toggles between "run-time" (no recursion) and "compile-time" (with recursion)
/// validation (e.g., pointer values are fine in integers at runtime).
pub fn validate_operand(
&mut self,
&self,
op: OpTy<'tcx, M::PointerTag>,
path: Vec<PathElem>,
ref_tracking: Option<&mut RefTracking<'tcx, M::PointerTag>>,

View File

@ -8,7 +8,7 @@ use rustc::mir::interpret::{
};
use super::{
Machine, EvalContext, MPlaceTy, PlaceTy, OpTy, ImmTy,
Machine, EvalContext, MPlaceTy, OpTy, ImmTy,
};
// A thing that we can project into, and that has a layout.
@ -38,12 +38,13 @@ pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy
/// Project to the n-th field.
fn project_field(
self,
ecx: &mut EvalContext<'a, 'mir, 'tcx, M>,
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
field: u64,
) -> EvalResult<'tcx, Self>;
}
// Operands and places are both values
// Operands and memory-places are both values.
// Places in general are not due to `place_field` having to do `force_allocation`.
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
for OpTy<'tcx, M::PointerTag>
{
@ -77,7 +78,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
#[inline(always)]
fn project_field(
self,
ecx: &mut EvalContext<'a, 'mir, 'tcx, M>,
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
field: u64,
) -> EvalResult<'tcx, Self> {
ecx.operand_field(self, field)
@ -116,58 +117,22 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
#[inline(always)]
fn project_field(
self,
ecx: &mut EvalContext<'a, 'mir, 'tcx, M>,
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
field: u64,
) -> EvalResult<'tcx, Self> {
ecx.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 to_op(
self,
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
ecx.place_to_op(self)
}
#[inline(always)]
fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
mplace.into()
}
#[inline(always)]
fn project_downcast(
self,
ecx: &EvalContext<'a, 'mir, 'tcx, M>,
variant: usize,
) -> EvalResult<'tcx, Self> {
ecx.place_downcast(self, variant)
}
#[inline(always)]
fn project_field(
self,
ecx: &mut EvalContext<'a, 'mir, 'tcx, M>,
field: u64,
) -> EvalResult<'tcx, Self> {
ecx.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: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Sized {
macro_rules! make_value_visitor {
($visitor_trait_name:ident, $($mutability:ident)*) => {
// How to traverse a value and what to do when we are at the leaves.
pub trait $visitor_trait_name<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Sized {
type V: Value<'a, 'mir, 'tcx, M>;
/// The visitor must have an `EvalContext` in it.
fn ecx(&mut self) -> &mut EvalContext<'a, 'mir, 'tcx, M>;
fn ecx(&$($mutability)* self)
-> &$($mutability)* EvalContext<'a, 'mir, 'tcx, M>;
// Recursive actions, ready to be overloaded.
/// Visit the given value, dispatching as appropriate to more specialized visitors.
@ -208,18 +173,19 @@ pub trait ValueVisitor<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Siz
/// Called whenever we reach a value with uninhabited layout.
/// Recursing to fields will *always* continue after this! This is not meant to control
/// whether and how we descend recursively/ into the scalar's fields if there are any, it is
/// meant to provide the chance for additional checks when a value of uninhabited layout is
/// detected.
/// whether and how we descend recursively/ into the scalar's fields if there are any,
/// it is meant to provide the chance for additional checks when a value of uninhabited
/// layout is detected.
#[inline(always)]
fn visit_uninhabited(&mut self) -> EvalResult<'tcx>
{ Ok(()) }
/// Called whenever we reach a value with scalar layout.
/// We do NOT provide a `ScalarMaybeUndef` here to avoid accessing memory if the visitor is not
/// even interested in scalars.
/// We do NOT provide a `ScalarMaybeUndef` here to avoid accessing memory if the
/// visitor is not even interested in scalars.
/// Recursing to fields will *always* continue after this! This is not meant to control
/// whether and how we descend recursively/ into the scalar's fields if there are any, it is
/// meant to provide the chance for additional checks when a value of scalar layout is detected.
/// whether and how we descend recursively/ into the scalar's fields if there are any,
/// it is meant to provide the chance for additional checks when a value of scalar
/// layout is detected.
#[inline(always)]
fn visit_scalar(&mut self, _v: Self::V, _layout: &layout::Scalar) -> EvalResult<'tcx>
{ Ok(()) }
@ -244,8 +210,8 @@ pub trait ValueVisitor<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Siz
}
fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx>
{
// If this is a multi-variant layout, we have find the right one and proceed with that.
// (No benefit from making this recursion, but it is equivalent to that.)
// If this is a multi-variant layout, we have find the right one and proceed with
// that.
match v.layout().variants {
layout::Variants::NicheFilling { .. } |
layout::Variants::Tagged { .. } => {
@ -297,7 +263,7 @@ pub trait ValueVisitor<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Siz
// It is CRITICAL that we get this check right, or we might be
// validating the wrong thing!
let primitive = match v.layout().fields {
// Primitives appear as Union with 0 fields -- except for Boxes and fat pointers.
// Primitives appear as Union with 0 fields - except for Boxes and fat pointers.
layout::FieldPlacement::Union(0) => true,
_ => v.layout().ty.builtin_deref(true).is_some(),
};
@ -345,4 +311,9 @@ pub trait ValueVisitor<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Siz
}
Ok(())
}
}
}
}
make_value_visitor!(ValueVisitor,);
make_value_visitor!(MutValueVisitor,mut);