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