]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/place.rs
miri: Rename to_{u,i}size to to_machine_{u,i}size
[rust.git] / src / librustc_mir / interpret / place.rs
1 //! Computations on places -- field projections, going from mir::Place, and writing
2 //! into a place.
3 //! All high-level functions to write to memory work on places as destinations.
4
5 use std::convert::TryFrom;
6 use std::hash::Hash;
7
8 use rustc::mir;
9 use rustc::mir::interpret::truncate;
10 use rustc::ty::{self, Ty};
11 use rustc::ty::layout::{
12     self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx, PrimitiveExt
13 };
14 use rustc::ty::TypeFoldable;
15
16 use super::{
17     GlobalId, AllocId, Allocation, Scalar, InterpResult, Pointer, PointerArithmetic,
18     InterpCx, Machine, AllocMap, AllocationExtra,
19     RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind, LocalValue,
20 };
21
22 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
23 pub struct MemPlace<Tag=(), Id=AllocId> {
24     /// A place may have an integral pointer for ZSTs, and since it might
25     /// be turned back into a reference before ever being dereferenced.
26     /// However, it may never be undef.
27     pub ptr: Scalar<Tag, Id>,
28     pub align: Align,
29     /// Metadata for unsized places. Interpretation is up to the type.
30     /// Must not be present for sized types, but can be missing for unsized types
31     /// (e.g., `extern type`).
32     pub meta: Option<Scalar<Tag, Id>>,
33 }
34
35 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
36 pub enum Place<Tag=(), Id=AllocId> {
37     /// A place referring to a value allocated in the `Memory` system.
38     Ptr(MemPlace<Tag, Id>),
39
40     /// To support alloc-free locals, we are able to write directly to a local.
41     /// (Without that optimization, we'd just always be a `MemPlace`.)
42     Local {
43         frame: usize,
44         local: mir::Local,
45     },
46 }
47
48 #[derive(Copy, Clone, Debug)]
49 pub struct PlaceTy<'tcx, Tag=()> {
50     place: Place<Tag>, // Keep this private, it helps enforce invariants
51     pub layout: TyLayout<'tcx>,
52 }
53
54 impl<'tcx, Tag> ::std::ops::Deref for PlaceTy<'tcx, Tag> {
55     type Target = Place<Tag>;
56     #[inline(always)]
57     fn deref(&self) -> &Place<Tag> {
58         &self.place
59     }
60 }
61
62 /// A MemPlace with its layout. Constructing it is only possible in this module.
63 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
64 pub struct MPlaceTy<'tcx, Tag=()> {
65     mplace: MemPlace<Tag>,
66     pub layout: TyLayout<'tcx>,
67 }
68
69 impl<'tcx, Tag> ::std::ops::Deref for MPlaceTy<'tcx, Tag> {
70     type Target = MemPlace<Tag>;
71     #[inline(always)]
72     fn deref(&self) -> &MemPlace<Tag> {
73         &self.mplace
74     }
75 }
76
77 impl<'tcx, Tag> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
78     #[inline(always)]
79     fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
80         PlaceTy {
81             place: Place::Ptr(mplace.mplace),
82             layout: mplace.layout
83         }
84     }
85 }
86
87 impl<Tag> MemPlace<Tag> {
88     /// Replace ptr tag, maintain vtable tag (if any)
89     #[inline]
90     pub fn replace_tag(self, new_tag: Tag) -> Self {
91         MemPlace {
92             ptr: self.ptr.erase_tag().with_tag(new_tag),
93             align: self.align,
94             meta: self.meta,
95         }
96     }
97
98     #[inline]
99     pub fn erase_tag(self) -> MemPlace {
100         MemPlace {
101             ptr: self.ptr.erase_tag(),
102             align: self.align,
103             meta: self.meta.map(Scalar::erase_tag),
104         }
105     }
106
107     #[inline(always)]
108     pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
109         MemPlace {
110             ptr,
111             align,
112             meta: None,
113         }
114     }
115
116     /// Produces a Place that will error if attempted to be read from or written to
117     #[inline(always)]
118     pub fn null(cx: &impl HasDataLayout) -> Self {
119         Self::from_scalar_ptr(Scalar::ptr_null(cx), Align::from_bytes(1).unwrap())
120     }
121
122     #[inline(always)]
123     pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
124         Self::from_scalar_ptr(ptr.into(), align)
125     }
126
127     /// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
128     /// This is the inverse of `ref_to_mplace`.
129     #[inline(always)]
130     pub fn to_ref(self) -> Immediate<Tag> {
131         match self.meta {
132             None => Immediate::Scalar(self.ptr.into()),
133             Some(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()),
134         }
135     }
136
137     pub fn offset(
138         self,
139         offset: Size,
140         meta: Option<Scalar<Tag>>,
141         cx: &impl HasDataLayout,
142     ) -> InterpResult<'tcx, Self> {
143         Ok(MemPlace {
144             ptr: self.ptr.ptr_offset(offset, cx)?,
145             align: self.align.restrict_for_offset(offset),
146             meta,
147         })
148     }
149 }
150
151 impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
152     /// Produces a MemPlace that works for ZST but nothing else
153     #[inline]
154     pub fn dangling(layout: TyLayout<'tcx>, cx: &impl HasDataLayout) -> Self {
155         MPlaceTy {
156             mplace: MemPlace::from_scalar_ptr(
157                 Scalar::from_uint(layout.align.abi.bytes(), cx.pointer_size()),
158                 layout.align.abi
159             ),
160             layout
161         }
162     }
163
164     /// Replace ptr tag, maintain vtable tag (if any)
165     #[inline]
166     pub fn replace_tag(self, new_tag: Tag) -> Self {
167         MPlaceTy {
168             mplace: self.mplace.replace_tag(new_tag),
169             layout: self.layout,
170         }
171     }
172
173     #[inline]
174     pub fn offset(
175         self,
176         offset: Size,
177         meta: Option<Scalar<Tag>>,
178         layout: TyLayout<'tcx>,
179         cx: &impl HasDataLayout,
180     ) -> InterpResult<'tcx, Self> {
181         Ok(MPlaceTy {
182             mplace: self.mplace.offset(offset, meta, cx)?,
183             layout,
184         })
185     }
186
187     #[inline]
188     fn from_aligned_ptr(ptr: Pointer<Tag>, layout: TyLayout<'tcx>) -> Self {
189         MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align.abi), layout }
190     }
191
192     #[inline]
193     pub(super) fn len(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
194         if self.layout.is_unsized() {
195             // We need to consult `meta` metadata
196             match self.layout.ty.kind {
197                 ty::Slice(..) | ty::Str =>
198                     return self.mplace.meta.unwrap().to_machine_usize(cx),
199                 _ => bug!("len not supported on unsized type {:?}", self.layout.ty),
200             }
201         } else {
202             // Go through the layout.  There are lots of types that support a length,
203             // e.g., SIMD types.
204             match self.layout.fields {
205                 layout::FieldPlacement::Array { count, .. } => Ok(count),
206                 _ => bug!("len not supported on sized type {:?}", self.layout.ty),
207             }
208         }
209     }
210
211     #[inline]
212     pub(super) fn vtable(self) -> Scalar<Tag> {
213         match self.layout.ty.kind {
214             ty::Dynamic(..) => self.mplace.meta.unwrap(),
215             _ => bug!("vtable not supported on type {:?}", self.layout.ty),
216         }
217     }
218 }
219
220 // These are defined here because they produce a place.
221 impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> {
222     #[inline(always)]
223     pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> {
224         match *self {
225             Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
226             Operand::Immediate(imm) => Err(ImmTy { imm, layout: self.layout }),
227         }
228     }
229
230     #[inline(always)]
231     pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> {
232         self.try_as_mplace().unwrap()
233     }
234 }
235
236 impl<Tag: ::std::fmt::Debug> Place<Tag> {
237     /// Produces a Place that will error if attempted to be read from or written to
238     #[inline(always)]
239     pub fn null(cx: &impl HasDataLayout) -> Self {
240         Place::Ptr(MemPlace::null(cx))
241     }
242
243     #[inline(always)]
244     pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
245         Place::Ptr(MemPlace::from_scalar_ptr(ptr, align))
246     }
247
248     #[inline(always)]
249     pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
250         Place::Ptr(MemPlace::from_ptr(ptr, align))
251     }
252
253     #[inline]
254     pub fn assert_mem_place(self) -> MemPlace<Tag> {
255         match self {
256             Place::Ptr(mplace) => mplace,
257             _ => bug!("assert_mem_place: expected Place::Ptr, got {:?}", self),
258
259         }
260     }
261 }
262
263 impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> {
264     #[inline]
265     pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> {
266         MPlaceTy { mplace: self.place.assert_mem_place(), layout: self.layout }
267     }
268 }
269
270 // separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385
271 impl<'mir, 'tcx, Tag, M> InterpCx<'mir, 'tcx, M>
272 where
273     // FIXME: Working around https://github.com/rust-lang/rust/issues/54385
274     Tag: ::std::fmt::Debug + Copy + Eq + Hash + 'static,
275     M: Machine<'mir, 'tcx, PointerTag = Tag>,
276     // FIXME: Working around https://github.com/rust-lang/rust/issues/24159
277     M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag, M::AllocExtra>)>,
278     M::AllocExtra: AllocationExtra<Tag>,
279 {
280     /// Take a value, which represents a (thin or fat) reference, and make it a place.
281     /// Alignment is just based on the type.  This is the inverse of `MemPlace::to_ref()`.
282     ///
283     /// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not
284     /// want to ever use the place for memory access!
285     /// Generally prefer `deref_operand`.
286     pub fn ref_to_mplace(
287         &self,
288         val: ImmTy<'tcx, M::PointerTag>,
289     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
290         let pointee_type = val.layout.ty.builtin_deref(true)
291             .expect("`ref_to_mplace` called on non-ptr type")
292             .ty;
293         let layout = self.layout_of(pointee_type)?;
294         let (ptr, meta) = match *val {
295             Immediate::Scalar(ptr) => (ptr.not_undef()?, None),
296             Immediate::ScalarPair(ptr, meta) => (ptr.not_undef()?, Some(meta.not_undef()?)),
297         };
298
299         let mplace = MemPlace {
300             ptr,
301             // We could use the run-time alignment here. For now, we do not, because
302             // the point of tracking the alignment here is to make sure that the *static*
303             // alignment information emitted with the loads is correct. The run-time
304             // alignment can only be more restrictive.
305             align: layout.align.abi,
306             meta,
307         };
308         Ok(MPlaceTy { mplace, layout })
309     }
310
311     /// Take an operand, representing a pointer, and dereference it to a place -- that
312     /// will always be a MemPlace.  Lives in `place.rs` because it creates a place.
313     pub fn deref_operand(
314         &self,
315         src: OpTy<'tcx, M::PointerTag>,
316     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
317         let val = self.read_immediate(src)?;
318         trace!("deref to {} on {:?}", val.layout.ty, *val);
319         let place = self.ref_to_mplace(val)?;
320         self.mplace_access_checked(place)
321     }
322
323     /// Check if the given place is good for memory access with the given
324     /// size, falling back to the layout's size if `None` (in the latter case,
325     /// this must be a statically sized type).
326     ///
327     /// On success, returns `None` for zero-sized accesses (where nothing else is
328     /// left to do) and a `Pointer` to use for the actual access otherwise.
329     #[inline]
330     pub fn check_mplace_access(
331         &self,
332         place: MPlaceTy<'tcx, M::PointerTag>,
333         size: Option<Size>,
334     ) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> {
335         let size = size.unwrap_or_else(|| {
336             assert!(!place.layout.is_unsized());
337             assert!(place.meta.is_none());
338             place.layout.size
339         });
340         self.memory.check_ptr_access(place.ptr, size, place.align)
341     }
342
343     /// Return the "access-checked" version of this `MPlace`, where for non-ZST
344     /// this is definitely a `Pointer`.
345     pub fn mplace_access_checked(
346         &self,
347         mut place: MPlaceTy<'tcx, M::PointerTag>,
348     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
349         let (size, align) = self.size_and_align_of_mplace(place)?
350             .unwrap_or((place.layout.size, place.layout.align.abi));
351         assert!(place.mplace.align <= align, "dynamic alignment less strict than static one?");
352         place.mplace.align = align; // maximally strict checking
353         // When dereferencing a pointer, it must be non-NULL, aligned, and live.
354         if let Some(ptr) = self.check_mplace_access(place, Some(size))? {
355             place.mplace.ptr = ptr.into();
356         }
357         Ok(place)
358     }
359
360     /// Force `place.ptr` to a `Pointer`.
361     /// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot.
362     pub fn force_mplace_ptr(
363         &self,
364         mut place: MPlaceTy<'tcx, M::PointerTag>,
365     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
366         place.mplace.ptr = self.force_ptr(place.mplace.ptr)?.into();
367         Ok(place)
368     }
369
370     /// Offset a pointer to project to a field. Unlike `place_field`, this is always
371     /// possible without allocating, so it can take `&self`. Also return the field's layout.
372     /// This supports both struct and array fields.
373     #[inline(always)]
374     pub fn mplace_field(
375         &self,
376         base: MPlaceTy<'tcx, M::PointerTag>,
377         field: u64,
378     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
379         // Not using the layout method because we want to compute on u64
380         let offset = match base.layout.fields {
381             layout::FieldPlacement::Arbitrary { ref offsets, .. } =>
382                 offsets[usize::try_from(field).unwrap()],
383             layout::FieldPlacement::Array { stride, .. } => {
384                 let len = base.len(self)?;
385                 if field >= len {
386                     // This can be violated because the index (field) can be a runtime value
387                     // provided by the user.
388                     debug!("tried to access element {} of array/slice with length {}", field, len);
389                     throw_panic!(BoundsCheck { len, index: field });
390                 }
391                 stride * field
392             }
393             layout::FieldPlacement::Union(count) => {
394                 assert!(field < count as u64,
395                         "Tried to access field {} of union {:#?} with {} fields",
396                         field, base.layout, count);
397                 // Offset is always 0
398                 Size::from_bytes(0)
399             }
400         };
401         // the only way conversion can fail if is this is an array (otherwise we already panicked
402         // above). In that case, all fields are equal.
403         let field_layout = base.layout.field(self, usize::try_from(field).unwrap_or(0))?;
404
405         // Offset may need adjustment for unsized fields.
406         let (meta, offset) = if field_layout.is_unsized() {
407             // Re-use parent metadata to determine dynamic field layout.
408             // With custom DSTS, this *will* execute user-defined code, but the same
409             // happens at run-time so that's okay.
410             let align = match self.size_and_align_of(base.meta, field_layout)? {
411                 Some((_, align)) => align,
412                 None if offset == Size::ZERO =>
413                     // An extern type at offset 0, we fall back to its static alignment.
414                     // FIXME: Once we have made decisions for how to handle size and alignment
415                     // of `extern type`, this should be adapted.  It is just a temporary hack
416                     // to get some code to work that probably ought to work.
417                     field_layout.align.abi,
418                 None =>
419                     bug!("Cannot compute offset for extern type field at non-0 offset"),
420             };
421             (base.meta, offset.align_to(align))
422         } else {
423             // base.meta could be present; we might be accessing a sized field of an unsized
424             // struct.
425             (None, offset)
426         };
427
428         // We do not look at `base.layout.align` nor `field_layout.align`, unlike
429         // codegen -- mostly to see if we can get away with that
430         base.offset(offset, meta, field_layout, self)
431     }
432
433     // Iterates over all fields of an array. Much more efficient than doing the
434     // same by repeatedly calling `mplace_array`.
435     pub fn mplace_array_fields(
436         &self,
437         base: MPlaceTy<'tcx, Tag>,
438     ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'tcx>
439     {
440         let len = base.len(self)?; // also asserts that we have a type where this makes sense
441         let stride = match base.layout.fields {
442             layout::FieldPlacement::Array { stride, .. } => stride,
443             _ => bug!("mplace_array_fields: expected an array layout"),
444         };
445         let layout = base.layout.field(self, 0)?;
446         let dl = &self.tcx.data_layout;
447         Ok((0..len).map(move |i| base.offset(i * stride, None, layout, dl)))
448     }
449
450     pub fn mplace_subslice(
451         &self,
452         base: MPlaceTy<'tcx, M::PointerTag>,
453         from: u64,
454         to: u64,
455     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
456         let len = base.len(self)?; // also asserts that we have a type where this makes sense
457         assert!(from <= len - to);
458
459         // Not using layout method because that works with usize, and does not work with slices
460         // (that have count 0 in their layout).
461         let from_offset = match base.layout.fields {
462             layout::FieldPlacement::Array { stride, .. } =>
463                 stride * from,
464             _ => bug!("Unexpected layout of index access: {:#?}", base.layout),
465         };
466
467         // Compute meta and new layout
468         let inner_len = len - to - from;
469         let (meta, ty) = match base.layout.ty.kind {
470             // It is not nice to match on the type, but that seems to be the only way to
471             // implement this.
472             ty::Array(inner, _) =>
473                 (None, self.tcx.mk_array(inner, inner_len)),
474             ty::Slice(..) => {
475                 let len = Scalar::from_uint(inner_len, self.pointer_size());
476                 (Some(len), base.layout.ty)
477             }
478             _ =>
479                 bug!("cannot subslice non-array type: `{:?}`", base.layout.ty),
480         };
481         let layout = self.layout_of(ty)?;
482         base.offset(from_offset, meta, layout, self)
483     }
484
485     pub fn mplace_downcast(
486         &self,
487         base: MPlaceTy<'tcx, M::PointerTag>,
488         variant: VariantIdx,
489     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
490         // Downcasts only change the layout
491         assert!(base.meta.is_none());
492         Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
493     }
494
495     /// Project into an mplace
496     pub fn mplace_projection(
497         &self,
498         base: MPlaceTy<'tcx, M::PointerTag>,
499         proj_elem: &mir::PlaceElem<'tcx>,
500     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
501         use rustc::mir::ProjectionElem::*;
502         Ok(match *proj_elem {
503             Field(field, _) => self.mplace_field(base, field.index() as u64)?,
504             Downcast(_, variant) => self.mplace_downcast(base, variant)?,
505             Deref => self.deref_operand(base.into())?,
506
507             Index(local) => {
508                 let layout = self.layout_of(self.tcx.types.usize)?;
509                 let n = self.access_local(self.frame(), local, Some(layout))?;
510                 let n = self.read_scalar(n)?;
511                 let n = self.force_bits(n.not_undef()?, self.tcx.data_layout.pointer_size)?;
512                 self.mplace_field(base, u64::try_from(n).unwrap())?
513             }
514
515             ConstantIndex {
516                 offset,
517                 min_length,
518                 from_end,
519             } => {
520                 let n = base.len(self)?;
521                 assert!(n >= min_length as u64);
522
523                 let index = if from_end {
524                     n - u64::from(offset)
525                 } else {
526                     u64::from(offset)
527                 };
528
529                 self.mplace_field(base, index)?
530             }
531
532             Subslice { from, to } =>
533                 self.mplace_subslice(base, u64::from(from), u64::from(to))?,
534         })
535     }
536
537     /// Gets the place of a field inside the place, and also the field's type.
538     /// Just a convenience function, but used quite a bit.
539     /// This is the only projection that might have a side-effect: We cannot project
540     /// into the field of a local `ScalarPair`, we have to first allocate it.
541     pub fn place_field(
542         &mut self,
543         base: PlaceTy<'tcx, M::PointerTag>,
544         field: u64,
545     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
546         // FIXME: We could try to be smarter and avoid allocation for fields that span the
547         // entire place.
548         let mplace = self.force_allocation(base)?;
549         Ok(self.mplace_field(mplace, field)?.into())
550     }
551
552     pub fn place_downcast(
553         &self,
554         base: PlaceTy<'tcx, M::PointerTag>,
555         variant: VariantIdx,
556     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
557         // Downcast just changes the layout
558         Ok(match base.place {
559             Place::Ptr(mplace) =>
560                 self.mplace_downcast(MPlaceTy { mplace, layout: base.layout }, variant)?.into(),
561             Place::Local { .. } => {
562                 let layout = base.layout.for_variant(self, variant);
563                 PlaceTy { layout, ..base }
564             }
565         })
566     }
567
568     /// Projects into a place.
569     pub fn place_projection(
570         &mut self,
571         base: PlaceTy<'tcx, M::PointerTag>,
572         proj_elem: &mir::ProjectionElem<mir::Local, Ty<'tcx>>,
573     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
574         use rustc::mir::ProjectionElem::*;
575         Ok(match *proj_elem {
576             Field(field, _) =>  self.place_field(base, field.index() as u64)?,
577             Downcast(_, variant) => self.place_downcast(base, variant)?,
578             Deref => self.deref_operand(self.place_to_op(base)?)?.into(),
579             // For the other variants, we have to force an allocation.
580             // This matches `operand_projection`.
581             Subslice { .. } | ConstantIndex { .. } | Index(_) => {
582                 let mplace = self.force_allocation(base)?;
583                 self.mplace_projection(mplace, proj_elem)?.into()
584             }
585         })
586     }
587
588     /// Evaluate statics and promoteds to an `MPlace`. Used to share some code between
589     /// `eval_place` and `eval_place_to_op`.
590     pub(super) fn eval_static_to_mplace(
591         &self,
592         place_static: &mir::Static<'tcx>
593     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
594         use rustc::mir::StaticKind;
595
596         Ok(match place_static.kind {
597             StaticKind::Promoted(promoted, promoted_substs) => {
598                 let substs = self.subst_from_frame_and_normalize_erasing_regions(promoted_substs);
599                 let instance = ty::Instance::new(place_static.def_id, substs);
600
601                 // Even after getting `substs` from the frame, this instance may still be
602                 // polymorphic because `ConstProp` will try to promote polymorphic MIR.
603                 if instance.needs_subst() {
604                     throw_inval!(TooGeneric);
605                 }
606
607                 self.const_eval_raw(GlobalId {
608                     instance,
609                     promoted: Some(promoted),
610                 })?
611             }
612
613             StaticKind::Static => {
614                 let ty = place_static.ty;
615                 assert!(!ty.needs_subst());
616                 let layout = self.layout_of(ty)?;
617                 let instance = ty::Instance::mono(*self.tcx, place_static.def_id);
618                 let cid = GlobalId {
619                     instance,
620                     promoted: None
621                 };
622                 // Just create a lazy reference, so we can support recursive statics.
623                 // tcx takes care of assigning every static one and only one unique AllocId.
624                 // When the data here is ever actually used, memory will notice,
625                 // and it knows how to deal with alloc_id that are present in the
626                 // global table but not in its local memory: It calls back into tcx through
627                 // a query, triggering the CTFE machinery to actually turn this lazy reference
628                 // into a bunch of bytes.  IOW, statics are evaluated with CTFE even when
629                 // this InterpCx uses another Machine (e.g., in miri).  This is what we
630                 // want!  This way, computing statics works consistently between codegen
631                 // and miri: They use the same query to eventually obtain a `ty::Const`
632                 // and use that for further computation.
633                 //
634                 // Notice that statics have *two* AllocIds: the lazy one, and the resolved
635                 // one.  Here we make sure that the interpreted program never sees the
636                 // resolved ID.  Also see the doc comment of `Memory::get_static_alloc`.
637                 let alloc_id = self.tcx.alloc_map.lock().create_static_alloc(cid.instance.def_id());
638                 let ptr = self.tag_static_base_pointer(Pointer::from(alloc_id));
639                 MPlaceTy::from_aligned_ptr(ptr, layout)
640             }
641         })
642     }
643
644     /// Computes a place. You should only use this if you intend to write into this
645     /// place; for reading, a more efficient alternative is `eval_place_for_read`.
646     pub fn eval_place(
647         &mut self,
648         place: &mir::Place<'tcx>,
649     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
650         use rustc::mir::PlaceBase;
651
652         let mut place_ty = match &place.base {
653             PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place {
654                 Some(return_place) => {
655                     // We use our layout to verify our assumption; caller will validate
656                     // their layout on return.
657                     PlaceTy {
658                         place: *return_place,
659                         layout: self.layout_of(
660                             self.subst_from_frame_and_normalize_erasing_regions(
661                                 self.frame().body.return_ty()
662                             )
663                         )?,
664                     }
665                 }
666                 None => throw_unsup!(InvalidNullPointerUsage),
667             },
668             PlaceBase::Local(local) => PlaceTy {
669                 // This works even for dead/uninitialized locals; we check further when writing
670                 place: Place::Local {
671                     frame: self.cur_frame(),
672                     local: *local,
673                 },
674                 layout: self.layout_of_local(self.frame(), *local, None)?,
675             },
676             PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(),
677         };
678
679         for elem in place.projection.iter() {
680             place_ty = self.place_projection(place_ty, elem)?
681         }
682
683         self.dump_place(place_ty.place);
684         Ok(place_ty)
685     }
686
687     /// Write a scalar to a place
688     pub fn write_scalar(
689         &mut self,
690         val: impl Into<ScalarMaybeUndef<M::PointerTag>>,
691         dest: PlaceTy<'tcx, M::PointerTag>,
692     ) -> InterpResult<'tcx> {
693         self.write_immediate(Immediate::Scalar(val.into()), dest)
694     }
695
696     /// Write an immediate to a place
697     #[inline(always)]
698     pub fn write_immediate(
699         &mut self,
700         src: Immediate<M::PointerTag>,
701         dest: PlaceTy<'tcx, M::PointerTag>,
702     ) -> InterpResult<'tcx> {
703         self.write_immediate_no_validate(src, dest)?;
704
705         if M::enforce_validity(self) {
706             // Data got changed, better make sure it matches the type!
707             self.validate_operand(self.place_to_op(dest)?, vec![], None)?;
708         }
709
710         Ok(())
711     }
712
713     /// Write an `Immediate` to memory.
714     #[inline(always)]
715     pub fn write_immediate_to_mplace(
716         &mut self,
717         src: Immediate<M::PointerTag>,
718         dest: MPlaceTy<'tcx, M::PointerTag>,
719     ) -> InterpResult<'tcx> {
720         self.write_immediate_to_mplace_no_validate(src, dest)?;
721
722         if M::enforce_validity(self) {
723             // Data got changed, better make sure it matches the type!
724             self.validate_operand(dest.into(), vec![], None)?;
725         }
726
727         Ok(())
728     }
729
730     /// Write an immediate to a place.
731     /// If you use this you are responsible for validating that things got copied at the
732     /// right type.
733     fn write_immediate_no_validate(
734         &mut self,
735         src: Immediate<M::PointerTag>,
736         dest: PlaceTy<'tcx, M::PointerTag>,
737     ) -> InterpResult<'tcx> {
738         if cfg!(debug_assertions) {
739             // This is a very common path, avoid some checks in release mode
740             assert!(!dest.layout.is_unsized(), "Cannot write unsized data");
741             match src {
742                 Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Ptr(_))) =>
743                     assert_eq!(self.pointer_size(), dest.layout.size,
744                         "Size mismatch when writing pointer"),
745                 Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Raw { size, .. })) =>
746                     assert_eq!(Size::from_bytes(size.into()), dest.layout.size,
747                         "Size mismatch when writing bits"),
748                 Immediate::Scalar(ScalarMaybeUndef::Undef) => {}, // undef can have any size
749                 Immediate::ScalarPair(_, _) => {
750                     // FIXME: Can we check anything here?
751                 }
752             }
753         }
754         trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
755
756         // See if we can avoid an allocation. This is the counterpart to `try_read_immediate`,
757         // but not factored as a separate function.
758         let mplace = match dest.place {
759             Place::Local { frame, local } => {
760                 match self.stack[frame].locals[local].access_mut()? {
761                     Ok(local) => {
762                         // Local can be updated in-place.
763                         *local = LocalValue::Live(Operand::Immediate(src));
764                         return Ok(());
765                     }
766                     Err(mplace) => {
767                         // The local is in memory, go on below.
768                         mplace
769                     }
770                 }
771             },
772             Place::Ptr(mplace) => mplace, // already referring to memory
773         };
774         let dest = MPlaceTy { mplace, layout: dest.layout };
775
776         // This is already in memory, write there.
777         self.write_immediate_to_mplace_no_validate(src, dest)
778     }
779
780     /// Write an immediate to memory.
781     /// If you use this you are responsible for validating that things got copied at the
782     /// right type.
783     fn write_immediate_to_mplace_no_validate(
784         &mut self,
785         value: Immediate<M::PointerTag>,
786         dest: MPlaceTy<'tcx, M::PointerTag>,
787     ) -> InterpResult<'tcx> {
788         // Note that it is really important that the type here is the right one, and matches the
789         // type things are read at. In case `src_val` is a `ScalarPair`, we don't do any magic here
790         // to handle padding properly, which is only correct if we never look at this data with the
791         // wrong type.
792
793         let ptr = match self.check_mplace_access(dest, None)
794             .expect("places should be checked on creation")
795         {
796             Some(ptr) => ptr,
797             None => return Ok(()), // zero-sized access
798         };
799
800         let tcx = &*self.tcx;
801         // FIXME: We should check that there are dest.layout.size many bytes available in
802         // memory.  The code below is not sufficient, with enough padding it might not
803         // cover all the bytes!
804         match value {
805             Immediate::Scalar(scalar) => {
806                 match dest.layout.abi {
807                     layout::Abi::Scalar(_) => {}, // fine
808                     _ => bug!("write_immediate_to_mplace: invalid Scalar layout: {:#?}",
809                             dest.layout)
810                 }
811                 self.memory.get_mut(ptr.alloc_id)?.write_scalar(
812                     tcx, ptr, scalar, dest.layout.size
813                 )
814             }
815             Immediate::ScalarPair(a_val, b_val) => {
816                 // We checked `ptr_align` above, so all fields will have the alignment they need.
817                 // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
818                 // which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
819                 let (a, b) = match dest.layout.abi {
820                     layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
821                     _ => bug!("write_immediate_to_mplace: invalid ScalarPair layout: {:#?}",
822                               dest.layout)
823                 };
824                 let (a_size, b_size) = (a.size(self), b.size(self));
825                 let b_offset = a_size.align_to(b.align(self).abi);
826                 let b_ptr = ptr.offset(b_offset, self)?;
827
828                 // It is tempting to verify `b_offset` against `layout.fields.offset(1)`,
829                 // but that does not work: We could be a newtype around a pair, then the
830                 // fields do not match the `ScalarPair` components.
831
832                 self.memory
833                     .get_mut(ptr.alloc_id)?
834                     .write_scalar(tcx, ptr, a_val, a_size)?;
835                 self.memory
836                     .get_mut(b_ptr.alloc_id)?
837                     .write_scalar(tcx, b_ptr, b_val, b_size)
838             }
839         }
840     }
841
842     /// Copies the data from an operand to a place. This does not support transmuting!
843     /// Use `copy_op_transmute` if the layouts could disagree.
844     #[inline(always)]
845     pub fn copy_op(
846         &mut self,
847         src: OpTy<'tcx, M::PointerTag>,
848         dest: PlaceTy<'tcx, M::PointerTag>,
849     ) -> InterpResult<'tcx> {
850         self.copy_op_no_validate(src, dest)?;
851
852         if M::enforce_validity(self) {
853             // Data got changed, better make sure it matches the type!
854             self.validate_operand(self.place_to_op(dest)?, vec![], None)?;
855         }
856
857         Ok(())
858     }
859
860     /// Copies the data from an operand to a place. This does not support transmuting!
861     /// Use `copy_op_transmute` if the layouts could disagree.
862     /// Also, if you use this you are responsible for validating that things get copied at the
863     /// right type.
864     fn copy_op_no_validate(
865         &mut self,
866         src: OpTy<'tcx, M::PointerTag>,
867         dest: PlaceTy<'tcx, M::PointerTag>,
868     ) -> InterpResult<'tcx> {
869         // We do NOT compare the types for equality, because well-typed code can
870         // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
871         assert!(src.layout.details == dest.layout.details,
872             "Layout mismatch when copying!\nsrc: {:#?}\ndest: {:#?}", src, dest);
873
874         // Let us see if the layout is simple so we take a shortcut, avoid force_allocation.
875         let src = match self.try_read_immediate(src)? {
876             Ok(src_val) => {
877                 assert!(!src.layout.is_unsized(), "cannot have unsized immediates");
878                 // Yay, we got a value that we can write directly.
879                 // FIXME: Add a check to make sure that if `src` is indirect,
880                 // it does not overlap with `dest`.
881                 return self.write_immediate_no_validate(*src_val, dest);
882             }
883             Err(mplace) => mplace,
884         };
885         // Slow path, this does not fit into an immediate. Just memcpy.
886         trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
887
888         // This interprets `src.meta` with the `dest` local's layout, if an unsized local
889         // is being initialized!
890         let (dest, size) = self.force_allocation_maybe_sized(dest, src.meta)?;
891         let size = size.unwrap_or_else(|| {
892             assert!(!dest.layout.is_unsized(),
893                 "Cannot copy into already initialized unsized place");
894             dest.layout.size
895         });
896         assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances");
897
898         let src = self.check_mplace_access(src, Some(size))
899             .expect("places should be checked on creation");
900         let dest = self.check_mplace_access(dest, Some(size))
901             .expect("places should be checked on creation");
902         let (src_ptr, dest_ptr) = match (src, dest) {
903             (Some(src_ptr), Some(dest_ptr)) => (src_ptr, dest_ptr),
904             (None, None) => return Ok(()), // zero-sized copy
905             _ => bug!("The pointers should both be Some or both None"),
906         };
907
908         self.memory.copy(
909             src_ptr,
910             dest_ptr,
911             size,
912             /*nonoverlapping*/ true,
913         )
914     }
915
916     /// Copies the data from an operand to a place. The layouts may disagree, but they must
917     /// have the same size.
918     pub fn copy_op_transmute(
919         &mut self,
920         src: OpTy<'tcx, M::PointerTag>,
921         dest: PlaceTy<'tcx, M::PointerTag>,
922     ) -> InterpResult<'tcx> {
923         if src.layout.details == dest.layout.details {
924             // Fast path: Just use normal `copy_op`
925             return self.copy_op(src, dest);
926         }
927         // We still require the sizes to match.
928         assert!(src.layout.size == dest.layout.size,
929             "Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest);
930         // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want
931         // to avoid that here.
932         assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(),
933             "Cannot transmute unsized data");
934
935         // The hard case is `ScalarPair`.  `src` is already read from memory in this case,
936         // using `src.layout` to figure out which bytes to use for the 1st and 2nd field.
937         // We have to write them to `dest` at the offsets they were *read at*, which is
938         // not necessarily the same as the offsets in `dest.layout`!
939         // Hence we do the copy with the source layout on both sides.  We also make sure to write
940         // into memory, because if `dest` is a local we would not even have a way to write
941         // at the `src` offsets; the fact that we came from a different layout would
942         // just be lost.
943         let dest = self.force_allocation(dest)?;
944         self.copy_op_no_validate(
945             src,
946             PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }),
947         )?;
948
949         if M::enforce_validity(self) {
950             // Data got changed, better make sure it matches the type!
951             self.validate_operand(dest.into(), vec![], None)?;
952         }
953
954         Ok(())
955     }
956
957     /// Ensures that a place is in memory, and returns where it is.
958     /// If the place currently refers to a local that doesn't yet have a matching allocation,
959     /// create such an allocation.
960     /// This is essentially `force_to_memplace`.
961     ///
962     /// This supports unsized types and returns the computed size to avoid some
963     /// redundant computation when copying; use `force_allocation` for a simpler, sized-only
964     /// version.
965     pub fn force_allocation_maybe_sized(
966         &mut self,
967         place: PlaceTy<'tcx, M::PointerTag>,
968         meta: Option<Scalar<M::PointerTag>>,
969     ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> {
970         let (mplace, size) = match place.place {
971             Place::Local { frame, local } => {
972                 match self.stack[frame].locals[local].access_mut()? {
973                     Ok(local_val) => {
974                         // We need to make an allocation.
975                         // FIXME: Consider not doing anything for a ZST, and just returning
976                         // a fake pointer?  Are we even called for ZST?
977
978                         // We cannot hold on to the reference `local_val` while allocating,
979                         // but we can hold on to the value in there.
980                         let old_val =
981                             if let LocalValue::Live(Operand::Immediate(value)) = *local_val {
982                                 Some(value)
983                             } else {
984                                 None
985                             };
986
987                         // We need the layout of the local.  We can NOT use the layout we got,
988                         // that might e.g., be an inner field of a struct with `Scalar` layout,
989                         // that has different alignment than the outer field.
990                         // We also need to support unsized types, and hence cannot use `allocate`.
991                         let local_layout = self.layout_of_local(&self.stack[frame], local, None)?;
992                         let (size, align) = self.size_and_align_of(meta, local_layout)?
993                             .expect("Cannot allocate for non-dyn-sized type");
994                         let ptr = self.memory.allocate(size, align, MemoryKind::Stack);
995                         let mplace = MemPlace { ptr: ptr.into(), align, meta };
996                         if let Some(value) = old_val {
997                             // Preserve old value.
998                             // We don't have to validate as we can assume the local
999                             // was already valid for its type.
1000                             let mplace = MPlaceTy { mplace, layout: local_layout };
1001                             self.write_immediate_to_mplace_no_validate(value, mplace)?;
1002                         }
1003                         // Now we can call `access_mut` again, asserting it goes well,
1004                         // and actually overwrite things.
1005                         *self.stack[frame].locals[local].access_mut().unwrap().unwrap() =
1006                             LocalValue::Live(Operand::Indirect(mplace));
1007                         (mplace, Some(size))
1008                     }
1009                     Err(mplace) => (mplace, None), // this already was an indirect local
1010                 }
1011             }
1012             Place::Ptr(mplace) => (mplace, None)
1013         };
1014         // Return with the original layout, so that the caller can go on
1015         Ok((MPlaceTy { mplace, layout: place.layout }, size))
1016     }
1017
1018     #[inline(always)]
1019     pub fn force_allocation(
1020         &mut self,
1021         place: PlaceTy<'tcx, M::PointerTag>,
1022     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
1023         Ok(self.force_allocation_maybe_sized(place, None)?.0)
1024     }
1025
1026     pub fn allocate(
1027         &mut self,
1028         layout: TyLayout<'tcx>,
1029         kind: MemoryKind<M::MemoryKinds>,
1030     ) -> MPlaceTy<'tcx, M::PointerTag> {
1031         let ptr = self.memory.allocate(layout.size, layout.align.abi, kind);
1032         MPlaceTy::from_aligned_ptr(ptr, layout)
1033     }
1034
1035     pub fn write_discriminant_index(
1036         &mut self,
1037         variant_index: VariantIdx,
1038         dest: PlaceTy<'tcx, M::PointerTag>,
1039     ) -> InterpResult<'tcx> {
1040         let variant_scalar = Scalar::from_u32(variant_index.as_u32()).into();
1041
1042         match dest.layout.variants {
1043             layout::Variants::Single { index } => {
1044                 if index != variant_index {
1045                     throw_ub!(InvalidDiscriminant(variant_scalar));
1046                 }
1047             }
1048             layout::Variants::Multiple {
1049                 discr_kind: layout::DiscriminantKind::Tag,
1050                 discr: ref discr_layout,
1051                 discr_index,
1052                 ..
1053             } => {
1054                 if !dest.layout.ty.variant_range(*self.tcx).unwrap().contains(&variant_index) {
1055                     throw_ub!(InvalidDiscriminant(variant_scalar));
1056                 }
1057                 let discr_val =
1058                     dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val;
1059
1060                 // raw discriminants for enums are isize or bigger during
1061                 // their computation, but the in-memory tag is the smallest possible
1062                 // representation
1063                 let size = discr_layout.value.size(self);
1064                 let discr_val = truncate(discr_val, size);
1065
1066                 let discr_dest = self.place_field(dest, discr_index as u64)?;
1067                 self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
1068             }
1069             layout::Variants::Multiple {
1070                 discr_kind: layout::DiscriminantKind::Niche {
1071                     dataful_variant,
1072                     ref niche_variants,
1073                     niche_start,
1074                 },
1075                 discr: ref discr_layout,
1076                 discr_index,
1077                 ..
1078             } => {
1079                 if !variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len() {
1080                     throw_ub!(InvalidDiscriminant(variant_scalar));
1081                 }
1082                 if variant_index != dataful_variant {
1083                     let variants_start = niche_variants.start().as_u32();
1084                     let variant_index_relative = variant_index.as_u32()
1085                         .checked_sub(variants_start)
1086                         .expect("overflow computing relative variant idx");
1087                     // We need to use machine arithmetic when taking into account `niche_start`:
1088                     // discr_val = variant_index_relative + niche_start_val
1089                     let discr_layout = self.layout_of(discr_layout.value.to_int_ty(*self.tcx))?;
1090                     let niche_start_val = ImmTy::from_uint(niche_start, discr_layout);
1091                     let variant_index_relative_val =
1092                         ImmTy::from_uint(variant_index_relative, discr_layout);
1093                     let discr_val = self.binary_op(
1094                         mir::BinOp::Add,
1095                         variant_index_relative_val,
1096                         niche_start_val,
1097                     )?;
1098                     // Write result.
1099                     let niche_dest = self.place_field(dest, discr_index as u64)?;
1100                     self.write_immediate(*discr_val, niche_dest)?;
1101                 }
1102             }
1103         }
1104
1105         Ok(())
1106     }
1107
1108     pub fn raw_const_to_mplace(
1109         &self,
1110         raw: RawConst<'tcx>,
1111     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
1112         // This must be an allocation in `tcx`
1113         assert!(self.tcx.alloc_map.lock().get(raw.alloc_id).is_some());
1114         let ptr = self.tag_static_base_pointer(Pointer::from(raw.alloc_id));
1115         let layout = self.layout_of(raw.ty)?;
1116         Ok(MPlaceTy::from_aligned_ptr(ptr, layout))
1117     }
1118
1119     /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
1120     /// Also return some more information so drop doesn't have to run the same code twice.
1121     pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx, M::PointerTag>)
1122     -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
1123         let vtable = mplace.vtable(); // also sanity checks the type
1124         let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
1125         let layout = self.layout_of(ty)?;
1126
1127         // More sanity checks
1128         if cfg!(debug_assertions) {
1129             let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
1130             assert_eq!(size, layout.size);
1131             // only ABI alignment is preserved
1132             assert_eq!(align, layout.align.abi);
1133         }
1134
1135         let mplace = MPlaceTy {
1136             mplace: MemPlace { meta: None, ..*mplace },
1137             layout
1138         };
1139         Ok((instance, mplace))
1140     }
1141 }