place.rs 39.6 KB
Newer Older
R
Ralf Jung 已提交
1 2 3 4 5
//! Computations on places -- field projections, going from mir::Place, and writing
//! into a place.
//! All high-level functions to write to memory work on places as destinations.

use std::convert::TryFrom;
6
use std::hash::Hash;
R
Ralf Jung 已提交
7

8
use rustc::hir;
9
use rustc::mir;
R
Ralf Jung 已提交
10
use rustc::ty::{self, Ty};
11
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx};
12
use rustc::ty::TypeFoldable;
O
Oliver Schneider 已提交
13

14
use super::{
15
    GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic,
O
Fallout  
Oliver Scherer 已提交
16
    EvalContext, Machine, AllocMap, AllocationExtra,
17
    RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind
R
Ralf Jung 已提交
18 19 20
};

#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
21
pub struct MemPlace<Tag=(), Id=AllocId> {
R
Ralf Jung 已提交
22 23 24
    /// A place may have an integral pointer for ZSTs, and since it might
    /// be turned back into a reference before ever being dereferenced.
    /// However, it may never be undef.
25
    pub ptr: Scalar<Tag, Id>,
26
    pub align: Align,
A
Alexander Regueiro 已提交
27
    /// Metadata for unsized places. Interpretation is up to the type.
R
Ralf Jung 已提交
28
    /// Must not be present for sized types, but can be missing for unsized types
29
    /// (e.g., `extern type`).
R
Ralf Jung 已提交
30
    pub meta: Option<Scalar<Tag, Id>>,
R
Ralf Jung 已提交
31
}
O
Oliver Schneider 已提交
32

33
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
34
pub enum Place<Tag=(), Id=AllocId> {
35
    /// A place referring to a value allocated in the `Memory` system.
36
    Ptr(MemPlace<Tag, Id>),
O
Oliver Schneider 已提交
37

R
Ralf Jung 已提交
38 39 40 41 42 43
    /// To support alloc-free locals, we are able to write directly to a local.
    /// (Without that optimization, we'd just always be a `MemPlace`.)
    Local {
        frame: usize,
        local: mir::Local,
    },
O
Oliver Schneider 已提交
44 45
}

R
Ralf Jung 已提交
46
#[derive(Copy, Clone, Debug)]
47 48
pub struct PlaceTy<'tcx, Tag=()> {
    place: Place<Tag>,
R
Ralf Jung 已提交
49 50 51
    pub layout: TyLayout<'tcx>,
}

52 53
impl<'tcx, Tag> ::std::ops::Deref for PlaceTy<'tcx, Tag> {
    type Target = Place<Tag>;
54
    #[inline(always)]
55
    fn deref(&self) -> &Place<Tag> {
R
Ralf Jung 已提交
56 57 58 59 60 61
        &self.place
    }
}

/// A MemPlace with its layout. Constructing it is only possible in this module.
#[derive(Copy, Clone, Debug)]
62 63
pub struct MPlaceTy<'tcx, Tag=()> {
    mplace: MemPlace<Tag>,
R
Ralf Jung 已提交
64 65 66
    pub layout: TyLayout<'tcx>,
}

67 68
impl<'tcx, Tag> ::std::ops::Deref for MPlaceTy<'tcx, Tag> {
    type Target = MemPlace<Tag>;
69
    #[inline(always)]
70
    fn deref(&self) -> &MemPlace<Tag> {
R
Ralf Jung 已提交
71
        &self.mplace
O
Oliver Schneider 已提交
72
    }
R
Ralf Jung 已提交
73 74
}

75
impl<'tcx, Tag> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
76
    #[inline(always)]
77
    fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
R
Ralf Jung 已提交
78 79 80 81 82 83
        PlaceTy {
            place: Place::Ptr(mplace.mplace),
            layout: mplace.layout
        }
    }
}
O
Oliver Schneider 已提交
84

R
Ralf Jung 已提交
85
impl MemPlace {
86 87 88 89 90 91 92
    #[inline]
    pub fn with_default_tag<Tag>(self) -> MemPlace<Tag>
        where Tag: Default
    {
        MemPlace {
            ptr: self.ptr.with_default_tag(),
            align: self.align,
R
Ralf Jung 已提交
93
            meta: self.meta.map(Scalar::with_default_tag),
94 95 96 97 98 99 100 101 102 103 104
        }
    }
}

impl<Tag> MemPlace<Tag> {
    #[inline]
    pub fn erase_tag(self) -> MemPlace
    {
        MemPlace {
            ptr: self.ptr.erase_tag(),
            align: self.align,
R
Ralf Jung 已提交
105
            meta: self.meta.map(Scalar::erase_tag),
106 107 108
        }
    }

109 110 111 112 113 114 115 116 117 118
    #[inline]
    pub fn with_tag(self, new_tag: Tag) -> Self
    {
        MemPlace {
            ptr: self.ptr.with_tag(new_tag),
            align: self.align,
            meta: self.meta,
        }
    }

R
Ralf Jung 已提交
119
    #[inline(always)]
120
    pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
R
Ralf Jung 已提交
121
        MemPlace {
122 123
            ptr,
            align,
R
Ralf Jung 已提交
124
            meta: None,
O
Oliver Schneider 已提交
125 126 127
        }
    }

128 129
    /// Produces a Place that will error if attempted to be read from or written to
    #[inline(always)]
130
    pub fn null(cx: &impl HasDataLayout) -> Self {
131
        Self::from_scalar_ptr(Scalar::ptr_null(cx), Align::from_bytes(1).unwrap())
132 133
    }

R
Ralf Jung 已提交
134
    #[inline(always)]
135
    pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
R
Ralf Jung 已提交
136 137 138 139
        Self::from_scalar_ptr(ptr.into(), align)
    }

    #[inline(always)]
