1 // Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Computations on places -- field projections, going from mir::Place, and writing
13 //! All high-level functions to write to memory work on places as destinations.
15 use std::convert::TryFrom;
18 use rustc::ich::StableHashingContext;
20 use rustc::ty::{self, Ty};
21 use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout};
22 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
24 use rustc::mir::interpret::{
25 GlobalId, AllocId, Scalar, EvalResult, Pointer, ScalarMaybeUndef, PointerArithmetic
27 use super::{EvalContext, Machine, Value, ValTy, Operand, OpTy, MemoryKind};
29 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
30 pub struct MemPlace<Id=AllocId> {
31 /// A place may have an integral pointer for ZSTs, and since it might
32 /// be turned back into a reference before ever being dereferenced.
33 /// However, it may never be undef.
36 /// Metadata for unsized places. Interpretation is up to the type.
37 /// Must not be present for sized types, but can be missing for unsized types
38 /// (e.g. `extern type`).
39 pub extra: Option<Scalar<Id>>,
42 impl_stable_hash_for!(struct ::interpret::MemPlace {
48 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
49 pub enum Place<Id=AllocId> {
50 /// A place referring to a value allocated in the `Memory` system.
53 /// To support alloc-free locals, we are able to write directly to a local.
54 /// (Without that optimization, we'd just always be a `MemPlace`.)
61 // Can't use the macro here because that does not support named enum fields.
62 impl<'a> HashStable<StableHashingContext<'a>> for Place {
63 fn hash_stable<W: StableHasherResult>(
64 &self, hcx: &mut StableHashingContext<'a>,
65 hasher: &mut StableHasher<W>)
67 mem::discriminant(self).hash_stable(hcx, hasher);
69 Place::Ptr(mem_place) => mem_place.hash_stable(hcx, hasher),
71 Place::Local { frame, local } => {
72 frame.hash_stable(hcx, hasher);
73 local.hash_stable(hcx, hasher);
78 #[derive(Copy, Clone, Debug)]
79 pub struct PlaceTy<'tcx> {
81 pub layout: TyLayout<'tcx>,
84 impl<'tcx> ::std::ops::Deref for PlaceTy<'tcx> {
87 fn deref(&self) -> &Place {
92 /// A MemPlace with its layout. Constructing it is only possible in this module.
93 #[derive(Copy, Clone, Debug)]
94 pub struct MPlaceTy<'tcx> {
96 pub layout: TyLayout<'tcx>,
99 impl<'tcx> ::std::ops::Deref for MPlaceTy<'tcx> {
100 type Target = MemPlace;
102 fn deref(&self) -> &MemPlace {
107 impl<'tcx> From<MPlaceTy<'tcx>> for PlaceTy<'tcx> {
109 fn from(mplace: MPlaceTy<'tcx>) -> Self {
111 place: Place::Ptr(mplace.mplace),
112 layout: mplace.layout
119 pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self {
128 pub fn from_ptr(ptr: Pointer, align: Align) -> Self {
129 Self::from_scalar_ptr(ptr.into(), align)
133 pub fn to_scalar_ptr_align(self) -> (Scalar, Align) {
134 assert_eq!(self.extra, None);
135 (self.ptr, self.align)
138 /// Extract the ptr part of the mplace
140 pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
141 // At this point, we forget about the alignment information --
142 // the place has been turned into a reference, and no matter where it came from,
143 // it now must be aligned.
144 self.to_scalar_ptr_align().0.to_ptr()
147 /// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
148 /// This is the inverse of `ref_to_mplace`.
149 pub fn to_ref(self) -> Value {
150 // We ignore the alignment of the place here -- special handling for packed structs ends
151 // at the `&` operator.
153 None => Value::Scalar(self.ptr.into()),
154 Some(extra) => Value::ScalarPair(self.ptr.into(), extra.into()),
159 impl<'tcx> MPlaceTy<'tcx> {
161 fn from_aligned_ptr(ptr: Pointer, layout: TyLayout<'tcx>) -> Self {
162 MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align), layout }
166 pub(super) fn len(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
167 if self.layout.is_unsized() {
168 // We need to consult `extra` metadata
169 match self.layout.ty.sty {
170 ty::Slice(..) | ty::Str =>
171 return self.extra.unwrap().to_usize(cx),
172 _ => bug!("len not supported on unsized type {:?}", self.layout.ty),
175 // Go through the layout. There are lots of types that support a length,
177 match self.layout.fields {
178 layout::FieldPlacement::Array { count, .. } => Ok(count),
179 _ => bug!("len not supported on sized type {:?}", self.layout.ty),
185 pub(super) fn vtable(self) -> EvalResult<'tcx, Pointer> {
186 match self.layout.ty.sty {
187 ty::Dynamic(..) => self.extra.unwrap().to_ptr(),
188 _ => bug!("vtable not supported on type {:?}", self.layout.ty),
193 impl<'tcx> OpTy<'tcx> {
195 pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx>, Value> {
197 Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
198 Operand::Immediate(value) => Err(value),
203 pub fn to_mem_place(self) -> MPlaceTy<'tcx> {
204 self.try_as_mplace().unwrap()
209 /// Produces a Place that will error if attempted to be read from or written to
211 pub fn null(cx: impl HasDataLayout) -> Self {
212 Self::from_scalar_ptr(Scalar::ptr_null(cx), Align::from_bytes(1, 1).unwrap())
216 pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self {
217 Place::Ptr(MemPlace::from_scalar_ptr(ptr, align))
221 pub fn from_ptr(ptr: Pointer, align: Align) -> Self {
222 Place::Ptr(MemPlace::from_ptr(ptr, align))
226 pub fn to_mem_place(self) -> MemPlace {
228 Place::Ptr(mplace) => mplace,
229 _ => bug!("to_mem_place: expected Place::Ptr, got {:?}", self),
235 pub fn to_scalar_ptr_align(self) -> (Scalar, Align) {
236 self.to_mem_place().to_scalar_ptr_align()
240 pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
241 self.to_mem_place().to_ptr()
245 impl<'tcx> PlaceTy<'tcx> {
246 /// Produces a Place that will error if attempted to be read from or written to
248 pub fn null(cx: impl HasDataLayout, layout: TyLayout<'tcx>) -> Self {
249 PlaceTy { place: Place::from_scalar_ptr(Scalar::ptr_null(cx), layout.align), layout }
253 pub fn to_mem_place(self) -> MPlaceTy<'tcx> {
254 MPlaceTy { mplace: self.place.to_mem_place(), layout: self.layout }
258 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
259 /// Take a value, which represents a (thin or fat) reference, and make it a place.
260 /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref`.
261 pub fn ref_to_mplace(
262 &self, val: ValTy<'tcx>
263 ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
264 let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty;
265 let layout = self.layout_of(pointee_type)?;
266 let align = layout.align;
267 let mplace = match *val {
268 Value::Scalar(ptr) =>
269 MemPlace { ptr: ptr.not_undef()?, align, extra: None },
270 Value::ScalarPair(ptr, extra) =>
271 MemPlace { ptr: ptr.not_undef()?, align, extra: Some(extra.not_undef()?) },
273 Ok(MPlaceTy { mplace, layout })
276 /// Offset a pointer to project to a field. Unlike place_field, this is always
277 /// possible without allocating, so it can take &self. Also return the field's layout.
278 /// This supports both struct and array fields.
282 base: MPlaceTy<'tcx>,
284 ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
285 // Not using the layout method because we want to compute on u64
286 let offset = match base.layout.fields {
287 layout::FieldPlacement::Arbitrary { ref offsets, .. } =>
288 offsets[usize::try_from(field).unwrap()],
289 layout::FieldPlacement::Array { stride, .. } => {
290 let len = base.len(self)?;
291 assert!(field < len, "Tried to access element {} of array/slice with length {}",
295 layout::FieldPlacement::Union(count) => {
296 assert!(field < count as u64,
297 "Tried to access field {} of union with {} fields", field, count);
298 // Offset is always 0
302 // the only way conversion can fail if is this is an array (otherwise we already panicked
303 // above). In that case, all fields are equal.
304 let field_layout = base.layout.field(self, usize::try_from(field).unwrap_or(0))?;
306 // Offset may need adjustment for unsized fields
307 let (extra, offset) = if field_layout.is_unsized() {
308 // re-use parent metadata to determine dynamic field layout
309 let (_, align) = self.size_and_align_of(base.extra, field_layout)?;
310 (base.extra, offset.abi_align(align))
313 // base.extra could be present; we might be accessing a sized field of an unsized
318 let ptr = base.ptr.ptr_offset(offset, self)?;
319 let align = base.align.min(field_layout.align); // only use static information
321 Ok(MPlaceTy { mplace: MemPlace { ptr, align, extra }, layout: field_layout })
324 // Iterates over all fields of an array. Much more efficient than doing the
325 // same by repeatedly calling `mplace_array`.
326 pub fn mplace_array_fields(
328 base: MPlaceTy<'tcx>,
329 ) -> EvalResult<'tcx, impl Iterator<Item=EvalResult<'tcx, MPlaceTy<'tcx>>> + 'a> {
330 let len = base.len(self)?; // also asserts that we have a type where this makes sense
331 let stride = match base.layout.fields {
332 layout::FieldPlacement::Array { stride, .. } => stride,
333 _ => bug!("mplace_array_fields: expected an array layout"),
335 let layout = base.layout.field(self, 0)?;
336 let dl = &self.tcx.data_layout;
337 Ok((0..len).map(move |i| {
338 let ptr = base.ptr.ptr_offset(i * stride, dl)?;
340 mplace: MemPlace { ptr, align: base.align, extra: None },
346 pub fn mplace_subslice(
348 base: MPlaceTy<'tcx>,
351 ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
352 let len = base.len(self)?; // also asserts that we have a type where this makes sense
353 assert!(from <= len - to);
355 // Not using layout method because that works with usize, and does not work with slices
356 // (that have count 0 in their layout).
357 let from_offset = match base.layout.fields {
358 layout::FieldPlacement::Array { stride, .. } =>
360 _ => bug!("Unexpected layout of index access: {:#?}", base.layout),
362 let ptr = base.ptr.ptr_offset(from_offset, self)?;
364 // Compute extra and new layout
365 let inner_len = len - to - from;
366 let (extra, ty) = match base.layout.ty.sty {
367 // It is not nice to match on the type, but that seems to be the only way to
369 ty::Array(inner, _) =>
370 (None, self.tcx.mk_array(inner, inner_len)),
372 let len = Scalar::from_uint(inner_len, self.pointer_size());
373 (Some(len), base.layout.ty)
376 bug!("cannot subslice non-array type: `{:?}`", base.layout.ty),
378 let layout = self.layout_of(ty)?;
381 mplace: MemPlace { ptr, align: base.align, extra },
386 pub fn mplace_downcast(
388 base: MPlaceTy<'tcx>,
390 ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
391 // Downcasts only change the layout
392 assert_eq!(base.extra, None);
393 Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
396 /// Project into an mplace
397 pub fn mplace_projection(
399 base: MPlaceTy<'tcx>,
400 proj_elem: &mir::PlaceElem<'tcx>,
401 ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
402 use rustc::mir::ProjectionElem::*;
403 Ok(match *proj_elem {
404 Field(field, _) => self.mplace_field(base, field.index() as u64)?,
405 Downcast(_, variant) => self.mplace_downcast(base, variant)?,
406 Deref => self.deref_operand(base.into())?,
409 let n = *self.frame().locals[local].access()?;
410 let n_layout = self.layout_of(self.tcx.types.usize)?;
411 let n = self.read_scalar(OpTy { op: n, layout: n_layout })?;
412 let n = n.to_bits(self.tcx.data_layout.pointer_size)?;
413 self.mplace_field(base, u64::try_from(n).unwrap())?
421 let n = base.len(self)?;
422 assert!(n >= min_length as u64);
424 let index = if from_end {
425 n - u64::from(offset)
430 self.mplace_field(base, index)?
433 Subslice { from, to } =>
434 self.mplace_subslice(base, u64::from(from), u64::from(to))?,
438 /// Get the place of a field inside the place, and also the field's type.
439 /// Just a convenience function, but used quite a bit.
444 ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
445 // FIXME: We could try to be smarter and avoid allocation for fields that span the
447 let mplace = self.force_allocation(base)?;
448 Ok(self.mplace_field(mplace, field)?.into())
451 pub fn place_downcast(
455 ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
456 // Downcast just changes the layout
457 Ok(match base.place {
458 Place::Ptr(mplace) =>
459 self.mplace_downcast(MPlaceTy { mplace, layout: base.layout }, variant)?.into(),
460 Place::Local { .. } => {
461 let layout = base.layout.for_variant(&self, variant);
462 PlaceTy { layout, ..base }
467 /// Project into a place
468 pub fn place_projection(
471 proj_elem: &mir::ProjectionElem<'tcx, mir::Local, Ty<'tcx>>,
472 ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
473 use rustc::mir::ProjectionElem::*;
474 Ok(match *proj_elem {
475 Field(field, _) => self.place_field(base, field.index() as u64)?,
476 Downcast(_, variant) => self.place_downcast(base, variant)?,
477 Deref => self.deref_operand(self.place_to_op(base)?)?.into(),
478 // For the other variants, we have to force an allocation.
479 // This matches `operand_projection`.
480 Subslice { .. } | ConstantIndex { .. } | Index(_) => {
481 let mplace = self.force_allocation(base)?;
482 self.mplace_projection(mplace, proj_elem)?.into()
487 /// Evaluate statics and promoteds to an `MPlace`. Used to share some code between
488 /// `eval_place` and `eval_place_to_op`.
489 pub(super) fn eval_place_to_mplace(
491 mir_place: &mir::Place<'tcx>
492 ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
493 use rustc::mir::Place::*;
494 Ok(match *mir_place {
495 Promoted(ref promoted) => {
496 let instance = self.frame().instance;
497 let op = self.global_to_op(GlobalId {
499 promoted: Some(promoted.0),
501 let mplace = op.to_mem_place(); // these are always in memory
502 let ty = self.monomorphize(promoted.1, self.substs());
505 layout: self.layout_of(ty)?,
509 Static(ref static_) => {
510 let ty = self.monomorphize(static_.ty, self.substs());
511 let layout = self.layout_of(ty)?;
512 let instance = ty::Instance::mono(*self.tcx, static_.def_id);
517 // Just create a lazy reference, so we can support recursive statics.
518 // tcx takes are of assigning every static one and only one unique AllocId.
519 // When the data here is ever actually used, memory will notice,
520 // and it knows how to deal with alloc_id that are present in the
521 // global table but not in its local memory: It calls back into tcx through
522 // a query, triggering the CTFE machinery to actually turn this lazy reference
523 // into a bunch of bytes. IOW, statics are evaluated with CTFE even when
524 // this EvalContext uses another Machine (e.g., in miri). This is what we
525 // want! This way, computing statics works concistently between codegen
526 // and miri: They use the same query to eventually obtain a `ty::Const`
527 // and use that for further computation.
528 let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
529 MPlaceTy::from_aligned_ptr(alloc.into(), layout)
532 _ => bug!("eval_place_to_mplace called on {:?}", mir_place),
536 /// Compute a place. You should only use this if you intend to write into this
537 /// place; for reading, a more efficient alternative is `eval_place_for_read`.
538 pub fn eval_place(&mut self, mir_place: &mir::Place<'tcx>) -> EvalResult<'tcx, PlaceTy<'tcx>> {
539 use rustc::mir::Place::*;
540 let place = match *mir_place {
541 Local(mir::RETURN_PLACE) => PlaceTy {
542 place: self.frame().return_place,
543 layout: self.layout_of_local(self.cur_frame(), mir::RETURN_PLACE)?,
545 Local(local) => PlaceTy {
546 place: Place::Local {
547 frame: self.cur_frame(),
550 layout: self.layout_of_local(self.cur_frame(), local)?,
553 Projection(ref proj) => {
554 let place = self.eval_place(&proj.base)?;
555 self.place_projection(place, &proj.elem)?
558 _ => self.eval_place_to_mplace(mir_place)?.into(),
561 self.dump_place(place.place);
565 /// Write a scalar to a place
568 val: impl Into<ScalarMaybeUndef>,
570 ) -> EvalResult<'tcx> {
571 self.write_value(Value::Scalar(val.into()), dest)
574 /// Write a value to a place
579 ) -> EvalResult<'tcx> {
580 trace!("write_value: {:?} <- {:?}", *dest, src_val);
581 // See if we can avoid an allocation. This is the counterpart to `try_read_value`,
582 // but not factored as a separate function.
583 let mplace = match dest.place {
584 Place::Local { frame, local } => {
585 match *self.stack[frame].locals[local].access_mut()? {
586 Operand::Immediate(ref mut dest_val) => {
587 // Yay, we can just change the local directly.
591 Operand::Indirect(mplace) => mplace, // already in memory
594 Place::Ptr(mplace) => mplace, // already in memory
597 // This is already in memory, write there.
598 let dest = MPlaceTy { mplace, layout: dest.layout };
599 self.write_value_to_mplace(src_val, dest)
602 /// Write a value to memory
603 fn write_value_to_mplace(
606 dest: MPlaceTy<'tcx>,
607 ) -> EvalResult<'tcx> {
608 let (ptr, ptr_align) = dest.to_scalar_ptr_align();
609 // Note that it is really important that the type here is the right one, and matches the
610 // type things are read at. In case `src_val` is a `ScalarPair`, we don't do any magic here
611 // to handle padding properly, which is only correct if we never look at this data with the
614 // Nothing to do for ZSTs, other than checking alignment
615 if dest.layout.size.bytes() == 0 {
616 self.memory.check_align(ptr, ptr_align)?;
620 let ptr = ptr.to_ptr()?;
622 Value::Scalar(scalar) => {
623 self.memory.write_scalar(
624 ptr, ptr_align.min(dest.layout.align), scalar, dest.layout.size
627 Value::ScalarPair(a_val, b_val) => {
628 let (a, b) = match dest.layout.abi {
629 layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
630 _ => bug!("write_value_to_mplace: invalid ScalarPair layout: {:#?}",
633 let (a_size, b_size) = (a.size(&self), b.size(&self));
634 let (a_align, b_align) = (a.align(&self), b.align(&self));
635 let b_offset = a_size.abi_align(b_align);
636 let b_ptr = ptr.offset(b_offset, &self)?.into();
638 self.memory.write_scalar(ptr, ptr_align.min(a_align), a_val, a_size)?;
639 self.memory.write_scalar(b_ptr, ptr_align.min(b_align), b_val, b_size)
644 /// Copy the data from an operand to a place
649 ) -> EvalResult<'tcx> {
650 assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(),
651 "Cannot copy unsized data");
652 assert_eq!(src.layout.size, dest.layout.size,
653 "Size mismatch when copying!\nsrc: {:#?}\ndest: {:#?}", src, dest);
655 // Let us see if the layout is simple so we take a shortcut, avoid force_allocation.
656 let (src_ptr, src_align) = match self.try_read_value(src)? {
658 // Yay, we got a value that we can write directly. We write with the
659 // *source layout*, because that was used to load, and if they do not match
660 // this is a transmute we want to support.
661 return self.write_value(src_val, PlaceTy { place: *dest, layout: src.layout }),
662 Err(mplace) => mplace.to_scalar_ptr_align(),
664 // Slow path, this does not fit into an immediate. Just memcpy.
665 trace!("copy_op: {:?} <- {:?}", *dest, *src);
666 let (dest_ptr, dest_align) = self.force_allocation(dest)?.to_scalar_ptr_align();
669 dest_ptr, dest_align,
670 src.layout.size, false
674 /// Make sure that a place is in memory, and return where it is.
675 /// This is essentially `force_to_memplace`.
676 pub fn force_allocation(
678 place: PlaceTy<'tcx>,
679 ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
680 let mplace = match place.place {
681 Place::Local { frame, local } => {
682 match *self.stack[frame].locals[local].access()? {
683 Operand::Indirect(mplace) => mplace,
684 Operand::Immediate(value) => {
685 // We need to make an allocation.
686 // FIXME: Consider not doing anything for a ZST, and just returning
687 // a fake pointer? Are we even called for ZST?
689 // We need the layout of the local. We can NOT use the layout we got,
690 // that might e.g. be an inner field of a struct with `Scalar` layout,
691 // that has different alignment than the outer field.
692 let local_layout = self.layout_of_local(frame, local)?;
693 let ptr = self.allocate(local_layout, MemoryKind::Stack)?;
694 self.write_value_to_mplace(value, ptr)?;
695 let mplace = ptr.mplace;
697 *self.stack[frame].locals[local].access_mut()? =
698 Operand::Indirect(mplace);
703 Place::Ptr(mplace) => mplace
705 // Return with the original layout, so that the caller can go on
706 Ok(MPlaceTy { mplace, layout: place.layout })
711 layout: TyLayout<'tcx>,
712 kind: MemoryKind<M::MemoryKinds>,
713 ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
714 assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
715 let ptr = self.memory.allocate(layout.size, layout.align, kind)?;
716 Ok(MPlaceTy::from_aligned_ptr(ptr, layout))
719 pub fn write_discriminant_index(
721 variant_index: usize,
723 ) -> EvalResult<'tcx> {
724 match dest.layout.variants {
725 layout::Variants::Single { index } => {
726 assert_eq!(index, variant_index);
728 layout::Variants::Tagged { ref tag, .. } => {
729 let adt_def = dest.layout.ty.ty_adt_def().unwrap();
730 assert!(variant_index < adt_def.variants.len());
731 let discr_val = adt_def
732 .discriminant_for_variant(*self.tcx, variant_index)
735 // raw discriminants for enums are isize or bigger during
736 // their computation, but the in-memory tag is the smallest possible
738 let size = tag.value.size(self.tcx.tcx);
739 let shift = 128 - size.bits();
740 let discr_val = (discr_val << shift) >> shift;
742 let discr_dest = self.place_field(dest, 0)?;
743 self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
745 layout::Variants::NicheFilling {
751 assert!(variant_index < dest.layout.ty.ty_adt_def().unwrap().variants.len());
752 if variant_index != dataful_variant {
754 self.place_field(dest, 0)?;
755 let niche_value = ((variant_index - niche_variants.start()) as u128)
756 .wrapping_add(niche_start);
758 Scalar::from_uint(niche_value, niche_dest.layout.size),
768 /// Every place can be read from, so we can turm them into an operand
770 pub fn place_to_op(&self, place: PlaceTy<'tcx>) -> EvalResult<'tcx, OpTy<'tcx>> {
771 let op = match place.place {
772 Place::Ptr(mplace) => {
773 Operand::Indirect(mplace)
775 Place::Local { frame, local } =>
776 *self.stack[frame].locals[local].access()?
778 Ok(OpTy { op, layout: place.layout })
781 /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
782 /// Also return some more information so drop doesn't have to run the same code twice.
783 pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx>)
784 -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx>)> {
785 let vtable = mplace.vtable()?; // also sanity checks the type
786 let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
787 let layout = self.layout_of(ty)?;
789 // More sanity checks
790 if cfg!(debug_assertions) {
791 let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
792 assert_eq!(size, layout.size);
793 assert_eq!(align.abi(), layout.align.abi()); // only ABI alignment is preserved
796 let mplace = MPlaceTy {
797 mplace: MemPlace { extra: None, ..*mplace },
800 Ok((instance, mplace))