]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/visitor.rs
Rollup merge of #67005 - andrewbanchich:master, r=joshtriplett
[rust.git] / src / librustc_mir / interpret / visitor.rs
1 //! Visitor for a run-time value with a given layout: Traverse enums, structs and other compound
2 //! types until we arrive at the leaves, with custom handling for primitive types.
3
4 use rustc::ty::layout::{self, TyLayout, VariantIdx};
5 use rustc::ty;
6 use rustc::mir::interpret::{
7     InterpResult,
8 };
9
10 use super::{
11     Machine, InterpCx, MPlaceTy, OpTy,
12 };
13
14 // A thing that we can project into, and that has a layout.
15 // This wouldn't have to depend on `Machine` but with the current type inference,
16 // that's just more convenient to work with (avoids repeating all the `Machine` bounds).
17 pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy {
18     /// Gets this value's layout.
19     fn layout(&self) -> TyLayout<'tcx>;
20
21     /// Makes this into an `OpTy`.
22     fn to_op(
23         self,
24         ecx: &InterpCx<'mir, 'tcx, M>,
25     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>;
26
27     /// Creates this from an `MPlaceTy`.
28     fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self;
29
30     /// Projects to the given enum variant.
31     fn project_downcast(
32         self,
33         ecx: &InterpCx<'mir, 'tcx, M>,
34         variant: VariantIdx,
35     ) -> InterpResult<'tcx, Self>;
36
37     /// Projects to the n-th field.
38     fn project_field(
39         self,
40         ecx: &InterpCx<'mir, 'tcx, M>,
41         field: u64,
42     ) -> InterpResult<'tcx, Self>;
43 }
44
45 // Operands and memory-places are both values.
46 // Places in general are not due to `place_field` having to do `force_allocation`.
47 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tcx, M::PointerTag> {
48     #[inline(always)]
49     fn layout(&self) -> TyLayout<'tcx> {
50         self.layout
51     }
52
53     #[inline(always)]
54     fn to_op(
55         self,
56         _ecx: &InterpCx<'mir, 'tcx, M>,
57     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
58         Ok(self)
59     }
60
61     #[inline(always)]
62     fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
63         mplace.into()
64     }
65
66     #[inline(always)]
67     fn project_downcast(
68         self,
69         ecx: &InterpCx<'mir, 'tcx, M>,
70         variant: VariantIdx,
71     ) -> InterpResult<'tcx, Self> {
72         ecx.operand_downcast(self, variant)
73     }
74
75     #[inline(always)]
76     fn project_field(
77         self,
78         ecx: &InterpCx<'mir, 'tcx, M>,
79         field: u64,
80     ) -> InterpResult<'tcx, Self> {
81         ecx.operand_field(self, field)
82     }
83 }
84
85 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for MPlaceTy<'tcx, M::PointerTag> {
86     #[inline(always)]
87     fn layout(&self) -> TyLayout<'tcx> {
88         self.layout
89     }
90
91     #[inline(always)]
92     fn to_op(
93         self,
94         _ecx: &InterpCx<'mir, 'tcx, M>,
95     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
96         Ok(self.into())
97     }
98
99     #[inline(always)]
100     fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
101         mplace
102     }
103
104     #[inline(always)]
105     fn project_downcast(
106         self,
107         ecx: &InterpCx<'mir, 'tcx, M>,
108         variant: VariantIdx,
109     ) -> InterpResult<'tcx, Self> {
110         ecx.mplace_downcast(self, variant)
111     }
112
113     #[inline(always)]
114     fn project_field(
115         self,
116         ecx: &InterpCx<'mir, 'tcx, M>,
117         field: u64,
118     ) -> InterpResult<'tcx, Self> {
119         ecx.mplace_field(self, field)
120     }
121 }
122
123 macro_rules! make_value_visitor {
124     ($visitor_trait_name:ident, $($mutability:ident)?) => {
125         // How to traverse a value and what to do when we are at the leaves.
126         pub trait $visitor_trait_name<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
127             type V: Value<'mir, 'tcx, M>;
128
129             /// The visitor must have an `InterpCx` in it.
130             fn ecx(&$($mutability)? self)
131                 -> &$($mutability)? InterpCx<'mir, 'tcx, M>;
132
133             // Recursive actions, ready to be overloaded.
134             /// Visits the given value, dispatching as appropriate to more specialized visitors.
135             #[inline(always)]
136             fn visit_value(&mut self, v: Self::V) -> InterpResult<'tcx>
137             {
138                 self.walk_value(v)
139             }
140             /// Visits the given value as a union. No automatic recursion can happen here.
141             #[inline(always)]
142             fn visit_union(&mut self, _v: Self::V) -> InterpResult<'tcx>
143             {
144                 Ok(())
145             }
146             /// Visits this value as an aggregate, you are getting an iterator yielding
147             /// all the fields (still in an `InterpResult`, you have to do error handling yourself).
148             /// Recurses into the fields.
149             #[inline(always)]
150             fn visit_aggregate(
151                 &mut self,
152                 v: Self::V,
153                 fields: impl Iterator<Item=InterpResult<'tcx, Self::V>>,
154             ) -> InterpResult<'tcx> {
155                 self.walk_aggregate(v, fields)
156             }
157
158             /// Called each time we recurse down to a field of a "product-like" aggregate
159             /// (structs, tuples, arrays and the like, but not enums), passing in old (outer)
160             /// and new (inner) value.
161             /// This gives the visitor the chance to track the stack of nested fields that
162             /// we are descending through.
163             #[inline(always)]
164             fn visit_field(
165                 &mut self,
166                 _old_val: Self::V,
167                 _field: usize,
168                 new_val: Self::V,
169             ) -> InterpResult<'tcx> {
170                 self.visit_value(new_val)
171             }
172
173             /// Called when recursing into an enum variant.
174             #[inline(always)]
175             fn visit_variant(
176                 &mut self,
177                 _old_val: Self::V,
178                 _variant: VariantIdx,
179                 new_val: Self::V,
180             ) -> InterpResult<'tcx> {
181                 self.visit_value(new_val)
182             }
183
184             /// Called whenever we reach a value with uninhabited layout.
185             /// Recursing to fields will *always* continue after this!  This is not meant to control
186             /// whether and how we descend recursively/ into the scalar's fields if there are any,
187             /// it is meant to provide the chance for additional checks when a value of uninhabited
188             /// layout is detected.
189             #[inline(always)]
190             fn visit_uninhabited(&mut self) -> InterpResult<'tcx>
191             { Ok(()) }
192             /// Called whenever we reach a value with scalar layout.
193             /// We do NOT provide a `ScalarMaybeUndef` here to avoid accessing memory if the
194             /// visitor is not even interested in scalars.
195             /// Recursing to fields will *always* continue after this!  This is not meant to control
196             /// whether and how we descend recursively/ into the scalar's fields if there are any,
197             /// it is meant to provide the chance for additional checks when a value of scalar
198             /// layout is detected.
199             #[inline(always)]
200             fn visit_scalar(&mut self, _v: Self::V, _layout: &layout::Scalar) -> InterpResult<'tcx>
201             { Ok(()) }
202
203             /// Called whenever we reach a value of primitive type. There can be no recursion
204             /// below such a value. This is the leaf function.
205             /// We do *not* provide an `ImmTy` here because some implementations might want
206             /// to write to the place this primitive lives in.
207             #[inline(always)]
208             fn visit_primitive(&mut self, _v: Self::V) -> InterpResult<'tcx>
209             { Ok(()) }
210
211             // Default recursors. Not meant to be overloaded.
212             fn walk_aggregate(
213                 &mut self,
214                 v: Self::V,
215                 fields: impl Iterator<Item=InterpResult<'tcx, Self::V>>,
216             ) -> InterpResult<'tcx> {
217                 // Now iterate over it.
218                 for (idx, field_val) in fields.enumerate() {
219                     self.visit_field(v, idx, field_val?)?;
220                 }
221                 Ok(())
222             }
223             fn walk_value(&mut self, v: Self::V) -> InterpResult<'tcx>
224             {
225                 trace!("walk_value: type: {}", v.layout().ty);
226                 // If this is a multi-variant layout, we have to find the right one and proceed with
227                 // that.
228                 match v.layout().variants {
229                     layout::Variants::Multiple { .. } => {
230                         let op = v.to_op(self.ecx())?;
231                         let idx = self.ecx().read_discriminant(op)?.1;
232                         let inner = v.project_downcast(self.ecx(), idx)?;
233                         trace!("walk_value: variant layout: {:#?}", inner.layout());
234                         // recurse with the inner type
235                         return self.visit_variant(v, idx, inner);
236                     }
237                     layout::Variants::Single { .. } => {}
238                 }
239
240                 // Even for single variants, we might be able to get a more refined type:
241                 // If it is a trait object, switch to the actual type that was used to create it.
242                 match v.layout().ty.kind {
243                     ty::Dynamic(..) => {
244                         // immediate trait objects are not a thing
245                         let dest = v.to_op(self.ecx())?.assert_mem_place();
246                         let inner = self.ecx().unpack_dyn_trait(dest)?.1;
247                         trace!("walk_value: dyn object layout: {:#?}", inner.layout);
248                         // recurse with the inner type
249                         return self.visit_field(v, 0, Value::from_mem_place(inner));
250                     },
251                     ty::Generator(..) => {
252                         // FIXME: Generator layout is lying: it claims a whole bunch of fields exist
253                         // when really many of them can be uninitialized.
254                         // Just treat them as a union for now, until hopefully the layout
255                         // computation is fixed.
256                         return self.visit_union(v);
257                     }
258                     _ => {},
259                 };
260
261                 // If this is a scalar, visit it as such.
262                 // Things can be aggregates and have scalar layout at the same time, and that
263                 // is very relevant for `NonNull` and similar structs: We need to visit them
264                 // at their scalar layout *before* descending into their fields.
265                 // FIXME: We could avoid some redundant checks here. For newtypes wrapping
266                 // scalars, we do the same check on every "level" (e.g., first we check
267                 // MyNewtype and then the scalar in there).
268                 match v.layout().abi {
269                     layout::Abi::Uninhabited => {
270                         self.visit_uninhabited()?;
271                     }
272                     layout::Abi::Scalar(ref layout) => {
273                         self.visit_scalar(v, layout)?;
274                     }
275                     // FIXME: Should we do something for ScalarPair? Vector?
276                     _ => {}
277                 }
278
279                 // Check primitive types.  We do this after checking the scalar layout,
280                 // just to have that done as well.  Primitives can have varying layout,
281                 // so we check them separately and before aggregate handling.
282                 // It is CRITICAL that we get this check right, or we might be
283                 // validating the wrong thing!
284                 let primitive = match v.layout().fields {
285                     // Primitives appear as Union with 0 fields - except for Boxes and fat pointers.
286                     layout::FieldPlacement::Union(0) => true,
287                     _ => v.layout().ty.builtin_deref(true).is_some(),
288                 };
289                 if primitive {
290                     return self.visit_primitive(v);
291                 }
292
293                 // Proceed into the fields.
294                 match v.layout().fields {
295                     layout::FieldPlacement::Union(fields) => {
296                         // Empty unions are not accepted by rustc. That's great, it means we can
297                         // use that as an unambiguous signal for detecting primitives.  Make sure
298                         // we did not miss any primitive.
299                         assert!(fields > 0);
300                         self.visit_union(v)
301                     },
302                     layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
303                         // FIXME: We collect in a vec because otherwise there are lifetime
304                         // errors: Projecting to a field needs access to `ecx`.
305                         let fields: Vec<InterpResult<'tcx, Self::V>> =
306                             (0..offsets.len()).map(|i| {
307                                 v.project_field(self.ecx(), i as u64)
308                             })
309                             .collect();
310                         self.visit_aggregate(v, fields.into_iter())
311                     },
312                     layout::FieldPlacement::Array { .. } => {
313                         // Let's get an mplace first.
314                         let mplace = if v.layout().is_zst() {
315                             // it's a ZST, the memory content cannot matter
316                             MPlaceTy::dangling(v.layout(), self.ecx())
317                         } else {
318                             // non-ZST array/slice/str cannot be immediate
319                             v.to_op(self.ecx())?.assert_mem_place()
320                         };
321                         // Now we can go over all the fields.
322                         let iter = self.ecx().mplace_array_fields(mplace)?
323                             .map(|f| f.and_then(|f| {
324                                 Ok(Value::from_mem_place(f))
325                             }));
326                         self.visit_aggregate(v, iter)
327                     }
328                 }
329             }
330         }
331     }
332 }
333
334 make_value_visitor!(ValueVisitor,);
335 make_value_visitor!(MutValueVisitor,mut);