140
    pub fn to_scalar_ptr_align(self) -> (Scalar<Tag>, Align) {
R
Ralf Jung 已提交
141
        assert!(self.meta.is_none());
R
Ralf Jung 已提交
142 143 144
        (self.ptr, self.align)
    }

R
Ralf Jung 已提交
145
    /// metact the ptr part of the mplace
R
Ralf Jung 已提交
146
    #[inline(always)]
147
    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
B
Bernardo Meurer 已提交
148 149 150
        // At this point, we forget about the alignment information --
        // the place has been turned into a reference, and no matter where it came from,
        // it now must be aligned.
R
Ralf Jung 已提交
151 152
        self.to_scalar_ptr_align().0.to_ptr()
    }
153 154 155 156 157 158 159 160 161 162

    /// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
    /// This is the inverse of `ref_to_mplace`.
    #[inline(always)]
    pub fn to_ref(self) -> Immediate<Tag> {
        match self.meta {
            None => Immediate::Scalar(self.ptr.into()),
            Some(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()),
        }
    }
163 164 165 166 167 168 169 170 171 172 173 174 175

    pub fn offset(
        self,
        offset: Size,
        meta: Option<Scalar<Tag>>,
        cx: &impl HasDataLayout,
    ) -> EvalResult<'tcx, Self> {
        Ok(MemPlace {
            ptr: self.ptr.ptr_offset(offset, cx)?,
            align: self.align.restrict_for_offset(offset),
            meta,
        })
    }
R
Ralf Jung 已提交
176 177
}

178
impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
R
Ralf Jung 已提交
179 180
    /// Produces a MemPlace that works for ZST but nothing else
    #[inline]
181
    pub fn dangling(layout: TyLayout<'tcx>, cx: &impl HasDataLayout) -> Self {
R
Ralf Jung 已提交
182 183
        MPlaceTy {
            mplace: MemPlace::from_scalar_ptr(
184
                Scalar::from_uint(layout.align.abi.bytes(), cx.pointer_size()),
185
                layout.align.abi
R
Ralf Jung 已提交
186 187 188 189 190
            ),
            layout
        }
    }

191 192 193 194 195 196 197 198 199 200
    #[inline]
    pub fn with_tag(self, new_tag: Tag) -> Self
    {
        MPlaceTy {
            mplace: self.mplace.with_tag(new_tag),
            layout: self.layout,
        }
    }

    #[inline]
201 202 203 204 205 206 207 208 209 210 211 212 213
    pub fn offset(
        self,
        offset: Size,
        meta: Option<Scalar<Tag>>,
        layout: TyLayout<'tcx>,
        cx: &impl HasDataLayout,
    ) -> EvalResult<'tcx, Self> {
        Ok(MPlaceTy {
            mplace: self.mplace.offset(offset, meta, cx)?,
            layout,
        })
    }

R
Ralf Jung 已提交
214
    #[inline]
215
    fn from_aligned_ptr(ptr: Pointer<Tag>, layout: TyLayout<'tcx>) -> Self {
216
        MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align.abi), layout }
R
Ralf Jung 已提交
217 218 219
    }

    #[inline]
220
    pub(super) fn len(self, cx: &impl HasDataLayout) -> EvalResult<'tcx, u64> {
221
        if self.layout.is_unsized() {
R
Ralf Jung 已提交
222
            // We need to consult `meta` metadata
223 224
            match self.layout.ty.sty {
                ty::Slice(..) | ty::Str =>
R
Ralf Jung 已提交
225
                    return self.mplace.meta.unwrap().to_usize(cx),
226
                _ => bug!("len not supported on unsized type {:?}", self.layout.ty),
227
            }
228 229
        } else {
            // Go through the layout.  There are lots of types that support a length,
230
            // e.g., SIMD types.
231 232 233
            match self.layout.fields {
                layout::FieldPlacement::Array { count, .. } => Ok(count),
                _ => bug!("len not supported on sized type {:?}", self.layout.ty),
234 235 236 237 238
            }
        }
    }

    #[inline]
239
    pub(super) fn vtable(self) -> EvalResult<'tcx, Pointer<Tag>> {
240
        match self.layout.ty.sty {
R
Ralf Jung 已提交
241
            ty::Dynamic(..) => self.mplace.meta.unwrap().to_ptr(),
242
            _ => bug!("vtable not supported on type {:?}", self.layout.ty),
R
Ralf Jung 已提交
243 244 245 246
        }
    }
}

247
impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> {
248
    #[inline(always)]
249
    pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx, Tag>, Immediate<Tag>> {
250
        match *self {
R
Ralf Jung 已提交
251
            Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
252
            Operand::Immediate(imm) => Err(imm),
R
Ralf Jung 已提交
253 254 255
        }
    }

256
    #[inline(always)]
257
    pub fn to_mem_place(self) -> MPlaceTy<'tcx, Tag> {
R
Ralf Jung 已提交
258 259 260 261
        self.try_as_mplace().unwrap()
    }
}

262
impl<'tcx, Tag: ::std::fmt::Debug> Place<Tag> {
R
Ralf Jung 已提交
263
    /// Produces a Place that will error if attempted to be read from or written to
264
    #[inline(always)]
265
    pub fn null(cx: &impl HasDataLayout) -> Self {
266
        Place::Ptr(MemPlace::null(cx))
R
Ralf Jung 已提交
267 268
    }

269
    #[inline(always)]
270
    pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
R
Ralf Jung 已提交
271 272 273
        Place::Ptr(MemPlace::from_scalar_ptr(ptr, align))
    }

274
    #[inline(always)]
275
    pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
R
Ralf Jung 已提交
276
        Place::Ptr(MemPlace::from_ptr(ptr, align))
O
Oliver Schneider 已提交
277 278
    }

R
Ralf Jung 已提交
279
    #[inline]
