) -> EvalResult<'tcx> {
self.walk_aggregate(v, fields)
}
- /// Called each time we recurse down to a field, passing in old and new value.
+
+ /// 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.
/// This gives the visitor the chance to track the stack of nested fields that
/// we are descending through.
#[inline(always)]
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.
#[inline(always)]
fn visit_variant(
&mut self,
// is very relevant for `NonNull` and similar structs: We need to visit them
// at their scalar layout *before* descending into their fields.
// FIXME: We could avoid some redundant checks here. For newtypes wrapping
- // scalars, we do the same check on every "level" (e.g. first we check
+ // scalars, we do the same check on every "level" (e.g., first we check
// MyNewtype and then the scalar in there).
match v.layout().abi {
layout::Abi::Uninhabited => {
// use that as an unambiguous signal for detecting primitives. Make sure
// we did not miss any primitive.
debug_assert!(fields > 0);
- self.visit_union(v)?;
+ self.visit_union(v)
},
layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
- // FIXME: We collect in a vec because otherwise there are lifetime errors:
- // Projecting to a field needs (mutable!) 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())?;
+ // Special handling needed for generators: All but the first field
+ // (which is the state) are actually implicitly `MaybeUninit`, i.e.,
+ // they may or may not be initialized, so we cannot visit them.
+ match v.layout().ty.sty {
+ ty::Generator(..) => {
+ let field = v.project_field(self.ecx(), 0)?;
+ self.visit_aggregate(v, std::iter::once(Ok(field)))?;
+ for i in 1..offsets.len() {
+ 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 { .. } => {
// Let's get an mplace first.
.map(|f| f.and_then(|f| {
Ok(Value::from_mem_place(f))
}));
- self.visit_aggregate(v, iter)?;
+ self.visit_aggregate(v, iter)
}
}
- Ok(())
}
}
}