]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/interpret/visitor.rs
Various minor/cosmetic improvements to code
[rust.git] / src / librustc_mir / interpret / visitor.rs
index f0a71242599bff68a6001753760487450b4e6ed4..4773f5627d716db0238f6b3d9ac616b20d8eb140 100644 (file)
@@ -158,7 +158,9 @@ fn visit_aggregate(
             ) -> 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 @@ fn visit_field(
                 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,
@@ -257,7 +272,7 @@ fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx>
                 // 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 => {
@@ -291,17 +306,33 @@ fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx>
                         // 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.
@@ -317,10 +348,9 @@ fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx>
                             .map(|f| f.and_then(|f| {
                                 Ok(Value::from_mem_place(f))
                             }));
-                        self.visit_aggregate(v, iter)?;
+                        self.visit_aggregate(v, iter)
                     }
                 }
-                Ok(())
             }
         }
     }