280
    pub fn to_mem_place(self) -> MemPlace<Tag> {
O
Oliver Schneider 已提交
281
        match self {
R
Ralf Jung 已提交
282 283
            Place::Ptr(mplace) => mplace,
            _ => bug!("to_mem_place: expected Place::Ptr, got {:?}", self),
O
Oliver Schneider 已提交
284 285 286 287

        }
    }

R
Ralf Jung 已提交
288
    #[inline]
289
    pub fn to_scalar_ptr_align(self) -> (Scalar<Tag>, Align) {
R
Ralf Jung 已提交
290
        self.to_mem_place().to_scalar_ptr_align()
291
    }
292

R
Ralf Jung 已提交
293
    #[inline]
294
    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
R
Ralf Jung 已提交
295 296 297
        self.to_mem_place().to_ptr()
    }
}
O
Oliver Schneider 已提交
298

299
impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> {
R
Ralf Jung 已提交
300
    #[inline]
301
    pub fn to_mem_place(self) -> MPlaceTy<'tcx, Tag> {
R
Ralf Jung 已提交
302
        MPlaceTy { mplace: self.place.to_mem_place(), layout: self.layout }
O
Oliver Schneider 已提交
303 304 305
    }
}

306
// separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385
307 308
impl<'a, 'mir, 'tcx, Tag, M> EvalContext<'a, 'mir, 'tcx, M>
where
R
Ralf Jung 已提交
309
    // FIXME: Working around https://github.com/rust-lang/rust/issues/54385
310 311
    Tag: ::std::fmt::Debug+Default+Copy+Eq+Hash+'static,
    M: Machine<'a, 'mir, 'tcx, PointerTag=Tag>,
R
Ralf Jung 已提交
312
    // FIXME: Working around https://github.com/rust-lang/rust/issues/24159
313
    M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag, M::AllocExtra>)>,
R
Ralf Jung 已提交
314
    M::AllocExtra: AllocationExtra<Tag, M::MemoryExtra>,
