]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/visitor.rs
Rollup merge of #56043 - nikomatsakis:issue-55756-via-outlives, r=eddyb
[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             #[inline(always)]
146             fn visit_union(&mut self, _v: Self::V) -> EvalResult<'tcx>
147             {
148                 Ok(())
149             }
150             /// Visit this vale as an aggregate, you are even 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             /// Called each time we recurse down to a field, passing in old and new value.
162             /// This gives the visitor the chance to track the stack of nested fields that
163             /// we are descending through.
164             #[inline(always)]
165             fn visit_field(
166                 &mut self,
167                 _old_val: Self::V,
168                 _field: usize,
169                 new_val: Self::V,
170             ) -> EvalResult<'tcx> {
171                 self.visit_value(new_val)
172             }
173
174             #[inline(always)]
175             fn visit_variant(
176                 &mut self,
177                 _old_val: Self::V,
178                 _variant: VariantIdx,
179                 new_val: Self::V,
180             ) -> EvalResult<'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) -> EvalResult<'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) -> EvalResult<'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) -> EvalResult<'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=EvalResult<'tcx, Self::V>>,
216             ) -> EvalResult<'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) -> EvalResult<'tcx>
224             {
225                 trace!("walk_value: type: {}", v.layout().ty);
226                 // If this is a multi-variant layout, we have find the right one and proceed with
227                 // that.
228                 match v.layout().variants {
229                     layout::Variants::NicheFilling { .. } |
230                     layout::Variants::Tagged { .. } => {
231                         let op = v.to_op(self.ecx())?;
232                         let idx = self.ecx().read_discriminant(op)?.1;
233                         let inner = v.project_downcast(self.ecx(), idx)?;
234                         trace!("walk_value: variant layout: {:#?}", inner.layout());
235                         // recurse with the inner type
236                         return self.visit_variant(v, idx, inner);
237                     }
238                     layout::Variants::Single { .. } => {}
239                 }
240
241                 // Even for single variants, we might be able to get a more refined type:
242                 // If it is a trait object, switch to the actual type that was used to create it.
243                 match v.layout().ty.sty {
244                     ty::Dynamic(..) => {
245                         // immediate trait objects are not a thing
246                         let dest = v.to_op(self.ecx())?.to_mem_place();
247                         let inner = self.ecx().unpack_dyn_trait(dest)?.1;
248                         trace!("walk_value: dyn object layout: {:#?}", inner.layout);
249                         // recurse with the inner type
250                         return self.visit_field(v, 0, Value::from_mem_place(inner));
251                     },
252                     _ => {},
253                 };
254
255                 // If this is a scalar, visit it as such.
256                 // Things can be aggregates and have scalar layout at the same time, and that
257                 // is very relevant for `NonNull` and similar structs: We need to visit them
258                 // at their scalar layout *before* descending into their fields.
259                 // FIXME: We could avoid some redundant checks here. For newtypes wrapping
260                 // scalars, we do the same check on every "level" (e.g. first we check
261                 // MyNewtype and then the scalar in there).
262                 match v.layout().abi {
263                     layout::Abi::Uninhabited => {
264                         self.visit_uninhabited()?;
265                     }
266                     layout::Abi::Scalar(ref layout) => {
267                         self.visit_scalar(v, layout)?;
268                     }
269                     // FIXME: Should we do something for ScalarPair? Vector?
270                     _ => {}
271                 }
272
273                 // Check primitive types.  We do this after checking the scalar layout,
274                 // just to have that done as well.  Primitives can have varying layout,
275                 // so we check them separately and before aggregate handling.
276                 // It is CRITICAL that we get this check right, or we might be
277                 // validating the wrong thing!
278                 let primitive = match v.layout().fields {
279                     // Primitives appear as Union with 0 fields - except for Boxes and fat pointers.
280                     layout::FieldPlacement::Union(0) => true,
281                     _ => v.layout().ty.builtin_deref(true).is_some(),
282                 };
283                 if primitive {
284                     return self.visit_primitive(v);
285                 }
286
287                 // Proceed into the fields.
288                 match v.layout().fields {
289                     layout::FieldPlacement::Union(fields) => {
290                         // Empty unions are not accepted by rustc. That's great, it means we can
291                         // use that as an unambiguous signal for detecting primitives.  Make sure
292                         // we did not miss any primitive.
293                         debug_assert!(fields > 0);
294                         self.visit_union(v)?;
295                     },
296                     layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
297                         // FIXME: We collect in a vec because otherwise there are lifetime errors:
298                         // Projecting to a field needs (mutable!) access to `ecx`.
299                         let fields: Vec<EvalResult<'tcx, Self::V>> =
300                             (0..offsets.len()).map(|i| {
301                                 v.project_field(self.ecx(), i as u64)
302                             })
303                             .collect();
304                         self.visit_aggregate(v, fields.into_iter())?;
305                     },
306                     layout::FieldPlacement::Array { .. } => {
307                         // Let's get an mplace first.
308                         let mplace = if v.layout().is_zst() {
309                             // it's a ZST, the memory content cannot matter
310                             MPlaceTy::dangling(v.layout(), self.ecx())
311                         } else {
312                             // non-ZST array/slice/str cannot be immediate
313                             v.to_op(self.ecx())?.to_mem_place()
314                         };
315                         // Now we can go over all the fields.
316                         let iter = self.ecx().mplace_array_fields(mplace)?
317                             .map(|f| f.and_then(|f| {
318                                 Ok(Value::from_mem_place(f))
319                             }));
320                         self.visit_aggregate(v, iter)?;
321                     }
322                 }
323                 Ok(())
324             }
325         }
326     }
327 }
328
329 make_value_visitor!(ValueVisitor,);
330 make_value_visitor!(MutValueVisitor,mut);