]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/visitor.rs
generator fields are not necessarily initialized
[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, EvalContext, 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     /// Get this value's layout.
20     fn layout(&self) -> TyLayout<'tcx>;
21
22     /// Make this into an `OpTy`.
23     fn to_op(
24         self,
25         ecx: &EvalContext<'a, 'mir, 'tcx, M>,
26     ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>>;
27
28     /// Create this from an `MPlaceTy`.
29     fn from_mem_place(MPlaceTy<'tcx, M::PointerTag>) -> Self;
30
31     /// Project to the given enum variant.
32     fn project_downcast(
33         self,
34         ecx: &EvalContext<'a, 'mir, 'tcx, M>,
35         variant: VariantIdx,
36     ) -> EvalResult<'tcx, Self>;
37
38     /// Project to the n-th field.
39     fn project_field(
40         self,
41         ecx: &EvalContext<'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: &EvalContext<'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: &EvalContext<'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: &EvalContext<'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: &EvalContext<'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: &EvalContext<'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: &EvalContext<'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 `EvalContext` in it.
134             fn ecx(&$($mutability)* self)
135                 -> &$($mutability)* EvalContext<'a, 'mir, 'tcx, M>;
136
137             // Recursive actions, ready to be overloaded.
138             /// Visit 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             /// Visit the given value as a union.  No automatic recursion can happen here.
145             /// Also called for the fields of a generator, which may or may not be initialized.
146             #[inline(always)]
147             fn visit_union(&mut self, _v: Self::V) -> EvalResult<'tcx>
148             {
149                 Ok(())
150             }
151             /// Visit this vale as an aggregate, you are even getting an iterator yielding
152             /// all the fields (still in an `EvalResult`, you have to do error handling yourself).
153             /// Recurses into the fields.
154             #[inline(always)]
155             fn visit_aggregate(
156                 &mut self,
157                 v: Self::V,
158                 fields: impl Iterator<Item=EvalResult<'tcx, Self::V>>,
159             ) -> EvalResult<'tcx> {
160                 self.walk_aggregate(v, fields)
161             }
162             /// Called each time we recurse down to a field, passing in old and new value.
163             /// This gives the visitor the chance to track the stack of nested fields that
164             /// we are descending through.
165             #[inline(always)]
166             fn visit_field(
167                 &mut self,
168                 _old_val: Self::V,
169                 _field: usize,
170                 new_val: Self::V,
171             ) -> EvalResult<'tcx> {
172                 self.visit_value(new_val)
173             }
174
175             #[inline(always)]
176             fn visit_variant(
177                 &mut self,
178                 _old_val: Self::V,
179                 _variant: VariantIdx,
180                 new_val: Self::V,
181             ) -> EvalResult<'tcx> {
182                 self.visit_value(new_val)
183             }
184
185             /// Called whenever we reach a value with uninhabited layout.
186             /// Recursing to fields will *always* continue after this!  This is not meant to control
187             /// whether and how we descend recursively/ into the scalar's fields if there are any,
188             /// it is meant to provide the chance for additional checks when a value of uninhabited
189             /// layout is detected.
190             #[inline(always)]
191             fn visit_uninhabited(&mut self) -> EvalResult<'tcx>
192             { Ok(()) }
193             /// Called whenever we reach a value with scalar layout.
194             /// We do NOT provide a `ScalarMaybeUndef` here to avoid accessing memory if the
195             /// visitor is not even interested in scalars.
196             /// Recursing to fields will *always* continue after this!  This is not meant to control
197             /// whether and how we descend recursively/ into the scalar's fields if there are any,
198             /// it is meant to provide the chance for additional checks when a value of scalar
199             /// layout is detected.
200             #[inline(always)]
201             fn visit_scalar(&mut self, _v: Self::V, _layout: &layout::Scalar) -> EvalResult<'tcx>
202             { Ok(()) }
203
204             /// Called whenever we reach a value of primitive type.  There can be no recursion
205             /// below such a value.  This is the leaf function.
206             /// We do *not* provide an `ImmTy` here because some implementations might want
207             /// to write to the place this primitive lives in.
208             #[inline(always)]
209             fn visit_primitive(&mut self, _v: Self::V) -> EvalResult<'tcx>
210             { Ok(()) }
211
212             // Default recursors. Not meant to be overloaded.
213             fn walk_aggregate(
214                 &mut self,
215                 v: Self::V,
216                 fields: impl Iterator<Item=EvalResult<'tcx, Self::V>>,
217             ) -> EvalResult<'tcx> {
218                 // Now iterate over it.
219                 for (idx, field_val) in fields.enumerate() {
220                     self.visit_field(v, idx, field_val?)?;
221                 }
222                 Ok(())
223             }
224             fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx>
225             {
226                 trace!("walk_value: type: {}", v.layout().ty);
227                 // If this is a multi-variant layout, we have find the right one and proceed with
228                 // that.
229                 match v.layout().variants {
230                     layout::Variants::NicheFilling { .. } |
231                     layout::Variants::Tagged { .. } => {
232                         let op = v.to_op(self.ecx())?;
233                         let idx = self.ecx().read_discriminant(op)?.1;
234                         let inner = v.project_downcast(self.ecx(), idx)?;
235                         trace!("walk_value: variant layout: {:#?}", inner.layout());
236                         // recurse with the inner type
237                         return self.visit_variant(v, idx, inner);
238                     }
239                     layout::Variants::Single { .. } => {}
240                 }
241
242                 // Even for single variants, we might be able to get a more refined type:
243                 // If it is a trait object, switch to the actual type that was used to create it.
244                 match v.layout().ty.sty {
245                     ty::Dynamic(..) => {
246                         // immediate trait objects are not a thing
247                         let dest = v.to_op(self.ecx())?.to_mem_place();
248                         let inner = self.ecx().unpack_dyn_trait(dest)?.1;
249                         trace!("walk_value: dyn object layout: {:#?}", inner.layout);
250                         // recurse with the inner type
251                         return self.visit_field(v, 0, Value::from_mem_place(inner));
252                     },
253                     _ => {},
254                 };
255
256                 // If this is a scalar, visit it as such.
257                 // Things can be aggregates and have scalar layout at the same time, and that
258                 // is very relevant for `NonNull` and similar structs: We need to visit them
259                 // at their scalar layout *before* descending into their fields.
260                 // FIXME: We could avoid some redundant checks here. For newtypes wrapping
261                 // scalars, we do the same check on every "level" (e.g. first we check
262                 // MyNewtype and then the scalar in there).
263                 match v.layout().abi {
264                     layout::Abi::Uninhabited => {
265                         self.visit_uninhabited()?;
266                     }
267                     layout::Abi::Scalar(ref layout) => {
268                         self.visit_scalar(v, layout)?;
269                     }
270                     // FIXME: Should we do something for ScalarPair? Vector?
271                     _ => {}
272                 }
273
274                 // Check primitive types.  We do this after checking the scalar layout,
275                 // just to have that done as well.  Primitives can have varying layout,
276                 // so we check them separately and before aggregate handling.
277                 // It is CRITICAL that we get this check right, or we might be
278                 // validating the wrong thing!
279                 let primitive = match v.layout().fields {
280                     // Primitives appear as Union with 0 fields - except for Boxes and fat pointers.
281                     layout::FieldPlacement::Union(0) => true,
282                     _ => v.layout().ty.builtin_deref(true).is_some(),
283                 };
284                 if primitive {
285                     return self.visit_primitive(v);
286                 }
287
288                 // Proceed into the fields.
289                 match v.layout().fields {
290                     layout::FieldPlacement::Union(fields) => {
291                         // Empty unions are not accepted by rustc. That's great, it means we can
292                         // use that as an unambiguous signal for detecting primitives.  Make sure
293                         // we did not miss any primitive.
294                         debug_assert!(fields > 0);
295                         self.visit_union(v)
296                     },
297                     layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
298                         // Special handling needed for generators: All but the first field
299                         // (which is the state) are actually implicitly `MaybeUninit`, i.e.,
300                         // they may or may not be initialized, so we cannot visit them.
301                         match v.layout().ty.sty {
302                             ty::Generator(..) => {
303                                 let field = v.project_field(self.ecx(), 0)?;
304                                 self.visit_aggregate(v, std::iter::once(Ok(field)))
305                             }
306                             _ => {
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                         }
317                     },
318                     layout::FieldPlacement::Array { .. } => {
319                         // Let's get an mplace first.
320                         let mplace = if v.layout().is_zst() {
321                             // it's a ZST, the memory content cannot matter
322                             MPlaceTy::dangling(v.layout(), self.ecx())
323                         } else {
324                             // non-ZST array/slice/str cannot be immediate
325                             v.to_op(self.ecx())?.to_mem_place()
326                         };
327                         // Now we can go over all the fields.
328                         let iter = self.ecx().mplace_array_fields(mplace)?
329                             .map(|f| f.and_then(|f| {
330                                 Ok(Value::from_mem_place(f))
331                             }));
332                         self.visit_aggregate(v, iter)
333                     }
334                 }
335             }
336         }
337     }
338 }
339
340 make_value_visitor!(ValueVisitor,);
341 make_value_visitor!(MutValueVisitor,mut);