315
{
R
Ralf Jung 已提交
316
    /// Take a value, which represents a (thin or fat) reference, and make it a place.
317
    /// Alignment is just based on the type.  This is the inverse of `MemPlace::to_ref()`.
318 319
    /// This does NOT call the "deref" machine hook, so it does NOT count as a
    /// deref as far as Stacked Borrows is concerned.  Use `deref_operand` for that!
R
Ralf Jung 已提交
320
    pub fn ref_to_mplace(
321
        &self,
322
        val: ImmTy<'tcx, M::PointerTag>,
323
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
324 325 326
        let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty;
        let layout = self.layout_of(pointee_type)?;

327 328
        let mplace = MemPlace {
            ptr: val.to_scalar_ptr()?,
329
            align: layout.align.abi,
330 331 332
            meta: val.to_meta()?,
        };
        Ok(MPlaceTy { mplace, layout })
R
Ralf Jung 已提交
333 334
    }

335 336 337 338 339 340 341 342 343 344 345
    // Take an operand, representing a pointer, and dereference it to a place -- that
    // will always be a MemPlace.  Lives in `place.rs` because it creates a place.
    // This calls the "deref" machine hook, and counts as a deref as far as
    // Stacked Borrows is concerned.
    pub fn deref_operand(
        &self,
        src: OpTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
        let val = self.read_immediate(src)?;
        trace!("deref to {} on {:?}", val.layout.ty, *val);
        let mut place = self.ref_to_mplace(val)?;
346
        // Pointer tag tracking might want to adjust the tag.
347 348 349 350 351 352 353
        let mutbl = match val.layout.ty.sty {
            // `builtin_deref` considers boxes immutable, that's useless for our purposes
            ty::Ref(_, _, mutbl) => Some(mutbl),
            ty::Adt(def, _) if def.is_box() => Some(hir::MutMutable),
            ty::RawPtr(_) => None,
            _ => bug!("Unexpected pointer type {}", val.layout.ty.sty),
        };
354 355
        place.mplace.ptr = M::tag_dereference(self, place, mutbl)?;
        Ok(place)
356 357
    }

R
Ralf Jung 已提交
358 359 360 361 362
    /// Offset a pointer to project to a field. Unlike place_field, this is always
    /// possible without allocating, so it can take &self. Also return the field's layout.
    /// This supports both struct and array fields.
    #[inline(always)]
    pub fn mplace_field(
O
Oliver Schneider 已提交
363
        &self,
364
        base: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
365
        field: u64,
366
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
367 368 369 370 371
        // Not using the layout method because we want to compute on u64
        let offset = match base.layout.fields {
            layout::FieldPlacement::Arbitrary { ref offsets, .. } =>
                offsets[usize::try_from(field).unwrap()],
            layout::FieldPlacement::Array { stride, .. } => {
372 373 374
                let len = base.len(self)?;
                assert!(field < len, "Tried to access element {} of array/slice with length {}",
                    field, len);
R
Ralf Jung 已提交
375 376
                stride * field
            }
377
            layout::FieldPlacement::Union(count) => {
B
Bernardo Meurer 已提交
378 379
                assert!(field < count as u64,
                        "Tried to access field {} of union with {} fields", field, count);
380 381 382
                // Offset is always 0
                Size::from_bytes(0)
            }
R
Ralf Jung 已提交
383 384 385
        };
        // the only way conversion can fail if is this is an array (otherwise we already panicked
        // above). In that case, all fields are equal.
R
Ralf Jung 已提交
386
        let field_layout = base.layout.field(self, usize::try_from(field).unwrap_or(0))?;
R
Ralf Jung 已提交
387

388
        // Offset may need adjustment for unsized fields
R
Ralf Jung 已提交
389
        let (meta, offset) = if field_layout.is_unsized() {
390
            // re-use parent metadata to determine dynamic field layout
391 392 393 394 395 396 397
            let align = match self.size_and_align_of(base.meta, field_layout)? {
                Some((_, align)) => align,
                None if offset == Size::ZERO =>
                    // An extern type at offset 0, we fall back to its static alignment.
                    // FIXME: Once we have made decisions for how to handle size and alignment
                    // of `extern type`, this should be adapted.  It is just a temporary hack
                    // to get some code to work that probably ought to work.
398
                    field_layout.align.abi,
399 400 401
                None =>
                    bug!("Cannot compute offset for extern type field at non-0 offset"),
            };
402
            (base.meta, offset.align_to(align))
R
Ralf Jung 已提交
403
        } else {
R
Ralf Jung 已提交
404
            // base.meta could be present; we might be accessing a sized field of an unsized
405 406
            // struct.
            (None, offset)
R
Ralf Jung 已提交
407 408
        };

409 410 411
        // We do not look at `base.layout.align` nor `field_layout.align`, unlike
        // codegen -- mostly to see if we can get away with that
        base.offset(offset, meta, field_layout, self)
O
Oliver Schneider 已提交
412 413
    }

414 415 416 417
    // Iterates over all fields of an array. Much more efficient than doing the
    // same by repeatedly calling `mplace_array`.
    pub fn mplace_array_fields(
        &self,
418 419 420 421
        base: MPlaceTy<'tcx, Tag>,
    ) ->
        EvalResult<'tcx, impl Iterator<Item=EvalResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
    {
422
        let len = base.len(self)?; // also asserts that we have a type where this makes sense
423 424 425 426 427 428
        let stride = match base.layout.fields {
            layout::FieldPlacement::Array { stride, .. } => stride,
            _ => bug!("mplace_array_fields: expected an array layout"),
        };
        let layout = base.layout.field(self, 0)?;
        let dl = &self.tcx.data_layout;
429
        Ok((0..len).map(move |i| base.offset(i * stride, None, layout, dl)))
430 431
    }

R
Ralf Jung 已提交
432
    pub fn mplace_subslice(
O
Oliver Schneider 已提交
433
        &self,
434
        base: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
435 436
        from: u64,
        to: u64,
437
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
438
        let len = base.len(self)?; // also asserts that we have a type where this makes sense
R
Ralf Jung 已提交
439 440 441 442 443 444 445 446
        assert!(from <= len - to);

        // Not using layout method because that works with usize, and does not work with slices
        // (that have count 0 in their layout).
        let from_offset = match base.layout.fields {
            layout::FieldPlacement::Array { stride, .. } =>
                stride * from,
            _ => bug!("Unexpected layout of index access: {:#?}", base.layout),
O
Oliver Schneider 已提交
447
        };
R
Ralf Jung 已提交
448

R
Ralf Jung 已提交
449
        // Compute meta and new layout
R
Ralf Jung 已提交
450
        let inner_len = len - to - from;
R
Ralf Jung 已提交
451
        let (meta, ty) = match base.layout.ty.sty {
R
Ralf Jung 已提交
452 453
            // It is not nice to match on the type, but that seems to be the only way to
            // implement this.
V
varkor 已提交
454
            ty::Array(inner, _) =>
455 456
                (None, self.tcx.mk_array(inner, inner_len)),
            ty::Slice(..) => {
457
                let len = Scalar::from_uint(inner_len, self.pointer_size());
458 459
                (Some(len), base.layout.ty)
            }
R
Ralf Jung 已提交
460 461 462 463
            _ =>
                bug!("cannot subslice non-array type: `{:?}`", base.layout.ty),
        };
        let layout = self.layout_of(ty)?;
464
        base.offset(from_offset, meta, layout, self)
R
Ralf Jung 已提交
465 466 467 468
    }

    pub fn mplace_downcast(
        &self,
469
        base: MPlaceTy<'tcx, M::PointerTag>,
470
        variant: VariantIdx,
471
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
472
        // Downcasts only change the layout
R
Ralf Jung 已提交
473
        assert!(base.meta.is_none());
R
Ralf Jung 已提交
474
        Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
O
Oliver Schneider 已提交
475 476
    }

R
Ralf Jung 已提交
477 478
    /// Project into an mplace
    pub fn mplace_projection(
O
Oliver Schneider 已提交
479
        &self,
480
        base: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
481
        proj_elem: &mir::PlaceElem<'tcx>,
482
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
483
        use rustc::mir::ProjectionElem::*;
R
Ralf Jung 已提交
484 485 486 487 488 489
        Ok(match *proj_elem {
            Field(field, _) => self.mplace_field(base, field.index() as u64)?,
            Downcast(_, variant) => self.mplace_downcast(base, variant)?,
            Deref => self.deref_operand(base.into())?,

            Index(local) => {
R
Ralf Jung 已提交
490
                let layout = self.layout_of(self.tcx.types.usize)?;
491 492
                let n = self.access_local(self.frame(), local, Some(layout))?;
                let n = self.read_scalar(n)?;
R
Ralf Jung 已提交
493 494 495 496 497 498 499 500 501
                let n = n.to_bits(self.tcx.data_layout.pointer_size)?;
                self.mplace_field(base, u64::try_from(n).unwrap())?
            }

            ConstantIndex {
                offset,
                min_length,
                from_end,
            } => {
502
                let n = base.len(self)?;
R
Ralf Jung 已提交
503 504 505 506 507 508 509 510 511 512 513 514 515 516
                assert!(n >= min_length as u64);

                let index = if from_end {
                    n - u64::from(offset)
                } else {
                    u64::from(offset)
                };

                self.mplace_field(base, index)?
            }

            Subslice { from, to } =>
                self.mplace_subslice(base, u64::from(from), u64::from(to))?,
        })
O
Oliver Schneider 已提交
517 518
    }

A
Alexander Regueiro 已提交
519
    /// Gets the place of a field inside the place, and also the field's type.
R
Ralf Jung 已提交
520
    /// Just a convenience function, but used quite a bit.
521 522
    /// This is the only projection that might have a side-effect: We cannot project
    /// into the field of a local `ScalarPair`, we have to first allocate it.
R
Ralf Jung 已提交
523
    pub fn place_field(
O
Oliver Schneider 已提交
524
        &mut self,
525
        base: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
526
        field: u64,
527
    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
528 529 530 531
        // FIXME: We could try to be smarter and avoid allocation for fields that span the
        // entire place.
        let mplace = self.force_allocation(base)?;
        Ok(self.mplace_field(mplace, field)?.into())
O
Oliver Schneider 已提交
532 533
    }

R
Ralf Jung 已提交
534
    pub fn place_downcast(
535
        &self,
536
        base: PlaceTy<'tcx, M::PointerTag>,
537
        variant: VariantIdx,
538
    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
539 540 541 542 543
        // Downcast just changes the layout
        Ok(match base.place {
            Place::Ptr(mplace) =>
                self.mplace_downcast(MPlaceTy { mplace, layout: base.layout }, variant)?.into(),
            Place::Local { .. } => {
544
                let layout = base.layout.for_variant(self, variant);
R
Ralf Jung 已提交
545
                PlaceTy { layout, ..base }
O
Oliver Schneider 已提交
546
            }
R
Ralf Jung 已提交
547
        })
O
Oliver Schneider 已提交
548 549
    }

A
Alexander Regueiro 已提交
550
    /// Projects into a place.
R
Ralf Jung 已提交
551 552
    pub fn place_projection(
        &mut self,
553
        base: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
554
        proj_elem: &mir::ProjectionElem<'tcx, mir::Local, Ty<'tcx>>,
555
    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
556 557 558 559 560 561 562 563 564 565 566 567 568 569
        use rustc::mir::ProjectionElem::*;
        Ok(match *proj_elem {
            Field(field, _) =>  self.place_field(base, field.index() as u64)?,
            Downcast(_, variant) => self.place_downcast(base, variant)?,
            Deref => self.deref_operand(self.place_to_op(base)?)?.into(),
            // For the other variants, we have to force an allocation.
            // This matches `operand_projection`.
            Subslice { .. } | ConstantIndex { .. } | Index(_) => {
                let mplace = self.force_allocation(base)?;
                self.mplace_projection(mplace, proj_elem)?.into()
            }
        })
    }

A
Alexander Regueiro 已提交
570
    /// Evaluate statics and promoteds to an `MPlace`. Used to share some code between
571 572 573 574
    /// `eval_place` and `eval_place_to_op`.
    pub(super) fn eval_place_to_mplace(
        &self,
        mir_place: &mir::Place<'tcx>
575
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
576
        use rustc::mir::Place::*;
577
        Ok(match *mir_place {
578 579
            Promoted(ref promoted) => {
                let instance = self.frame().instance;
R
Ralf Jung 已提交
580
                self.const_eval_raw(GlobalId {
581 582
                    instance,
                    promoted: Some(promoted.0),
R
Ralf Jung 已提交
583
                })?
584 585
            }

O
Oliver Schneider 已提交
586
            Static(ref static_) => {
587 588
                assert!(!static_.ty.needs_subst());
                let layout = self.layout_of(static_.ty)?;
589 590 591 592 593
                let instance = ty::Instance::mono(*self.tcx, static_.def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None
                };
R
Ralf Jung 已提交
594
                // Just create a lazy reference, so we can support recursive statics.
R
Ralf Jung 已提交
595
                // tcx takes are of assigning every static one and only one unique AllocId.
R
Ralf Jung 已提交
596 597
                // When the data here is ever actually used, memory will notice,
                // and it knows how to deal with alloc_id that are present in the
R
Ralf Jung 已提交
598 599 600 601 602 603 604 605
                // global table but not in its local memory: It calls back into tcx through
                // a query, triggering the CTFE machinery to actually turn this lazy reference
                // into a bunch of bytes.  IOW, statics are evaluated with CTFE even when
                // this EvalContext uses another Machine (e.g., in miri).  This is what we
                // want!  This way, computing statics works concistently between codegen
                // and miri: They use the same query to eventually obtain a `ty::Const`
                // and use that for further computation.
                let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
606
                MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
O
Oliver Schneider 已提交
607 608
            }

609 610 611 612
            _ => bug!("eval_place_to_mplace called on {:?}", mir_place),
        })
    }

A
Alexander Regueiro 已提交
613
    /// Computes a place. You should only use this if you intend to write into this
614
    /// place; for reading, a more efficient alternative is `eval_place_for_read`.
R
Ralf Jung 已提交
615 616 617 618
    pub fn eval_place(
        &mut self,
        mir_place: &mir::Place<'tcx>
    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
619 620
        use rustc::mir::Place::*;
        let place = match *mir_place {
R
Ralf Jung 已提交
621 622 623 624 625 626
            Local(mir::RETURN_PLACE) => match self.frame().return_place {
                Some(return_place) =>
                    // We use our layout to verify our assumption; caller will validate
                    // their layout on return.
                    PlaceTy {
                        place: *return_place,
627
                        layout: self.layout_of(self.monomorphize(self.frame().mir.return_ty())?)?,
R
Ralf Jung 已提交
628 629
                    },
                None => return err!(InvalidNullPointerUsage),
630 631 632 633 634 635
            },
            Local(local) => PlaceTy {
                place: Place::Local {
                    frame: self.cur_frame(),
                    local,
                },
636
                layout: self.layout_of_local(self.frame(), local, None)?,
637 638
            },

O
Oliver Schneider 已提交
639 640
            Projection(ref proj) => {
                let place = self.eval_place(&proj.base)?;
R
Ralf Jung 已提交
641
                self.place_projection(place, &proj.elem)?
O
Oliver Schneider 已提交
642
            }
643 644

            _ => self.eval_place_to_mplace(mir_place)?.into(),
O
Oliver Schneider 已提交
645 646
        };

R
Ralf Jung 已提交
647
        self.dump_place(place.place);
O
Oliver Schneider 已提交
648 649 650
        Ok(place)
    }

R
Ralf Jung 已提交
651 652
    /// Write a scalar to a place
    pub fn write_scalar(
O
Oliver Schneider 已提交
653
        &mut self,
654 655
        val: impl Into<ScalarMaybeUndef<M::PointerTag>>,
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
656
    ) -> EvalResult<'tcx> {
657
        self.write_immediate(Immediate::Scalar(val.into()), dest)
R
Ralf Jung 已提交
658
    }
