place.rs 40.4 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;
10
use rustc::mir::interpret::truncate;
R
Ralf Jung 已提交
11
use rustc::ty::{self, Ty};
12
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx};
13
use rustc::ty::TypeFoldable;
O
Oliver Schneider 已提交
14

15
use super::{
16
    GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic,
K
kenta7777 已提交
17
    InterpretCx, Machine, AllocMap, AllocationExtra,
18
    RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind
R
Ralf Jung 已提交
19 20 21
};

#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
22
pub struct MemPlace<Tag=(), Id=AllocId> {
R
Ralf Jung 已提交
23 24 25
    /// 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.
26
    pub ptr: Scalar<Tag, Id>,
27
    pub align: Align,
A
Alexander Regueiro 已提交
28
    /// Metadata for unsized places. Interpretation is up to the type.
R
Ralf Jung 已提交
29
    /// Must not be present for sized types, but can be missing for unsized types
30
    /// (e.g., `extern type`).
R
Ralf Jung 已提交
31
    pub meta: Option<Scalar<Tag, Id>>,
R
Ralf Jung 已提交
32
}
O
Oliver Schneider 已提交
33

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

R
Ralf Jung 已提交
39 40 41 42 43 44
    /// 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 已提交
45 46
}

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

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

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

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

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

R
Ralf Jung 已提交
86
impl MemPlace {
87 88 89 90 91 92 93
    #[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 已提交
94
            meta: self.meta.map(Scalar::with_default_tag),
95 96 97 98 99 100 101 102 103 104 105
        }
    }
}

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

110 111 112 113 114 115 116 117 118 119
    #[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 已提交
120
    #[inline(always)]
121
    pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
R
Ralf Jung 已提交
122
        MemPlace {
123 124
            ptr,
            align,
R
Ralf Jung 已提交
125
            meta: None,
O
Oliver Schneider 已提交
126 127 128
        }
    }

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

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

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

R
Ralf Jung 已提交
146
    /// metact the ptr part of the mplace
R
Ralf Jung 已提交
147
    #[inline(always)]
148
    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
B
Bernardo Meurer 已提交
149 150 151
        // 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 已提交
152 153
        self.to_scalar_ptr_align().0.to_ptr()
    }
154 155 156 157 158 159 160 161 162 163

    /// 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()),
        }
    }
164 165 166 167 168 169 170 171 172 173 174 175 176

    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 已提交
177 178
}

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

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

    #[inline]
202 203 204 205 206 207 208 209 210 211 212 213 214
    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 已提交
215
    #[inline]
216
    fn from_aligned_ptr(ptr: Pointer<Tag>, layout: TyLayout<'tcx>) -> Self {
217
        MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align.abi), layout }
R
Ralf Jung 已提交
218 219 220
    }

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

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

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

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

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

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

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

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

        }
    }

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

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

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

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

328 329
        let mplace = MemPlace {
            ptr: val.to_scalar_ptr()?,
330 331 332 333
            // We could use the run-time alignment here. For now, we do not, because
            // the point of tracking the alignment here is to make sure that the *static*
            // alignment information emitted with the loads is correct. The run-time
            // alignment can only be more restrictive.
334
            align: layout.align.abi,
335 336 337
            meta: val.to_meta()?,
        };
        Ok(MPlaceTy { mplace, layout })
R
Ralf Jung 已提交
338 339
    }

340 341 342 343 344 345 346 347 348 349 350
    // 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)?;
351
        // Pointer tag tracking might want to adjust the tag.
352 353 354 355 356
        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,
357
            _ => bug!("Unexpected pointer type {}", val.layout.ty),
358
        };
359 360
        place.mplace.ptr = M::tag_dereference(self, place, mutbl)?;
        Ok(place)
361 362
    }

R
Ralf Jung 已提交
363 364 365 366 367
    /// 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 已提交
368
        &self,
369
        base: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
370
        field: u64,
371
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
372 373 374 375 376
        // 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, .. } => {
377 378 379
                let len = base.len(self)?;
                assert!(field < len, "Tried to access element {} of array/slice with length {}",
                    field, len);
R
Ralf Jung 已提交
380 381
                stride * field
            }
382
            layout::FieldPlacement::Union(count) => {
B
Bernardo Meurer 已提交
383 384
                assert!(field < count as u64,
                        "Tried to access field {} of union with {} fields", field, count);
385 386 387
                // Offset is always 0
                Size::from_bytes(0)
            }
R
Ralf Jung 已提交
388 389 390
        };
        // 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 已提交
