place.rs 38.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

R
Ralf Jung 已提交
11 12 13 14 15
//! 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;
16
use std::hash::Hash;
R
Ralf Jung 已提交
17

18
use rustc::hir;
19
use rustc::mir;
R
Ralf Jung 已提交
20
use rustc::ty::{self, Ty};
21
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout};
O
Oliver Schneider 已提交
22

R
Ralf Jung 已提交
23
use rustc::mir::interpret::{
24 25 26 27 28
    GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic
};
use super::{
    EvalContext, Machine, AllocMap,
    Value, ValTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind
R
Ralf Jung 已提交
29 30 31
};

#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
32
pub struct MemPlace<Tag=(), Id=AllocId> {
R
Ralf Jung 已提交
33 34 35
    /// 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.
36
    pub ptr: Scalar<Tag, Id>,
R
Ralf Jung 已提交
37
    pub align: Align,
38
    /// Metadata for unsized places.  Interpretation is up to the type.
R
Ralf Jung 已提交
39 40
    /// Must not be present for sized types, but can be missing for unsized types
    /// (e.g. `extern type`).
R
Ralf Jung 已提交
41
    pub meta: Option<Scalar<Tag, Id>>,
R
Ralf Jung 已提交
42
}
O
Oliver Schneider 已提交
43

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

R
Ralf Jung 已提交
49 50 51 52 53 54
    /// 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 已提交
55 56
}

R
Ralf Jung 已提交
57
#[derive(Copy, Clone, Debug)]
58 59
pub struct PlaceTy<'tcx, Tag=()> {
    place: Place<Tag>,
R
Ralf Jung 已提交
60 61 62
    pub layout: TyLayout<'tcx>,
}

63 64
impl<'tcx, Tag> ::std::ops::Deref for PlaceTy<'tcx, Tag> {
    type Target = Place<Tag>;
65
    #[inline(always)]
66
    fn deref(&self) -> &Place<Tag> {
R
Ralf Jung 已提交
67 68 69 70 71 72
        &self.place
    }
}

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

78 79
impl<'tcx, Tag> ::std::ops::Deref for MPlaceTy<'tcx, Tag> {
    type Target = MemPlace<Tag>;
80
    #[inline(always)]
81
    fn deref(&self) -> &MemPlace<Tag> {
R
Ralf Jung 已提交
82
        &self.mplace
O
Oliver Schneider 已提交
83
    }
R
Ralf Jung 已提交
84 85
}

86
impl<'tcx, Tag> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
87
    #[inline(always)]
88
    fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
R
Ralf Jung 已提交
89 90 91 92 93 94
        PlaceTy {
            place: Place::Ptr(mplace.mplace),
            layout: mplace.layout
        }
    }
}
O
Oliver Schneider 已提交
95

R
Ralf Jung 已提交
96
impl MemPlace {
97 98 99 100 101 102 103
    #[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 已提交
104
            meta: self.meta.map(Scalar::with_default_tag),
105 106 107 108 109 110 111 112 113 114 115
        }
    }
}

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

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

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 154 155
        self.to_scalar_ptr_align().0.to_ptr()
    }
}

156
impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
R
Ralf Jung 已提交
157 158 159 160 161 162 163 164 165 166 167 168
    /// Produces a MemPlace that works for ZST but nothing else
    #[inline]
    pub fn dangling(layout: TyLayout<'tcx>, cx: impl HasDataLayout) -> Self {
        MPlaceTy {
            mplace: MemPlace::from_scalar_ptr(
                Scalar::from_uint(layout.align.abi(), cx.pointer_size()),
                layout.align
            ),
            layout
        }
    }

R
Ralf Jung 已提交
169
    #[inline]
170
    fn from_aligned_ptr(ptr: Pointer<Tag>, layout: TyLayout<'tcx>) -> Self {
R
Ralf Jung 已提交
171 172 173 174
        MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align), layout }
    }

    #[inline]