O
Oliver Schneider 已提交
659

660
    /// Write an immediate to a place
661
    #[inline(always)]
662
    pub fn write_immediate(
R
Ralf Jung 已提交
663
        &mut self,
664
        src: Immediate<M::PointerTag>,
665
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
666
    ) -> EvalResult<'tcx> {
667
        self.write_immediate_no_validate(src, dest)?;
668

R
Ralf Jung 已提交
669
        if M::enforce_validity(self) {
670
            // Data got changed, better make sure it matches the type!
671
            self.validate_operand(self.place_to_op(dest)?, vec![], None, /*const_mode*/false)?;
672 673
        }

674 675 676
        Ok(())
    }

677
    /// Write an immediate to a place.
678 679
    /// If you use this you are responsible for validating that things got copied at the
    /// right type.
680
    fn write_immediate_no_validate(
681
        &mut self,
682
        src: Immediate<M::PointerTag>,
683 684 685 686 687
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx> {
        if cfg!(debug_assertions) {
            // This is a very common path, avoid some checks in release mode
            assert!(!dest.layout.is_unsized(), "Cannot write unsized data");
688 689
            match src {
                Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Ptr(_))) =>
690 691
                    assert_eq!(self.pointer_size(), dest.layout.size,
                        "Size mismatch when writing pointer"),
692
                Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { size, .. })) =>
693 694
                    assert_eq!(Size::from_bytes(size.into()), dest.layout.size,
                        "Size mismatch when writing bits"),
695 696
                Immediate::Scalar(ScalarMaybeUndef::Undef) => {}, // undef can have any size
                Immediate::ScalarPair(_, _) => {
697 698 699 700
                    // FIXME: Can we check anything here?
                }
            }
        }
701
        trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
702

703
        // See if we can avoid an allocation. This is the counterpart to `try_read_immediate`,
R
Ralf Jung 已提交
704
        // but not factored as a separate function.
R
Ralf Jung 已提交
705
        let mplace = match dest.place {
O
Oliver Schneider 已提交
706
            Place::Local { frame, local } => {
R
Ralf Jung 已提交
707 708 709
                match *self.stack[frame].locals[local].access_mut()? {
                    Operand::Immediate(ref mut dest_val) => {
                        // Yay, we can just change the local directly.
710
                        *dest_val = src;
R
Ralf Jung 已提交
711
                        return Ok(());
712
                    },
R
Ralf Jung 已提交
713
                    Operand::Indirect(mplace) => mplace, // already in memory
O
Oliver Schneider 已提交
714
                }
R
Ralf Jung 已提交
715
            },
R
Ralf Jung 已提交
716
            Place::Ptr(mplace) => mplace, // already in memory
O
Oliver Schneider 已提交
717
        };
718
        let dest = MPlaceTy { mplace, layout: dest.layout };
O
Oliver Schneider 已提交
719

R
Ralf Jung 已提交
720
        // This is already in memory, write there.
721
        self.write_immediate_to_mplace_no_validate(src, dest)
O
Oliver Schneider 已提交
722 723
    }

724
    /// Write an immediate to memory.
725 726
    /// If you use this you are responsible for validating that things git copied at the
    /// right type.
727
    fn write_immediate_to_mplace_no_validate(
R
Ralf Jung 已提交
728
        &mut self,
729
        value: Immediate<M::PointerTag>,
730
        dest: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
731
    ) -> EvalResult<'tcx> {
732
        let (ptr, ptr_align) = dest.to_scalar_ptr_align();
B
Bernardo Meurer 已提交
733 734 735 736
        // Note that it is really important that the type here is the right one, and matches the
        // type things are read at. In case `src_val` is a `ScalarPair`, we don't do any magic here
        // to handle padding properly, which is only correct if we never look at this data with the
        // wrong type.
737 738

        // Nothing to do for ZSTs, other than checking alignment
739
        if dest.layout.is_zst() {
740
            return self.memory.check_align(ptr, ptr_align);
741 742
        }

743
        // check for integer pointers before alignment to report better errors
744
        let ptr = ptr.to_ptr()?;
745
        self.memory.check_align(ptr.into(), ptr_align)?;
746
        let tcx = &*self.tcx;
747 748 749
        // FIXME: We should check that there are dest.layout.size many bytes available in
        // memory.  The code below is not sufficient, with enough padding it might not
        // cover all the bytes!