391
        let field_layout = base.layout.field(self, usize::try_from(field).unwrap_or(0))?;
R
Ralf Jung 已提交
392

393
        // Offset may need adjustment for unsized fields.
R
Ralf Jung 已提交
394
        let (meta, offset) = if field_layout.is_unsized() {
395 396 397
            // Re-use parent metadata to determine dynamic field layout.
            // With custom DSTS, this *will* execute user-defined code, but the same
            // happens at run-time so that's okay.
398 399 400 401 402 403 404
            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.
405
                    field_layout.align.abi,
406 407 408
                None =>
                    bug!("Cannot compute offset for extern type field at non-0 offset"),
            };
409
            (base.meta, offset.align_to(align))
R
Ralf Jung 已提交
410
        } else {
R
Ralf Jung 已提交
411
            // base.meta could be present; we might be accessing a sized field of an unsized
412 413
            // struct.
            (None, offset)
R
Ralf Jung 已提交
414 415
        };

416 417 418
        // 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 已提交
419 420
    }

421 422 423 424
    // 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,
425 426 427 428
        base: MPlaceTy<'tcx, Tag>,
    ) ->
        EvalResult<'tcx, impl Iterator<Item=EvalResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
    {
429
        let len = base.len(self)?; // also asserts that we have a type where this makes sense
430 431 432 433 434 435
        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;
436
        Ok((0..len).map(move |i| base.offset(i * stride, None, layout, dl)))
437 438
    }

R
Ralf Jung 已提交
439
    pub fn mplace_subslice(
O
Oliver Schneider 已提交
440
        &self,
441
        base: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
442 443
        from: u64,
        to: u64,
444
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
445
        let len = base.len(self)?; // also asserts that we have a type where this makes sense
R
Ralf Jung 已提交
446 447 448 449 450 451 452 453
        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 已提交
454
        };
R
Ralf Jung 已提交
455

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

    pub fn mplace_downcast(
        &self,
476
        base: MPlaceTy<'tcx, M::PointerTag>,
477
        variant: VariantIdx,
478
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
479
        // Downcasts only change the layout
R
Ralf Jung 已提交
480
        assert!(base.meta.is_none());
R
Ralf Jung 已提交
481
        Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
O
Oliver Schneider 已提交
482 483
    }

R
Ralf Jung 已提交
484 485
    /// Project into an mplace
    pub fn mplace_projection(
O
Oliver Schneider 已提交
486
        &self,
487
        base: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
488
        proj_elem: &mir::PlaceElem<'tcx>,
489
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
490
        use rustc::mir::ProjectionElem::*;
R
Ralf Jung 已提交
491 492 493 494 495 496
        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 已提交
497
                let layout = self.layout_of(self.tcx.types.usize)?;
498 499
                let n = self.access_local(self.frame(), local, Some(layout))?;
                let n = self.read_scalar(n)?;
R
Ralf Jung 已提交
500 501 502 503 504 505 506 507 508
                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,
            } => {
509
                let n = base.len(self)?;
R
Ralf Jung 已提交
510 511 512 513 514 515 516 517 518 519 520 521 522 523
                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 已提交
524 525
    }

A
Alexander Regueiro 已提交
526
    /// Gets the place of a field inside the place, and also the field's type.
R
Ralf Jung 已提交
527
    /// Just a convenience function, but used quite a bit.
528 529
    /// 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 已提交
530
    pub fn place_field(
O
Oliver Schneider 已提交
531
        &mut self,
532
        base: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
533
        field: u64,
534
    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
535 536 537 538
        // 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 已提交
539 540
    }

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

A
Alexander Regueiro 已提交
557
    /// Projects into a place.
