diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index f0a71242599bf..81e56f3115d26 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -158,7 +158,9 @@ macro_rules! make_value_visitor { ) -> 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)] @@ -171,6 +173,19 @@ macro_rules! make_value_visitor { 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, @@ -291,17 +306,33 @@ macro_rules! make_value_visitor { // 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> = - (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> = + (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. @@ -317,10 +348,9 @@ macro_rules! make_value_visitor { .map(|f| f.and_then(|f| { Ok(Value::from_mem_place(f)) })); - self.visit_aggregate(v, iter)?; + self.visit_aggregate(v, iter) } } - Ok(()) } } }