R
Ralf Jung 已提交
750
        match value {
751
            Immediate::Scalar(scalar) => {
752 753
                match dest.layout.abi {
                    layout::Abi::Scalar(_) => {}, // fine
754
                    _ => bug!("write_immediate_to_mplace: invalid Scalar layout: {:#?}",
755 756
                            dest.layout)
                }
757
                self.memory.get_mut(ptr.alloc_id)?.write_scalar(
758
                    tcx, ptr, scalar, dest.layout.size
R
Ralf Jung 已提交
759
                )
O
Oliver Schneider 已提交
760
            }
761
            Immediate::ScalarPair(a_val, b_val) => {
R
Ralf Jung 已提交
762 763
                let (a, b) = match dest.layout.abi {
                    layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
764
                    _ => bug!("write_immediate_to_mplace: invalid ScalarPair layout: {:#?}",
B
Bernardo Meurer 已提交
765
                              dest.layout)
R
Ralf Jung 已提交
766
                };
767
                let (a_size, b_size) = (a.size(self), b.size(self));
768 769
                let b_offset = a_size.align_to(b.align(self).abi);
                let b_align = ptr_align.restrict_for_offset(b_offset);
770
                let b_ptr = ptr.offset(b_offset, self)?;
771

772
                self.memory.check_align(b_ptr.into(), b_align)?;
773

774 775 776 777
                // It is tempting to verify `b_offset` against `layout.fields.offset(1)`,
                // but that does not work: We could be a newtype around a pair, then the
                // fields do not match the `ScalarPair` components.

778 779
                self.memory
                    .get_mut(ptr.alloc_id)?
780
                    .write_scalar(tcx, ptr, a_val, a_size)?;
781 782
                self.memory
                    .get_mut(b_ptr.alloc_id)?
783
                    .write_scalar(tcx, b_ptr, b_val, b_size)
O
Oliver Schneider 已提交
784
            }
R
Ralf Jung 已提交
785
        }
O
Oliver Schneider 已提交
786 787
    }

A
Alexander Regueiro 已提交
788
    /// Copies the data from an operand to a place. This does not support transmuting!
789 790
    /// Use `copy_op_transmute` if the layouts could disagree.
    #[inline(always)]
R
Ralf Jung 已提交
791
    pub fn copy_op(
O
Oliver Schneider 已提交
792
        &mut self,
793 794
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
795
    ) -> EvalResult<'tcx> {
796 797
        self.copy_op_no_validate(src, dest)?;

R
Ralf Jung 已提交
798
        if M::enforce_validity(self) {
799
            // Data got changed, better make sure it matches the type!
800
            self.validate_operand(self.place_to_op(dest)?, vec![], None, /*const_mode*/false)?;
801 802 803 804 805
        }

        Ok(())
    }

A
Alexander Regueiro 已提交
806
    /// Copies the data from an operand to a place. This does not support transmuting!
807 808 809 810 811 812 813 814 815
    /// Use `copy_op_transmute` if the layouts could disagree.
    /// Also, if you use this you are responsible for validating that things git copied at the
    /// right type.
    fn copy_op_no_validate(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx> {
        debug_assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(),
816
            "Cannot copy unsized data");
817 818 819 820
        // We do NOT compare the types for equality, because well-typed code can
        // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
        assert!(src.layout.details == dest.layout.details,
            "Layout mismatch when copying!\nsrc: {:#?}\ndest: {:#?}", src, dest);
R
Ralf Jung 已提交
821 822

        // Let us see if the layout is simple so we take a shortcut, avoid force_allocation.
823
        let src = match self.try_read_immediate(src)? {
824 825
            Ok(src_val) => {
                // Yay, we got a value that we can write directly.
826 827
                // FIXME: Add a check to make sure that if `src` is indirect,
                // it does not overlap with `dest`.
828
                return self.write_immediate_no_validate(src_val, dest);
829 830
            }
            Err(mplace) => mplace,
R
Ralf Jung 已提交
831 832
        };
        // Slow path, this does not fit into an immediate. Just memcpy.
833 834
        trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);

835
        let dest = self.force_allocation(dest)?;
836
        let (src_ptr, src_align) = src.to_scalar_ptr_align();
837
        let (dest_ptr, dest_align) = dest.to_scalar_ptr_align();
R
Ralf Jung 已提交
838 839 840
        self.memory.copy(
            src_ptr, src_align,
            dest_ptr, dest_align,
841 842
            dest.layout.size,
            /*nonoverlapping*/ true,
843
        )?;
844 845 846 847

        Ok(())
    }

A
Alexander Regueiro 已提交
848
    /// Copies the data from an operand to a place. The layouts may disagree, but they must
849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878
    /// have the same size.
    pub fn copy_op_transmute(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx> {
        if src.layout.details == dest.layout.details {
            // Fast path: Just use normal `copy_op`
            return self.copy_op(src, dest);
        }
        // We still require the sizes to match
        debug_assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(),
            "Cannot copy unsized data");
        assert!(src.layout.size == dest.layout.size,
            "Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest);

        // The hard case is `ScalarPair`.  `src` is already read from memory in this case,
        // using `src.layout` to figure out which bytes to use for the 1st and 2nd field.
        // We have to write them to `dest` at the offsets they were *read at*, which is
        // not necessarily the same as the offsets in `dest.layout`!
        // Hence we do the copy with the source layout on both sides.  We also make sure to write
        // into memory, because if `dest` is a local we would not even have a way to write
        // at the `src` offsets; the fact that we came from a different layout would
        // just be lost.
        let dest = self.force_allocation(dest)?;
        self.copy_op_no_validate(
            src,
            PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }),
        )?;

R
Ralf Jung 已提交
879
        if M::enforce_validity(self) {
880
            // Data got changed, better make sure it matches the type!
881
            self.validate_operand(dest.into(), vec![], None, /*const_mode*/false)?;
882
        }
883

884
        Ok(())
O
Oliver Schneider 已提交
885 886
    }

A
Alexander Regueiro 已提交
887
    /// Ensures that a place is in memory, and returns where it is.
888 889
    /// If the place currently refers to a local that doesn't yet have a matching allocation,
    /// create such an allocation.
