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:
commit
c6b1698764
2 changed files with 29 additions and 42 deletions
|
@ -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]
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue