1
Fork 0

Auto merge of #60541 - RalfJung:miri-visitor-generators, r=oli-obk

fix Miri visiting generators

Fixes fall-out caused by https://github.com/rust-lang/rust/pull/59897.

r? @oli-obk
This commit is contained in:
bors 2019-05-05 15:28:08 +00:00
commit c6b1698764
2 changed files with 29 additions and 42 deletions

View file

@ -66,6 +66,7 @@ macro_rules! try_validation {
pub enum PathElem { pub enum PathElem {
Field(Symbol), Field(Symbol),
Variant(Symbol), Variant(Symbol),
GeneratoreState(VariantIdx),
ClosureVar(Symbol), ClosureVar(Symbol),
ArrayElem(usize), ArrayElem(usize),
TupleElem(usize), TupleElem(usize),
@ -100,6 +101,7 @@ fn path_format(path: &Vec<PathElem>) -> String {
match elem { match elem {
Field(name) => write!(out, ".{}", name), Field(name) => write!(out, ".{}", name),
Variant(name) => write!(out, ".<downcast-variant({})>", name), Variant(name) => write!(out, ".<downcast-variant({})>", name),
GeneratoreState(idx) => write!(out, ".<generator-state({})>", idx.index()),
ClosureVar(name) => write!(out, ".<closure-var({})>", name), ClosureVar(name) => write!(out, ".<closure-var({})>", name),
TupleElem(idx) => write!(out, ".{}", idx), TupleElem(idx) => write!(out, ".{}", idx),
ArrayElem(idx) => write!(out, "[{}]", idx), ArrayElem(idx) => write!(out, "[{}]", idx),
@ -262,8 +264,13 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
variant_id: VariantIdx, variant_id: VariantIdx,
new_op: OpTy<'tcx, M::PointerTag> new_op: OpTy<'tcx, M::PointerTag>
) -> EvalResult<'tcx> { ) -> EvalResult<'tcx> {
let name = old_op.layout.ty.ty_adt_def().unwrap().variants[variant_id].ident.name; let name = match old_op.layout.ty.sty {
self.visit_elem(new_op, PathElem::Variant(name)) ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name),
// Generators also have variants
ty::Generator(..) => PathElem::GeneratoreState(variant_id),
_ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty),
};
self.visit_elem(new_op, name)
} }
#[inline] #[inline]

View file

@ -147,7 +147,7 @@ macro_rules! make_value_visitor {
{ {
Ok(()) Ok(())
} }
/// Visits this vale as an aggregate, you are even getting an iterator yielding /// Visits this value as an aggregate, you are getting an iterator yielding
/// all the fields (still in an `EvalResult`, you have to do error handling yourself). /// all the fields (still in an `EvalResult`, you have to do error handling yourself).
/// Recurses into the fields. /// Recurses into the fields.
#[inline(always)] #[inline(always)]
@ -160,7 +160,8 @@ macro_rules! make_value_visitor {
} }
/// Called each time we recurse down to a field of a "product-like" aggregate /// Called each time we recurse down to a field of a "product-like" aggregate
/// (structs, tuples, arrays and the like, but not enums), passing in old and new value. /// (structs, tuples, arrays and the like, but not enums), passing in old (outer)
/// and new (inner) value.
/// This gives the visitor the chance to track the stack of nested fields that /// This gives the visitor the chance to track the stack of nested fields that
/// we are descending through. /// we are descending through.
#[inline(always)] #[inline(always)]
@ -173,18 +174,6 @@ macro_rules! make_value_visitor {
self.visit_value(new_val) self.visit_value(new_val)
} }
/// Called for recursing into the field of a generator. These are not known to be
/// initialized, so we treat them like unions.
#[inline(always)]
fn visit_generator_field(
&mut self,
_old_val: Self::V,
_field: usize,
new_val: Self::V,
) -> EvalResult<'tcx> {
self.visit_union(new_val)
}
/// Called when recursing into an enum variant. /// Called when recursing into an enum variant.
#[inline(always)] #[inline(always)]
fn visit_variant( fn visit_variant(
@ -238,7 +227,7 @@ macro_rules! make_value_visitor {
fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx> fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx>
{ {
trace!("walk_value: type: {}", v.layout().ty); trace!("walk_value: type: {}", v.layout().ty);
// If this is a multi-variant layout, we have find the right one and proceed with // If this is a multi-variant layout, we have to find the right one and proceed with
// that. // that.
match v.layout().variants { match v.layout().variants {
layout::Variants::Multiple { .. } => { layout::Variants::Multiple { .. } => {
@ -263,6 +252,13 @@ macro_rules! make_value_visitor {
// recurse with the inner type // recurse with the inner type
return self.visit_field(v, 0, Value::from_mem_place(inner)); return self.visit_field(v, 0, Value::from_mem_place(inner));
}, },
ty::Generator(..) => {
// FIXME: Generator layout is lying: it claims a whole bunch of fields exist
// when really many of them can be uninitialized.
// Just treat them as a union for now, until hopefully the layout
// computation is fixed.
return self.visit_union(v);
}
_ => {}, _ => {},
}; };
@ -304,34 +300,18 @@ macro_rules! make_value_visitor {
// Empty unions are not accepted by rustc. That's great, it means we can // Empty unions are not accepted by rustc. That's great, it means we can
// use that as an unambiguous signal for detecting primitives. Make sure // use that as an unambiguous signal for detecting primitives. Make sure
// we did not miss any primitive. // we did not miss any primitive.
debug_assert!(fields > 0); assert!(fields > 0);
self.visit_union(v) self.visit_union(v)
}, },
layout::FieldPlacement::Arbitrary { ref offsets, .. } => { layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
// Special handling needed for generators: All but the first field // FIXME: We collect in a vec because otherwise there are lifetime
// (which is the state) are actually implicitly `MaybeUninit`, i.e., // errors: Projecting to a field needs access to `ecx`.
// they may or may not be initialized, so we cannot visit them. let fields: Vec<EvalResult<'tcx, Self::V>> =
match v.layout().ty.sty { (0..offsets.len()).map(|i| {
ty::Generator(..) => { v.project_field(self.ecx(), i as u64)
let field = v.project_field(self.ecx(), 0)?; })
self.visit_aggregate(v, std::iter::once(Ok(field)))?; .collect();
for i in 1..offsets.len() { self.visit_aggregate(v, fields.into_iter())
let field = v.project_field(self.ecx(), i as u64)?;
self.visit_generator_field(v, i, field)?;
}
Ok(())
}
_ => {
// FIXME: We collect in a vec because otherwise there are lifetime
// errors: Projecting to a field needs access to `ecx`.
let fields: Vec<EvalResult<'tcx, Self::V>> =
(0..offsets.len()).map(|i| {
v.project_field(self.ecx(), i as u64)
})
.collect();
self.visit_aggregate(v, fields.into_iter())
}
}
}, },
layout::FieldPlacement::Array { .. } => { layout::FieldPlacement::Array { .. } => {
// Let's get an mplace first. // Let's get an mplace first.