R
Ralf Jung 已提交
890 891
    /// This is essentially `force_to_memplace`.
    pub fn force_allocation(
O
Oliver Schneider 已提交
892
        &mut self,
893 894
        place: PlaceTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
895 896
        let mplace = match place.place {
            Place::Local { frame, local } => {
897 898 899 900 901 902 903 904
                match *self.stack[frame].locals[local].access()? {
                    Operand::Indirect(mplace) => mplace,
                    Operand::Immediate(value) => {
                        // We need to make an allocation.
                        // FIXME: Consider not doing anything for a ZST, and just returning
                        // a fake pointer?  Are we even called for ZST?

                        // We need the layout of the local.  We can NOT use the layout we got,
905
                        // that might e.g., be an inner field of a struct with `Scalar` layout,
R
Ralf Jung 已提交
906
                        // that has different alignment than the outer field.
907
                        let local_layout = self.layout_of_local(&self.stack[frame], local, None)?;
R
Ralf Jung 已提交
908
                        let ptr = self.allocate(local_layout, MemoryKind::Stack);
909 910
                        // We don't have to validate as we can assume the local
                        // was already valid for its type.
911
                        self.write_immediate_to_mplace_no_validate(value, ptr)?;
912 913 914 915 916 917 918
                        let mplace = ptr.mplace;
                        // Update the local
                        *self.stack[frame].locals[local].access_mut()? =
                            Operand::Indirect(mplace);
                        mplace
                    }
                }
R
Ralf Jung 已提交
919 920 921 922 923
            }
            Place::Ptr(mplace) => mplace
        };
        // Return with the original layout, so that the caller can go on
        Ok(MPlaceTy { mplace, layout: place.layout })
O
Oliver Schneider 已提交
924 925
    }

R
Ralf Jung 已提交
926
    pub fn allocate(
O
Oliver Schneider 已提交
927
        &mut self,
R
Ralf Jung 已提交
928 929
        layout: TyLayout<'tcx>,
        kind: MemoryKind<M::MemoryKinds>,
R
Ralf Jung 已提交
930
    ) -> MPlaceTy<'tcx, M::PointerTag> {
O
Oliver Schneider 已提交
931 932
        if layout.is_unsized() {
            assert!(self.tcx.features().unsized_locals, "cannot alloc memory for unsized type");
933
            // FIXME: What should we do here? We should definitely also tag!
R
Ralf Jung 已提交
934
            MPlaceTy::dangling(layout, self)
O
Oliver Schneider 已提交
935
        } else {
R
Ralf Jung 已提交
936 937 938
            let ptr = self.memory.allocate(layout.size, layout.align.abi, kind);
            let ptr = M::tag_new_allocation(self, ptr, kind);
            MPlaceTy::from_aligned_ptr(ptr, layout)
O
Oliver Schneider 已提交
939
        }
R
Ralf Jung 已提交
940
    }
O
Oliver Schneider 已提交
941

942
    pub fn write_discriminant_index(
R
Ralf Jung 已提交
943
        &mut self,
944
        variant_index: VariantIdx,
945
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
946 947 948
    ) -> EvalResult<'tcx> {
        match dest.layout.variants {
            layout::Variants::Single { index } => {
R
Ralf Jung 已提交
949
                assert_eq!(index, variant_index);
O
Oliver Schneider 已提交
950
            }
R
Ralf Jung 已提交
951
            layout::Variants::Tagged { ref tag, .. } => {
952
                let adt_def = dest.layout.ty.ty_adt_def().unwrap();
953
                assert!(variant_index.as_usize() < adt_def.variants.len());
954
                let discr_val = adt_def
R
Ralf Jung 已提交
955 956 957 958 959 960
                    .discriminant_for_variant(*self.tcx, variant_index)
                    .val;

                // raw discriminants for enums are isize or bigger during
                // their computation, but the in-memory tag is the smallest possible
                // representation
961
                let size = tag.value.size(self);
R
Ralf Jung 已提交
962 963 964 965
                let shift = 128 - size.bits();
                let discr_val = (discr_val << shift) >> shift;

                let discr_dest = self.place_field(dest, 0)?;
966
                self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
O
Oliver Schneider 已提交
967
            }
R
Ralf Jung 已提交
968 969 970 971 972
            layout::Variants::NicheFilling {
                dataful_variant,
                ref niche_variants,
                niche_start,
                ..
O
Oliver Schneider 已提交
973
            } => {
974 975 976
                assert!(
                    variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len(),
                );
R
Ralf Jung 已提交
977 978 979
                if variant_index != dataful_variant {
                    let niche_dest =
                        self.place_field(dest, 0)?;
980 981
                    let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
                    let niche_value = (niche_value as u128)
R
Ralf Jung 已提交
982
                        .wrapping_add(niche_start);
983 984 985 986
                    self.write_scalar(
                        Scalar::from_uint(niche_value, niche_dest.layout.size),
                        niche_dest
                    )?;
R
Ralf Jung 已提交
987
                }
O
Oliver Schneider 已提交
988
            }
989
        }
R
Ralf Jung 已提交
990 991

        Ok(())
O
Oliver Schneider 已提交
992 993
    }

994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
    pub fn raw_const_to_mplace(
        &self,
        raw: RawConst<'tcx>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
        // This must be an allocation in `tcx`
        assert!(self.tcx.alloc_map.lock().get(raw.alloc_id).is_some());
        let layout = self.layout_of(raw.ty)?;
        Ok(MPlaceTy::from_aligned_ptr(
            Pointer::new(raw.alloc_id, Size::ZERO).with_default_tag(),
            layout,
        ))
    }

1007 1008
    /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
    /// Also return some more information so drop doesn't have to run the same code twice.
1009 1010
    pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx, M::PointerTag>)
    -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
1011 1012 1013 1014 1015
        let vtable = mplace.vtable()?; // also sanity checks the type
        let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
        let layout = self.layout_of(ty)?;

        // More sanity checks
1016 1017 1018
        if cfg!(debug_assertions) {
            let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
            assert_eq!(size, layout.size);
1019
            // only ABI alignment is preserved
1020
            assert_eq!(align, layout.align.abi);
1021
        }
1022 1023

        let mplace = MPlaceTy {
R
Ralf Jung 已提交
1024
            mplace: MemPlace { meta: None, ..*mplace },
1025
            layout
1026 1027
        };
        Ok((instance, mplace))
1028
    }
O
Oliver Schneider 已提交
1029
}