175
    pub(super) fn len(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
176
        if self.layout.is_unsized() {
R
Ralf Jung 已提交
177
            // We need to consult `meta` metadata
178 179
            match self.layout.ty.sty {
                ty::Slice(..) | ty::Str =>
R
Ralf Jung 已提交
180
                    return self.mplace.meta.unwrap().to_usize(cx),
181
                _ => bug!("len not supported on unsized type {:?}", self.layout.ty),
182
            }
183 184 185 186 187 188
        } else {
            // Go through the layout.  There are lots of types that support a length,
            // e.g. SIMD types.
            match self.layout.fields {
                layout::FieldPlacement::Array { count, .. } => Ok(count),
                _ => bug!("len not supported on sized type {:?}", self.layout.ty),
189 190 191 192 193
            }
        }
    }

    #[inline]
194
    pub(super) fn vtable(self) -> EvalResult<'tcx, Pointer<Tag>> {
195
        match self.layout.ty.sty {
R
Ralf Jung 已提交
196
            ty::Dynamic(..) => self.mplace.meta.unwrap().to_ptr(),
197
            _ => bug!("vtable not supported on type {:?}", self.layout.ty),
R
Ralf Jung 已提交
198 199 200 201
        }
    }
}

202
impl<'tcx, Tag: ::std::fmt::Debug> OpTy<'tcx, Tag> {
203
    #[inline(always)]
204 205
    pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx, Tag>, Value<Tag>> {
        match self.op {
R
Ralf Jung 已提交
206 207 208 209 210
            Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
            Operand::Immediate(value) => Err(value),
        }
    }

211
    #[inline(always)]
212
    pub fn to_mem_place(self) -> MPlaceTy<'tcx, Tag> {
R
Ralf Jung 已提交
213 214 215 216
        self.try_as_mplace().unwrap()
    }
}

217
impl<'tcx, Tag: ::std::fmt::Debug> Place<Tag> {
R
Ralf Jung 已提交
218
    /// Produces a Place that will error if attempted to be read from or written to
219
    #[inline(always)]
R
Ralf Jung 已提交
220
    pub fn null(cx: impl HasDataLayout) -> Self {
221
        Place::Ptr(MemPlace::null(cx))
R
Ralf Jung 已提交
222 223
    }

224
    #[inline(always)]
225
    pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
R
Ralf Jung 已提交
226 227 228
        Place::Ptr(MemPlace::from_scalar_ptr(ptr, align))
    }

229
    #[inline(always)]
230
    pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
R
Ralf Jung 已提交
231
        Place::Ptr(MemPlace::from_ptr(ptr, align))
O
Oliver Schneider 已提交
232 233
    }

R
Ralf Jung 已提交
234
    #[inline]
235
    pub fn to_mem_place(self) -> MemPlace<Tag> {
O
Oliver Schneider 已提交
236
        match self {
R
Ralf Jung 已提交
237 238
            Place::Ptr(mplace) => mplace,
            _ => bug!("to_mem_place: expected Place::Ptr, got {:?}", self),
O
Oliver Schneider 已提交
239 240 241 242

        }
    }

R
Ralf Jung 已提交
243
    #[inline]
244
    pub fn to_scalar_ptr_align(self) -> (Scalar<Tag>, Align) {
R
Ralf Jung 已提交
245
        self.to_mem_place().to_scalar_ptr_align()
246
    }
247

R
Ralf Jung 已提交
248
    #[inline]
249
    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
R
Ralf Jung 已提交
250 251 252
        self.to_mem_place().to_ptr()
    }
}
O
Oliver Schneider 已提交
253

254
impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> {
R
Ralf Jung 已提交
255
    #[inline]
256
    pub fn to_mem_place(self) -> MPlaceTy<'tcx, Tag> {
R
Ralf Jung 已提交
257
        MPlaceTy { mplace: self.place.to_mem_place(), layout: self.layout }
O
Oliver Schneider 已提交
258 259 260
    }
}

261
// separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385
262 263 264 265
impl<'a, 'mir, 'tcx, Tag, M> EvalContext<'a, 'mir, 'tcx, M>
where
    Tag: ::std::fmt::Debug+Default+Copy+Eq+Hash+'static,
    M: Machine<'a, 'mir, 'tcx, PointerTag=Tag>,
266
    M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag, M::AllocExtra>)>,
