eval_context.rs 64.7 KB
Newer Older
1 2
use std::cell::Ref;
use std::collections::HashMap;
S
Scott Olson 已提交
3
use std::fmt::Write;
4

5
use rustc::hir::def_id::DefId;
6
use rustc::hir::map::definitions::DefPathData;
7
use rustc::middle::const_val::ConstVal;
8
use rustc::mir;
S
Scott Olson 已提交
9
use rustc::traits::Reveal;
10
use rustc::ty::layout::{self, Layout, Size};
11
use rustc::ty::subst::{self, Subst, Substs};
12
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
13
use rustc_data_structures::indexed_vec::Idx;
14
use rustc_data_structures::fx::FxHashSet;
15
use syntax::codemap::{self, DUMMY_SP};
16

17
use error::{EvalError, EvalResult};
18
use lvalue::{Global, GlobalId, Lvalue, LvalueExtra};
19
use memory::{Memory, Pointer};
20
use operator;
S
Scott Olson 已提交
21
use value::{PrimVal, PrimValKind, Value};
O
Oliver Schneider 已提交
22

S
Scott Olson 已提交
23
pub type MirRef<'tcx> = Ref<'tcx, mir::Mir<'tcx>>;
24

25
pub struct EvalContext<'a, 'tcx: 'a> {
26
    /// The results of the type checker, from rustc.
27
    pub(super) tcx: TyCtxt<'a, 'tcx, 'tcx>,
28 29

    /// The virtual memory system.
30
    pub(super) memory: Memory<'a, 'tcx>,
31

32
    /// Precomputed statics, constants and promoteds.
33
    pub(super) globals: HashMap<GlobalId<'tcx>, Global<'tcx>>,
34 35

    /// The virtual call stack.
36
    pub(super) stack: Vec<Frame<'tcx>>,
37 38

    /// The maximum number of stack frames allowed
39
    pub(super) stack_limit: usize,
40 41 42 43

    /// 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.
44
    pub(super) steps_remaining: u64,
45 46
}

47
/// A stack frame.
48
pub struct Frame<'tcx> {
49 50 51
    ////////////////////////////////////////////////////////////////////////////////
    // Function and callsite information
    ////////////////////////////////////////////////////////////////////////////////
52

53
    /// The MIR for the function called on this frame.
54
    pub mir: MirRef<'tcx>,
55 56 57

    /// The def_id of the current function.
    pub def_id: DefId,
58

59
    /// type substitutions for the current function invocation.
60
    pub substs: &'tcx Substs<'tcx>,
61

62 63
    /// The span of the call site.
    pub span: codemap::Span,
64

65
    ////////////////////////////////////////////////////////////////////////////////
66
    // Return lvalue and locals
67
    ////////////////////////////////////////////////////////////////////////////////
68

69
    /// The block to return to when returning from the current stack frame
70
    pub return_to_block: StackPopCleanup,
71

72
    /// The location where the result of the current stack frame should be written to.
73
    pub return_lvalue: Lvalue<'tcx>,
74 75 76 77

    /// The list of locals for this stack frame, stored in order as
    /// `[arguments..., variables..., temporaries...]`. The locals are stored as `Value`s, which
    /// can either directly contain `PrimVal` or refer to some part of an `Allocation`.
S
Scott Olson 已提交
78
    ///
79 80
    /// Before being initialized, all locals are `Value::ByVal(PrimVal::Undef)`.
    pub locals: Vec<Value>,
81

O
Oliver Schneider 已提交
82
    /// Temporary allocations introduced to save stackframes
83 84
    /// This is pure interpreter magic and has nothing to do with how rustc does it
    /// An example is calling an FnMut closure that has been converted to a FnOnce closure
O
Oliver Schneider 已提交
85
    /// The memory will be freed when the stackframe finishes
86
    pub interpreter_temporaries: Vec<Pointer>,
87

88 89 90 91 92 93 94 95 96
    ////////////////////////////////////////////////////////////////////////////////
    // 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,

    /// The index of the currently evaluated statment.
97
    pub stmt: usize,
98
}
99

100 101
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum StackPopCleanup {
102
    /// The stackframe existed to compute the initial value of a static/constant, make sure it
103 104 105 106 107
    /// 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
    /// The bool decides whether the value is mutable (true) or not (false)
    MarkStatic(bool),
108 109 110 111 112 113 114
    /// 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 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
#[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,
        }
    }
}

132
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
S
Scott Olson 已提交
133
    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, limits: ResourceLimits) -> Self {
134
        EvalContext {
S
Scott Olson 已提交
135
            tcx,
S
Scott Olson 已提交
136
            memory: Memory::new(&tcx.data_layout, limits.memory_size),
137
            globals: HashMap::new(),
138
            stack: Vec::new(),
S
Scott Olson 已提交
139 140
            stack_limit: limits.stack_limit,
            steps_remaining: limits.step_limit,
141 142
        }
    }
143

S
Scott Olson 已提交
144 145 146 147 148 149
    pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, Pointer> {
        let substs = self.substs();
        self.alloc_ptr_with_substs(ty, substs)
    }

    pub fn alloc_ptr_with_substs(
150 151 152 153
        &mut self,
        ty: Ty<'tcx>,
        substs: &'tcx Substs<'tcx>
    ) -> EvalResult<'tcx, Pointer> {
154 155
        let size = self.type_size_with_substs(ty, substs)?.expect("cannot alloc memory for unsized type");
        let align = self.type_align_with_substs(ty, substs)?;
S
Scott Olson 已提交
156
        self.memory.allocate(size, align)
157
    }
O
Oliver Schneider 已提交
158

159
    pub fn memory(&self) -> &Memory<'a, 'tcx> {
160 161 162
        &self.memory
    }

163
    pub fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx> {
O
Oliver Schneider 已提交
164 165 166
        &mut self.memory
    }

167
    pub fn stack(&self) -> &[Frame<'tcx>] {
168 169 170
        &self.stack
    }

171
    pub(super) fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
172
        // FIXME: cache these allocs
173
        let ptr = self.memory.allocate(s.len() as u64, 1)?;
174
        self.memory.write_bytes(ptr, s.as_bytes())?;
175
        self.memory.mark_static_initalized(ptr.alloc_id, false)?;
O
Oliver Schneider 已提交
176
        Ok(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::from_u128(s.len() as u128)))
177 178
    }

179
    pub(super) fn const_to_value(&mut self, const_val: &ConstVal) -> EvalResult<'tcx, Value> {
180
        use rustc::middle::const_val::ConstVal::*;
S
Scott Olson 已提交
181
        use rustc_const_math::ConstFloat;
182 183

        let primval = match *const_val {
O
Oliver Schneider 已提交
184
            Integral(const_int) => PrimVal::Bytes(const_int.to_u128_unchecked()),
S
Scott Olson 已提交
185 186 187 188 189 190 191 192

            Float(ConstFloat::F32(f)) => PrimVal::from_f32(f),
            Float(ConstFloat::F64(f)) => PrimVal::from_f64(f),
            Float(ConstFloat::FInfer { .. }) =>
                bug!("uninferred constants only exist before typeck"),

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

194
            Str(ref s) => return self.str_to_value(s),
195

196
            ByteStr(ref bs) => {
197
                // FIXME: cache these allocs
198
                let ptr = self.memory.allocate(bs.len() as u64, 1)?;
199
                self.memory.write_bytes(ptr, bs)?;
200
                self.memory.mark_static_initalized(ptr.alloc_id, false)?;
201
                PrimVal::Ptr(ptr)
202
            }
203 204 205 206

            Struct(_)    => unimplemented!(),
            Tuple(_)     => unimplemented!(),
            Function(_)  => unimplemented!(),
S
Scott Olson 已提交
207
            Array(_)     => unimplemented!(),
208 209 210
            Repeat(_, _) => unimplemented!(),
        };

211
        Ok(Value::ByVal(primval))
212 213
    }

214
    pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
O
Oliver Schneider 已提交
215
        // generics are weird, don't run this function on a generic
216
        assert!(!ty.needs_subst());
217 218 219
        ty.is_sized(self.tcx, &self.tcx.empty_parameter_environment(), DUMMY_SP)
    }

220
    pub fn load_mir(&self, def_id: DefId) -> EvalResult<'tcx, MirRef<'tcx>> {
221
        trace!("load mir {:?}", def_id);
222 223
        if def_id.is_local() || self.tcx.sess.cstore.is_item_mir_available(def_id) {
            Ok(self.tcx.item_mir(def_id))
S
Scott Olson 已提交
224
        } else {
225
            Err(EvalError::NoMirFor(self.tcx.item_path_str(def_id)))
226 227
        }
    }
O
Oliver Schneider 已提交
228

229
    pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
O
Oliver Schneider 已提交
230 231 232 233
        // 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);
S
Scott Olson 已提交
234
        self.tcx.normalize_associated_type(&substituted)
O
Oliver Schneider 已提交
235 236
    }

237
    pub(super) fn type_size(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<u64>> {
238
        self.type_size_with_substs(ty, self.substs())
O
Oliver Schneider 已提交
239 240
    }

241
    pub(super) fn type_align(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, u64> {
242 243 244
        self.type_align_with_substs(ty, self.substs())
    }

245 246 247 248 249
    fn type_size_with_substs(
        &self,
        ty: Ty<'tcx>,
        substs: &'tcx Substs<'tcx>,
    ) -> EvalResult<'tcx, Option<u64>> {
250
        let layout = self.type_layout_with_substs(ty, substs)?;
251
        if layout.is_unsized() {
252
            Ok(None)
253
        } else {
254
            Ok(Some(layout.size(&self.tcx.data_layout).bytes()))
255
        }
256 257
    }

258 259
    fn type_align_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, u64> {
        self.type_layout_with_substs(ty, substs).map(|layout| layout.align(&self.tcx.data_layout).abi())
260 261
    }

262
    pub(super) fn type_layout(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, &'tcx Layout> {
263 264 265
        self.type_layout_with_substs(ty, self.substs())
    }

266
    fn type_layout_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, &'tcx Layout> {
O
Oliver Schneider 已提交
267 268 269
        // TODO(solson): Is this inefficient? Needs investigation.
        let ty = self.monomorphize(ty, substs);

O
Oliver Schneider 已提交
270
        self.tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
271
            ty.layout(&infcx).map_err(EvalError::Layout)
O
Oliver Schneider 已提交
272 273
        })
    }
274

O
Oliver Schneider 已提交
275 276 277 278
    pub fn push_stack_frame(
        &mut self,
        def_id: DefId,
        span: codemap::Span,
279
        mir: MirRef<'tcx>,
O
Oliver Schneider 已提交
280
        substs: &'tcx Substs<'tcx>,
281
        return_lvalue: Lvalue<'tcx>,
282
        return_to_block: StackPopCleanup,
283
        temporaries: Vec<Pointer>,
284
    ) -> EvalResult<'tcx> {
285 286
        ::log_settings::settings().indentation += 1;

S
Scott Olson 已提交
287 288 289
        // Subtract 1 because `local_decls` includes the ReturnPointer, but we don't store a local
        // `Value` for that.
        let num_locals = mir.local_decls.len() - 1;
290
        let locals = vec![Value::ByVal(PrimVal::Undef); num_locals];
291

292
        self.stack.push(Frame {
S
Scott Olson 已提交
293
            mir,
294
            block: mir::START_BLOCK,
S
Scott Olson 已提交
295 296 297
            return_to_block,
            return_lvalue,
            locals,
298
            interpreter_temporaries: temporaries,
S
Scott Olson 已提交
299 300 301
            span,
            def_id,
            substs,
302
            stmt: 0,
303
        });
304

305 306 307 308 309
        if self.stack.len() > self.stack_limit {
            Err(EvalError::StackFrameLimitReached)
        } else {
            Ok(())
        }
310 311
    }

312
    pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
313
        ::log_settings::settings().indentation -= 1;
314
        let frame = self.stack.pop().expect("tried to pop a stack frame, but there were none");
315
        match frame.return_to_block {
316
            StackPopCleanup::MarkStatic(mutable) => if let Lvalue::Global(id) = frame.return_lvalue {
317
                let global_value = self.globals.get_mut(&id)
O
Oliver Schneider 已提交
318
                    .expect("global should have been cached (static)");
319
                match global_value.value {
320
                    Value::ByRef(ptr) => self.memory.mark_static_initalized(ptr.alloc_id, mutable)?,
321
                    Value::ByVal(val) => if let PrimVal::Ptr(ptr) = val {
322
                        self.memory.mark_static_initalized(ptr.alloc_id, mutable)?;
323
                    },
324 325
                    Value::ByValPair(val1, val2) => {
                        if let PrimVal::Ptr(ptr) = val1 {
326
                            self.memory.mark_static_initalized(ptr.alloc_id, mutable)?;
327
                        }
328
                        if let PrimVal::Ptr(ptr) = val2 {
329
                            self.memory.mark_static_initalized(ptr.alloc_id, mutable)?;
330 331 332
                        }
                    },
                }
333 334 335
                // see comment on `initialized` field
                assert!(!global_value.initialized);
                global_value.initialized = true;
336
                assert!(global_value.mutable);
337
                global_value.mutable = mutable;
338
            } else {
O
Oliver Schneider 已提交
339
                bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_lvalue);
340
            },
341 342
            StackPopCleanup::Goto(target) => self.goto_block(target),
            StackPopCleanup::None => {},
343
        }
O
Oliver Schneider 已提交
344
        // deallocate all locals that are backed by an allocation
S
Scott Olson 已提交
345
        for local in frame.locals {
346
            if let Value::ByRef(ptr) = local {
347
                trace!("deallocating local");
348
                self.memory.dump_alloc(ptr.alloc_id);
349
                match self.memory.deallocate(ptr) {
O
Oliver Schneider 已提交
350 351
                    // We could alternatively check whether the alloc_id is static before calling
                    // deallocate, but this is much simpler and is probably the rare case.
352
                    Ok(()) | Err(EvalError::DeallocatedStaticMemory) => {},
353 354 355 356
                    other => return other,
                }
            }
        }
357 358 359
        // deallocate all temporary allocations
        for ptr in frame.interpreter_temporaries {
            trace!("deallocating temporary allocation");
360
            self.memory.dump_alloc(ptr.alloc_id);
361 362
            self.memory.deallocate(ptr)?;
        }
363
        Ok(())
364 365
    }

366 367 368 369 370
    pub fn assign_discr_and_fields<
        I: IntoIterator<Item = u64>,
        V: IntoValTyPair<'tcx>,
        J: IntoIterator<Item = V>,
    >(
371
        &mut self,
372
        dest: Lvalue<'tcx>,
373
        offsets: I,
374 375 376
        operands: J,
        discr_val: u128,
        discr_size: u64,
377
    ) -> EvalResult<'tcx> {
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
        // FIXME(solson)
        let dest_ptr = self.force_allocation(dest)?.to_ptr();

        let mut offsets = offsets.into_iter();
        let discr_offset = offsets.next().unwrap();
        let discr_dest = dest_ptr.offset(discr_offset);
        self.memory.write_uint(discr_dest, discr_val, discr_size)?;

        self.assign_fields(dest, offsets, operands)
    }

    pub fn assign_fields<
        I: IntoIterator<Item = u64>,
        V: IntoValTyPair<'tcx>,
        J: IntoIterator<Item = V>,
    >(
        &mut self,
        dest: Lvalue<'tcx>,
        offsets: I,
        operands: J,
398
    ) -> EvalResult<'tcx> {
399
        // FIXME(solson)
400
        let dest = self.force_allocation(dest)?.to_ptr();
401

402
        for (offset, operand) in offsets.into_iter().zip(operands) {
403
            let (value, value_ty) = operand.into_val_ty_pair(self)?;
404
            let field_dest = dest.offset(offset);
405
            self.write_value_to_ptr(value, field_dest, value_ty)?;
406 407 408 409
        }
        Ok(())
    }

410 411 412 413
    /// Evaluate an assignment statement.
    ///
    /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
    /// type writes its results directly into the memory specified by the lvalue.
414
    pub(super) fn eval_rvalue_into_lvalue(
415 416 417
        &mut self,
        rvalue: &mir::Rvalue<'tcx>,
        lvalue: &mir::Lvalue<'tcx>,
418
    ) -> EvalResult<'tcx> {
419
        let dest = self.eval_lvalue(lvalue)?;
S
Scott Olson 已提交
420
        let dest_ty = self.lvalue_ty(lvalue);
421
        let dest_layout = self.type_layout(dest_ty)?;
422

423
        use rustc::mir::Rvalue::*;
424
        match *rvalue {
425
            Use(ref operand) => {
426 427
                let value = self.eval_operand(operand)?;
                self.write_value(value, dest, dest_ty)?;
428
            }
429

430
            BinaryOp(bin_op, ref left, ref right) => {
431
                // ignore overflow bit, rustc inserts check branches for us
432
                self.intrinsic_overflowing(bin_op, left, right, dest, dest_ty)?;
433
            }
434

435
            CheckedBinaryOp(bin_op, ref left, ref right) => {
436
                self.intrinsic_with_overflow(bin_op, left, right, dest, dest_ty)?;
437
            }
438

439
            UnaryOp(un_op, ref operand) => {
440
                let val = self.eval_operand_to_primval(operand)?;
441
                let kind = self.ty_to_primval_kind(dest_ty)?;
442
                self.write_primval(dest, operator::unary_op(un_op, val, kind)?, dest_ty)?;
443
            }
444

445
            Aggregate(ref kind, ref operands) => {
446
                self.inc_step_counter_and_check_limit(operands.len() as u64)?;
447
                use rustc::ty::layout::Layout::*;
448
                match *dest_layout {
449
                    Univariant { ref variant, .. } => {
S
Scott Olson 已提交
450
                        let offsets = variant.offsets.iter().map(|s| s.bytes());
451 452 453 454
                        if variant.packed {
                            let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
                            self.memory.mark_packed(ptr, variant.stride().bytes());
                        }
S
Scott Olson 已提交
455
                        self.assign_fields(dest, offsets, operands)?;
456 457
                    }

458
                    Array { .. } => {
459
                        let elem_size = match dest_ty.sty {
460 461
                            ty::TyArray(elem_ty, _) => self.type_size(elem_ty)?
                                .expect("array elements are sized") as u64,
462
                            _ => bug!("tried to assign {:?} to non-array type {:?}", kind, dest_ty),
463 464
                        };
                        let offsets = (0..).map(|i| i * elem_size);
S
Scott Olson 已提交
465
                        self.assign_fields(dest, offsets, operands)?;
466
                    }
467

468
                    General { discr, ref variants, .. } => {
469
                        if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind {
O
Oliver Schneider 已提交
470
                            let discr_val = adt_def.variants[variant].disr_val.to_u128_unchecked();
471
                            let discr_size = discr.size().bytes();
472 473 474 475
                            if variants[variant].packed {
                                let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
                                self.memory.mark_packed(ptr, variants[variant].stride().bytes());
                            }
476

477 478 479 480 481 482 483
                            self.assign_discr_and_fields(
                                dest,
                                variants[variant].offsets.iter().cloned().map(Size::bytes),
                                operands,
                                discr_val,
                                discr_size,
                            )?;
484
                        } else {
485
                            bug!("tried to assign {:?} to Layout::General", kind);
S
Scott Olson 已提交
486
                        }
487 488
                    }

489
                    RawNullablePointer { nndiscr, .. } => {
490
                        if let mir::AggregateKind::Adt(_, variant, _, _) = *kind {
491 492 493
                            if nndiscr == variant as u64 {
                                assert_eq!(operands.len(), 1);
                                let operand = &operands[0];
494 495 496
                                let value = self.eval_operand(operand)?;
                                let value_ty = self.operand_ty(operand);
                                self.write_value(value, dest, value_ty)?;
497
                            } else {
498 499 500
                                if let Some(operand) = operands.get(0) {
                                    assert_eq!(operands.len(), 1);
                                    let operand_ty = self.operand_ty(operand);
501
                                    assert_eq!(self.type_size(operand_ty)?, Some(0));
502
                                }
S
Scott Olson 已提交
503
                                self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
504 505
                            }
                        } else {
506
                            bug!("tried to assign {:?} to Layout::RawNullablePointer", kind);
S
Scott Olson 已提交
507
                        }
508 509
                    }

S
Scott Olson 已提交
510
                    StructWrappedNullablePointer { nndiscr, ref nonnull, ref discrfield, .. } => {
511
                        if let mir::AggregateKind::Adt(_, variant, _, _) = *kind {
512 513 514 515
                            if nonnull.packed {
                                let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
                                self.memory.mark_packed(ptr, nonnull.stride().bytes());
                            }
516
                            if nndiscr == variant as u64 {
S
Scott Olson 已提交
517
                                let offsets = nonnull.offsets.iter().map(|s| s.bytes());
S
Scott Olson 已提交
518
                                self.assign_fields(dest, offsets, operands)?;
519
                            } else {
520 521
                                for operand in operands {
                                    let operand_ty = self.operand_ty(operand);
522
                                    assert_eq!(self.type_size(operand_ty)?, Some(0));
523
                                }
524
                                let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
525 526

                                // FIXME(solson)
527
                                let dest = self.force_allocation(dest)?.to_ptr();
528

529
                                let dest = dest.offset(offset.bytes());
530 531
                                let dest_size = self.type_size(ty)?
                                    .expect("bad StructWrappedNullablePointer discrfield");
S
Scott Olson 已提交
532
                                self.memory.write_int(dest, 0, dest_size)?;
533 534
                            }
                        } else {
535
                            bug!("tried to assign {:?} to Layout::RawNullablePointer", kind);
536 537 538
                        }
                    }

539
                    CEnum { .. } => {
540
                        assert_eq!(operands.len(), 0);
541
                        if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind {
O
Oliver Schneider 已提交
542
                            let n = adt_def.variants[variant].disr_val.to_u128_unchecked();
543
                            self.write_primval(dest, PrimVal::Bytes(n), dest_ty)?;
544
                        } else {
545
                            bug!("tried to assign {:?} to Layout::CEnum", kind);
546 547 548
                        }
                    }

O
Oliver Schneider 已提交
549 550 551 552 553 554 555
                    Vector { element, count } => {
                        let elem_size = element.size(&self.tcx.data_layout).bytes();
                        debug_assert_eq!(count, operands.len() as u64);
                        let offsets = (0..).map(|i| i * elem_size);
                        self.assign_fields(dest, offsets, operands)?;
                    }

S
Scott Olson 已提交
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
                    UntaggedUnion { .. } => {
                        assert_eq!(operands.len(), 1);
                        let operand = &operands[0];
                        let value = self.eval_operand(operand)?;
                        let value_ty = self.operand_ty(operand);
                        self.write_value(value, dest, value_ty)?;
                    }

                    _ => {
                        return Err(EvalError::Unimplemented(format!(
                            "can't handle destination layout {:?} when assigning {:?}",
                            dest_layout,
                            kind
                        )));
                    }
571
                }
572
            }
573

574
            Repeat(ref operand, _) => {
575
                let (elem_ty, length) = match dest_ty.sty {
576
                    ty::TyArray(elem_ty, n) => (elem_ty, n as u64),
577
                    _ => bug!("tried to assign array-repeat to non-array type {:?}", dest_ty),
578
                };
579
                self.inc_step_counter_and_check_limit(length)?;
580 581
                let elem_size = self.type_size(elem_ty)?
                    .expect("repeat element type must be sized");
582
                let value = self.eval_operand(operand)?;
583 584

                // FIXME(solson)
585
                let dest = self.force_allocation(dest)?.to_ptr();
586

587
                for i in 0..length {
588
                    let elem_dest = dest.offset(i * elem_size);
589
                    self.write_value_to_ptr(value, elem_dest, elem_ty)?;
590 591
                }
            }
592

593
            Len(ref lvalue) => {
S
Scott Olson 已提交
594
                let src = self.eval_lvalue(lvalue)?;
595
                let ty = self.lvalue_ty(lvalue);
O
Oliver Schneider 已提交
596
                let (_, len) = src.elem_ty_and_len(ty);
O
Oliver Schneider 已提交
597
                self.write_primval(dest, PrimVal::from_u128(len as u128), dest_ty)?;
598 599
            }

S
Scott Olson 已提交
600
            Ref(_, _, ref lvalue) => {
601 602
                let src = self.eval_lvalue(lvalue)?;
                let (raw_ptr, extra) = self.force_allocation(src)?.to_ptr_and_extra();
603
                let ptr = PrimVal::Ptr(raw_ptr);
604

605 606
                let val = match extra {
                    LvalueExtra::None => Value::ByVal(ptr),
O
Oliver Schneider 已提交
607
                    LvalueExtra::Length(len) => Value::ByValPair(ptr, PrimVal::from_u128(len as u128)),
608
                    LvalueExtra::Vtable(vtable) => Value::ByValPair(ptr, PrimVal::Ptr(vtable)),
609 610
                    LvalueExtra::DowncastVariant(..) =>
                        bug!("attempted to take a reference to an enum downcast lvalue"),
611 612 613
                };

                self.write_value(val, dest, dest_ty)?;
S
Scott Olson 已提交
614
            }
S
Scott Olson 已提交
615

S
Scott Olson 已提交
616
            Box(ty) => {
617
                let ptr = self.alloc_ptr(ty)?;
618
                self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
S
Scott Olson 已提交
619 620
            }

621 622
            Cast(kind, ref operand, cast_ty) => {
                debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest_ty);
623
                use rustc::mir::CastKind::*;
624 625
                match kind {
                    Unsize => {
626
                        let src = self.eval_operand(operand)?;
O
Oliver Schneider 已提交
627
                        let src_ty = self.operand_ty(operand);
628
                        self.unsize_into(src, src_ty, dest, dest_ty)?;
629 630 631
                    }

                    Misc => {
632
                        let src = self.eval_operand(operand)?;
633
                        let src_ty = self.operand_ty(operand);
634
                        if self.type_is_fat_ptr(src_ty) {
635 636
                            trace!("misc cast: {:?}", src);
                            match (src, self.type_is_fat_ptr(dest_ty)) {
637 638 639
                                (Value::ByRef(_), _) |
                                (Value::ByValPair(..), true) => {
                                    self.write_value(src, dest, dest_ty)?;
640
                                },
641
                                (Value::ByValPair(data, _), false) => {
642
                                    self.write_value(Value::ByVal(data), dest, dest_ty)?;
643 644
                                },
                                (Value::ByVal(_), _) => bug!("expected fat ptr"),
O
Oliver Schneider 已提交
645
                            }
646
                        } else {
647
                            let src_val = self.value_to_primval(src, src_ty)?;
648
                            let dest_val = self.cast_primval(src_val, src_ty, dest_ty)?;
649
                            self.write_value(Value::ByVal(dest_val), dest, dest_ty)?;
650
                        }
651 652
                    }

O
Oliver Schneider 已提交
653
                    ReifyFnPointer => match self.operand_ty(operand).sty {
654
                        ty::TyFnDef(def_id, substs, fn_ty) => {
655
                            let fn_ty = self.tcx.erase_regions(&fn_ty);
656
                            let fn_ptr = self.memory.create_fn_ptr(self.tcx,def_id, substs, fn_ty);
657
                            self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?;
O
Oliver Schneider 已提交
658
                        },
659
                        ref other => bug!("reify fn pointer on {:?}", other),
O
Oliver Schneider 已提交
660 661
                    },

662 663
                    UnsafeFnPointer => match dest_ty.sty {
                        ty::TyFnPtr(unsafe_fn_ty) => {
664 665
                            let src = self.eval_operand(operand)?;
                            let ptr = src.read_ptr(&self.memory)?;
666
                            let fn_def = self.memory.get_fn(ptr.alloc_id)?.expect_concrete()?;
667
                            let unsafe_fn_ty = self.tcx.erase_regions(&unsafe_fn_ty);
668
                            let fn_ptr = self.memory.create_fn_ptr(self.tcx, fn_def.def_id, fn_def.substs, unsafe_fn_ty);
669
                            self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?;
670
                        },
671
                        ref other => bug!("fn to unsafe fn cast on {:?}", other),
672
                    },
673 674 675
                }
            }

S
Scott Olson 已提交
676
            InlineAsm { .. } => return Err(EvalError::InlineAsm),
677
        }
678

S
Scott Olson 已提交
679 680 681 682
        if log_enabled!(::log::LogLevel::Trace) {
            self.dump_local(dest);
        }

683
        Ok(())
684 685
    }

O
Oliver Schneider 已提交
686 687
    fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
        match ty.sty {
O
rustup  
Oliver Schneider 已提交
688 689 690
            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 已提交
691 692 693 694
            _ => false,
        }
    }

695 696 697 698 699 700
    pub(super) fn nonnull_offset_and_ty(
        &self,
        ty: Ty<'tcx>,
        nndiscr: u64,
        discrfield: &[u32],
    ) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
701 702
        // Skip the constant 0 at the start meant for LLVM GEP and the outer non-null variant
        let path = discrfield.iter().skip(2).map(|&i| i as usize);
703 704

        // Handle the field index for the outer non-null variant.
705
        let (inner_offset, inner_ty) = match ty.sty {
S
Scott Olson 已提交
706
            ty::TyAdt(adt_def, substs) => {
707
                let variant = &adt_def.variants[nndiscr as usize];
708 709
                let index = discrfield[1];
                let field = &variant.fields[index as usize];
710
                (self.get_field_offset(ty, index as usize)?, field.ty(self.tcx, substs))
711
            }
712
            _ => bug!("non-enum for StructWrappedNullablePointer: {}", ty),
713 714
        };

715
        self.field_path_offset_and_ty(inner_offset, inner_ty, path)
716 717
    }

718 719 720 721 722 723
    fn field_path_offset_and_ty<I: Iterator<Item = usize>>(
        &self,
        mut offset: Size,
        mut ty: Ty<'tcx>,
        path: I,
    ) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
724 725
        // Skip the initial 0 intended for LLVM GEP.
        for field_index in path {
726
            let field_offset = self.get_field_offset(ty, field_index)?;
727
            trace!("field_path_offset_and_ty: {}, {}, {:?}, {:?}", field_index, ty, field_offset, offset);
728
            ty = self.get_field_ty(ty, field_index)?;
729 730 731
            offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap();
        }

732
        Ok((offset, ty))
733
    }
O
rustup  
Oliver Schneider 已提交
734 735 736 737 738 739 740 741 742
    fn get_fat_field(&self, pointee_ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {
        match (field_index, &self.tcx.struct_tail(pointee_ty).sty) {
            (1, &ty::TyStr) |
            (1, &ty::TySlice(_)) => Ok(self.tcx.types.usize),
            (1, &ty::TyDynamic(..)) |
            (0, _) => Ok(self.tcx.mk_imm_ptr(self.tcx.types.u8)),
            _ => bug!("invalid fat pointee type: {}", pointee_ty),
        }
    }
743

O
Oliver Schneider 已提交
744
    pub fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {
745
        match ty.sty {
O
rustup  
Oliver Schneider 已提交
746
            ty::TyAdt(adt_def, _) if adt_def.is_box() => self.get_fat_field(ty.boxed_ty(), field_index),
S
Scott Olson 已提交
747
            ty::TyAdt(adt_def, substs) => {
748
                Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs))
749 750
            }

S
Scott Olson 已提交
751
            ty::TyTuple(fields, _) => Ok(fields[field_index]),
752

O
rustup  
Oliver Schneider 已提交
753 754
            ty::TyRef(_, ref tam) |
            ty::TyRawPtr(ref tam) => self.get_fat_field(tam.ty, field_index),
755
            _ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, {:?}", ty, ty.sty))),
756 757 758
        }
    }

759
    fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Size> {
760
        let layout = self.type_layout(ty)?;
761 762 763

        use rustc::ty::layout::Layout::*;
        match *layout {
764
            Univariant { ref variant, .. } => {
S
Scott Olson 已提交
765
                Ok(variant.offsets[field_index])
766 767
            }
            FatPointer { .. } => {
768 769
                let bytes = field_index as u64 * self.memory.pointer_size();
                Ok(Size::from_bytes(bytes))
770
            }
771 772 773
            StructWrappedNullablePointer { ref nonnull, .. } => {
                Ok(nonnull.offsets[field_index])
            }
774 775 776 777 778 779 780 781
            _ => {
                let msg = format!("can't handle type: {:?}, with layout: {:?}", ty, layout);
                Err(EvalError::Unimplemented(msg))
            }
        }
    }

    fn get_field_count(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, usize> {
782
        let layout = self.type_layout(ty)?;
783 784 785 786 787

        use rustc::ty::layout::Layout::*;
        match *layout {
            Univariant { ref variant, .. } => Ok(variant.offsets.len()),
            FatPointer { .. } => Ok(2),
788
            StructWrappedNullablePointer { ref nonnull, .. } => Ok(nonnull.offsets.len()),
789 790 791 792
            _ => {
                let msg = format!("can't handle type: {:?}, with layout: {:?}", ty, layout);
                Err(EvalError::Unimplemented(msg))
            }
793 794 795
        }
    }

796
    pub(super) fn eval_operand_to_primval(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, PrimVal> {
797 798 799 800 801
        let value = self.eval_operand(op)?;
        let ty = self.operand_ty(op);
        self.value_to_primval(value, ty)
    }

802
    pub(super) fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, Value> {
803
        use rustc::mir::Operand::*;
804
        match *op {
805
            Consume(ref lvalue) => self.eval_and_read_lvalue(lvalue),
806

807
            Constant(mir::Constant { ref literal, ty, .. }) => {
808
                use rustc::mir::Literal;
809
                let value = match *literal {
810
                    Literal::Value { ref value } => self.const_to_value(value)?,
811 812

                    Literal::Item { def_id, substs } => {
813
                        if let ty::TyFnDef(..) = ty.sty {
O
Oliver Schneider 已提交
814
                            // function items are zero sized
815
                            Value::ByRef(self.memory.allocate(0, 0)?)
816
                        } else {
S
Scott Olson 已提交
817
                            let (def_id, substs) = self.resolve_associated_const(def_id, substs);
S
Scott Olson 已提交
818
                            let cid = GlobalId { def_id, substs, promoted: None };
819
                            self.globals.get(&cid).expect("static/const not cached").value
820
                        }
821 822 823
                    }

                    Literal::Promoted { index } => {
824
                        let cid = GlobalId {
825 826
                            def_id: self.frame().def_id,
                            substs: self.substs(),
O
Oliver Schneider 已提交
827
                            promoted: Some(index),
828
                        };
829
                        self.globals.get(&cid).expect("promoted not cached").value
830 831 832 833
                    }
                };

                Ok(value)
834 835 836
            }
        }
    }
S
Scott Olson 已提交
837

838
    pub(super) fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> Ty<'tcx> {
S
Scott Olson 已提交
839
        self.monomorphize(operand.ty(&self.mir(), self.tcx), self.substs())
840 841
    }

842
    fn copy(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx> {
843 844
        let size = self.type_size(ty)?.expect("cannot copy from an unsized type");
        let align = self.type_align(ty)?;
845
        self.memory.copy(src, dest, size, align)?;
S
Scott Olson 已提交
846 847 848
        Ok(())
    }

849 850 851 852
    pub(super) fn force_allocation(
        &mut self,
        lvalue: Lvalue<'tcx>,
    ) -> EvalResult<'tcx, Lvalue<'tcx>> {
853
        let new_lvalue = match lvalue {
854 855 856 857 858 859 860
            Lvalue::Local { frame, local, field } => {
                // -1 since we don't store the return value
                match self.stack[frame].locals[local.index() - 1] {
                    Value::ByRef(ptr) => {
                        assert!(field.is_none());
                        Lvalue::from_ptr(ptr)
                    },
861
                    val => {
862
                        let ty = self.stack[frame].mir.local_decls[local].ty;
863
                        let ty = self.monomorphize(ty, self.stack[frame].substs);
864
                        let substs = self.stack[frame].substs;
S
Scott Olson 已提交
865
                        let ptr = self.alloc_ptr_with_substs(ty, substs)?;
866
                        self.stack[frame].locals[local.index() - 1] = Value::ByRef(ptr);
867
                        self.write_value_to_ptr(val, ptr, ty)?;
868 869 870 871 872 873
                        let lval = Lvalue::from_ptr(ptr);
                        if let Some((field, field_ty)) = field {
                            self.lvalue_field(lval, field, ty, field_ty)?
                        } else {
                            lval
                        }
874
                    }
875
                }
876 877
            }
            Lvalue::Ptr { .. } => lvalue,
878 879
            Lvalue::Global(cid) => {
                let global_val = *self.globals.get(&cid).expect("global not cached");
880 881
                match global_val.value {
                    Value::ByRef(ptr) => Lvalue::from_ptr(ptr),
882
                    _ => {
883
                        let ptr = self.alloc_ptr_with_substs(global_val.ty, cid.substs)?;
884
                        self.memory.mark_static(ptr.alloc_id);
885
                        self.write_value_to_ptr(global_val.value, ptr, global_val.ty)?;
886 887
                        // see comment on `initialized` field
                        if global_val.initialized {
888
                            self.memory.mark_static_initalized(ptr.alloc_id, global_val.mutable)?;
889
                        }
890 891
                        let lval = self.globals.get_mut(&cid).expect("already checked");
                        *lval = Global {
892
                            value: Value::ByRef(ptr),
893
                            .. global_val
894 895 896 897 898
                        };
                        Lvalue::from_ptr(ptr)
                    },
                }
            }
899 900 901 902
        };
        Ok(new_lvalue)
    }

903
    /// ensures this Value is not a ByRef
904
    pub(super) fn follow_by_ref_value(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
905
        match value {
906 907 908 909 910
            Value::ByRef(ptr) => self.read_value(ptr, ty),
            other => Ok(other),
        }
    }

911
    pub(super) fn value_to_primval(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
912 913
        match self.follow_by_ref_value(value, ty)? {
            Value::ByRef(_) => bug!("follow_by_ref_value can't result in `ByRef`"),
914

915
            Value::ByVal(primval) => {
916 917
                self.ensure_valid_value(primval, ty)?;
                Ok(primval)
918 919
            }

920
            Value::ByValPair(..) => bug!("value_to_primval can't work with fat pointers"),
921 922 923
        }
    }

924
    pub(super) fn write_primval(
925
        &mut self,
926
        dest: Lvalue<'tcx>,
927
        val: PrimVal,
928
        dest_ty: Ty<'tcx>,
929
    ) -> EvalResult<'tcx> {
930 931 932
        match dest {
            Lvalue::Ptr { ptr, extra } => {
                assert_eq!(extra, LvalueExtra::None);
933 934
                let size = self.type_size(dest_ty)?.expect("dest type must be sized");
                self.memory.write_primval(ptr, val, size)
935
            }
936 937
            Lvalue::Local { frame, local, field } => {
                self.stack[frame].set_local(local, field.map(|(i, _)| i), Value::ByVal(val));
938 939
                Ok(())
            }
940 941
            Lvalue::Global(cid) => {
                let global_val = self.globals.get_mut(&cid).expect("global not cached");
942
                if global_val.mutable {
943
                    global_val.value = Value::ByVal(val);
944 945 946 947
                    Ok(())
                } else {
                    Err(EvalError::ModifiedConstantMemory)
                }
948
            }
949
        }
950 951
    }

952
    pub(super) fn write_value(
953
        &mut self,
954
        src_val: Value,
955
        dest: Lvalue<'tcx>,
956
        dest_ty: Ty<'tcx>,
957
    ) -> EvalResult<'tcx> {
958
        match dest {
959 960
            Lvalue::Global(cid) => {
                let dest = *self.globals.get_mut(&cid).expect("global should be cached");
961 962 963
                if !dest.mutable {
                    return Err(EvalError::ModifiedConstantMemory);
                }
964 965 966 967 968 969 970
                let write_dest = |this: &mut Self, val| {
                    *this.globals.get_mut(&cid).expect("already checked") = Global {
                        value: val,
                        ..dest
                    }
                };
                self.write_value_possibly_by_val(src_val, write_dest, dest.value, dest_ty)
971 972
            },

973 974
            Lvalue::Ptr { ptr, extra } => {
                assert_eq!(extra, LvalueExtra::None);
975
                self.write_value_to_ptr(src_val, ptr, dest_ty)
976
            }
977

978 979
            Lvalue::Local { frame, local, field } => {
                let dest = self.stack[frame].get_local(local, field.map(|(i, _)| i));
980
                self.write_value_possibly_by_val(
981
                    src_val,
982
                    |this, val| this.stack[frame].set_local(local, field.map(|(i, _)| i), val),
983 984 985
                    dest,
                    dest_ty,
                )
986 987
            }
        }
988 989 990
    }

    // The cases here can be a bit subtle. Read carefully!
991
    fn write_value_possibly_by_val<F: FnOnce(&mut Self, Value)>(
992 993 994
        &mut self,
        src_val: Value,
        write_dest: F,
995
        old_dest_val: Value,
996
        dest_ty: Ty<'tcx>,
997
    ) -> EvalResult<'tcx> {
998
        if let Value::ByRef(dest_ptr) = old_dest_val {
999
            // If the value is already `ByRef` (that is, backed by an `Allocation`),
1000 1001 1002 1003 1004
            // 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
1005
            // knew for certain that there were no outstanding pointers to this allocation.
1006 1007 1008
            self.write_value_to_ptr(src_val, dest_ptr, dest_ty)?;

        } else if let Value::ByRef(src_ptr) = src_val {
1009
            // If the value is not `ByRef`, then we know there are no pointers to it
1010 1011 1012 1013 1014 1015 1016
            // 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.
            //
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
            // 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.
            if let Ok(Some(src_val)) = self.try_read_value(src_ptr, dest_ty) {
                write_dest(self, src_val);
            } else {
                let dest_ptr = self.alloc_ptr(dest_ty)?;
                self.copy(src_ptr, dest_ptr, dest_ty)?;
                write_dest(self, Value::ByRef(dest_ptr));
            }
1027 1028 1029

        } else {
            // Finally, we have the simple case where neither source nor destination are
1030
            // `ByRef`. We may simply copy the source value over the the destintion.
1031 1032
            write_dest(self, src_val);
        }
1033
        Ok(())
1034 1035
    }

1036
    pub(super) fn write_value_to_ptr(
1037 1038 1039
        &mut self,
        value: Value,
        dest: Pointer,
1040
        dest_ty: Ty<'tcx>,
1041
    ) -> EvalResult<'tcx> {
1042
        match value {
1043
            Value::ByRef(ptr) => self.copy(ptr, dest, dest_ty),
1044
            Value::ByVal(primval) => {
1045 1046
                let size = self.type_size(dest_ty)?.expect("dest type must be sized");
                self.memory.write_primval(dest, primval, size)
1047
            }
1048
            Value::ByValPair(a, b) => self.write_pair_to_ptr(a, b, dest, dest_ty),
1049 1050 1051
        }
    }

1052
    pub(super) fn write_pair_to_ptr(
1053 1054 1055 1056 1057
        &mut self,
        a: PrimVal,
        b: PrimVal,
        ptr: Pointer,
        ty: Ty<'tcx>
1058
    ) -> EvalResult<'tcx> {
1059
        assert_eq!(self.get_field_count(ty)?, 2);
1060 1061
        let field_0 = self.get_field_offset(ty, 0)?.bytes();
        let field_1 = self.get_field_offset(ty, 1)?.bytes();
1062 1063
        let field_0_ty = self.get_field_ty(ty, 0)?;
        let field_1_ty = self.get_field_ty(ty, 1)?;
1064 1065 1066 1067
        let field_0_size = self.type_size(field_0_ty)?.expect("pair element type must be sized");
        let field_1_size = self.type_size(field_1_ty)?.expect("pair element type must be sized");
        self.memory.write_primval(ptr.offset(field_0), a, field_0_size)?;
        self.memory.write_primval(ptr.offset(field_1), b, field_1_size)?;
1068 1069 1070
        Ok(())
    }

O
Oliver Schneider 已提交
1071
    pub fn ty_to_primval_kind(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimValKind> {
1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
        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 已提交
1085
                    I128 => 16,
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
                    Is => self.memory.pointer_size(),
                };
                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 已提交
1098
                    U128 => 16,
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
                    Us => self.memory.pointer_size(),
                };
                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 已提交
1109 1110 1111 1112
            ty::TyRef(_, ref tam) |
            ty::TyRawPtr(ref tam) if self.type_is_sized(tam.ty) => PrimValKind::Ptr,

            ty::TyAdt(ref def, _) if def.is_box() => PrimValKind::Ptr,
1113 1114 1115

            ty::TyAdt(..) => {
                use rustc::ty::layout::Layout::*;
1116 1117 1118 1119 1120 1121 1122 1123
                match *self.type_layout(ty)? {
                    CEnum { discr, signed, .. } => {
                        let size = discr.size().bytes();
                        if signed {
                            PrimValKind::from_int_size(size)
                        } else {
                            PrimValKind::from_uint_size(size)
                        }
1124
                    }
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137

                    RawNullablePointer { value, .. } => {
                        use rustc::ty::layout::Primitive::*;
                        match value {
                            // TODO(solson): Does signedness matter here? What should the sign be?
                            Int(int) => PrimValKind::from_uint_size(int.size().bytes()),
                            F32 => PrimValKind::F32,
                            F64 => PrimValKind::F64,
                            Pointer => PrimValKind::Ptr,
                        }
                    }

                    _ => return Err(EvalError::TypeNotPrimitive(ty)),
1138
                }
1139
            }
1140

1141
            _ => return Err(EvalError::TypeNotPrimitive(ty)),
1142 1143 1144 1145 1146
        };

        Ok(kind)
    }

1147
    fn ensure_valid_value(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx> {
1148
        match ty.sty {
1149
            ty::TyBool if val.to_bytes()? > 1 => Err(EvalError::InvalidBool),
1150

1151
            ty::TyChar if ::std::char::from_u32(val.to_bytes()? as u32).is_none()
O
Oliver Schneider 已提交
1152
                => Err(EvalError::InvalidChar(val.to_bytes()? as u32 as u128)),
1153 1154 1155 1156 1157

            _ => Ok(()),
        }
    }

1158
    pub(super) fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
1159 1160 1161 1162 1163 1164 1165
        if let Some(val) = self.try_read_value(ptr, ty)? {
            Ok(val)
        } else {
            bug!("primitive read failed for type: {:?}", ty);
        }
    }

O
rustup  
Oliver Schneider 已提交
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182
    fn read_ptr(&mut self, ptr: Pointer, pointee_ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
        let p = self.memory.read_ptr(ptr)?;
        if self.type_is_sized(pointee_ty) {
            Ok(Value::ByVal(PrimVal::Ptr(p)))
        } else {
            trace!("reading fat pointer extra of type {}", pointee_ty);
            let extra = ptr.offset(self.memory.pointer_size());
            let extra = match self.tcx.struct_tail(pointee_ty).sty {
                ty::TyDynamic(..) => PrimVal::Ptr(self.memory.read_ptr(extra)?),
                ty::TySlice(..) |
                ty::TyStr => PrimVal::from_u128(self.memory.read_usize(extra)? as u128),
                _ => bug!("unsized primval ptr read from {:?}", pointee_ty),
            };
            Ok(Value::ByValPair(PrimVal::Ptr(p), extra))
        }
    }

1183
    fn try_read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
1184 1185
        use syntax::ast::FloatTy;

S
Scott Olson 已提交
1186
        let val = match ty.sty {
S
Scott Olson 已提交
1187
            ty::TyBool => PrimVal::from_bool(self.memory.read_bool(ptr)?),
S
Scott Olson 已提交
1188
            ty::TyChar => {
O
Oliver Schneider 已提交
1189 1190
                let c = self.memory.read_uint(ptr, 4)? as u32;
                match ::std::char::from_u32(c) {
S
Scott Olson 已提交
1191
                    Some(ch) => PrimVal::from_char(ch),
O
Oliver Schneider 已提交
1192
                    None => return Err(EvalError::InvalidChar(c as u128)),
O
Oliver Schneider 已提交
1193 1194
                }
            }
1195

S
Scott Olson 已提交
1196
            ty::TyInt(int_ty) => {
1197 1198 1199 1200 1201 1202
                use syntax::ast::IntTy::*;
                let size = match int_ty {
                    I8 => 1,
                    I16 => 2,
                    I32 => 4,
                    I64 => 8,
O
Oliver Schneider 已提交
1203
                    I128 => 16,
1204 1205
                    Is => self.memory.pointer_size(),
                };
O
Oliver Schneider 已提交
1206
                PrimVal::from_i128(self.memory.read_int(ptr, size)?)
1207
            }
1208

S
Scott Olson 已提交
1209
            ty::TyUint(uint_ty) => {
1210 1211 1212 1213 1214 1215
                use syntax::ast::UintTy::*;
                let size = match uint_ty {
                    U8 => 1,
                    U16 => 2,
                    U32 => 4,
                    U64 => 8,
O
Oliver Schneider 已提交
1216
                    U128 => 16,
1217 1218
                    Us => self.memory.pointer_size(),
                };
O
Oliver Schneider 已提交
1219
                PrimVal::from_u128(self.memory.read_uint(ptr, size)?)
1220
            }
1221

S
Scott Olson 已提交
1222 1223
            ty::TyFloat(FloatTy::F32) => PrimVal::from_f32(self.memory.read_f32(ptr)?),
            ty::TyFloat(FloatTy::F64) => PrimVal::from_f64(self.memory.read_f64(ptr)?),
1224

1225
            ty::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::Ptr)?,
O
rustup  
Oliver Schneider 已提交
1226 1227
            ty::TyRef(_, ref tam) |
            ty::TyRawPtr(ref tam) => return self.read_ptr(ptr, tam.ty).map(Some),
1228

O
rustup  
Oliver Schneider 已提交
1229 1230 1231 1232
            ty::TyAdt(def, _) => {
                if def.is_box() {
                    return self.read_ptr(ptr, ty.boxed_ty()).map(Some);
                }
O
Oliver Schneider 已提交
1233
                use rustc::ty::layout::Layout::*;
1234
                if let CEnum { discr, signed, .. } = *self.type_layout(ty)? {
1235
                    let size = discr.size().bytes();
1236
                    if signed {
O
Oliver Schneider 已提交
1237
                        PrimVal::from_i128(self.memory.read_int(ptr, size)?)
1238
                    } else {
O
Oliver Schneider 已提交
1239
                        PrimVal::from_u128(self.memory.read_uint(ptr, size)?)
O
Oliver Schneider 已提交
1240 1241
                    }
                } else {
1242
                    return Ok(None);
O
Oliver Schneider 已提交
1243 1244 1245
                }
            },

1246
            _ => return Ok(None),
1247
        };
S
Scott Olson 已提交
1248

1249
        Ok(Some(Value::ByVal(val)))
1250 1251
    }

1252
    pub(super) fn frame(&self) -> &Frame<'tcx> {
1253 1254
        self.stack.last().expect("no call frames exist")
    }
1255

1256
    pub(super) fn frame_mut(&mut self) -> &mut Frame<'tcx> {
1257 1258
        self.stack.last_mut().expect("no call frames exist")
    }
1259

1260
    pub(super) fn mir(&self) -> MirRef<'tcx> {
1261
        Ref::clone(&self.frame().mir)
S
Scott Olson 已提交
1262
    }
O
Oliver Schneider 已提交
1263

1264
    pub(super) fn substs(&self) -> &'tcx Substs<'tcx> {
O
Oliver Schneider 已提交
1265 1266
        self.frame().substs
    }
1267

O
rustup  
Oliver Schneider 已提交
1268 1269 1270 1271 1272 1273 1274 1275
    fn unsize_into_ptr(
        &mut self,
        src: Value,
        src_ty: Ty<'tcx>,
        dest: Lvalue<'tcx>,
        dest_ty: Ty<'tcx>,
        sty: Ty<'tcx>,
        dty: Ty<'tcx>,
1276
    ) -> EvalResult<'tcx> {
O
rustup  
Oliver Schneider 已提交
1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
        // 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(_)) => {
                let ptr = src.read_ptr(&self.memory)?;
                let len = PrimVal::from_u128(length as u128);
                let ptr = PrimVal::Ptr(ptr);
                self.write_value(Value::ByValPair(ptr, len), dest, dest_ty)
            }
            (&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.
                self.write_value(src, dest, dest_ty)
            },
            (_, &ty::TyDynamic(ref data, _)) => {
                let trait_ref = data.principal().unwrap().with_self_ty(self.tcx, src_pointee_ty);
                let trait_ref = self.tcx.erase_regions(&trait_ref);
                let vtable = self.get_vtable(trait_ref)?;
                let ptr = src.read_ptr(&self.memory)?;
                let ptr = PrimVal::Ptr(ptr);
                let extra = PrimVal::Ptr(vtable);
                self.write_value(Value::ByValPair(ptr, extra), dest, dest_ty)
            },

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

1307 1308 1309 1310
    fn unsize_into(
        &mut self,
        src: Value,
        src_ty: Ty<'tcx>,
1311
        dest: Lvalue<'tcx>,
1312
        dest_ty: Ty<'tcx>,
1313
    ) -> EvalResult<'tcx> {
1314
        match (&src_ty.sty, &dest_ty.sty) {
O
rustup  
Oliver Schneider 已提交
1315 1316 1317 1318 1319 1320 1321
            (&ty::TyRef(_, ref s), &ty::TyRef(_, ref d)) |
            (&ty::TyRef(_, ref s), &ty::TyRawPtr(ref d)) |
            (&ty::TyRawPtr(ref s), &ty::TyRawPtr(ref d)) => self.unsize_into_ptr(src, src_ty, dest, dest_ty, s.ty, d.ty),
            (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) => {
                if def_a.is_box() || def_b.is_box() {
                    if !def_a.is_box() || !def_b.is_box() {
                        panic!("invalid unsizing between {:?} -> {:?}", src_ty, dest_ty);
1322
                    }
O
rustup  
Oliver Schneider 已提交
1323
                    return self.unsize_into_ptr(src, src_ty, dest, dest_ty, src_ty.boxed_ty(), dest_ty.boxed_ty());
1324
                }
1325 1326
                // FIXME(solson)
                let dest = self.force_allocation(dest)?.to_ptr();
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339
                // 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

                assert_eq!(def_a, def_b);

                let src_fields = def_a.variants[0].fields.iter();
                let dst_fields = def_b.variants[0].fields.iter();

                //let src = adt::MaybeSizedValue::sized(src);
                //let dst = adt::MaybeSizedValue::sized(dst);
                let src_ptr = match src {
                    Value::ByRef(ptr) => ptr,
O
Oliver Schneider 已提交
1340
                    _ => bug!("expected pointer, got {:?}", src),
1341 1342 1343 1344
                };

                let iter = src_fields.zip(dst_fields).enumerate();
                for (i, (src_f, dst_f)) in iter {
1345 1346
                    let src_fty = monomorphize_field_ty(self.tcx, src_f, substs_a);
                    let dst_fty = monomorphize_field_ty(self.tcx, dst_f, substs_b);
1347
                    if self.type_size(dst_fty)? == Some(0) {
1348 1349
                        continue;
                    }
1350 1351
                    let src_field_offset = self.get_field_offset(src_ty, i)?.bytes();
                    let dst_field_offset = self.get_field_offset(dest_ty, i)?.bytes();
1352 1353 1354
                    let src_f_ptr = src_ptr.offset(src_field_offset);
                    let dst_f_ptr = dest.offset(dst_field_offset);
                    if src_fty == dst_fty {
1355
                        self.copy(src_f_ptr, dst_f_ptr, src_fty)?;
1356
                    } else {
1357
                        self.unsize_into(Value::ByRef(src_f_ptr), src_fty, Lvalue::from_ptr(dst_f_ptr), dst_fty)?;
1358 1359
                    }
                }
O
rustup  
Oliver Schneider 已提交
1360
                Ok(())
1361
            }
1362
            _ => bug!("unsize_into: invalid conversion: {:?} -> {:?}", src_ty, dest_ty),
1363 1364
        }
    }
S
Scott Olson 已提交
1365

1366
    pub(super) fn dump_local(&self, lvalue: Lvalue<'tcx>) {
1367
        if let Lvalue::Local { frame, local, field } = lvalue {
S
Scott Olson 已提交
1368 1369
            let mut allocs = Vec::new();
            let mut msg = format!("{:?}", local);
1370 1371 1372
            if let Some(field) = field {
                write!(msg, ".{}", field).unwrap();
            }
S
Scott Olson 已提交
1373 1374 1375 1376 1377 1378
            let last_frame = self.stack.len() - 1;
            if frame != last_frame {
                write!(msg, " ({} frames up)", last_frame - frame).unwrap();
            }
            write!(msg, ":").unwrap();

1379
            match self.stack[frame].get_local(local, field.map(|(i, _)| i)) {
1380 1381 1382 1383
                Value::ByRef(ptr) => {
                    allocs.push(ptr.alloc_id);
                }
                Value::ByVal(val) => {
S
Scott Olson 已提交
1384
                    write!(msg, " {:?}", val).unwrap();
1385 1386 1387
                    if let PrimVal::Ptr(ptr) = val { allocs.push(ptr.alloc_id); }
                }
                Value::ByValPair(val1, val2) => {
S
Scott Olson 已提交
1388
                    write!(msg, " ({:?}, {:?})", val1, val2).unwrap();
1389 1390
                    if let PrimVal::Ptr(ptr) = val1 { allocs.push(ptr.alloc_id); }
                    if let PrimVal::Ptr(ptr) = val2 { allocs.push(ptr.alloc_id); }
1391 1392
                }
            }
1393

S
Scott Olson 已提交
1394 1395 1396
            trace!("{}", msg);
            self.memory.dump_allocs(allocs);
        }
1397
    }
1398

1399
    /// Convenience function to ensure correct usage of globals and code-sharing with locals.
1400
    pub fn modify_global<F>(&mut self, cid: GlobalId<'tcx>, f: F) -> EvalResult<'tcx>
1401 1402
        where F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
    {
1403 1404 1405 1406
        let mut val = *self.globals.get(&cid).expect("global not cached");
        if !val.mutable {
            return Err(EvalError::ModifiedConstantMemory);
        }
1407
        val.value = f(self, val.value)?;
1408 1409 1410 1411
        *self.globals.get_mut(&cid).expect("already checked") = val;
        Ok(())
    }

1412 1413
    /// Convenience function to ensure correct usage of locals and code-sharing with globals.
    pub fn modify_local<F>(
1414 1415 1416
        &mut self,
        frame: usize,
        local: mir::Local,
1417
        field: Option<usize>,
1418
        f: F,
1419
    ) -> EvalResult<'tcx>
1420 1421
        where F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
    {
1422
        let val = self.stack[frame].get_local(local, field);
1423
        let new_val = f(self, val)?;
1424
        self.stack[frame].set_local(local, field, new_val);
1425 1426 1427 1428
        // 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)?;
        // }
1429 1430
        Ok(())
    }
1431 1432
}

1433
impl<'tcx> Frame<'tcx> {
1434
    pub fn get_local(&self, local: mir::Local, field: Option<usize>) -> Value {
1435
        // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453
        if let Some(field) = field {
            match self.locals[local.index() - 1] {
                Value::ByRef(_) => bug!("can't have lvalue fields for ByRef"),
                val @ Value::ByVal(_) => {
                    assert_eq!(field, 0);
                    val
                },
                Value::ByValPair(a, b) => {
                    match field {
                        0 => Value::ByVal(a),
                        1 => Value::ByVal(b),
                        _ => bug!("ByValPair has only two fields, tried to access {}", field),
                    }
                },
            }
        } else {
            self.locals[local.index() - 1]
        }
1454 1455
    }

1456
    fn set_local(&mut self, local: mir::Local, field: Option<usize>, value: Value) {
1457
        // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480
        if let Some(field) = field {
            match self.locals[local.index() - 1] {
                Value::ByRef(_) => bug!("can't have lvalue fields for ByRef"),
                Value::ByVal(_) => {
                    assert_eq!(field, 0);
                    self.set_local(local, None, value);
                },
                Value::ByValPair(a, b) => {
                    let prim = match value {
                        Value::ByRef(_) => bug!("can't set ValPair field to ByRef"),
                        Value::ByVal(val) => val,
                        Value::ByValPair(_, _) => bug!("can't set ValPair field to ValPair"),
                    };
                    match field {
                        0 => self.set_local(local, None, Value::ByValPair(prim, b)),
                        1 => self.set_local(local, None, Value::ByValPair(a, prim)),
                        _ => bug!("ByValPair has only two fields, tried to access {}", field),
                    }
                },
            }
        } else {
            self.locals[local.index() - 1] = value;
        }
1481 1482 1483
    }
}

1484 1485
pub fn eval_main<'a, 'tcx: 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
S
Scott Olson 已提交
1486
    def_id: DefId,
S
Scott Olson 已提交
1487
    limits: ResourceLimits,
1488
) {
S
Scott Olson 已提交
1489
    let mut ecx = EvalContext::new(tcx, limits);
1490
    let mir = ecx.load_mir(def_id).expect("main function's MIR not found");
1491

S
Scott Olson 已提交
1492 1493 1494 1495 1496 1497
    if !mir.return_ty.is_nil() || mir.arg_count != 0 {
        let msg = "miri does not support main functions without `fn()` type signatures";
        tcx.sess.err(&EvalError::Unimplemented(String::from(msg)).to_string());
        return;
    }

1498 1499
    ecx.push_stack_frame(
        def_id,
1500
        DUMMY_SP,
1501
        mir,
1502
        tcx.intern_substs(&[]),
S
Scott Olson 已提交
1503
        Lvalue::from_ptr(Pointer::zst_ptr()),
1504
        StackPopCleanup::None,
1505
        Vec::new(),
1506
    ).expect("could not allocate first stack frame");
1507

1508
    loop {
1509
        match ecx.step() {
1510
            Ok(true) => {}
O
Oliver Schneider 已提交
1511
            Ok(false) => return,
1512 1513
            Err(e) => {
                report(tcx, &ecx, e);
O
Oliver Schneider 已提交
1514
                return;
1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529
            }
        }
    }
}

fn report(tcx: TyCtxt, ecx: &EvalContext, e: EvalError) {
    let frame = ecx.stack().last().expect("stackframe was empty");
    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 = tcx.sess.struct_span_err(span, &e.to_string());
    for &Frame { def_id, substs, span, .. } in ecx.stack().iter().rev() {
1530 1531 1532 1533
        if tcx.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr {
            err.span_note(span, "inside call to closure");
            continue;
        }
1534 1535 1536 1537
        // FIXME(solson): Find a way to do this without this Display impl hack.
        use rustc::util::ppaux;
        use std::fmt;
        struct Instance<'tcx>(DefId, &'tcx subst::Substs<'tcx>);
1538 1539
        impl<'tcx> ::std::panic::UnwindSafe for Instance<'tcx> {}
        impl<'tcx> ::std::panic::RefUnwindSafe for Instance<'tcx> {}
1540 1541
        impl<'tcx> fmt::Display for Instance<'tcx> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1542
                ppaux::parameterized(f, self.1, self.0, &[])
1543 1544
            }
        }
O
Oliver Schneider 已提交
1545
        err.span_note(span, &format!("inside call to {}", Instance(def_id, substs)));
1546 1547 1548
    }
    err.emit();
}
1549

1550
pub fn run_mir_passes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
1551 1552 1553
    let mut passes = ::rustc::mir::transform::Passes::new();
    passes.push_hook(Box::new(::rustc_mir::transform::dump_mir::DumpMir));
    passes.push_pass(Box::new(::rustc_mir::transform::no_landing_pads::NoLandingPads));
S
Scott Olson 已提交
1554
    passes.push_pass(Box::new(::rustc_mir::transform::simplify::SimplifyCfg::new("no-landing-pads")));
1555

S
Scott Olson 已提交
1556
    // From here on out, regions are gone.
1557 1558
    passes.push_pass(Box::new(::rustc_mir::transform::erase_regions::EraseRegions));

S
Scott Olson 已提交
1559
    passes.push_pass(Box::new(::rustc_mir::transform::add_call_guards::AddCallGuards));
1560 1561
    passes.push_pass(Box::new(::rustc_borrowck::ElaborateDrops));
    passes.push_pass(Box::new(::rustc_mir::transform::no_landing_pads::NoLandingPads));
S
Scott Olson 已提交
1562
    passes.push_pass(Box::new(::rustc_mir::transform::simplify::SimplifyCfg::new("elaborate-drops")));
S
Scott Olson 已提交
1563 1564 1565 1566 1567 1568 1569 1570

    // No lifetime analysis based on borrowing can be done from here on out.
    passes.push_pass(Box::new(::rustc_mir::transform::instcombine::InstCombine::new()));
    passes.push_pass(Box::new(::rustc_mir::transform::deaggregator::Deaggregator));
    passes.push_pass(Box::new(::rustc_mir::transform::copy_prop::CopyPropagation));

    passes.push_pass(Box::new(::rustc_mir::transform::simplify::SimplifyLocals));
    passes.push_pass(Box::new(::rustc_mir::transform::add_call_guards::AddCallGuards));
1571 1572
    passes.push_pass(Box::new(::rustc_mir::transform::dump_mir::Marker("PreMiri")));

1573
    passes.run_passes(tcx);
1574 1575
}

1576 1577
// TODO(solson): Upstream these methods into rustc::ty::layout.

1578
pub(super) trait IntegerExt {
1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589
    fn size(self) -> Size;
}

impl IntegerExt for layout::Integer {
    fn size(self) -> Size {
        use rustc::ty::layout::Integer::*;
        match self {
            I1 | I8 => Size::from_bits(8),
            I16 => Size::from_bits(16),
            I32 => Size::from_bits(32),
            I64 => Size::from_bits(64),
O
Oliver Schneider 已提交
1590
            I128 => Size::from_bits(128),
1591 1592 1593
        }
    }
}
1594 1595


O
rustup  
Oliver Schneider 已提交
1596
pub fn monomorphize_field_ty<'a, 'tcx:'a >(tcx: TyCtxt<'a, 'tcx, 'tcx>, f: &ty::FieldDef, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
S
Scott Olson 已提交
1597
    let substituted = f.ty(tcx, substs);
1598 1599
    tcx.normalize_associated_type(&substituted)
}
1600 1601 1602 1603

pub fn is_inhabited<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
    ty.uninhabited_from(&mut FxHashSet::default(), tcx).is_empty()
}
1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621

pub trait IntoValTyPair<'tcx> {
    fn into_val_ty_pair<'a>(self, ecx: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a;
}

impl<'tcx> IntoValTyPair<'tcx> for (Value, Ty<'tcx>) {
    fn into_val_ty_pair<'a>(self, _: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a {
        Ok(self)
    }
}

impl<'b, 'tcx: 'b> IntoValTyPair<'tcx> for &'b mir::Operand<'tcx> {
    fn into_val_ty_pair<'a>(self, ecx: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a {
        let value = ecx.eval_operand(self)?;
        let value_ty = ecx.operand_ty(self);
        Ok((value, value_ty))
    }
}