R
Ralf Jung 已提交
558 559
    pub fn place_projection(
        &mut self,
560
        base: PlaceTy<'tcx, M::PointerTag>,
561
        proj_elem: &mir::ProjectionElem<mir::Local, Ty<'tcx>>,
562
    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
563 564 565 566 567 568 569 570 571 572 573 574 575 576
        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 已提交
577
    /// Evaluate statics and promoteds to an `MPlace`. Used to share some code between
578 579 580 581
    /// `eval_place` and `eval_place_to_op`.
    pub(super) fn eval_place_to_mplace(
        &self,
        mir_place: &mir::Place<'tcx>
582
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
583
        use rustc::mir::Place::*;
584
        use rustc::mir::PlaceBase;
585
        use rustc::mir::{Static, StaticKind};
586
        Ok(match *mir_place {
587
            Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(promoted), .. })) => {
S
Saleem Jaffer 已提交
588 589 590 591 592 593 594
                let instance = self.frame().instance;
                self.const_eval_raw(GlobalId {
                    instance,
                    promoted: Some(promoted),
                })?
            }

595
            Base(PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), ty })) => {
S
Saleem Jaffer 已提交
596 597 598 599 600 601 602 603 604 605 606 607 608 609
                assert!(!ty.needs_subst());
                let layout = self.layout_of(ty)?;
                let instance = ty::Instance::mono(*self.tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None
                };
                // Just create a lazy reference, so we can support recursive statics.
                // tcx takes are of assigning every static one and only one unique AllocId.
                // 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
                // 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
K
kenta7777 已提交
610
                // this InterpretCx uses another Machine (e.g., in miri).  This is what we
S
Saleem Jaffer 已提交
611 612 613 614 615
                // 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());
                MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
O
Oliver Schneider 已提交
616 617
            }

618 619 620 621
            _ => bug!("eval_place_to_mplace called on {:?}", mir_place),
        })
    }

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

O
Oliver Schneider 已提交
649 650
            Projection(ref proj) => {
                let place = self.eval_place(&proj.base)?;
R
Ralf Jung 已提交
651
                self.place_projection(place, &proj.elem)?
O
Oliver Schneider 已提交
652
            }
653 654

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

R
Ralf Jung 已提交
657
        self.dump_place(place.place);
O
Oliver Schneider 已提交
658 659 660
        Ok(place)
    }

R
Ralf Jung 已提交
661 662
    /// Write a scalar to a place
    pub fn write_scalar(
O
Oliver Schneider 已提交
663
        &mut self,
664 665
        val: impl Into<ScalarMaybeUndef<M::PointerTag>>,
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
666
    ) -> EvalResult<'tcx> {
667
        self.write_immediate(Immediate::Scalar(val.into()), dest)
R
Ralf Jung 已提交
668
    }
O
Oliver Schneider 已提交
669

670
    /// Write an immediate to a place
671
    #[inline(always)]
672
    pub fn write_immediate(
R
Ralf Jung 已提交
673
        &mut self,
674
        src: Immediate<M::PointerTag>,
675
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
676
    ) -> EvalResult<'tcx> {
677
        self.write_immediate_no_validate(src, dest)?;
678

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

684 685 686
        Ok(())
    }

687
    /// Write an immediate to a place.
688 689
    /// If you use this you are responsible for validating that things got copied at the
    /// right type.
690
    fn write_immediate_no_validate(
691
        &mut self,
692
        src: Immediate<M::PointerTag>,
693 694 695 696 697
        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");
698 699
            match src {
                Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Ptr(_))) =>
700 701
                    assert_eq!(self.pointer_size(), dest.layout.size,
                        "Size mismatch when writing pointer"),
702
                Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { size, .. })) =>
703 704
                    assert_eq!(Size::from_bytes(size.into()), dest.layout.size,
                        "Size mismatch when writing bits"),
705 706
                Immediate::Scalar(ScalarMaybeUndef::Undef) => {}, // undef can have any size
                Immediate::ScalarPair(_, _) => {
707 708 709 710
                    // FIXME: Can we check anything here?
                }
            }
        }
711
        trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
712

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

R
Ralf Jung 已提交
730
        // This is already in memory, write there.
731
        self.write_immediate_to_mplace_no_validate(src, dest)
O
Oliver Schneider 已提交
732 733
    }

734
    /// Write an immediate to memory.
735 736
    /// If you use this you are responsible for validating that things git copied at the
    /// right type.
737
    fn write_immediate_to_mplace_no_validate(
R
Ralf Jung 已提交
738
        &mut self,
739
        value: Immediate<M::PointerTag>,
740
        dest: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
741
    ) -> EvalResult<'tcx> {
742
        let (ptr, ptr_align) = dest.to_scalar_ptr_align();
B
Bernardo Meurer 已提交
743 744 745 746
        // 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.
747 748

        // Nothing to do for ZSTs, other than checking alignment
749
        if dest.layout.is_zst() {
750
            return self.memory.check_align(ptr, ptr_align);
751 752
        }

753
        // check for integer pointers before alignment to report better errors
754
        let ptr = ptr.to_ptr()?;
755
        self.memory.check_align(ptr.into(), ptr_align)?;
756
        let tcx = &*self.tcx;
757 758 759
        // 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 已提交