267
{
R
Ralf Jung 已提交
268
    /// Take a value, which represents a (thin or fat) reference, and make it a place.
269
    /// Alignment is just based on the type.  This is the inverse of `create_ref`.
R
Ralf Jung 已提交
270
    pub fn ref_to_mplace(
271 272
        &self,
        val: ValTy<'tcx, M::PointerTag>,
273
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
274 275 276 277 278
        let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty;
        let layout = self.layout_of(pointee_type)?;

        let align = layout.align;
        let meta = val.to_meta()?;
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
        let ptr = val.to_scalar_ptr()?;
        let mplace = MemPlace { ptr, align, meta };
        // Pointer tag tracking might want to adjust the tag.
        let mplace = if M::ENABLE_PTR_TRACKING_HOOKS {
            let (size, _) = self.size_and_align_of(meta, layout)?
                // for extern types, just cover what we can
                .unwrap_or_else(|| layout.size_and_align());
            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),
            };
            M::tag_dereference(self, mplace, pointee_type, size, mutbl)?
        } else {
            mplace
R
Ralf Jung 已提交
296
        };
297
        Ok(MPlaceTy { mplace, layout })
R
Ralf Jung 已提交
298 299
    }

300 301
    /// 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`.
302
    /// `mutbl` indicates whether we are create a shared or mutable ref, or a raw pointer (`None`).
303 304 305
    pub fn create_ref(
        &mut self,
        place: MPlaceTy<'tcx, M::PointerTag>,
306
        mutbl: Option<hir::Mutability>,
307
    ) -> EvalResult<'tcx, Value<M::PointerTag>> {
308 309 310 311 312 313 314 315
        // Pointer tag tracking might want to adjust the tag
        let place = if M::ENABLE_PTR_TRACKING_HOOKS {
            let (size, _) = self.size_and_align_of_mplace(place)?
                // for extern types, just cover what we can
                .unwrap_or_else(|| place.layout.size_and_align());
            M::tag_reference(self, *place, place.layout.ty, size, mutbl)?
        } else {
            *place
316 317
        };
        Ok(match place.meta {
318 319
            None => Value::Scalar(place.ptr.into()),
            Some(meta) => Value::ScalarPair(place.ptr.into(), meta.into()),
320 321 322
        })
    }

R
Ralf Jung 已提交
323 324 325 326 327
    /// 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 已提交
328
        &self,
329
        base: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
330
        field: u64,
331
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
332 333 334 335 336
        // 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, .. } => {
337 338 339
                let len = base.len(self)?;
                assert!(field < len, "Tried to access element {} of array/slice with length {}",
                    field, len);
R
Ralf Jung 已提交
340 341
                stride * field
            }
342
            layout::FieldPlacement::Union(count) => {
B
Bernardo Meurer 已提交
343 344
                assert!(field < count as u64,
                        "Tried to access field {} of union with {} fields", field, count);
345 346 347
                // Offset is always 0
                Size::from_bytes(0)
            }
R
Ralf Jung 已提交
348 349 350
        };
        // 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 已提交
351
        let field_layout = base.layout.field(self, usize::try_from(field).unwrap_or(0))?;
R
Ralf Jung 已提交
352

353
        // Offset may need adjustment for unsized fields
R
Ralf Jung 已提交
354
        let (meta, offset) = if field_layout.is_unsized() {
355
            // re-use parent metadata to determine dynamic field layout
356 357
            let (_, align) = self.size_and_align_of(base.meta, field_layout)?
                .expect("Fields cannot be extern types");
R
Ralf Jung 已提交
358
            (base.meta, offset.abi_align(align))
R
Ralf Jung 已提交
359
        } else {
R
Ralf Jung 已提交
360
            // base.meta could be present; we might be accessing a sized field of an unsized
361 362
            // struct.
            (None, offset)
R
Ralf Jung 已提交
363 364
        };

365
        let ptr = base.ptr.ptr_offset(offset, self)?;
366 367 368 369
        let align = base.align
            // We do not look at `base.layout.align` nor `field_layout.align`, unlike
            // codegen -- mostly to see if we can get away with that
            .restrict_for_offset(offset); // must be last thing that happens
370

R
Ralf Jung 已提交
371
        Ok(MPlaceTy { mplace: MemPlace { ptr, align, meta }, layout: field_layout })
O
Oliver Schneider 已提交
372 373
    }

374 375 376 377
    // 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,
