eval_context.rs 63.8 KB
Newer Older
O
Oliver Schneider 已提交
1
use std::collections::HashSet;
S
Scott Olson 已提交
2
use std::fmt::Write;
3

4 5 6 7 8 9
use rustc::hir::def_id::DefId;
use rustc::hir::map::definitions::DefPathData;
use rustc::middle::const_val::ConstVal;
use rustc::mir;
use rustc::traits::Reveal;
use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout};
V
varkor 已提交
10
use rustc::ty::subst::{Subst, Substs};
11
use rustc::ty::{self, Ty, TyCtxt};
12
use rustc_data_structures::indexed_vec::Idx;
13 14
use syntax::codemap::{self, DUMMY_SP};
use syntax::ast::Mutability;
15
use rustc::mir::interpret::{
16
    GlobalId, Value, Pointer, PrimVal, PrimValKind,
17 18
    EvalError, EvalResult, EvalErrorKind, MemoryPointer,
};
19

20 21
use super::{Place, PlaceExtra, Memory,
            HasMemory, MemoryKind, operator,
O
Oliver Schneider 已提交
22
            Machine};
O
Oliver Schneider 已提交
23

24
pub struct EvalContext<'a, 'tcx: 'a, M: Machine<'tcx>> {
25 26
    /// Stores the `Machine` instance.
    pub machine: M,
27

28
    /// The results of the type checker, from rustc.
29
    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
30

31 32 33
    /// Bounds in scope for polymorphic evaluations.
    pub param_env: ty::ParamEnv<'tcx>,

34
    /// The virtual memory system.
35
    pub memory: Memory<'a, 'tcx, M>,
36

37
    /// The virtual call stack.
S
Scott Olson 已提交
38
    pub(crate) stack: Vec<Frame<'tcx>>,
39 40

    /// The maximum number of stack frames allowed
S
Scott Olson 已提交
41
    pub(crate) stack_limit: usize,
42 43 44 45

    /// The maximum number of operations that may be executed.
    /// This prevents infinite loops and huge computations from freezing up const eval.
    /// Remove once halting problem is solved.
S
Scott Olson 已提交
46
    pub(crate) steps_remaining: u64,
47 48
}

49
/// A stack frame.
50
pub struct Frame<'tcx> {
51 52 53 54
    ////////////////////////////////////////////////////////////////////////////////
    // Function and callsite information
    ////////////////////////////////////////////////////////////////////////////////
    /// The MIR for the function called on this frame.
55
    pub mir: &'tcx mir::Mir<'tcx>,
56

O
Oliver Schneider 已提交
57 58
    /// The def_id and substs of the current function
    pub instance: ty::Instance<'tcx>,
59

60 61
    /// The span of the call site.
    pub span: codemap::Span,
62

63
    ////////////////////////////////////////////////////////////////////////////////
O
Oliver Schneider 已提交
64
    // Return place and locals
65
    ////////////////////////////////////////////////////////////////////////////////
66
    /// The block to return to when returning from the current stack frame
67
    pub return_to_block: StackPopCleanup,
68

69
    /// The location where the result of the current stack frame should be written to.
O
Oliver Schneider 已提交
70
    pub return_place: Place,
71 72

    /// The list of locals for this stack frame, stored in order as
73 74
    /// `[arguments..., variables..., temporaries...]`. The locals are stored as `Option<Value>`s.
    /// `None` represents a local that is currently dead, while a live local
75
    /// can either directly contain `PrimVal` or refer to some part of an `Allocation`.
S
Scott Olson 已提交
76
    ///
77 78
    /// Before being initialized, arguments are `Value::ByVal(PrimVal::Undef)` and other locals are `None`.
    pub locals: Vec<Option<Value>>,
79

80 81 82 83 84 85 86
    ////////////////////////////////////////////////////////////////////////////////
    // Current position within the function
    ////////////////////////////////////////////////////////////////////////////////
    /// The block that is currently executed (or will be executed after the above call stacks
    /// return).
    pub block: mir::BasicBlock,

87
    /// The index of the currently evaluated statement.
88
    pub stmt: usize,
89
}
90

91 92
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum StackPopCleanup {
93
    /// The stackframe existed to compute the initial value of a static/constant, make sure it
94 95 96
    /// isn't modifyable afterwards in case of constants.
    /// In case of `static mut`, mark the memory to ensure it's never marked as immutable through
    /// references or deallocated
O
Oliver Schneider 已提交
97
    MarkStatic(Mutability),
98 99 100 101 102 103 104
    /// A regular stackframe added due to a function call will need to get forwarded to the next
    /// block
    Goto(mir::BasicBlock),
    /// The main function and diverging functions have nowhere to return to
    None,
}

S
Scott Olson 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
#[derive(Copy, Clone, Debug)]
pub struct ResourceLimits {
    pub memory_size: u64,
    pub step_limit: u64,
    pub stack_limit: usize,
}

impl Default for ResourceLimits {
    fn default() -> Self {
        ResourceLimits {
            memory_size: 100 * 1024 * 1024, // 100 MB
            step_limit: 1_000_000,
            stack_limit: 100,
        }
    }
}

R
Ralf Jung 已提交
122 123 124 125 126 127
#[derive(Copy, Clone, Debug)]
pub struct TyAndPacked<'tcx> {
    pub ty: Ty<'tcx>,
    pub packed: bool,
}

128 129 130 131 132 133 134 135 136 137 138 139 140
#[derive(Copy, Clone, Debug)]
pub struct ValTy<'tcx> {
    pub value: Value,
    pub ty: Ty<'tcx>,
}

impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
    type Target = Value;
    fn deref(&self) -> &Value {
        &self.value
    }
}

O
Oliver Schneider 已提交
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
impl<'a, 'tcx, M: Machine<'tcx>> HasDataLayout for &'a EvalContext<'a, 'tcx, M> {
    #[inline]
    fn data_layout(&self) -> &layout::TargetDataLayout {
        &self.tcx.data_layout
    }
}

impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> HasDataLayout
    for &'c &'b mut EvalContext<'a, 'tcx, M> {
    #[inline]
    fn data_layout(&self) -> &layout::TargetDataLayout {
        &self.tcx.data_layout
    }
}

impl<'a, 'tcx, M: Machine<'tcx>> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'tcx, M> {
    #[inline]
    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
        self.tcx
    }
}

impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> layout::HasTyCtxt<'tcx>
    for &'c &'b mut EvalContext<'a, 'tcx, M> {
    #[inline]
    fn tcx<'d>(&'d self) -> TyCtxt<'d, 'tcx, 'tcx> {
        self.tcx
    }
}

impl<'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>> for &'a EvalContext<'a, 'tcx, M> {
    type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;

    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
175
        self.tcx.layout_of(self.param_env.and(ty))
O
Oliver Schneider 已提交
176 177 178 179 180 181 182 183 184 185 186 187 188 189
            .map_err(|layout| EvalErrorKind::Layout(layout).into())
    }
}

impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>>
    for &'c &'b mut EvalContext<'a, 'tcx, M> {
    type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;

    #[inline]
    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
        (&**self).layout_of(ty)
    }
}

190 191 192
impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
    pub fn new(
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
193
        param_env: ty::ParamEnv<'tcx>,
194
        limits: ResourceLimits,
195
        machine: M,
196 197
        memory_data: M::MemoryData,
    ) -> Self {
198
        EvalContext {
199
            machine,
S
Scott Olson 已提交
200
            tcx,
201
            param_env,
O
Oliver Schneider 已提交
202
            memory: Memory::new(tcx, limits.memory_size, memory_data),
203
            stack: Vec::new(),
S
Scott Olson 已提交
204 205
            stack_limit: limits.stack_limit,
            steps_remaining: limits.step_limit,
206 207
        }
    }
208

209
    pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, MemoryPointer> {
210 211
        let layout = self.layout_of(ty)?;
        assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
S
Scott Olson 已提交
212

213
        let size = layout.size.bytes();
214
        self.memory.allocate(size, layout.align, Some(MemoryKind::Stack))
215
    }
O
Oliver Schneider 已提交
216

217
    pub fn memory(&self) -> &Memory<'a, 'tcx, M> {
218 219 220
        &self.memory
    }

221
    pub fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> {
O
Oliver Schneider 已提交
222 223 224
        &mut self.memory
    }

225
    pub fn stack(&self) -> &[Frame<'tcx>] {
226 227 228
        &self.stack
    }

229 230 231 232 233 234
    #[inline]
    pub fn cur_frame(&self) -> usize {
        assert!(self.stack.len() > 0);
        self.stack.len() - 1
    }

235
    pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
O
Oliver Schneider 已提交
236
        let ptr = self.memory.allocate_cached(s.as_bytes());
R
rustfmt  
Ralf Jung 已提交
237 238 239 240
        Ok(Value::ByValPair(
            PrimVal::Ptr(ptr),
            PrimVal::from_u128(s.len() as u128),
        ))
241 242
    }

243
    pub(super) fn const_to_value(&mut self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
244
        use rustc::middle::const_val::ConstVal::*;
245 246

        let primval = match *const_val {
O
Oliver Schneider 已提交
247
            Integral(const_int) => PrimVal::Bytes(const_int.to_u128_unchecked()),
S
Scott Olson 已提交
248

O
Rustup  
Oliver Schneider 已提交
249
            Float(val) => PrimVal::Bytes(val.bits),
S
Scott Olson 已提交
250 251 252

            Bool(b) => PrimVal::from_bool(b),
            Char(c) => PrimVal::from_char(c),
253

254
            Str(ref s) => return self.str_to_value(s),
255

256
            ByteStr(ref bs) => {
O
Oliver Schneider 已提交
257
                let ptr = self.memory.allocate_cached(bs.data);
258
                PrimVal::Ptr(ptr)
259
            }
260

O
Oliver Schneider 已提交
261
            Unevaluated(def_id, substs) => {
O
Oliver Schneider 已提交
262
                let instance = self.resolve(def_id, substs)?;
263
                return Ok(self.read_global_as_value(GlobalId {
O
Oliver Schneider 已提交
264 265
                    instance,
                    promoted: None,
266
                }, self.layout_of(ty)?));
O
Oliver Schneider 已提交
267 268 269
            }

            Aggregate(..) |
270
            Variant(_) => bug!("should not have aggregate or variant constants in MIR"),
271
            // function items are zero sized and thus have no readable value
R
rustfmt  
Ralf Jung 已提交
272
            Function(..) => PrimVal::Undef,
273 274
        };

275
        Ok(Value::ByVal(primval))
276 277
    }

O
Oliver Schneider 已提交
278 279 280 281
    pub(super) fn resolve(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, ty::Instance<'tcx>> {
        let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs);
        ty::Instance::resolve(
            self.tcx,
282
            self.param_env,
O
Oliver Schneider 已提交
283 284 285 286 287
            def_id,
            substs,
        ).ok_or(EvalErrorKind::TypeckError.into()) // turn error prop into a panic to expose associated type in const issue
    }

288
    pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
P
Pramod Bisht 已提交
289
        ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env)
290 291
    }

R
rustfmt  
Ralf Jung 已提交
292 293 294 295
    pub fn load_mir(
        &self,
        instance: ty::InstanceDef<'tcx>,
    ) -> EvalResult<'tcx, &'tcx mir::Mir<'tcx>> {
O
Oliver Schneider 已提交
296 297 298 299 300
        // do not continue if typeck errors occurred (can only occur in local crate)
        let did = instance.def_id();
        if did.is_local() && self.tcx.has_typeck_tables(did) && self.tcx.typeck_tables_of(did).tainted_by_errors {
            return err!(TypeckError);
        }
O
Oliver Schneider 已提交
301 302
        trace!("load mir {:?}", instance);
        match instance {
R
rustfmt  
Ralf Jung 已提交
303 304 305 306 307
            ty::InstanceDef::Item(def_id) => {
                self.tcx.maybe_optimized_mir(def_id).ok_or_else(|| {
                    EvalErrorKind::NoMirFor(self.tcx.item_path_str(def_id)).into()
                })
            }
O
Oliver Schneider 已提交
308
            _ => Ok(self.tcx.instance_mir(instance)),
309 310
        }
    }
O
Oliver Schneider 已提交
311

312
    pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
O
Oliver Schneider 已提交
313 314 315 316
        // miri doesn't care about lifetimes, and will choke on some crazy ones
        // let's simply get rid of them
        let without_lifetimes = self.tcx.erase_regions(&ty);
        let substituted = without_lifetimes.subst(self.tcx, substs);
O
Oliver Schneider 已提交
317
        let substituted = self.tcx.fully_normalize_monormophic_ty(&substituted);
318
        substituted
319 320
    }

R
Ralf Jung 已提交
321 322 323
    /// Return the size and aligment of the value at the given type.
    /// Note that the value does not matter if the type is sized. For unsized types,
    /// the value has to be a fat pointer, and we only care about the "extra" data in it.
324 325
    pub fn size_and_align_of_dst(
        &mut self,
326
        ty: Ty<'tcx>,
R
Ralf Jung 已提交
327
        value: Value,
O
Oliver Schneider 已提交
328
    ) -> EvalResult<'tcx, (Size, Align)> {
329
        let layout = self.layout_of(ty)?;
O
Oliver Schneider 已提交
330 331
        if !layout.is_unsized() {
            Ok(layout.size_and_align())
332 333
        } else {
            match ty.sty {
R
Ralf Jung 已提交
334
                ty::TyAdt(..) | ty::TyTuple(..) => {
335 336 337 338 339 340 341
                    // First get the size of all statically known fields.
                    // Don't use type_of::sizing_type_of because that expects t to be sized,
                    // and it also rounds up to alignment, which we want to avoid,
                    // as the unsized field's alignment could be smaller.
                    assert!(!ty.is_simd());
                    debug!("DST {} layout: {:?}", ty, layout);

O
Oliver Schneider 已提交
342 343
                    let sized_size = layout.fields.offset(layout.fields.count() - 1);
                    let sized_align = layout.align;
R
rustfmt  
Ralf Jung 已提交
344
                    debug!(
O
Oliver Schneider 已提交
345
                        "DST {} statically sized prefix size: {:?} align: {:?}",
R
rustfmt  
Ralf Jung 已提交
346 347 348 349
                        ty,
                        sized_size,
                        sized_align
                    );
350 351 352

                    // Recurse to get the size of the dynamically sized field (must be
                    // the last field).
353 354 355
                    let field_ty = layout.field(&self, layout.fields.count() - 1)?.ty;
                    let (unsized_size, unsized_align) =
                        self.size_and_align_of_dst(field_ty, value)?;
356 357 358 359 360 361 362 363 364 365 366 367 368

                    // FIXME (#26403, #27023): We should be adding padding
                    // to `sized_size` (to accommodate the `unsized_align`
                    // required of the unsized field that follows) before
                    // summing it with `sized_size`. (Note that since #26403
                    // is unfixed, we do not yet add the necessary padding
                    // here. But this is where the add would go.)

                    // Return the sum of sizes and max of aligns.
                    let size = sized_size + unsized_size;

                    // Choose max of two known alignments (combined value must
                    // be aligned according to more restrictive of the two).
O
Oliver Schneider 已提交
369
                    let align = sized_align.max(unsized_align);
370 371 372 373 374 375 376 377 378 379 380 381

                    // Issue #27023: must add any necessary padding to `size`
                    // (to make it a multiple of `align`) before returning it.
                    //
                    // Namely, the returned size should be, in C notation:
                    //
                    //   `size + ((size & (align-1)) ? align : 0)`
                    //
                    // emulated via the semi-standard fast bit trick:
                    //
                    //   `(size + (align-1)) & -align`

O
Oliver Schneider 已提交
382
                    Ok((size.abi_align(align), align))
383 384
                }
                ty::TyDynamic(..) => {
385
                    let (_, vtable) = self.into_ptr_vtable_pair(value)?;
386 387 388 389 390
                    // the second entry in the vtable is the dynamic size of the object.
                    self.read_size_and_align_from_vtable(vtable)
                }

                ty::TySlice(_) | ty::TyStr => {
O
Oliver Schneider 已提交
391
                    let (elem_size, align) = layout.field(&self, 0)?.size_and_align();
392
                    let (_, len) = self.into_slice(value)?;
O
Oliver Schneider 已提交
393
                    Ok((elem_size * len, align))
394 395 396 397 398 399 400
                }

                _ => bug!("size_of_val::<{:?}>", ty),
            }
        }
    }

O
Oliver Schneider 已提交
401 402
    pub fn push_stack_frame(
        &mut self,
O
Oliver Schneider 已提交
403
        instance: ty::Instance<'tcx>,
O
Oliver Schneider 已提交
404
        span: codemap::Span,
405
        mir: &'tcx mir::Mir<'tcx>,
O
Oliver Schneider 已提交
406
        return_place: Place,
407
        return_to_block: StackPopCleanup,
408
    ) -> EvalResult<'tcx> {
409 410
        ::log_settings::settings().indentation += 1;

R
Ralf Jung 已提交
411
        /// Return the set of locals that have a storage annotation anywhere
412
        fn collect_storage_annotations<'tcx>(mir: &'tcx mir::Mir<'tcx>) -> HashSet<mir::Local> {
413
            use rustc::mir::StatementKind::*;
414 415 416 417 418

            let mut set = HashSet::new();
            for block in mir.basic_blocks() {
                for stmt in block.statements.iter() {
                    match stmt.kind {
O
Rustup  
Oliver Schneider 已提交
419 420
                        StorageLive(local) |
                        StorageDead(local) => {
421 422 423 424 425
                            set.insert(local);
                        }
                        _ => {}
                    }
                }
R
rustfmt  
Ralf Jung 已提交
426
            }
427 428 429
            set
        }

430
        // Subtract 1 because `local_decls` includes the ReturnMemoryPointer, but we don't store a local
S
Scott Olson 已提交
431 432
        // `Value` for that.
        let num_locals = mir.local_decls.len() - 1;
O
Oliver Schneider 已提交
433

434
        let locals = {
O
Oliver Schneider 已提交
435 436 437 438 439 440 441
            let annotated_locals = collect_storage_annotations(mir);
            let mut locals = vec![None; num_locals];
            for i in 0..num_locals {
                let local = mir::Local::new(i + 1);
                if !annotated_locals.contains(&local) {
                    locals[i] = Some(Value::ByVal(PrimVal::Undef));
                }
R
Ralf Jung 已提交
442
            }
O
Oliver Schneider 已提交
443 444
            locals
        };
445

446
        self.stack.push(Frame {
S
Scott Olson 已提交
447
            mir,
448
            block: mir::START_BLOCK,
S
Scott Olson 已提交
449
            return_to_block,
O
Oliver Schneider 已提交
450
            return_place,
S
Scott Olson 已提交
451 452
            locals,
            span,
O
Oliver Schneider 已提交
453
            instance,
454
            stmt: 0,
455
        });
456

457
        self.memory.cur_frame = self.cur_frame();
458

459
        if self.stack.len() > self.stack_limit {
460
            err!(StackFrameLimitReached)
461 462 463
        } else {
            Ok(())
        }
464 465
    }

466
    pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
467
        ::log_settings::settings().indentation -= 1;
O
Oliver Schneider 已提交
468
        M::end_region(self, None)?;
R
rustfmt  
Ralf Jung 已提交
469 470 471
        let frame = self.stack.pop().expect(
            "tried to pop a stack frame, but there were none",
        );
472
        if !self.stack.is_empty() {
473 474
            // TODO: Is this the correct time to start considering these accesses as originating from the returned-to stack frame?
            self.memory.cur_frame = self.cur_frame();
475
        }
476
        match frame.return_to_block {
R
rustfmt  
Ralf Jung 已提交
477
            StackPopCleanup::MarkStatic(mutable) => {
O
Oliver Schneider 已提交
478
                if let Place::Ptr { ptr, .. } = frame.return_place {
R
rustfmt  
Ralf Jung 已提交
479 480 481 482 483 484
                    // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
                    self.memory.mark_static_initalized(
                        ptr.to_ptr()?.alloc_id,
                        mutable,
                    )?
                } else {
O
Oliver Schneider 已提交
485
                    bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_place);
R
rustfmt  
Ralf Jung 已提交
486 487
                }
            }
488
            StackPopCleanup::Goto(target) => self.goto_block(target),
R
rustfmt  
Ralf Jung 已提交
489
            StackPopCleanup::None => {}
490
        }
O
Oliver Schneider 已提交
491
        // deallocate all locals that are backed by an allocation
S
Scott Olson 已提交
492
        for local in frame.locals {
493
            self.deallocate_local(local)?;
494
        }
O
Oliver Schneider 已提交
495

496
        Ok(())
497 498
    }

499
    pub fn deallocate_local(&mut self, local: Option<Value>) -> EvalResult<'tcx> {
500
        if let Some(Value::ByRef(ptr, _align)) = local {
501
            trace!("deallocating local");
502
            let ptr = ptr.to_ptr()?;
503
            self.memory.dump_alloc(ptr.alloc_id);
O
Oliver Schneider 已提交
504
            self.memory.deallocate_local(ptr)?;
505 506 507 508
        };
        Ok(())
    }

509 510 511
    /// Evaluate an assignment statement.
    ///
    /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
O
Oliver Schneider 已提交
512 513
    /// type writes its results directly into the memory specified by the place.
    pub(super) fn eval_rvalue_into_place(
514 515
        &mut self,
        rvalue: &mir::Rvalue<'tcx>,
O
Oliver Schneider 已提交
516
        place: &mir::Place<'tcx>,
517
    ) -> EvalResult<'tcx> {
O
Oliver Schneider 已提交
518 519
        let dest = self.eval_place(place)?;
        let dest_ty = self.place_ty(place);
520

521
        use rustc::mir::Rvalue::*;
522
        match *rvalue {
523
            Use(ref operand) => {
524 525 526 527 528 529
                let value = self.eval_operand(operand)?.value;
                let valty = ValTy {
                    value,
                    ty: dest_ty,
                };
                self.write_value(valty, dest)?;
530
            }
531

532
            BinaryOp(bin_op, ref left, ref right) => {
533 534
                let left = self.eval_operand(left)?;
                let right = self.eval_operand(right)?;
R
rustfmt  
Ralf Jung 已提交
535 536 537 538 539 540 541 542
                if self.intrinsic_overflowing(
                    bin_op,
                    left,
                    right,
                    dest,
                    dest_ty,
                )?
                {
543 544
                    // There was an overflow in an unchecked binop.  Right now, we consider this an error and bail out.
                    // The rationale is that the reason rustc emits unchecked binops in release mode (vs. the checked binops
R
typos  
Ralf Jung 已提交
545
                    // it emits in debug mode) is performance, but it doesn't cost us any performance in miri.
546 547
                    // If, however, the compiler ever starts transforming unchecked intrinsics into unchecked binops,
                    // we have to go back to just ignoring the overflow here.
548
                    return err!(OverflowingMath);
549
                }
550
            }
551

552
            CheckedBinaryOp(bin_op, ref left, ref right) => {
553 554
                let left = self.eval_operand(left)?;
                let right = self.eval_operand(right)?;
R
rustfmt  
Ralf Jung 已提交
555 556 557 558 559 560 561
                self.intrinsic_with_overflow(
                    bin_op,
                    left,
                    right,
                    dest,
                    dest_ty,
                )?;
562
            }
563

564
            UnaryOp(un_op, ref operand) => {
565
                let val = self.eval_operand_to_primval(operand)?;
566
                let kind = self.ty_to_primval_kind(dest_ty)?;
R
rustfmt  
Ralf Jung 已提交
567 568 569 570 571
                self.write_primval(
                    dest,
                    operator::unary_op(un_op, val, kind)?,
                    dest_ty,
                )?;
572
            }
573

574
            Aggregate(ref kind, ref operands) => {
575
                self.inc_step_counter_and_check_limit(operands.len() as u64)?;
576

O
Oliver Schneider 已提交
577 578 579 580 581
                let (dest, active_field_index) = match **kind {
                    mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
                        self.write_discriminant_value(dest_ty, dest, variant_index)?;
                        if adt_def.is_enum() {
                            (self.place_downcast(dest, variant_index)?, active_field_index)
582
                        } else {
O
Oliver Schneider 已提交
583
                            (dest, active_field_index)
584 585
                        }
                    }
O
Oliver Schneider 已提交
586 587
                    _ => (dest, None)
                };
588

589
                let layout = self.layout_of(dest_ty)?;
O
Oliver Schneider 已提交
590 591 592
                for (i, operand) in operands.iter().enumerate() {
                    let value = self.eval_operand(operand)?;
                    // Ignore zero-sized fields.
593
                    if !self.layout_of(value.ty)?.is_zst() {
O
Oliver Schneider 已提交
594 595 596
                        let field_index = active_field_index.unwrap_or(i);
                        let (field_dest, _) = self.place_field(dest, mir::Field::new(field_index), layout)?;
                        self.write_value(value, field_dest)?;
S
Scott Olson 已提交
597
                    }
598
                }
599
            }
600

601
            Repeat(ref operand, _) => {
602
                let (elem_ty, length) = match dest_ty.sty {
R
Ralf Jung 已提交
603
                    ty::TyArray(elem_ty, n) => (elem_ty, n.val.to_const_int().unwrap().to_u64().unwrap()),
R
rustfmt  
Ralf Jung 已提交
604 605 606 607 608 609
                    _ => {
                        bug!(
                            "tried to assign array-repeat to non-array type {:?}",
                            dest_ty
                        )
                    }
610
                };
611
                let elem_size = self.layout_of(elem_ty)?.size.bytes();
612
                let value = self.eval_operand(operand)?.value;
613

614
                let (dest, dest_align) = self.force_allocation(dest)?.to_ptr_align();
615

O
Oliver Schneider 已提交
616
                // FIXME: speed up repeat filling
617
                for i in 0..length {
618
                    let elem_dest = dest.offset(i * elem_size, &self)?;
619
                    self.write_value_to_ptr(value, elem_dest, dest_align, elem_ty)?;
620 621
                }
            }
622

O
Oliver Schneider 已提交
623
            Len(ref place) => {
624
                // FIXME(CTFE): don't allow computing the length of arrays in const eval
O
Oliver Schneider 已提交
625 626
                let src = self.eval_place(place)?;
                let ty = self.place_ty(place);
O
Oliver Schneider 已提交
627
                let (_, len) = src.elem_ty_and_len(ty);
R
rustfmt  
Ralf Jung 已提交
628 629 630 631 632
                self.write_primval(
                    dest,
                    PrimVal::from_u128(len as u128),
                    dest_ty,
                )?;
633 634
            }

O
Oliver Schneider 已提交
635 636 637
            Ref(_, _, ref place) => {
                let src = self.eval_place(place)?;
                // We ignore the alignment of the place here -- special handling for packed structs ends
R
Ralf Jung 已提交
638
                // at the `&` operator.
639
                let (ptr, _align, extra) = self.force_allocation(src)?.to_ptr_align_extra();
640

641
                let val = match extra {
642 643 644
                    PlaceExtra::None => ptr.to_value(),
                    PlaceExtra::Length(len) => ptr.to_value_with_len(len),
                    PlaceExtra::Vtable(vtable) => ptr.to_value_with_vtable(vtable),
O
Oliver Schneider 已提交
645 646
                    PlaceExtra::DowncastVariant(..) => {
                        bug!("attempted to take a reference to an enum downcast place")
R
rustfmt  
Ralf Jung 已提交
647
                    }
648
                };
649 650 651 652 653
                let valty = ValTy {
                    value: val,
                    ty: dest_ty,
                };
                self.write_value(valty, dest)?;
S
Scott Olson 已提交
654
            }
S
Scott Olson 已提交
655

D
David Renshaw 已提交
656
            NullaryOp(mir::NullOp::Box, ty) => {
657
                let ty = self.monomorphize(ty, self.substs());
658
                M::box_alloc(self, ty, dest)?;
S
Scott Olson 已提交
659 660
            }

661
            NullaryOp(mir::NullOp::SizeOf, ty) => {
662 663 664 665
                let ty = self.monomorphize(ty, self.substs());
                let layout = self.layout_of(ty)?;
                assert!(!layout.is_unsized(),
                        "SizeOf nullary MIR operator called for unsized type");
R
rustfmt  
Ralf Jung 已提交
666 667
                self.write_primval(
                    dest,
668
                    PrimVal::from_u128(layout.size.bytes() as u128),
R
rustfmt  
Ralf Jung 已提交
669 670
                    dest_ty,
                )?;
D
David Renshaw 已提交
671 672
            }

673 674
            Cast(kind, ref operand, cast_ty) => {
                debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest_ty);
675
                use rustc::mir::CastKind::*;
676 677
                match kind {
                    Unsize => {
678
                        let src = self.eval_operand(operand)?;
679 680 681
                        let src_layout = self.layout_of(src.ty)?;
                        let dst_layout = self.layout_of(dest_ty)?;
                        self.unsize_into(src.value, src_layout, dest, dst_layout)?;
682 683 684
                    }

                    Misc => {
685
                        let src = self.eval_operand(operand)?;
686 687
                        if self.type_is_fat_ptr(src.ty) {
                            match (src.value, self.type_is_fat_ptr(dest_ty)) {
R
rustfmt  
Ralf Jung 已提交
688
                                (Value::ByRef { .. }, _) |
689
                                (Value::ByValPair(..), true) => {
690 691 692 693 694
                                    let valty = ValTy {
                                        value: src.value,
                                        ty: dest_ty,
                                    };
                                    self.write_value(valty, dest)?;
R
rustfmt  
Ralf Jung 已提交
695
                                }
696
                                (Value::ByValPair(data, _), false) => {
697 698 699 700 701
                                    let valty = ValTy {
                                        value: Value::ByVal(data),
                                        ty: dest_ty,
                                    };
                                    self.write_value(valty, dest)?;
R
rustfmt  
Ralf Jung 已提交
702
                                }
703
                                (Value::ByVal(_), _) => bug!("expected fat ptr"),
O
Oliver Schneider 已提交
704
                            }
705
                        } else {
706 707 708 709 710 711 712
                            let src_val = self.value_to_primval(src)?;
                            let dest_val = self.cast_primval(src_val, src.ty, dest_ty)?;
                            let valty = ValTy {
                                value: Value::ByVal(dest_val),
                                ty: dest_ty,
                            };
                            self.write_value(valty, dest)?;
713
                        }
714 715
                    }

R
rustfmt  
Ralf Jung 已提交
716
                    ReifyFnPointer => {
717
                        match self.eval_operand(operand)?.ty.sty {
R
rustfmt  
Ralf Jung 已提交
718
                            ty::TyFnDef(def_id, substs) => {
719 720 721 722
                                if self.tcx.has_attr(def_id, "rustc_args_required_const") {
                                    bug!("reifying a fn ptr that requires \
                                          const arguments");
                                }
O
Oliver Schneider 已提交
723
                                let instance = self.resolve(def_id, substs)?;
R
rustfmt  
Ralf Jung 已提交
724
                                let fn_ptr = self.memory.create_fn_alloc(instance);
725 726 727 728 729
                                let valty = ValTy {
                                    value: Value::ByVal(PrimVal::Ptr(fn_ptr)),
                                    ty: dest_ty,
                                };
                                self.write_value(valty, dest)?;
R
rustfmt  
Ralf Jung 已提交
730 731 732 733 734 735 736 737
                            }
                            ref other => bug!("reify fn pointer on {:?}", other),
                        }
                    }

                    UnsafeFnPointer => {
                        match dest_ty.sty {
                            ty::TyFnPtr(_) => {
738 739 740
                                let mut src = self.eval_operand(operand)?;
                                src.ty = dest_ty;
                                self.write_value(src, dest)?;
R
rustfmt  
Ralf Jung 已提交
741 742 743 744 745 746
                            }
                            ref other => bug!("fn to unsafe fn cast on {:?}", other),
                        }
                    }

                    ClosureFnPointer => {
747
                        match self.eval_operand(operand)?.ty.sty {
R
rustfmt  
Ralf Jung 已提交
748
                            ty::TyClosure(def_id, substs) => {
O
Oliver Schneider 已提交
749 750
                                let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs);
                                let instance = ty::Instance::resolve_closure(
R
rustfmt  
Ralf Jung 已提交
751 752 753 754 755 756
                                    self.tcx,
                                    def_id,
                                    substs,
                                    ty::ClosureKind::FnOnce,
                                );
                                let fn_ptr = self.memory.create_fn_alloc(instance);
757 758 759 760 761
                                let valty = ValTy {
                                    value: Value::ByVal(PrimVal::Ptr(fn_ptr)),
                                    ty: dest_ty,
                                };
                                self.write_value(valty, dest)?;
R
rustfmt  
Ralf Jung 已提交
762 763 764 765
                            }
                            ref other => bug!("closure fn pointer on {:?}", other),
                        }
                    }
766 767 768
                }
            }

O
Oliver Schneider 已提交
769 770 771 772
            Discriminant(ref place) => {
                let ty = self.place_ty(place);
                let place = self.eval_place(place)?;
                let discr_val = self.read_discriminant_value(place, ty)?;
O
rustup  
Oliver Schneider 已提交
773
                if let ty::TyAdt(adt_def, _) = ty.sty {
774
                    trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(self.tcx).collect::<Vec<_>>());
R
rustfmt  
Ralf Jung 已提交
775 776 777 778
                    if adt_def.discriminants(self.tcx).all(|v| {
                        discr_val != v.to_u128_unchecked()
                    })
                    {
779
                        return err!(InvalidDiscriminant);
O
rustup  
Oliver Schneider 已提交
780
                    }
781
                    self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
O
rustup  
Oliver Schneider 已提交
782 783 784
                } else {
                    bug!("rustc only generates Rvalue::Discriminant for enums");
                }
R
rustfmt  
Ralf Jung 已提交
785
            }
786
        }
787

788
        if log_enabled!(::log::Level::Trace) {
S
Scott Olson 已提交
789 790 791
            self.dump_local(dest);
        }

792
        Ok(())
793 794
    }

795
    pub(super) fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
O
Oliver Schneider 已提交
796
        match ty.sty {
O
rustup  
Oliver Schneider 已提交
797 798 799
            ty::TyRawPtr(ref tam) |
            ty::TyRef(_, ref tam) => !self.type_is_sized(tam.ty),
            ty::TyAdt(def, _) if def.is_box() => !self.type_is_sized(ty.boxed_ty()),
O
Oliver Schneider 已提交
800 801 802 803
            _ => false,
        }
    }

R
rustfmt  
Ralf Jung 已提交
804 805 806 807
    pub(super) fn eval_operand_to_primval(
        &mut self,
        op: &mir::Operand<'tcx>,
    ) -> EvalResult<'tcx, PrimVal> {
808 809 810 811 812 813 814 815 816 817 818
        let valty = self.eval_operand(op)?;
        self.value_to_primval(valty)
    }

    pub(crate) fn operands_to_args(
        &mut self,
        ops: &[mir::Operand<'tcx>],
    ) -> EvalResult<'tcx, Vec<ValTy<'tcx>>> {
        ops.into_iter()
            .map(|op| self.eval_operand(op))
            .collect()
819 820
    }

821
    pub fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> {
822
        use rustc::mir::Operand::*;
823
        let ty = self.monomorphize(op.ty(self.mir(), self.tcx), self.substs());
824
        match *op {
O
Oliver Schneider 已提交
825 826 827
            // FIXME: do some more logic on `move` to invalidate the old location
            Copy(ref place) |
            Move(ref place) => {
828
                Ok(ValTy {
O
Oliver Schneider 已提交
829
                    value: self.eval_and_read_place(place)?,
830
                    ty
831 832
                })
            },
833

D
David Renshaw 已提交
834
            Constant(ref constant) => {
835
                use rustc::mir::Literal;
D
David Renshaw 已提交
836
                let mir::Constant { ref literal, .. } = **constant;
837
                let value = match *literal {
838
                    Literal::Value { ref value } => self.const_to_value(&value.val, ty)?,
839 840

                    Literal::Promoted { index } => {
841
                        self.read_global_as_value(GlobalId {
O
Oliver Schneider 已提交
842
                            instance: self.frame().instance,
O
Oliver Schneider 已提交
843
                            promoted: Some(index),
844
                        }, self.layout_of(ty)?)
845 846 847
                    }
                };

848 849
                Ok(ValTy {
                    value,
850
                    ty,
851
                })
852 853 854
            }
        }
    }
S
Scott Olson 已提交
855

856
    pub fn read_discriminant_value(
O
Oliver Schneider 已提交
857 858 859
        &mut self,
        place: Place,
        ty: Ty<'tcx>,
860
    ) -> EvalResult<'tcx, u128> {
861
        let layout = self.layout_of(ty)?;
O
Oliver Schneider 已提交
862 863 864 865 866
        //trace!("read_discriminant_value {:#?}", layout);

        match layout.variants {
            layout::Variants::Single { index } => {
                return Ok(index as u128);
867
            }
O
Oliver Schneider 已提交
868 869 870
            layout::Variants::Tagged { .. } |
            layout::Variants::NicheFilling { .. } => {},
        }
871

O
Oliver Schneider 已提交
872 873 874 875 876 877 878 879 880 881 882 883
        let (discr_place, discr) = self.place_field(place, mir::Field::new(0), layout)?;
        let raw_discr = self.value_to_primval(ValTy {
            value: self.read_place(discr_place)?,
            ty: discr.ty
        })?;
        let discr_val = match layout.variants {
            layout::Variants::Single { .. } => bug!(),
            layout::Variants::Tagged { .. } => raw_discr.to_bytes()?,
            layout::Variants::NicheFilling {
                dataful_variant,
                ref niche_variants,
                niche_start,
884 885
                ..
            } => {
O
Oliver Schneider 已提交
886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904
                let variants_start = niche_variants.start as u128;
                let variants_end = niche_variants.end as u128;
                match raw_discr {
                    PrimVal::Ptr(_) => {
                        assert!(niche_start == 0);
                        assert!(variants_start == variants_end);
                        dataful_variant as u128
                    },
                    PrimVal::Bytes(raw_discr) => {
                        let discr = raw_discr.wrapping_sub(niche_start)
                            .wrapping_add(variants_start);
                        if variants_start <= discr && discr <= variants_end {
                            discr
                        } else {
                            dataful_variant as u128
                        }
                    },
                    PrimVal::Undef => return err!(ReadUndefBytes),
                }
905
            }
O
Oliver Schneider 已提交
906
        };
907

O
Oliver Schneider 已提交
908 909 910 911 912 913 914 915 916 917
        Ok(discr_val)
    }


    pub(crate) fn write_discriminant_value(
        &mut self,
        dest_ty: Ty<'tcx>,
        dest: Place,
        variant_index: usize,
    ) -> EvalResult<'tcx> {
918
        let layout = self.layout_of(dest_ty)?;
O
Oliver Schneider 已提交
919 920 921 922 923 924 925 926 927

        match layout.variants {
            layout::Variants::Single { index } => {
                if index != variant_index {
                    // If the layout of an enum is `Single`, all
                    // other variants are necessarily uninhabited.
                    assert_eq!(layout.for_variant(&self, variant_index).abi,
                               layout::Abi::Uninhabited);
                }
928
            }
O
Oliver Schneider 已提交
929 930 931 932
            layout::Variants::Tagged { .. } => {
                let discr_val = dest_ty.ty_adt_def().unwrap()
                    .discriminant_for_variant(self.tcx, variant_index)
                    .to_u128_unchecked();
933

O
Oliver Schneider 已提交
934 935 936 937 938 939 940
                let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?;
                self.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?;
            }
            layout::Variants::NicheFilling {
                dataful_variant,
                ref niche_variants,
                niche_start,
941 942
                ..
            } => {
O
Oliver Schneider 已提交
943 944 945 946 947 948 949
                if variant_index != dataful_variant {
                    let (niche_dest, niche) =
                        self.place_field(dest, mir::Field::new(0), layout)?;
                    let niche_value = ((variant_index - niche_variants.start) as u128)
                        .wrapping_add(niche_start);
                    self.write_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?;
                }
950
            }
O
Oliver Schneider 已提交
951
        }
952

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

956
    pub fn read_global_as_value(&self, gid: GlobalId, layout: TyLayout) -> Value {
957 958
        let alloc = self.tcx.interpret_interner.borrow().get_cached(gid).expect("global not cached");
        Value::ByRef(MemoryPointer::new(alloc, 0).into(), layout.align)
O
Oliver Schneider 已提交
959 960
    }

O
Oliver Schneider 已提交
961 962 963
    pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> {
        let new_place = match place {
            Place::Local { frame, local } => {
964 965
                // -1 since we don't store the return value
                match self.stack[frame].locals[local.index() - 1] {
966
                    None => return err!(DeadLocal),
967
                    Some(Value::ByRef(ptr, align)) => {
O
Oliver Schneider 已提交
968
                        Place::Ptr {
R
rustfmt  
Ralf Jung 已提交
969
                            ptr,
970
                            align,
O
Oliver Schneider 已提交
971
                            extra: PlaceExtra::None,
R
rustfmt  
Ralf Jung 已提交
972 973
                        }
                    }
974
                    Some(val) => {
975
                        let ty = self.stack[frame].mir.local_decls[local].ty;
O
Oliver Schneider 已提交
976
                        let ty = self.monomorphize(ty, self.stack[frame].instance.substs);
977
                        let layout = self.layout_of(ty)?;
978
                        let ptr = self.alloc_ptr(ty)?;
R
rustfmt  
Ralf Jung 已提交
979
                        self.stack[frame].locals[local.index() - 1] =
980
                            Some(Value::ByRef(ptr.into(), layout.align)); // it stays live
981 982 983
                        let place = Place::from_ptr(ptr, layout.align);
                        self.write_value(ValTy { value: val, ty }, place)?;
                        place
984
                    }
985
                }
986
            }
O
Oliver Schneider 已提交
987
            Place::Ptr { .. } => place,
988
        };
O
Oliver Schneider 已提交
989
        Ok(new_place)
990 991
    }

992
    /// ensures this Value is not a ByRef
O
Oliver Schneider 已提交
993
    pub fn follow_by_ref_value(
994
        &self,
R
rustfmt  
Ralf Jung 已提交
995 996 997
        value: Value,
        ty: Ty<'tcx>,
    ) -> EvalResult<'tcx, Value> {
998
        match value {
999
            Value::ByRef(ptr, align) => {
1000
                self.read_value(ptr, align, ty)
1001
            }
1002 1003 1004 1005
            other => Ok(other),
        }
    }

1006
    pub fn value_to_primval(
1007
        &self,
1008 1009
        ValTy { value, ty } : ValTy<'tcx>,
    ) -> EvalResult<'tcx, PrimVal> {
1010
        match self.follow_by_ref_value(value, ty)? {
R
rustfmt  
Ralf Jung 已提交
1011
            Value::ByRef { .. } => bug!("follow_by_ref_value can't result in `ByRef`"),
1012

1013
            Value::ByVal(primval) => {
1014
                // TODO: Do we really want insta-UB here?
1015 1016
                self.ensure_valid_value(primval, ty)?;
                Ok(primval)
1017 1018
            }

1019
            Value::ByValPair(..) => bug!("value_to_primval can't work with fat pointers"),
1020 1021 1022
        }
    }

O
Oliver Schneider 已提交
1023
    pub fn write_ptr(&mut self, dest: Place, val: Pointer, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> {
1024 1025 1026 1027 1028
        let valty = ValTy {
            value: val.to_value(),
            ty: dest_ty,
        };
        self.write_value(valty, dest)
1029 1030
    }

1031
    pub fn write_primval(
1032
        &mut self,
O
Oliver Schneider 已提交
1033
        dest: Place,
1034
        val: PrimVal,
1035
        dest_ty: Ty<'tcx>,
1036
    ) -> EvalResult<'tcx> {
1037 1038 1039 1040 1041
        let valty = ValTy {
            value: Value::ByVal(val),
            ty: dest_ty,
        };
        self.write_value(valty, dest)
1042 1043
    }

1044
    pub fn write_value(
1045
        &mut self,
1046
        ValTy { value: src_val, ty: dest_ty } : ValTy<'tcx>,
O
Oliver Schneider 已提交
1047
        dest: Place,
1048
    ) -> EvalResult<'tcx> {
1049
        //trace!("Writing {:?} to {:?} at type {:?}", src_val, dest, dest_ty);
R
Ralf Jung 已提交
1050 1051 1052 1053
        // 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 `ByValPair`, 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.

1054
        match dest {
1055
            Place::Ptr { ptr, align, extra } => {
O
Oliver Schneider 已提交
1056
                assert_eq!(extra, PlaceExtra::None);
1057
                self.write_value_to_ptr(src_val, ptr, align, dest_ty)
1058
            }
1059

O
Oliver Schneider 已提交
1060
            Place::Local { frame, local } => {
O
Oliver Schneider 已提交
1061
                let dest = self.stack[frame].get_local(local)?;
1062
                self.write_value_possibly_by_val(
1063
                    src_val,
O
Oliver Schneider 已提交
1064
                    |this, val| this.stack[frame].set_local(local, val),
1065 1066 1067
                    dest,
                    dest_ty,
                )
1068 1069
            }
        }
1070 1071 1072
    }

    // The cases here can be a bit subtle. Read carefully!
1073
    fn write_value_possibly_by_val<F: FnOnce(&mut Self, Value) -> EvalResult<'tcx>>(
1074 1075 1076
        &mut self,
        src_val: Value,
        write_dest: F,
1077
        old_dest_val: Value,
1078
        dest_ty: Ty<'tcx>,
1079
    ) -> EvalResult<'tcx> {
1080
        if let Value::ByRef(dest_ptr, align) = old_dest_val {
1081
            // If the value is already `ByRef` (that is, backed by an `Allocation`),
1082 1083 1084 1085 1086
            // then we must write the new value into this allocation, because there may be
            // other pointers into the allocation. These other pointers are logically
            // pointers into the local variable, and must be able to observe the change.
            //
            // Thus, it would be an error to replace the `ByRef` with a `ByVal`, unless we
1087
            // knew for certain that there were no outstanding pointers to this allocation.
1088
            self.write_value_to_ptr(src_val, dest_ptr, align, dest_ty)?;
1089
        } else if let Value::ByRef(src_ptr, align) = src_val {
1090
            // If the value is not `ByRef`, then we know there are no pointers to it
1091 1092 1093 1094 1095 1096 1097
            // and we can simply overwrite the `Value` in the locals array directly.
            //
            // In this specific case, where the source value is `ByRef`, we must duplicate
            // the allocation, because this is a by-value operation. It would be incorrect
            // if they referred to the same allocation, since then a change to one would
            // implicitly change the other.
            //
1098 1099 1100
            // It is a valid optimization to attempt reading a primitive value out of the
            // source and write that into the destination without making an allocation, so
            // we do so here.
1101 1102 1103 1104 1105 1106 1107 1108
            if let Ok(Some(src_val)) = self.try_read_value(src_ptr, align, dest_ty) {
                write_dest(self, src_val)?;
            } else {
                let dest_ptr = self.alloc_ptr(dest_ty)?.into();
                let layout = self.layout_of(dest_ty)?;
                self.memory.copy(src_ptr, align.min(layout.align), dest_ptr, layout.align, layout.size.bytes(), false)?;
                write_dest(self, Value::ByRef(dest_ptr, layout.align))?;
            }
1109 1110
        } else {
            // Finally, we have the simple case where neither source nor destination are
1111
            // `ByRef`. We may simply copy the source value over the the destintion.
1112
            write_dest(self, src_val)?;
1113
        }
1114
        Ok(())
1115 1116
    }

1117
    pub fn write_value_to_ptr(
1118 1119
        &mut self,
        value: Value,
1120
        dest: Pointer,
1121
        dest_align: Align,
1122
        dest_ty: Ty<'tcx>,
1123
    ) -> EvalResult<'tcx> {
O
Oliver Schneider 已提交
1124
        trace!("write_value_to_ptr: {:#?}", value);
1125
        let layout = self.layout_of(dest_ty)?;
1126
        match value {
1127
            Value::ByRef(ptr, align) => {
1128
                self.memory.copy(ptr, align.min(layout.align), dest, dest_align.min(layout.align), layout.size.bytes(), false)
R
rustfmt  
Ralf Jung 已提交
1129
            }
1130
            Value::ByVal(primval) => {
1131 1132 1133 1134
                match layout.abi {
                    layout::Abi::Scalar(_) => {}
                    _ if primval.is_undef() => {}
                    _ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout)
1135
                }
1136
                // TODO: Do we need signedness?
1137
                self.memory.write_primval(dest.to_ptr()?, dest_align, primval, layout.size.bytes(), false)
1138
            }
1139
            Value::ByValPair(a_val, b_val) => {
O
Oliver Schneider 已提交
1140 1141
                let ptr = dest.to_ptr()?;
                trace!("write_value_to_ptr valpair: {:#?}", layout);
1142 1143 1144 1145 1146 1147 1148 1149
                let (a, b) = match layout.abi {
                    layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
                    _ => bug!("write_value_to_ptr: invalid ByValPair layout: {:#?}", layout)
                };
                let (a_size, b_size) = (a.size(&self), b.size(&self));
                let a_ptr = ptr;
                let b_offset = a_size.abi_align(b.align(&self));
                let b_ptr = ptr.offset(b_offset.bytes(), &self)?.into();
O
Oliver Schneider 已提交
1150
                // TODO: What about signedess?
1151 1152
                self.memory.write_primval(a_ptr, dest_align, a_val, a_size.bytes(), false)?;
                self.memory.write_primval(b_ptr, dest_align, b_val, b_size.bytes(), false)
O
Oliver Schneider 已提交
1153
            }
1154
        }
1155 1156
    }

O
Oliver Schneider 已提交
1157
    pub fn ty_to_primval_kind(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimValKind> {
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
        use syntax::ast::FloatTy;

        let kind = match ty.sty {
            ty::TyBool => PrimValKind::Bool,
            ty::TyChar => PrimValKind::Char,

            ty::TyInt(int_ty) => {
                use syntax::ast::IntTy::*;
                let size = match int_ty {
                    I8 => 1,
                    I16 => 2,
                    I32 => 4,
                    I64 => 8,
O
Oliver Schneider 已提交
1171
                    I128 => 16,
1172
                    Isize => self.memory.pointer_size(),
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
                };
                PrimValKind::from_int_size(size)
            }

            ty::TyUint(uint_ty) => {
                use syntax::ast::UintTy::*;
                let size = match uint_ty {
                    U8 => 1,
                    U16 => 2,
                    U32 => 4,
                    U64 => 8,
O
Oliver Schneider 已提交
1184
                    U128 => 16,
1185
                    Usize => self.memory.pointer_size(),
1186 1187 1188 1189 1190 1191 1192 1193 1194
                };
                PrimValKind::from_uint_size(size)
            }

            ty::TyFloat(FloatTy::F32) => PrimValKind::F32,
            ty::TyFloat(FloatTy::F64) => PrimValKind::F64,

            ty::TyFnPtr(_) => PrimValKind::FnPtr,

O
rustup  
Oliver Schneider 已提交
1195 1196 1197
            ty::TyRef(_, ref tam) |
            ty::TyRawPtr(ref tam) if self.type_is_sized(tam.ty) => PrimValKind::Ptr,

O
Oliver Schneider 已提交
1198
            ty::TyAdt(def, _) if def.is_box() => PrimValKind::Ptr,
1199

O
Oliver Schneider 已提交
1200
            ty::TyAdt(..) => {
1201
                match self.layout_of(ty)?.abi {
O
Oliver Schneider 已提交
1202
                    layout::Abi::Scalar(ref scalar) => {
1203
                        use rustc::ty::layout::Primitive::*;
O
Oliver Schneider 已提交
1204 1205 1206
                        match scalar.value {
                            Int(i, false) => PrimValKind::from_uint_size(i.size().bytes()),
                            Int(i, true) => PrimValKind::from_int_size(i.size().bytes()),
1207 1208 1209 1210 1211 1212
                            F32 => PrimValKind::F32,
                            F64 => PrimValKind::F64,
                            Pointer => PrimValKind::Ptr,
                        }
                    }

1213
                    _ => return err!(TypeNotPrimitive(ty)),
1214
                }
1215
            }
1216

1217
            _ => return err!(TypeNotPrimitive(ty)),
1218 1219 1220 1221 1222
        };

        Ok(kind)
    }

1223
    fn ensure_valid_value(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx> {
1224
        match ty.sty {
1225
            ty::TyBool if val.to_bytes()? > 1 => err!(InvalidBool),
1226

R
rustfmt  
Ralf Jung 已提交
1227 1228 1229
            ty::TyChar if ::std::char::from_u32(val.to_bytes()? as u32).is_none() => {
                err!(InvalidChar(val.to_bytes()? as u32 as u128))
            }
1230 1231 1232 1233 1234

            _ => Ok(()),
        }
    }

1235 1236
    pub fn read_value(&self, ptr: Pointer, align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
        if let Some(val) = self.try_read_value(ptr, align, ty)? {
1237 1238 1239 1240 1241 1242
            Ok(val)
        } else {
            bug!("primitive read failed for type: {:?}", ty);
        }
    }

R
rustfmt  
Ralf Jung 已提交
1243 1244 1245
    pub(crate) fn read_ptr(
        &self,
        ptr: MemoryPointer,
1246
        ptr_align: Align,
R
rustfmt  
Ralf Jung 已提交
1247 1248
        pointee_ty: Ty<'tcx>,
    ) -> EvalResult<'tcx, Value> {
1249
        let ptr_size = self.memory.pointer_size();
1250
        let p: Pointer = self.memory.read_ptr_sized_unsigned(ptr, ptr_align)?.into();
O
rustup  
Oliver Schneider 已提交
1251
        if self.type_is_sized(pointee_ty) {
1252
            Ok(p.to_value())
O
rustup  
Oliver Schneider 已提交
1253 1254
        } else {
            trace!("reading fat pointer extra of type {}", pointee_ty);
1255
            let extra = ptr.offset(ptr_size, self)?;
O
Oliver Schneider 已提交
1256
            match self.tcx.struct_tail(pointee_ty).sty {
R
rustfmt  
Ralf Jung 已提交
1257
                ty::TyDynamic(..) => Ok(p.to_value_with_vtable(
1258
                    self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_ptr()?,
R
rustfmt  
Ralf Jung 已提交
1259 1260
                )),
                ty::TySlice(..) | ty::TyStr => Ok(
1261
                    p.to_value_with_len(self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_bytes()? as u64),
R
rustfmt  
Ralf Jung 已提交
1262
                ),
O
rustup  
Oliver Schneider 已提交
1263
                _ => bug!("unsized primval ptr read from {:?}", pointee_ty),
O
Oliver Schneider 已提交
1264
            }
O
rustup  
Oliver Schneider 已提交
1265 1266 1267
        }
    }

1268
    pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
1269 1270
        use syntax::ast::FloatTy;

1271
        let ptr = ptr.to_ptr()?;
S
Scott Olson 已提交
1272
        let val = match ty.sty {
1273
            ty::TyBool => {
1274
                let val = self.memory.read_primval(ptr, ptr_align, 1, false)?;
1275 1276 1277
                let val = match val {
                    PrimVal::Bytes(0) => false,
                    PrimVal::Bytes(1) => true,
R
Ralf Jung 已提交
1278
                    // TODO: This seems a little overeager, should reading at bool type already be insta-UB?
1279 1280 1281 1282
                    _ => return err!(InvalidBool),
                };
                PrimVal::from_bool(val)
            }
S
Scott Olson 已提交
1283
            ty::TyChar => {
1284
                let c = self.memory.read_primval(ptr, ptr_align, 4, false)?.to_bytes()? as u32;
O
Oliver Schneider 已提交
1285
                match ::std::char::from_u32(c) {
S
Scott Olson 已提交
1286
                    Some(ch) => PrimVal::from_char(ch),
1287
                    None => return err!(InvalidChar(c as u128)),
O
Oliver Schneider 已提交
1288 1289
                }
            }
1290

S
Scott Olson 已提交
1291
            ty::TyInt(int_ty) => {
1292 1293 1294 1295 1296 1297
                use syntax::ast::IntTy::*;
                let size = match int_ty {
                    I8 => 1,
                    I16 => 2,
                    I32 => 4,
                    I64 => 8,
O
Oliver Schneider 已提交
1298
                    I128 => 16,
1299
                    Isize => self.memory.pointer_size(),
1300
                };
1301
                self.memory.read_primval(ptr, ptr_align, size, true)?
1302
            }
1303

S
Scott Olson 已提交
1304
            ty::TyUint(uint_ty) => {
1305 1306 1307 1308 1309 1310
                use syntax::ast::UintTy::*;
                let size = match uint_ty {
                    U8 => 1,
                    U16 => 2,
                    U32 => 4,
                    U64 => 8,
O
Oliver Schneider 已提交
1311
                    U128 => 16,
1312
                    Usize => self.memory.pointer_size(),
1313
                };
1314
                self.memory.read_primval(ptr, ptr_align, size, false)?
1315
            }
1316

1317 1318 1319 1320 1321 1322
            ty::TyFloat(FloatTy::F32) => {
                PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 4, false)?.to_bytes()?)
            }
            ty::TyFloat(FloatTy::F64) => {
                PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 8, false)?.to_bytes()?)
            }
1323

1324
            ty::TyFnPtr(_) => self.memory.read_ptr_sized_unsigned(ptr, ptr_align)?,
O
rustup  
Oliver Schneider 已提交
1325
            ty::TyRef(_, ref tam) |
1326
            ty::TyRawPtr(ref tam) => return self.read_ptr(ptr, ptr_align, tam.ty).map(Some),
1327

O
rustup  
Oliver Schneider 已提交
1328 1329
            ty::TyAdt(def, _) => {
                if def.is_box() {
1330
                    return self.read_ptr(ptr, ptr_align, ty.boxed_ty()).map(Some);
O
rustup  
Oliver Schneider 已提交
1331
                }
O
Oliver Schneider 已提交
1332

1333
                if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi {
O
Oliver Schneider 已提交
1334 1335 1336 1337 1338
                    let mut signed = false;
                    if let layout::Int(_, s) = scalar.value {
                        signed = s;
                    }
                    let size = scalar.value.size(self).bytes();
1339
                    self.memory.read_primval(ptr, ptr_align, size, signed)?
O
Oliver Schneider 已提交
1340
                } else {
1341
                    return Ok(None);
O
Oliver Schneider 已提交
1342
                }
R
rustfmt  
Ralf Jung 已提交
1343
            }
O
Oliver Schneider 已提交
1344

1345
            _ => return Ok(None),
1346
        };
S
Scott Olson 已提交
1347

1348
        Ok(Some(Value::ByVal(val)))
1349 1350
    }

1351
    pub fn frame(&self) -> &Frame<'tcx> {
1352 1353
        self.stack.last().expect("no call frames exist")
    }
1354

O
Oliver Schneider 已提交
1355
    pub fn frame_mut(&mut self) -> &mut Frame<'tcx> {
1356 1357
        self.stack.last_mut().expect("no call frames exist")
    }
1358

1359 1360
    pub(super) fn mir(&self) -> &'tcx mir::Mir<'tcx> {
        self.frame().mir
S
Scott Olson 已提交
1361
    }
O
Oliver Schneider 已提交
1362

O
Oliver Schneider 已提交
1363
    pub fn substs(&self) -> &'tcx Substs<'tcx> {
1364 1365 1366 1367 1368
        if let Some(frame) = self.stack.last() {
            frame.instance.substs
        } else {
            Substs::empty()
        }
O
Oliver Schneider 已提交
1369
    }
1370

O
rustup  
Oliver Schneider 已提交
1371 1372 1373 1374
    fn unsize_into_ptr(
        &mut self,
        src: Value,
        src_ty: Ty<'tcx>,
O
Oliver Schneider 已提交
1375
        dest: Place,
O
rustup  
Oliver Schneider 已提交
1376 1377 1378
        dest_ty: Ty<'tcx>,
        sty: Ty<'tcx>,
        dty: Ty<'tcx>,
1379
    ) -> EvalResult<'tcx> {
O
rustup  
Oliver Schneider 已提交
1380 1381 1382 1383 1384
        // A<Struct> -> A<Trait> conversion
        let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty);

        match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
            (&ty::TyArray(_, length), &ty::TySlice(_)) => {
1385
                let ptr = self.into_ptr(src)?;
O
Oliver Schneider 已提交
1386
                // u64 cast is from usize to u64, which is always good
1387
                let valty = ValTy {
R
Ralf Jung 已提交
1388
                    value: ptr.to_value_with_len(length.val.to_const_int().unwrap().to_u64().unwrap() ),
1389 1390 1391
                    ty: dest_ty,
                };
                self.write_value(valty, dest)
O
rustup  
Oliver Schneider 已提交
1392 1393 1394 1395 1396
            }
            (&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
                // For now, upcasts are limited to changes in marker
                // traits, and hence never actually require an actual
                // change to the vtable.
1397 1398 1399 1400 1401
                let valty = ValTy {
                    value: src,
                    ty: dest_ty,
                };
                self.write_value(valty, dest)
R
rustfmt  
Ralf Jung 已提交
1402
            }
O
rustup  
Oliver Schneider 已提交
1403
            (_, &ty::TyDynamic(ref data, _)) => {
R
rustfmt  
Ralf Jung 已提交
1404 1405 1406 1407
                let trait_ref = data.principal().unwrap().with_self_ty(
                    self.tcx,
                    src_pointee_ty,
                );
O
rustup  
Oliver Schneider 已提交
1408
                let trait_ref = self.tcx.erase_regions(&trait_ref);
O
Oliver Schneider 已提交
1409
                let vtable = self.get_vtable(src_pointee_ty, trait_ref)?;
1410
                let ptr = self.into_ptr(src)?;
1411 1412 1413 1414 1415
                let valty = ValTy {
                    value: ptr.to_value_with_vtable(vtable),
                    ty: dest_ty,
                };
                self.write_value(valty, dest)
R
rustfmt  
Ralf Jung 已提交
1416
            }
O
rustup  
Oliver Schneider 已提交
1417 1418 1419 1420 1421

            _ => bug!("invalid unsizing {:?} -> {:?}", src_ty, dest_ty),
        }
    }

1422 1423 1424
    fn unsize_into(
        &mut self,
        src: Value,
1425
        src_layout: TyLayout<'tcx>,
1426
        dst: Place,
1427
        dst_layout: TyLayout<'tcx>,
1428
    ) -> EvalResult<'tcx> {
1429
        match (&src_layout.ty.sty, &dst_layout.ty.sty) {
O
rustup  
Oliver Schneider 已提交
1430 1431
            (&ty::TyRef(_, ref s), &ty::TyRef(_, ref d)) |
            (&ty::TyRef(_, ref s), &ty::TyRawPtr(ref d)) |
R
rustfmt  
Ralf Jung 已提交
1432
            (&ty::TyRawPtr(ref s), &ty::TyRawPtr(ref d)) => {
1433
                self.unsize_into_ptr(src, src_layout.ty, dst, dst_layout.ty, s.ty, d.ty)
R
rustfmt  
Ralf Jung 已提交
1434
            }
1435
            (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => {
1436
                assert_eq!(def_a, def_b);
O
rustup  
Oliver Schneider 已提交
1437 1438
                if def_a.is_box() || def_b.is_box() {
                    if !def_a.is_box() || !def_b.is_box() {
1439
                        bug!("invalid unsizing between {:?} -> {:?}", src_layout, dst_layout);
1440
                    }
R
rustfmt  
Ralf Jung 已提交
1441 1442
                    return self.unsize_into_ptr(
                        src,
1443
                        src_layout.ty,
1444
                        dst,
1445 1446 1447
                        dst_layout.ty,
                        src_layout.ty.boxed_ty(),
                        dst_layout.ty.boxed_ty(),
R
rustfmt  
Ralf Jung 已提交
1448
                    );
1449
                }
1450

1451 1452 1453
                // unsizing of generic struct with pointer fields
                // Example: `Arc<T>` -> `Arc<Trait>`
                // here we need to increase the size of every &T thin ptr field to a fat ptr
1454
                for i in 0..src_layout.fields.count() {
1455 1456
                    let (dst_f_place, dst_field) =
                        self.place_field(dst, mir::Field::new(i), dst_layout)?;
1457
                    if dst_field.is_zst() {
1458 1459
                        continue;
                    }
1460
                    let (src_f_value, src_field) = match src {
1461
                        Value::ByRef(ptr, align) => {
1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473
                            let src_place = Place::from_primval_ptr(ptr, align);
                            let (src_f_place, src_field) =
                                self.place_field(src_place, mir::Field::new(i), src_layout)?;
                            (self.read_place(src_f_place)?, src_field)
                        }
                        Value::ByVal(_) | Value::ByValPair(..) => {
                            let src_field = src_layout.field(&self, i)?;
                            assert_eq!(src_layout.fields.offset(i).bytes(), 0);
                            assert_eq!(src_field.size, src_layout.size);
                            (src, src_field)
                        }
                    };
1474
                    if src_field.ty == dst_field.ty {
1475 1476 1477 1478
                        self.write_value(ValTy {
                            value: src_f_value,
                            ty: src_field.ty,
                        }, dst_f_place)?;
1479
                    } else {
1480
                        self.unsize_into(src_f_value, src_field, dst_f_place, dst_field)?;
1481 1482
                    }
                }
O
rustup  
Oliver Schneider 已提交
1483
                Ok(())
1484
            }
R
rustfmt  
Ralf Jung 已提交
1485 1486 1487
            _ => {
                bug!(
                    "unsize_into: invalid conversion: {:?} -> {:?}",
1488 1489
                    src_layout,
                    dst_layout
R
rustfmt  
Ralf Jung 已提交
1490 1491
                )
            }
1492 1493
        }
    }
S
Scott Olson 已提交
1494

O
Oliver Schneider 已提交
1495
    pub fn dump_local(&self, place: Place) {
R
Ralf Jung 已提交
1496
        // Debug output
O
Oliver Schneider 已提交
1497 1498
        match place {
            Place::Local { frame, local } => {
1499 1500 1501 1502
                let mut allocs = Vec::new();
                let mut msg = format!("{:?}", local);
                if frame != self.cur_frame() {
                    write!(msg, " ({} frames up)", self.cur_frame() - frame).unwrap();
1503
                }
1504 1505 1506
                write!(msg, ":").unwrap();

                match self.stack[frame].get_local(local) {
R
rustfmt  
Ralf Jung 已提交
1507
                    Err(EvalError { kind: EvalErrorKind::DeadLocal, .. }) => {
1508 1509 1510 1511 1512
                        write!(msg, " is dead").unwrap();
                    }
                    Err(err) => {
                        panic!("Failed to access local: {:?}", err);
                    }
1513
                    Ok(Value::ByRef(ptr, align)) => {
R
rustfmt  
Ralf Jung 已提交
1514 1515
                        match ptr.into_inner_primval() {
                            PrimVal::Ptr(ptr) => {
1516
                                write!(msg, " by align({}) ref:", align.abi()).unwrap();
R
rustfmt  
Ralf Jung 已提交
1517 1518 1519 1520 1521
                                allocs.push(ptr.alloc_id);
                            }
                            ptr => write!(msg, " integral by ref: {:?}", ptr).unwrap(),
                        }
                    }
1522 1523
                    Ok(Value::ByVal(val)) => {
                        write!(msg, " {:?}", val).unwrap();
R
rustfmt  
Ralf Jung 已提交
1524 1525 1526
                        if let PrimVal::Ptr(ptr) = val {
                            allocs.push(ptr.alloc_id);
                        }
1527 1528 1529
                    }
                    Ok(Value::ByValPair(val1, val2)) => {
                        write!(msg, " ({:?}, {:?})", val1, val2).unwrap();
R
rustfmt  
Ralf Jung 已提交
1530 1531 1532 1533 1534 1535
                        if let PrimVal::Ptr(ptr) = val1 {
                            allocs.push(ptr.alloc_id);
                        }
                        if let PrimVal::Ptr(ptr) = val2 {
                            allocs.push(ptr.alloc_id);
                        }
1536
                    }
1537
                }
1538 1539 1540 1541

                trace!("{}", msg);
                self.memory.dump_allocs(allocs);
            }
1542
            Place::Ptr { ptr, align, .. } => {
1543
                match ptr.into_inner_primval() {
1544
                    PrimVal::Ptr(ptr) => {
1545
                        trace!("by align({}) ref:", align.abi());
1546
                        self.memory.dump_alloc(ptr.alloc_id);
R
rustfmt  
Ralf Jung 已提交
1547
                    }
1548
                    ptr => trace!(" integral by ref: {:?}", ptr),
1549 1550
                }
            }
S
Scott Olson 已提交
1551
        }
1552
    }
1553

O
Oliver Schneider 已提交
1554
    /// Convenience function to ensure correct usage of locals
R
rustfmt  
Ralf Jung 已提交
1555 1556 1557
    pub fn modify_local<F>(&mut self, frame: usize, local: mir::Local, f: F) -> EvalResult<'tcx>
    where
        F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
1558
    {
O
Oliver Schneider 已提交
1559
        let val = self.stack[frame].get_local(local)?;
1560
        let new_val = f(self, val)?;
O
Oliver Schneider 已提交
1561
        self.stack[frame].set_local(local, new_val)?;
1562 1563 1564 1565
        // FIXME(solson): Run this when setting to Undef? (See previous version of this code.)
        // if let Value::ByRef(ptr) = self.stack[frame].get_local(local) {
        //     self.memory.deallocate(ptr)?;
        // }
1566 1567
        Ok(())
    }
1568

1569 1570 1571 1572
    pub fn report(&self, e: &mut EvalError) {
        if let Some(ref mut backtrace) = e.backtrace {
            let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
            backtrace.resolve();
O
Oliver Schneider 已提交
1573
            write!(trace_text, "backtrace frames: {}\n", backtrace.frames().len()).unwrap();
1574
            'frames: for (i, frame) in backtrace.frames().iter().enumerate() {
O
Oliver Schneider 已提交
1575 1576
                if frame.symbols().is_empty() {
                    write!(trace_text, "{}: no symbols\n", i).unwrap();
1577
                }
1578
                for symbol in frame.symbols() {
R
rustfmt  
Ralf Jung 已提交
1579
                    write!(trace_text, "{}: ", i).unwrap();
1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595
                    if let Some(name) = symbol.name() {
                        write!(trace_text, "{}\n", name).unwrap();
                    } else {
                        write!(trace_text, "<unknown>\n").unwrap();
                    }
                    write!(trace_text, "\tat ").unwrap();
                    if let Some(file_path) = symbol.filename() {
                        write!(trace_text, "{}", file_path.display()).unwrap();
                    } else {
                        write!(trace_text, "<unknown_file>").unwrap();
                    }
                    if let Some(line) = symbol.lineno() {
                        write!(trace_text, ":{}\n", line).unwrap();
                    } else {
                        write!(trace_text, "\n").unwrap();
                    }
1596
                }
1597
            }
1598
            error!("{}", trace_text);
1599
        }
1600 1601 1602 1603 1604 1605 1606 1607 1608
        if let Some(frame) = self.stack().last() {
            let block = &frame.mir.basic_blocks()[frame.block];
            let span = if frame.stmt < block.statements.len() {
                block.statements[frame.stmt].source_info.span
            } else {
                block.terminator().source_info.span
            };
            let mut err = self.tcx.sess.struct_span_err(span, &e.to_string());
            for &Frame { instance, span, .. } in self.stack().iter().rev() {
R
rustfmt  
Ralf Jung 已提交
1609 1610 1611
                if self.tcx.def_key(instance.def_id()).disambiguated_data.data ==
                    DefPathData::ClosureExpr
                {
1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
                    err.span_note(span, "inside call to closure");
                    continue;
                }
                err.span_note(span, &format!("inside call to {}", instance));
            }
            err.emit();
        } else {
            self.tcx.sess.err(&e.to_string());
        }
    }
1622 1623
}

1624
impl<'tcx> Frame<'tcx> {
O
Oliver Schneider 已提交
1625
    pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> {
1626
        // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
1627
        self.locals[local.index() - 1].ok_or(EvalErrorKind::DeadLocal.into())
1628 1629
    }

O
Oliver Schneider 已提交
1630
    fn set_local(&mut self, local: mir::Local, value: Value) -> EvalResult<'tcx> {
1631
        // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
O
Oliver Schneider 已提交
1632
        match self.locals[local.index() - 1] {
1633
            None => err!(DeadLocal),
O
Oliver Schneider 已提交
1634 1635 1636
            Some(ref mut local) => {
                *local = value;
                Ok(())
1637
            }
1638
        }
1639 1640
    }

1641
    pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, Option<Value>> {
1642
        trace!("{:?} is now live", local);
1643 1644 1645 1646

        let old = self.locals[local.index() - 1];
        self.locals[local.index() - 1] = Some(Value::ByVal(PrimVal::Undef)); // StorageLive *always* kills the value that's currently stored
        return Ok(old);
1647 1648 1649 1650 1651 1652 1653 1654 1655
    }

    /// Returns the old value of the local
    pub fn storage_dead(&mut self, local: mir::Local) -> EvalResult<'tcx, Option<Value>> {
        trace!("{:?} is now dead", local);

        let old = self.locals[local.index() - 1];
        self.locals[local.index() - 1] = None;
        return Ok(old);
1656 1657 1658
    }
}

1659 1660
// TODO(solson): Upstream these methods into rustc::ty::layout.

1661 1662 1663
pub fn resolve_drop_in_place<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    ty: Ty<'tcx>,
R
rustfmt  
Ralf Jung 已提交
1664
) -> ty::Instance<'tcx> {
1665
    let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem);
V
varkor 已提交
1666
    let substs = tcx.intern_substs(&[ty.into()]);
O
Oliver Schneider 已提交
1667
    ty::Instance::resolve(tcx, ty::ParamEnv::empty(Reveal::All), def_id, substs).unwrap()
1668
}