760
        match value {
761
            Immediate::Scalar(scalar) => {
762 763
                match dest.layout.abi {
                    layout::Abi::Scalar(_) => {}, // fine
764
                    _ => bug!("write_immediate_to_mplace: invalid Scalar layout: {:#?}",
765 766
                            dest.layout)
                }
767
                self.memory.get_mut(ptr.alloc_id)?.write_scalar(
768
                    tcx, ptr, scalar, dest.layout.size
R
Ralf Jung 已提交
769
                )
O
Oliver Schneider 已提交
770
            }
771
            Immediate::ScalarPair(a_val, b_val) => {
R
Ralf Jung 已提交
772 773
                let (a, b) = match dest.layout.abi {
                    layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
774
                    _ => bug!("write_immediate_to_mplace: invalid ScalarPair layout: {:#?}",
B
Bernardo Meurer 已提交
775
                              dest.layout)
R
Ralf Jung 已提交
776
                };
777
                let (a_size, b_size) = (a.size(self), b.size(self));
778 779
                let b_offset = a_size.align_to(b.align(self).abi);
                let b_align = ptr_align.restrict_for_offset(b_offset);
780
                let b_ptr = ptr.offset(b_offset, self)?;
781

782
                self.memory.check_align(b_ptr.into(), b_align)?;
783

784 785 786 787
                // 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.

788 789
                self.memory
                    .get_mut(ptr.alloc_id)?
790
                    .write_scalar(tcx, ptr, a_val, a_size)?;
791 792
                self.memory
                    .get_mut(b_ptr.alloc_id)?
793
                    .write_scalar(tcx, b_ptr, b_val, b_size)
O
Oliver Schneider 已提交
794
            }
R
Ralf Jung 已提交
795
        }
O
Oliver Schneider 已提交
796 797
    }

A
Alexander Regueiro 已提交
798
    /// Copies the data from an operand to a place. This does not support transmuting!
799 800
    /// Use `copy_op_transmute` if the layouts could disagree.
    #[inline(always)]
R
Ralf Jung 已提交
801
    pub fn copy_op(
O
Oliver Schneider 已提交
802
        &mut self,
803 804
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
805
    ) -> EvalResult<'tcx> {
806 807
        self.copy_op_no_validate(src, dest)?;

R
Ralf Jung 已提交
808
        if M::enforce_validity(self) {
809
            // Data got changed, better make sure it matches the type!
810
            self.validate_operand(self.place_to_op(dest)?, vec![], None, /*const_mode*/false)?;
811 812 813 814 815
        }

        Ok(())
    }

A
Alexander Regueiro 已提交
816
    /// Copies the data from an operand to a place. This does not support transmuting!
817 818 819 820 821 822 823 824 825
    /// 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(),
826
            "Cannot copy unsized data");
827 828 829 830
        // 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 已提交
831 832

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

845
        let dest = self.force_allocation(dest)?;
846
        let (src_ptr, src_align) = src.to_scalar_ptr_align();
847
        let (dest_ptr, dest_align) = dest.to_scalar_ptr_align();
R
Ralf Jung 已提交
848 849 850
        self.memory.copy(
            src_ptr, src_align,
            dest_ptr, dest_align,
851 852
            dest.layout.size,
            /*nonoverlapping*/ true,
853
        )?;
854 855 856 857

        Ok(())
    }

A
Alexander Regueiro 已提交
858
    /// Copies the data from an operand to a place. The layouts may disagree, but they must
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888
    /// 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 已提交
889
        if M::enforce_validity(self) {
890
            // Data got changed, better make sure it matches the type!
891
            self.validate_operand(dest.into(), vec![], None, /*const_mode*/false)?;
892
        }
893

894
        Ok(())
O
Oliver Schneider 已提交
895 896
    }

A
Alexander Regueiro 已提交
897
    /// Ensures that a place is in memory, and returns where it is.
898 899
    /// If the place currently refers to a local that doesn't yet have a matching allocation,
    /// create such an allocation.