378 379 380 381
        base: MPlaceTy<'tcx, Tag>,
    ) ->
        EvalResult<'tcx, impl Iterator<Item=EvalResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
    {
382
        let len = base.len(self)?; // also asserts that we have a type where this makes sense
383 384 385 386 387 388 389 390 391
        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;
        Ok((0..len).map(move |i| {
            let ptr = base.ptr.ptr_offset(i * stride, dl)?;
            Ok(MPlaceTy {
R
Ralf Jung 已提交
392
                mplace: MemPlace { ptr, align: base.align, meta: None },
393 394 395 396 397
                layout
            })
        }))
    }

R
Ralf Jung 已提交
398
    pub fn mplace_subslice(
O
Oliver Schneider 已提交
399
        &self,
400
        base: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
401 402
        from: u64,
        to: u64,
403
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
404
        let len = base.len(self)?; // also asserts that we have a type where this makes sense
R
Ralf Jung 已提交
405 406 407 408 409 410 411 412
        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 已提交
413
        };
R
Ralf Jung 已提交
414 415
        let ptr = base.ptr.ptr_offset(from_offset, self)?;

R
Ralf Jung 已提交
416
        // Compute meta and new layout
R
Ralf Jung 已提交
417
        let inner_len = len - to - from;
R
Ralf Jung 已提交
418
        let (meta, ty) = match base.layout.ty.sty {
R
Ralf Jung 已提交
419 420
            // It is not nice to match on the type, but that seems to be the only way to
            // implement this.
V
varkor 已提交
421
            ty::Array(inner, _) =>
422 423
                (None, self.tcx.mk_array(inner, inner_len)),
            ty::Slice(..) => {
424
                let len = Scalar::from_uint(inner_len, self.pointer_size());
425 426
                (Some(len), base.layout.ty)
            }
R
Ralf Jung 已提交
427 428 429 430 431 432
            _ =>
                bug!("cannot subslice non-array type: `{:?}`", base.layout.ty),
        };
        let layout = self.layout_of(ty)?;

        Ok(MPlaceTy {
R
Ralf Jung 已提交
433
            mplace: MemPlace { ptr, align: base.align, meta },
R
Ralf Jung 已提交
434 435 436 437 438 439
            layout
        })
    }

    pub fn mplace_downcast(
        &self,
440
        base: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
441
        variant: usize,
442
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
443
        // Downcasts only change the layout
R
Ralf Jung 已提交
444
        assert!(base.meta.is_none());
R
Ralf Jung 已提交
445
        Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
O
Oliver Schneider 已提交
446 447
    }

R
Ralf Jung 已提交
448 449
    /// Project into an mplace
    pub fn mplace_projection(
O
Oliver Schneider 已提交
450
        &self,
451
        base: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
452
        proj_elem: &mir::PlaceElem<'tcx>,
453
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
454
        use rustc::mir::ProjectionElem::*;
R
Ralf Jung 已提交
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
        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) => {
                let n = *self.frame().locals[local].access()?;
                let n_layout = self.layout_of(self.tcx.types.usize)?;
                let n = self.read_scalar(OpTy { op: n, layout: n_layout })?;
                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,
            } => {
473
                let n = base.len(self)?;
R
Ralf Jung 已提交
474 475 476 477 478 479 480 481 482 483 484 485 486 487
                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 已提交
488 489
    }

R
Ralf Jung 已提交
490 491 492
    /// Get the place of a field inside the place, and also the field's type.
    /// Just a convenience function, but used quite a bit.
    pub fn place_field(
O
Oliver Schneider 已提交
493
        &mut self,
494
        base: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
495
        field: u64,
496
    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
497 498 499 500
        // 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 已提交
501 502
    }

R
Ralf Jung 已提交
503 504
    pub fn place_downcast(
        &mut self,
505
        base: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
506
        variant: usize,
507
    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
508 509 510 511 512 513 514
        // Downcast just changes the layout
        Ok(match base.place {
            Place::Ptr(mplace) =>
                self.mplace_downcast(MPlaceTy { mplace, layout: base.layout }, variant)?.into(),
            Place::Local { .. } => {
                let layout = base.layout.for_variant(&self, variant);
                PlaceTy { layout, ..base }
O
Oliver Schneider 已提交
515
            }
R
Ralf Jung 已提交
516
        })
O
Oliver Schneider 已提交
517 518
    }

