about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-05-05 15:28:08 +0000
committerbors <bors@rust-lang.org>2019-05-05 15:28:08 +0000
commitc6b16987645dd8980f40efe7c72d4f3fd4b399d3 (patch)
treea05f1662a3af8c8912d9ec1609341a4cc6c84557
parent5d8fd98d347239bc7e29c19988d7c19cf860cced (diff)
parentc5c161e39497887abf78ef7da0d53c3dcf22a059 (diff)
downloadrust-c6b16987645dd8980f40efe7c72d4f3fd4b399d3.tar.gz
rust-c6b16987645dd8980f40efe7c72d4f3fd4b399d3.zip
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
-rw-r--r--src/librustc_mir/interpret/validity.rs11
-rw-r--r--src/librustc_mir/interpret/visitor.rs60
2 files changed, 29 insertions, 42 deletions
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index bd6f005e873..772cbcf9447 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -66,6 +66,7 @@ macro_rules! try_validation {
 pub enum PathElem {
     Field(Symbol),
     Variant(Symbol),
+    GeneratoreState(VariantIdx),
     ClosureVar(Symbol),
     ArrayElem(usize),
     TupleElem(usize),
@@ -100,6 +101,7 @@ fn path_format(path: &Vec<PathElem>) -> String {
         match elem {
             Field(name) => write!(out, ".{}", name),
             Variant(name) => write!(out, ".<downcast-variant({})>", name),
+            GeneratoreState(idx) => write!(out, ".<generator-state({})>", idx.index()),
             ClosureVar(name) => write!(out, ".<closure-var({})>", name),
             TupleElem(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,
         new_op: OpTy<'tcx, M::PointerTag>
     ) -> EvalResult<'tcx> {
-        let name = old_op.layout.ty.ty_adt_def().unwrap().variants[variant_id].ident.name;
-        self.visit_elem(new_op, PathElem::Variant(name))
+        let name = match old_op.layout.ty.sty {
+            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]
diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs
index 05343ac66d9..cf67b0a97bc 100644
--- a/src/librustc_mir/interpret/visitor.rs
+++ b/src/librustc_mir/interpret/visitor.rs
@@ -147,7 +147,7 @@ macro_rules! make_value_visitor {
             {
                 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).
             /// Recurses into the fields.
             #[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
-            /// (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
             /// we are descending through.
             #[inline(always)]
@@ -173,18 +174,6 @@ 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(
@@ -238,7 +227,7 @@ macro_rules! make_value_visitor {
             fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx>
             {
                 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.
                 match v.layout().variants {
                     layout::Variants::Multiple { .. } => {
@@ -263,6 +252,13 @@ macro_rules! make_value_visitor {
                         // recurse with the inner type
                         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
                         // use that as an unambiguous signal for detecting primitives.  Make sure
                         // we did not miss any primitive.
-                        debug_assert!(fields > 0);
+                        assert!(fields > 0);
                         self.visit_union(v)
                     },
                     layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
-                        // 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())
-                            }
-                        }
+                        // 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.