R
Ralf Jung 已提交
900 901
    /// This is essentially `force_to_memplace`.
    pub fn force_allocation(
O
Oliver Schneider 已提交
902
        &mut self,
903 904
        place: PlaceTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
905 906
        let mplace = match place.place {
            Place::Local { frame, local } => {
907 908 909 910 911 912 913 914
                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,
915
                        // that might e.g., be an inner field of a struct with `Scalar` layout,
R
Ralf Jung 已提交
916
                        // that has different alignment than the outer field.
917
                        let local_layout = self.layout_of_local(&self.stack[frame], local, None)?;
R
Ralf Jung 已提交
918
                        let ptr = self.allocate(local_layout, MemoryKind::Stack);
919 920
                        // We don't have to validate as we can assume the local
                        // was already valid for its type.
921
                        self.write_immediate_to_mplace_no_validate(value, ptr)?;
922 923 924 925 926 927 928
                        let mplace = ptr.mplace;
                        // Update the local
                        *self.stack[frame].locals[local].access_mut()? =
                            Operand::Indirect(mplace);
                        mplace
                    }
                }
R
Ralf Jung 已提交
929 930 931 932 933
            }
            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 已提交
934 935
    }

R
Ralf Jung 已提交
936
    pub fn allocate(
O
Oliver Schneider 已提交
937
        &mut self,
R
Ralf Jung 已提交
938 939
        layout: TyLayout<'tcx>,
        kind: MemoryKind<M::MemoryKinds>,
R
Ralf Jung 已提交
940
    ) -> MPlaceTy<'tcx, M::PointerTag> {
O
Oliver Schneider 已提交
941 942
        if layout.is_unsized() {
            assert!(self.tcx.features().unsized_locals, "cannot alloc memory for unsized type");
943
            // FIXME: What should we do here? We should definitely also tag!
R
Ralf Jung 已提交
944
            MPlaceTy::dangling(layout, self)
O
Oliver Schneider 已提交
945
        } else {
R
Ralf Jung 已提交
946 947 948
            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 已提交
949
        }
R
Ralf Jung 已提交
950
    }
O
Oliver Schneider 已提交
951

952
    pub fn write_discriminant_index(
R
Ralf Jung 已提交
953
        &mut self,
954
        variant_index: VariantIdx,
955
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
956 957 958
    ) -> EvalResult<'tcx> {
        match dest.layout.variants {
            layout::Variants::Single { index } => {
R
Ralf Jung 已提交
959
                assert_eq!(index, variant_index);
O
Oliver Schneider 已提交
960
            }
961 962 963 964 965
            layout::Variants::Multiple {
                discr_kind: layout::DiscriminantKind::Tag,
                ref discr,
                ..
            } => {
966
                let adt_def = dest.layout.ty.ty_adt_def().unwrap();
967
                assert!(variant_index.as_usize() < adt_def.variants.len());
968
                let discr_val = adt_def
R
Ralf Jung 已提交
969 970 971 972 973 974
                    .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
975
                let size = discr.value.size(self);
976
                let discr_val = truncate(discr_val, size);
R
Ralf Jung 已提交
977 978

                let discr_dest = self.place_field(dest, 0)?;
979
                self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
O
Oliver Schneider 已提交
980
            }
981 982 983 984 985 986
            layout::Variants::Multiple {
                discr_kind: layout::DiscriminantKind::Niche {
                    dataful_variant,
                    ref niche_variants,
                    niche_start,
                },
R
Ralf Jung 已提交
987
                ..
O
Oliver Schneider 已提交
988
            } => {
989 990 991
                assert!(
                    variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len(),
                );
R
Ralf Jung 已提交
992 993 994
                if variant_index != dataful_variant {
                    let niche_dest =
                        self.place_field(dest, 0)?;
995 996
                    let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
                    let niche_value = (niche_value as u128)
R
Ralf Jung 已提交
997
                        .wrapping_add(niche_start);
998 999 1000 1001
                    self.write_scalar(
                        Scalar::from_uint(niche_value, niche_dest.layout.size),
                        niche_dest
                    )?;
R
Ralf Jung 已提交
1002
                }
O
Oliver Schneider 已提交
1003
            }
1004
        }
R
Ralf Jung 已提交
1005 1006

        Ok(())
O
Oliver Schneider 已提交
1007 1008
    }

1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021
    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,
        ))
    }

1022 1023
    /// 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.
1024 1025
    pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx, M::PointerTag>)
    -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
1026 1027 1028 1029 1030
        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
1031 1032 1033
        if cfg!(debug_assertions) {
            let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
            assert_eq!(size, layout.size);
1034
            // only ABI alignment is preserved
1035
            assert_eq!(align, layout.align.abi);
1036
        }
1037 1038

        let mplace = MPlaceTy {
R
Ralf Jung 已提交
1039
            mplace: MemPlace { meta: None, ..*mplace },
1040
            layout
1041 1042
        };
        Ok((instance, mplace))
1043
    }
O
Oliver Schneider 已提交
1044
}