R
Ralf Jung 已提交
519 520 521
    /// Project into a place
    pub fn place_projection(
        &mut self,
522
        base: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
523
        proj_elem: &mir::ProjectionElem<'tcx, mir::Local, Ty<'tcx>>,
524
    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
525 526 527 528 529 530 531 532 533 534 535 536 537 538
        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()
            }
        })
    }

539 540 541 542 543
    /// Evaluate statics and promoteds to an `MPlace`.  Used to share some code between
    /// `eval_place` and `eval_place_to_op`.
    pub(super) fn eval_place_to_mplace(
        &self,
        mir_place: &mir::Place<'tcx>
544
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
545
        use rustc::mir::Place::*;
546
        Ok(match *mir_place {
547 548
            Promoted(ref promoted) => {
                let instance = self.frame().instance;
R
Ralf Jung 已提交
549
                let op = self.global_to_op(GlobalId {
550 551 552
                    instance,
                    promoted: Some(promoted.0),
                })?;
553
                let mplace = op.to_mem_place(); // these are always in memory
R
Ralf Jung 已提交
554
                let ty = self.monomorphize(promoted.1, self.substs());
555 556
                MPlaceTy {
                    mplace,
R
Ralf Jung 已提交
557
                    layout: self.layout_of(ty)?,
558 559 560
                }
            }

O
Oliver Schneider 已提交
561
            Static(ref static_) => {
R
Ralf Jung 已提交
562 563
                let ty = self.monomorphize(static_.ty, self.substs());
                let layout = self.layout_of(ty)?;
564 565 566 567 568
                let instance = ty::Instance::mono(*self.tcx, static_.def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None
                };
R
Ralf Jung 已提交
569
                // Just create a lazy reference, so we can support recursive statics.
R
Ralf Jung 已提交
570
                // tcx takes are of assigning every static one and only one unique AllocId.
R
Ralf Jung 已提交
571 572
                // 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 已提交
573 574 575 576 577 578 579 580
                // 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());
581
                MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
O
Oliver Schneider 已提交
582 583
            }

584 585 586 587 588 589
            _ => bug!("eval_place_to_mplace called on {:?}", mir_place),
        })
    }

    /// Compute a place.  You should only use this if you intend to write into this
    /// place; for reading, a more efficient alternative is `eval_place_for_read`.
R
Ralf Jung 已提交
590 591 592 593
    pub fn eval_place(
        &mut self,
        mir_place: &mir::Place<'tcx>
    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
594 595
        use rustc::mir::Place::*;
        let place = match *mir_place {
R
Ralf Jung 已提交
596 597 598 599 600 601
            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,
602
                        layout: self.layout_of_local(self.frame(), mir::RETURN_PLACE)?,
R
Ralf Jung 已提交
603 604
                    },
                None => return err!(InvalidNullPointerUsage),
605 606 607 608 609 610
            },
            Local(local) => PlaceTy {
                place: Place::Local {
                    frame: self.cur_frame(),
                    local,
                },
611
                layout: self.layout_of_local(self.frame(), local)?,
612 613
            },

O
Oliver Schneider 已提交
614 615
            Projection(ref proj) => {
                let place = self.eval_place(&proj.base)?;
R
Ralf Jung 已提交
616
                self.place_projection(place, &proj.elem)?
O
Oliver Schneider 已提交
617
            }
618 619

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

R
Ralf Jung 已提交
622
        self.dump_place(place.place);
O
Oliver Schneider 已提交
623 624 625
        Ok(place)
    }

R
Ralf Jung 已提交
626 627
    /// Write a scalar to a place
    pub fn write_scalar(
O
Oliver Schneider 已提交
628
        &mut self,
629 630
        val: impl Into<ScalarMaybeUndef<M::PointerTag>>,
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
631 632 633
    ) -> EvalResult<'tcx> {
        self.write_value(Value::Scalar(val.into()), dest)
    }
O
Oliver Schneider 已提交
634

R
Ralf Jung 已提交
635
    /// Write a value to a place
636
    #[inline(always)]
R
Ralf Jung 已提交
637 638
    pub fn write_value(
        &mut self,
639 640
        src_val: Value<M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
641
    ) -> EvalResult<'tcx> {
642 643
        self.write_value_no_validate(src_val, dest)?;

R
Ralf Jung 已提交
644
        if M::enforce_validity(self) {
645 646
            // Data got changed, better make sure it matches the type!
            self.validate_operand(self.place_to_op(dest)?, &mut vec![], None, /*const_mode*/false)?;
647 648
        }

649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
        Ok(())
    }

    /// Write a value to a place.
    /// If you use this you are responsible for validating that things got copied at the
    /// right type.
    fn write_value_no_validate(
        &mut self,
        src_val: Value<M::PointerTag>,
        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");
            match src_val {
                Value::Scalar(ScalarMaybeUndef::Scalar(Scalar::Ptr(_))) =>
                    assert_eq!(self.pointer_size(), dest.layout.size,
                        "Size mismatch when writing pointer"),
                Value::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { size, .. })) =>
                    assert_eq!(Size::from_bytes(size.into()), dest.layout.size,
                        "Size mismatch when writing bits"),
                Value::Scalar(ScalarMaybeUndef::Undef) => {}, // undef can have any size
                Value::ScalarPair(_, _) => {
                    // FIXME: Can we check anything here?
                }
            }
        }
        trace!("write_value: {:?} <- {:?}: {}", *dest, src_val, dest.layout.ty);

R
Ralf Jung 已提交
678 679
        // See if we can avoid an allocation. This is the counterpart to `try_read_value`,
        // but not factored as a separate function.
R
Ralf Jung 已提交
680
        let mplace = match dest.place {
O
Oliver Schneider 已提交
681
            Place::Local { frame, local } => {
R
Ralf Jung 已提交
682 683 684 685 686
                match *self.stack[frame].locals[local].access_mut()? {
                    Operand::Immediate(ref mut dest_val) => {
                        // Yay, we can just change the local directly.
                        *dest_val = src_val;
                        return Ok(());
687
                    },
R
Ralf Jung 已提交
688
                    Operand::Indirect(mplace) => mplace, // already in memory
O
Oliver Schneider 已提交
689
                }
R
Ralf Jung 已提交
690
            },
R
Ralf Jung 已提交
691
            Place::Ptr(mplace) => mplace, // already in memory
O
Oliver Schneider 已提交
692
        };
693
        let dest = MPlaceTy { mplace, layout: dest.layout };
O
Oliver Schneider 已提交
694

R
Ralf Jung 已提交
695
        // This is already in memory, write there.
696
        self.write_value_to_mplace_no_validate(src_val, dest)
O
Oliver Schneider 已提交
697 698
    }

699 700 701 702
    /// Write a value to memory.
    /// If you use this you are responsible for validating that things git copied at the
    /// right type.
    fn write_value_to_mplace_no_validate(
R
Ralf Jung 已提交
703
        &mut self,
704 705
        value: Value<M::PointerTag>,
        dest: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
706
    ) -> EvalResult<'tcx> {
707
        let (ptr, ptr_align) = dest.to_scalar_ptr_align();
B
Bernardo Meurer 已提交
708 709 710 711
        // 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.
712 713

        // Nothing to do for ZSTs, other than checking alignment
714
        if dest.layout.is_zst() {
715 716 717 718 719
            self.memory.check_align(ptr, ptr_align)?;
            return Ok(());
        }

        let ptr = ptr.to_ptr()?;
720 721 722
        // 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 已提交
723 724
        match value {
            Value::Scalar(scalar) => {
725 726 727 728 729 730
                match dest.layout.abi {
                    layout::Abi::Scalar(_) => {}, // fine
                    _ => bug!("write_value_to_mplace: invalid Scalar layout: {:#?}",
                            dest.layout)
                }

R
Ralf Jung 已提交
731
                self.memory.write_scalar(
732
                    ptr, ptr_align.min(dest.layout.align), scalar, dest.layout.size
R
Ralf Jung 已提交
733
                )
O
Oliver Schneider 已提交
734
            }
R
Ralf Jung 已提交
735 736 737
            Value::ScalarPair(a_val, b_val) => {
                let (a, b) = match dest.layout.abi {
                    layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
B
Bernardo Meurer 已提交
738 739
                    _ => bug!("write_value_to_mplace: invalid ScalarPair layout: {:#?}",
                              dest.layout)
R
Ralf Jung 已提交
740 741 742 743
                };
                let (a_size, b_size) = (a.size(&self), b.size(&self));
                let (a_align, b_align) = (a.align(&self), b.align(&self));
                let b_offset = a_size.abi_align(b_align);
744
                let b_ptr = ptr.offset(b_offset, &self)?.into();
745

746 747 748 749
                // 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.

750 751
                self.memory.write_scalar(ptr, ptr_align.min(a_align), a_val, a_size)?;
                self.memory.write_scalar(b_ptr, ptr_align.min(b_align), b_val, b_size)
O
Oliver Schneider 已提交
752
            }
R
Ralf Jung 已提交
753
        }
O
Oliver Schneider 已提交
754 755
    }

756 757 758
    /// Copy the data from an operand to a place.  This does not support transmuting!
    /// Use `copy_op_transmute` if the layouts could disagree.
    #[inline(always)]
R
Ralf Jung 已提交
759
    pub fn copy_op(
O
Oliver Schneider 已提交
760
        &mut self,
761 762
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
763
    ) -> EvalResult<'tcx> {
764 765
        self.copy_op_no_validate(src, dest)?;

R
Ralf Jung 已提交
766
        if M::enforce_validity(self) {
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
            // Data got changed, better make sure it matches the type!
            self.validate_operand(self.place_to_op(dest)?, &mut vec![], None, /*const_mode*/false)?;
        }

        Ok(())
    }

    /// Copy the data from an operand to a place.  This does not support transmuting!
    /// 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(),
784
            "Cannot copy unsized data");
785 786 787 788
        // 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 已提交
789 790

        // Let us see if the layout is simple so we take a shortcut, avoid force_allocation.
791 792 793 794 795 796
        let src = match self.try_read_value(src)? {
            Ok(src_val) => {
                // Yay, we got a value that we can write directly.
                return self.write_value_no_validate(src_val, dest);
            }
            Err(mplace) => mplace,
R
Ralf Jung 已提交
797 798
        };
        // Slow path, this does not fit into an immediate. Just memcpy.
799 800
        trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);

801
        let dest = self.force_allocation(dest)?;
802
        let (src_ptr, src_align) = src.to_scalar_ptr_align();
803
        let (dest_ptr, dest_align) = dest.to_scalar_ptr_align();
R
Ralf Jung 已提交
804 805 806
        self.memory.copy(
            src_ptr, src_align,
            dest_ptr, dest_align,
807
            dest.layout.size, false
808
        )?;
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843

        Ok(())
    }

    /// Copy the data from an operand to a place.  The layouts may disagree, but they must
    /// 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 已提交
844
        if M::enforce_validity(self) {
845
            // Data got changed, better make sure it matches the type!
846 847
            self.validate_operand(dest.into(), &mut vec![], None, /*const_mode*/false)?;
        }
848

849
        Ok(())
O
Oliver Schneider 已提交
850 851
    }

R
Ralf Jung 已提交
852
    /// Make sure that a place is in memory, and return where it is.
853 854
    /// If the place currently refers to a local that doesn't yet have a matching allocation,
    /// create such an allocation.
R
Ralf Jung 已提交
855 856
    /// This is essentially `force_to_memplace`.
    pub fn force_allocation(
O
Oliver Schneider 已提交
857
        &mut self,
858 859
        place: PlaceTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
860 861
        let mplace = match place.place {
            Place::Local { frame, local } => {
862 863 864 865 866 867 868 869
                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,
R
Ralf Jung 已提交
870 871
                        // that might e.g. be an inner field of a struct with `Scalar` layout,
                        // that has different alignment than the outer field.
872
                        let local_layout = self.layout_of_local(&self.stack[frame], local)?;
873
                        let ptr = self.allocate(local_layout, MemoryKind::Stack)?;
874 875
                        // We don't have to validate as we can assume the local
                        // was already valid for its type.
876
                        self.write_value_to_mplace_no_validate(value, ptr)?;
877 878 879 880 881 882 883
                        let mplace = ptr.mplace;
                        // Update the local
                        *self.stack[frame].locals[local].access_mut()? =
                            Operand::Indirect(mplace);
                        mplace
                    }
                }
R
Ralf Jung 已提交
884 885 886 887 888
            }
            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 已提交
889 890
    }

R
Ralf Jung 已提交
891
    pub fn allocate(
O
Oliver Schneider 已提交
892
        &mut self,
R
Ralf Jung 已提交
893 894
        layout: TyLayout<'tcx>,
        kind: MemoryKind<M::MemoryKinds>,
895
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
O
Oliver Schneider 已提交
896 897
        if layout.is_unsized() {
            assert!(self.tcx.features().unsized_locals, "cannot alloc memory for unsized type");
898
            // FIXME: What should we do here? We should definitely also tag!
899
            Ok(MPlaceTy::dangling(layout, &self))
O
Oliver Schneider 已提交
900 901
        } else {
            let ptr = self.memory.allocate(layout.size, layout.align, kind)?;
902
            let ptr = M::tag_new_allocation(self, ptr, kind)?;
O
Oliver Schneider 已提交
903 904
            Ok(MPlaceTy::from_aligned_ptr(ptr, layout))
        }
R
Ralf Jung 已提交
905
    }
O
Oliver Schneider 已提交
906

907
    pub fn write_discriminant_index(
R
Ralf Jung 已提交
908 909
        &mut self,
        variant_index: usize,
910
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
911 912 913
    ) -> EvalResult<'tcx> {
        match dest.layout.variants {
            layout::Variants::Single { index } => {
R
Ralf Jung 已提交
914
                assert_eq!(index, variant_index);
O
Oliver Schneider 已提交
915
            }
R
Ralf Jung 已提交
916
            layout::Variants::Tagged { ref tag, .. } => {
917
                let adt_def = dest.layout.ty.ty_adt_def().unwrap();
R
Ralf Jung 已提交
918
                assert!(variant_index < adt_def.variants.len());
919
                let discr_val = adt_def
R
Ralf Jung 已提交
920 921 922 923 924 925 926 927 928 929 930
                    .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
                let size = tag.value.size(self.tcx.tcx);
                let shift = 128 - size.bits();
                let discr_val = (discr_val << shift) >> shift;

                let discr_dest = self.place_field(dest, 0)?;
931
                self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
O
Oliver Schneider 已提交
932
            }
R
Ralf Jung 已提交
933 934 935 936 937
            layout::Variants::NicheFilling {
                dataful_variant,
                ref niche_variants,
                niche_start,
                ..
O
Oliver Schneider 已提交
938
            } => {
R
Ralf Jung 已提交
939
                assert!(variant_index < dest.layout.ty.ty_adt_def().unwrap().variants.len());
R
Ralf Jung 已提交
940 941 942 943 944
                if variant_index != dataful_variant {
                    let niche_dest =
                        self.place_field(dest, 0)?;
                    let niche_value = ((variant_index - niche_variants.start()) as u128)
                        .wrapping_add(niche_start);
945 946 947 948
                    self.write_scalar(
                        Scalar::from_uint(niche_value, niche_dest.layout.size),
                        niche_dest
                    )?;
R
Ralf Jung 已提交
949
                }
O
Oliver Schneider 已提交
950
            }
951
        }
R
Ralf Jung 已提交
952 953

        Ok(())
O
Oliver Schneider 已提交
954 955
    }

R
Ralf Jung 已提交
956
    /// Every place can be read from, so we can turm them into an operand
957
    #[inline(always)]
R
Ralf Jung 已提交
958 959 960 961
    pub fn place_to_op(
        &self,
        place: PlaceTy<'tcx, M::PointerTag>
    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
962 963 964 965 966 967 968 969
        let op = match place.place {
            Place::Ptr(mplace) => {
                Operand::Indirect(mplace)
            }
            Place::Local { frame, local } =>
                *self.stack[frame].locals[local].access()?
        };
        Ok(OpTy { op, layout: place.layout })
O
Oliver Schneider 已提交
970
    }
971

972 973
    /// 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.
974 975
    pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx, M::PointerTag>)
    -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
976 977 978 979 980
        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
981 982 983 984 985
        if cfg!(debug_assertions) {
            let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
            assert_eq!(size, layout.size);
            assert_eq!(align.abi(), layout.align.abi()); // only ABI alignment is preserved
        }
986 987

        let mplace = MPlaceTy {
R
Ralf Jung 已提交
988
            mplace: MemPlace { meta: None, ..*mplace },
989
            layout
990 991
        };
        Ok((instance, mplace))
992
    }
O
Oliver Schneider 已提交
993
}