]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/eval_context.rs
Rollup merge of #48934 - Phlosioneer:42453-debug-hygene, r=petrochenkov
[rust.git] / src / librustc_mir / interpret / eval_context.rs
1 use std::collections::HashSet;
2 use std::fmt::Write;
3
4 use rustc::hir::def_id::DefId;
5 use rustc::hir::map::definitions::DefPathData;
6 use rustc::middle::const_val::{ConstVal, ErrKind};
7 use rustc::mir;
8 use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout};
9 use rustc::ty::subst::{Subst, Substs};
10 use rustc::ty::{self, Ty, TyCtxt};
11 use rustc::ty::maps::TyCtxtAt;
12 use rustc_data_structures::indexed_vec::Idx;
13 use rustc::middle::const_val::FrameInfo;
14 use syntax::codemap::{self, Span};
15 use syntax::ast::Mutability;
16 use rustc::mir::interpret::{
17     GlobalId, Value, Pointer, PrimVal, PrimValKind,
18     EvalError, EvalResult, EvalErrorKind, MemoryPointer,
19 };
20
21 use super::{Place, PlaceExtra, Memory,
22             HasMemory, MemoryKind,
23             Machine};
24
25 pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
26     /// Stores the `Machine` instance.
27     pub machine: M,
28
29     /// The results of the type checker, from rustc.
30     pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
31
32     /// Bounds in scope for polymorphic evaluations.
33     pub param_env: ty::ParamEnv<'tcx>,
34
35     /// The virtual memory system.
36     pub memory: Memory<'a, 'mir, 'tcx, M>,
37
38     /// The virtual call stack.
39     pub(crate) stack: Vec<Frame<'mir, 'tcx>>,
40
41     /// The maximum number of stack frames allowed
42     pub(crate) stack_limit: usize,
43
44     /// The maximum number of terminators that may be evaluated.
45     /// This prevents infinite loops and huge computations from freezing up const eval.
46     /// Remove once halting problem is solved.
47     pub(crate) steps_remaining: usize,
48 }
49
50 /// A stack frame.
51 pub struct Frame<'mir, 'tcx: 'mir> {
52     ////////////////////////////////////////////////////////////////////////////////
53     // Function and callsite information
54     ////////////////////////////////////////////////////////////////////////////////
55     /// The MIR for the function called on this frame.
56     pub mir: &'mir mir::Mir<'tcx>,
57
58     /// The def_id and substs of the current function
59     pub instance: ty::Instance<'tcx>,
60
61     /// The span of the call site.
62     pub span: codemap::Span,
63
64     ////////////////////////////////////////////////////////////////////////////////
65     // Return place and locals
66     ////////////////////////////////////////////////////////////////////////////////
67     /// The block to return to when returning from the current stack frame
68     pub return_to_block: StackPopCleanup,
69
70     /// The location where the result of the current stack frame should be written to.
71     pub return_place: Place,
72
73     /// The list of locals for this stack frame, stored in order as
74     /// `[arguments..., variables..., temporaries...]`. The locals are stored as `Option<Value>`s.
75     /// `None` represents a local that is currently dead, while a live local
76     /// can either directly contain `PrimVal` or refer to some part of an `Allocation`.
77     ///
78     /// Before being initialized, arguments are `Value::ByVal(PrimVal::Undef)` and other locals are `None`.
79     pub locals: Vec<Option<Value>>,
80
81     ////////////////////////////////////////////////////////////////////////////////
82     // Current position within the function
83     ////////////////////////////////////////////////////////////////////////////////
84     /// The block that is currently executed (or will be executed after the above call stacks
85     /// return).
86     pub block: mir::BasicBlock,
87
88     /// The index of the currently evaluated statement.
89     pub stmt: usize,
90 }
91
92 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
93 pub enum StackPopCleanup {
94     /// The stackframe existed to compute the initial value of a static/constant, make sure it
95     /// isn't modifyable afterwards in case of constants.
96     /// In case of `static mut`, mark the memory to ensure it's never marked as immutable through
97     /// references or deallocated
98     MarkStatic(Mutability),
99     /// A regular stackframe added due to a function call will need to get forwarded to the next
100     /// block
101     Goto(mir::BasicBlock),
102     /// The main function and diverging functions have nowhere to return to
103     None,
104 }
105
106 #[derive(Copy, Clone, Debug)]
107 pub struct TyAndPacked<'tcx> {
108     pub ty: Ty<'tcx>,
109     pub packed: bool,
110 }
111
112 #[derive(Copy, Clone, Debug)]
113 pub struct ValTy<'tcx> {
114     pub value: Value,
115     pub ty: Ty<'tcx>,
116 }
117
118 impl<'tcx> ValTy<'tcx> {
119     pub fn from(val: &ty::Const<'tcx>) -> Option<Self> {
120         match val.val {
121             ConstVal::Value(value) => Some(ValTy { value, ty: val.ty }),
122             ConstVal::Unevaluated { .. } => None,
123         }
124     }
125 }
126
127 impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
128     type Target = Value;
129     fn deref(&self) -> &Value {
130         &self.value
131     }
132 }
133
134 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for &'a EvalContext<'a, 'mir, 'tcx, M> {
135     #[inline]
136     fn data_layout(&self) -> &layout::TargetDataLayout {
137         &self.tcx.data_layout
138     }
139 }
140
141 impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout
142     for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
143     #[inline]
144     fn data_layout(&self) -> &layout::TargetDataLayout {
145         &self.tcx.data_layout
146     }
147 }
148
149 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'mir, 'tcx, M> {
150     #[inline]
151     fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
152         *self.tcx
153     }
154 }
155
156 impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx>
157     for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
158     #[inline]
159     fn tcx<'d>(&'d self) -> TyCtxt<'d, 'tcx, 'tcx> {
160         *self.tcx
161     }
162 }
163
164 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf<Ty<'tcx>> for &'a EvalContext<'a, 'mir, 'tcx, M> {
165     type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
166
167     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
168         self.tcx.layout_of(self.param_env.and(ty))
169             .map_err(|layout| EvalErrorKind::Layout(layout).into())
170     }
171 }
172
173 impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf<Ty<'tcx>>
174     for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
175     type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
176
177     #[inline]
178     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
179         (&**self).layout_of(ty)
180     }
181 }
182
183 impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
184     pub fn new(
185         tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
186         param_env: ty::ParamEnv<'tcx>,
187         machine: M,
188         memory_data: M::MemoryData,
189     ) -> Self {
190         EvalContext {
191             machine,
192             tcx,
193             param_env,
194             memory: Memory::new(tcx, memory_data),
195             stack: Vec::new(),
196             stack_limit: tcx.sess.const_eval_stack_frame_limit.get(),
197             steps_remaining: tcx.sess.const_eval_step_limit.get(),
198         }
199     }
200
201     pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, MemoryPointer> {
202         let layout = self.layout_of(ty)?;
203         assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
204
205         let size = layout.size.bytes();
206         self.memory.allocate(size, layout.align, Some(MemoryKind::Stack))
207     }
208
209     pub fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
210         &self.memory
211     }
212
213     pub fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
214         &mut self.memory
215     }
216
217     pub fn stack(&self) -> &[Frame<'mir, 'tcx>] {
218         &self.stack
219     }
220
221     #[inline]
222     pub fn cur_frame(&self) -> usize {
223         assert!(self.stack.len() > 0);
224         self.stack.len() - 1
225     }
226
227     pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
228         let ptr = self.memory.allocate_cached(s.as_bytes());
229         Ok(Value::ByValPair(
230             PrimVal::Ptr(ptr),
231             PrimVal::from_u128(s.len() as u128),
232         ))
233     }
234
235     pub(super) fn const_to_value(&self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
236         match *const_val {
237             ConstVal::Unevaluated(def_id, substs) => {
238                 let instance = self.resolve(def_id, substs)?;
239                 self.read_global_as_value(GlobalId {
240                     instance,
241                     promoted: None,
242                 }, ty)
243             }
244             ConstVal::Value(val) => Ok(val),
245         }
246     }
247
248     pub(super) fn resolve(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, ty::Instance<'tcx>> {
249         trace!("resolve: {:?}, {:#?}", def_id, substs);
250         trace!("substs: {:#?}", self.substs());
251         trace!("param_env: {:#?}", self.param_env);
252         let substs = self.tcx.trans_apply_param_substs_env(self.substs(), self.param_env, &substs);
253         ty::Instance::resolve(
254             *self.tcx,
255             self.param_env,
256             def_id,
257             substs,
258         ).ok_or(EvalErrorKind::TypeckError.into()) // turn error prop into a panic to expose associated type in const issue
259     }
260
261     pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
262         ty.is_sized(self.tcx, self.param_env)
263     }
264
265     pub fn load_mir(
266         &self,
267         instance: ty::InstanceDef<'tcx>,
268     ) -> EvalResult<'tcx, &'tcx mir::Mir<'tcx>> {
269         // do not continue if typeck errors occurred (can only occur in local crate)
270         let did = instance.def_id();
271         if did.is_local() && self.tcx.has_typeck_tables(did) && self.tcx.typeck_tables_of(did).tainted_by_errors {
272             return err!(TypeckError);
273         }
274         trace!("load mir {:?}", instance);
275         match instance {
276             ty::InstanceDef::Item(def_id) => {
277                 self.tcx.maybe_optimized_mir(def_id).ok_or_else(|| {
278                     EvalErrorKind::NoMirFor(self.tcx.item_path_str(def_id)).into()
279                 })
280             }
281             _ => Ok(self.tcx.instance_mir(instance)),
282         }
283     }
284
285     pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
286         // miri doesn't care about lifetimes, and will choke on some crazy ones
287         // let's simply get rid of them
288         let without_lifetimes = self.tcx.erase_regions(&ty);
289         let substituted = without_lifetimes.subst(*self.tcx, substs);
290         let substituted = self.tcx.fully_normalize_monormophic_ty(&substituted);
291         substituted
292     }
293
294     /// Return the size and aligment of the value at the given type.
295     /// Note that the value does not matter if the type is sized. For unsized types,
296     /// the value has to be a fat pointer, and we only care about the "extra" data in it.
297     pub fn size_and_align_of_dst(
298         &mut self,
299         ty: Ty<'tcx>,
300         value: Value,
301     ) -> EvalResult<'tcx, (Size, Align)> {
302         let layout = self.layout_of(ty)?;
303         if !layout.is_unsized() {
304             Ok(layout.size_and_align())
305         } else {
306             match ty.sty {
307                 ty::TyAdt(..) | ty::TyTuple(..) => {
308                     // First get the size of all statically known fields.
309                     // Don't use type_of::sizing_type_of because that expects t to be sized,
310                     // and it also rounds up to alignment, which we want to avoid,
311                     // as the unsized field's alignment could be smaller.
312                     assert!(!ty.is_simd());
313                     debug!("DST {} layout: {:?}", ty, layout);
314
315                     let sized_size = layout.fields.offset(layout.fields.count() - 1);
316                     let sized_align = layout.align;
317                     debug!(
318                         "DST {} statically sized prefix size: {:?} align: {:?}",
319                         ty,
320                         sized_size,
321                         sized_align
322                     );
323
324                     // Recurse to get the size of the dynamically sized field (must be
325                     // the last field).
326                     let field_ty = layout.field(&self, layout.fields.count() - 1)?.ty;
327                     let (unsized_size, unsized_align) =
328                         self.size_and_align_of_dst(field_ty, value)?;
329
330                     // FIXME (#26403, #27023): We should be adding padding
331                     // to `sized_size` (to accommodate the `unsized_align`
332                     // required of the unsized field that follows) before
333                     // summing it with `sized_size`. (Note that since #26403
334                     // is unfixed, we do not yet add the necessary padding
335                     // here. But this is where the add would go.)
336
337                     // Return the sum of sizes and max of aligns.
338                     let size = sized_size + unsized_size;
339
340                     // Choose max of two known alignments (combined value must
341                     // be aligned according to more restrictive of the two).
342                     let align = sized_align.max(unsized_align);
343
344                     // Issue #27023: must add any necessary padding to `size`
345                     // (to make it a multiple of `align`) before returning it.
346                     //
347                     // Namely, the returned size should be, in C notation:
348                     //
349                     //   `size + ((size & (align-1)) ? align : 0)`
350                     //
351                     // emulated via the semi-standard fast bit trick:
352                     //
353                     //   `(size + (align-1)) & -align`
354
355                     Ok((size.abi_align(align), align))
356                 }
357                 ty::TyDynamic(..) => {
358                     let (_, vtable) = self.into_ptr_vtable_pair(value)?;
359                     // the second entry in the vtable is the dynamic size of the object.
360                     self.read_size_and_align_from_vtable(vtable)
361                 }
362
363                 ty::TySlice(_) | ty::TyStr => {
364                     let (elem_size, align) = layout.field(&self, 0)?.size_and_align();
365                     let (_, len) = self.into_slice(value)?;
366                     Ok((elem_size * len, align))
367                 }
368
369                 _ => bug!("size_of_val::<{:?}>", ty),
370             }
371         }
372     }
373
374     pub fn push_stack_frame(
375         &mut self,
376         instance: ty::Instance<'tcx>,
377         span: codemap::Span,
378         mir: &'mir mir::Mir<'tcx>,
379         return_place: Place,
380         return_to_block: StackPopCleanup,
381     ) -> EvalResult<'tcx> {
382         ::log_settings::settings().indentation += 1;
383
384         /// Return the set of locals that have a storage annotation anywhere
385         fn collect_storage_annotations<'mir, 'tcx>(mir: &'mir mir::Mir<'tcx>) -> HashSet<mir::Local> {
386             use rustc::mir::StatementKind::*;
387
388             let mut set = HashSet::new();
389             for block in mir.basic_blocks() {
390                 for stmt in block.statements.iter() {
391                     match stmt.kind {
392                         StorageLive(local) |
393                         StorageDead(local) => {
394                             set.insert(local);
395                         }
396                         _ => {}
397                     }
398                 }
399             }
400             set
401         }
402
403         // Subtract 1 because `local_decls` includes the ReturnMemoryPointer, but we don't store a local
404         // `Value` for that.
405         let num_locals = mir.local_decls.len() - 1;
406
407         let locals = {
408             let annotated_locals = collect_storage_annotations(mir);
409             let mut locals = vec![None; num_locals];
410             for i in 0..num_locals {
411                 let local = mir::Local::new(i + 1);
412                 if !annotated_locals.contains(&local) {
413                     locals[i] = Some(Value::ByVal(PrimVal::Undef));
414                 }
415             }
416             locals
417         };
418
419         self.stack.push(Frame {
420             mir,
421             block: mir::START_BLOCK,
422             return_to_block,
423             return_place,
424             locals,
425             span,
426             instance,
427             stmt: 0,
428         });
429
430         self.memory.cur_frame = self.cur_frame();
431
432         if self.stack.len() > self.stack_limit {
433             err!(StackFrameLimitReached)
434         } else {
435             Ok(())
436         }
437     }
438
439     pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
440         ::log_settings::settings().indentation -= 1;
441         M::end_region(self, None)?;
442         let frame = self.stack.pop().expect(
443             "tried to pop a stack frame, but there were none",
444         );
445         if !self.stack.is_empty() {
446             // TODO: Is this the correct time to start considering these accesses as originating from the returned-to stack frame?
447             self.memory.cur_frame = self.cur_frame();
448         }
449         match frame.return_to_block {
450             StackPopCleanup::MarkStatic(mutable) => {
451                 if let Place::Ptr { ptr, .. } = frame.return_place {
452                     // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
453                     self.memory.mark_static_initialized(
454                         ptr.to_ptr()?.alloc_id,
455                         mutable,
456                     )?
457                 } else {
458                     bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_place);
459                 }
460             }
461             StackPopCleanup::Goto(target) => self.goto_block(target),
462             StackPopCleanup::None => {}
463         }
464         // deallocate all locals that are backed by an allocation
465         for local in frame.locals {
466             self.deallocate_local(local)?;
467         }
468
469         Ok(())
470     }
471
472     pub fn deallocate_local(&mut self, local: Option<Value>) -> EvalResult<'tcx> {
473         if let Some(Value::ByRef(ptr, _align)) = local {
474             trace!("deallocating local");
475             let ptr = ptr.to_ptr()?;
476             self.memory.dump_alloc(ptr.alloc_id);
477             self.memory.deallocate_local(ptr)?;
478         };
479         Ok(())
480     }
481
482     /// Evaluate an assignment statement.
483     ///
484     /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
485     /// type writes its results directly into the memory specified by the place.
486     pub(super) fn eval_rvalue_into_place(
487         &mut self,
488         rvalue: &mir::Rvalue<'tcx>,
489         place: &mir::Place<'tcx>,
490     ) -> EvalResult<'tcx> {
491         let dest = self.eval_place(place)?;
492         let dest_ty = self.place_ty(place);
493
494         use rustc::mir::Rvalue::*;
495         match *rvalue {
496             Use(ref operand) => {
497                 let value = self.eval_operand(operand)?.value;
498                 let valty = ValTy {
499                     value,
500                     ty: dest_ty,
501                 };
502                 self.write_value(valty, dest)?;
503             }
504
505             BinaryOp(bin_op, ref left, ref right) => {
506                 let left = self.eval_operand(left)?;
507                 let right = self.eval_operand(right)?;
508                 if self.intrinsic_overflowing(
509                     bin_op,
510                     left,
511                     right,
512                     dest,
513                     dest_ty,
514                 )?
515                 {
516                     // There was an overflow in an unchecked binop.  Right now, we consider this an error and bail out.
517                     // The rationale is that the reason rustc emits unchecked binops in release mode (vs. the checked binops
518                     // it emits in debug mode) is performance, but it doesn't cost us any performance in miri.
519                     // If, however, the compiler ever starts transforming unchecked intrinsics into unchecked binops,
520                     // we have to go back to just ignoring the overflow here.
521                     return err!(OverflowingMath);
522                 }
523             }
524
525             CheckedBinaryOp(bin_op, ref left, ref right) => {
526                 let left = self.eval_operand(left)?;
527                 let right = self.eval_operand(right)?;
528                 self.intrinsic_with_overflow(
529                     bin_op,
530                     left,
531                     right,
532                     dest,
533                     dest_ty,
534                 )?;
535             }
536
537             UnaryOp(un_op, ref operand) => {
538                 let val = self.eval_operand_to_primval(operand)?;
539                 let val = self.unary_op(un_op, val, dest_ty)?;
540                 self.write_primval(
541                     dest,
542                     val,
543                     dest_ty,
544                 )?;
545             }
546
547             Aggregate(ref kind, ref operands) => {
548                 self.inc_step_counter_and_check_limit(operands.len())?;
549
550                 let (dest, active_field_index) = match **kind {
551                     mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
552                         self.write_discriminant_value(dest_ty, dest, variant_index)?;
553                         if adt_def.is_enum() {
554                             (self.place_downcast(dest, variant_index)?, active_field_index)
555                         } else {
556                             (dest, active_field_index)
557                         }
558                     }
559                     _ => (dest, None)
560                 };
561
562                 let layout = self.layout_of(dest_ty)?;
563                 for (i, operand) in operands.iter().enumerate() {
564                     let value = self.eval_operand(operand)?;
565                     // Ignore zero-sized fields.
566                     if !self.layout_of(value.ty)?.is_zst() {
567                         let field_index = active_field_index.unwrap_or(i);
568                         let (field_dest, _) = self.place_field(dest, mir::Field::new(field_index), layout)?;
569                         self.write_value(value, field_dest)?;
570                     }
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.val.unwrap_u64()),
577                     _ => {
578                         bug!(
579                             "tried to assign array-repeat to non-array type {:?}",
580                             dest_ty
581                         )
582                     }
583                 };
584                 let elem_size = self.layout_of(elem_ty)?.size.bytes();
585                 let value = self.eval_operand(operand)?.value;
586
587                 let (dest, dest_align) = self.force_allocation(dest)?.to_ptr_align();
588
589                 // FIXME: speed up repeat filling
590                 for i in 0..length {
591                     let elem_dest = dest.offset(i * elem_size, &self)?;
592                     self.write_value_to_ptr(value, elem_dest, dest_align, elem_ty)?;
593                 }
594             }
595
596             Len(ref place) => {
597                 // FIXME(CTFE): don't allow computing the length of arrays in const eval
598                 let src = self.eval_place(place)?;
599                 let ty = self.place_ty(place);
600                 let (_, len) = src.elem_ty_and_len(ty);
601                 self.write_primval(
602                     dest,
603                     PrimVal::from_u128(len as u128),
604                     dest_ty,
605                 )?;
606             }
607
608             Ref(_, _, ref place) => {
609                 let src = self.eval_place(place)?;
610                 // We ignore the alignment of the place here -- special handling for packed structs ends
611                 // at the `&` operator.
612                 let (ptr, _align, extra) = self.force_allocation(src)?.to_ptr_align_extra();
613
614                 let val = match extra {
615                     PlaceExtra::None => ptr.to_value(),
616                     PlaceExtra::Length(len) => ptr.to_value_with_len(len),
617                     PlaceExtra::Vtable(vtable) => ptr.to_value_with_vtable(vtable),
618                     PlaceExtra::DowncastVariant(..) => {
619                         bug!("attempted to take a reference to an enum downcast place")
620                     }
621                 };
622                 let valty = ValTy {
623                     value: val,
624                     ty: dest_ty,
625                 };
626                 self.write_value(valty, dest)?;
627             }
628
629             NullaryOp(mir::NullOp::Box, ty) => {
630                 let ty = self.monomorphize(ty, self.substs());
631                 M::box_alloc(self, ty, dest)?;
632             }
633
634             NullaryOp(mir::NullOp::SizeOf, ty) => {
635                 let ty = self.monomorphize(ty, self.substs());
636                 let layout = self.layout_of(ty)?;
637                 assert!(!layout.is_unsized(),
638                         "SizeOf nullary MIR operator called for unsized type");
639                 self.write_primval(
640                     dest,
641                     PrimVal::from_u128(layout.size.bytes() as u128),
642                     dest_ty,
643                 )?;
644             }
645
646             Cast(kind, ref operand, cast_ty) => {
647                 debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest_ty);
648                 use rustc::mir::CastKind::*;
649                 match kind {
650                     Unsize => {
651                         let src = self.eval_operand(operand)?;
652                         let src_layout = self.layout_of(src.ty)?;
653                         let dst_layout = self.layout_of(dest_ty)?;
654                         self.unsize_into(src.value, src_layout, dest, dst_layout)?;
655                     }
656
657                     Misc => {
658                         let src = self.eval_operand(operand)?;
659                         if self.type_is_fat_ptr(src.ty) {
660                             match (src.value, self.type_is_fat_ptr(dest_ty)) {
661                                 (Value::ByRef { .. }, _) |
662                                 (Value::ByValPair(..), true) => {
663                                     let valty = ValTy {
664                                         value: src.value,
665                                         ty: dest_ty,
666                                     };
667                                     self.write_value(valty, dest)?;
668                                 }
669                                 (Value::ByValPair(data, _), false) => {
670                                     let valty = ValTy {
671                                         value: Value::ByVal(data),
672                                         ty: dest_ty,
673                                     };
674                                     self.write_value(valty, dest)?;
675                                 }
676                                 (Value::ByVal(_), _) => bug!("expected fat ptr"),
677                             }
678                         } else {
679                             let src_val = self.value_to_primval(src)?;
680                             let dest_val = self.cast_primval(src_val, src.ty, dest_ty)?;
681                             let valty = ValTy {
682                                 value: Value::ByVal(dest_val),
683                                 ty: dest_ty,
684                             };
685                             self.write_value(valty, dest)?;
686                         }
687                     }
688
689                     ReifyFnPointer => {
690                         match self.eval_operand(operand)?.ty.sty {
691                             ty::TyFnDef(def_id, substs) => {
692                                 if self.tcx.has_attr(def_id, "rustc_args_required_const") {
693                                     bug!("reifying a fn ptr that requires \
694                                           const arguments");
695                                 }
696                                 let instance: EvalResult<'tcx, _> = ty::Instance::resolve(
697                                     *self.tcx,
698                                     self.param_env,
699                                     def_id,
700                                     substs,
701                                 ).ok_or(EvalErrorKind::TypeckError.into());
702                                 let fn_ptr = self.memory.create_fn_alloc(instance?);
703                                 let valty = ValTy {
704                                     value: Value::ByVal(PrimVal::Ptr(fn_ptr)),
705                                     ty: dest_ty,
706                                 };
707                                 self.write_value(valty, dest)?;
708                             }
709                             ref other => bug!("reify fn pointer on {:?}", other),
710                         }
711                     }
712
713                     UnsafeFnPointer => {
714                         match dest_ty.sty {
715                             ty::TyFnPtr(_) => {
716                                 let mut src = self.eval_operand(operand)?;
717                                 src.ty = dest_ty;
718                                 self.write_value(src, dest)?;
719                             }
720                             ref other => bug!("fn to unsafe fn cast on {:?}", other),
721                         }
722                     }
723
724                     ClosureFnPointer => {
725                         match self.eval_operand(operand)?.ty.sty {
726                             ty::TyClosure(def_id, substs) => {
727                                 let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs);
728                                 let instance = ty::Instance::resolve_closure(
729                                     *self.tcx,
730                                     def_id,
731                                     substs,
732                                     ty::ClosureKind::FnOnce,
733                                 );
734                                 let fn_ptr = self.memory.create_fn_alloc(instance);
735                                 let valty = ValTy {
736                                     value: Value::ByVal(PrimVal::Ptr(fn_ptr)),
737                                     ty: dest_ty,
738                                 };
739                                 self.write_value(valty, dest)?;
740                             }
741                             ref other => bug!("closure fn pointer on {:?}", other),
742                         }
743                     }
744                 }
745             }
746
747             Discriminant(ref place) => {
748                 let ty = self.place_ty(place);
749                 let place = self.eval_place(place)?;
750                 let discr_val = self.read_discriminant_value(place, ty)?;
751                 if let ty::TyAdt(adt_def, _) = ty.sty {
752                     trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(*self.tcx).collect::<Vec<_>>());
753                     if adt_def.discriminants(*self.tcx).all(|v| {
754                         discr_val != v.val
755                     })
756                     {
757                         return err!(InvalidDiscriminant);
758                     }
759                     self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
760                 } else {
761                     bug!("rustc only generates Rvalue::Discriminant for enums");
762                 }
763             }
764         }
765
766         if log_enabled!(::log::Level::Trace) {
767             self.dump_local(dest);
768         }
769
770         Ok(())
771     }
772
773     pub(super) fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
774         match ty.sty {
775             ty::TyRawPtr(ref tam) |
776             ty::TyRef(_, ref tam) => !self.type_is_sized(tam.ty),
777             ty::TyAdt(def, _) if def.is_box() => !self.type_is_sized(ty.boxed_ty()),
778             _ => false,
779         }
780     }
781
782     pub(super) fn eval_operand_to_primval(
783         &mut self,
784         op: &mir::Operand<'tcx>,
785     ) -> EvalResult<'tcx, PrimVal> {
786         let valty = self.eval_operand(op)?;
787         self.value_to_primval(valty)
788     }
789
790     pub(crate) fn operands_to_args(
791         &mut self,
792         ops: &[mir::Operand<'tcx>],
793     ) -> EvalResult<'tcx, Vec<ValTy<'tcx>>> {
794         ops.into_iter()
795             .map(|op| self.eval_operand(op))
796             .collect()
797     }
798
799     pub fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> {
800         use rustc::mir::Operand::*;
801         let ty = self.monomorphize(op.ty(self.mir(), *self.tcx), self.substs());
802         match *op {
803             // FIXME: do some more logic on `move` to invalidate the old location
804             Copy(ref place) |
805             Move(ref place) => {
806                 Ok(ValTy {
807                     value: self.eval_and_read_place(place)?,
808                     ty
809                 })
810             },
811
812             Constant(ref constant) => {
813                 use rustc::mir::Literal;
814                 let mir::Constant { ref literal, .. } = **constant;
815                 let value = match *literal {
816                     Literal::Value { ref value } => self.const_to_value(&value.val, ty)?,
817
818                     Literal::Promoted { index } => {
819                         self.read_global_as_value(GlobalId {
820                             instance: self.frame().instance,
821                             promoted: Some(index),
822                         }, ty)?
823                     }
824                 };
825
826                 Ok(ValTy {
827                     value,
828                     ty,
829                 })
830             }
831         }
832     }
833
834     pub fn read_discriminant_value(
835         &mut self,
836         place: Place,
837         ty: Ty<'tcx>,
838     ) -> EvalResult<'tcx, u128> {
839         let layout = self.layout_of(ty)?;
840         //trace!("read_discriminant_value {:#?}", layout);
841
842         match layout.variants {
843             layout::Variants::Single { index } => {
844                 return Ok(index as u128);
845             }
846             layout::Variants::Tagged { .. } |
847             layout::Variants::NicheFilling { .. } => {},
848         }
849
850         let (discr_place, discr) = self.place_field(place, mir::Field::new(0), layout)?;
851         let raw_discr = self.value_to_primval(ValTy {
852             value: self.read_place(discr_place)?,
853             ty: discr.ty
854         })?;
855         let discr_val = match layout.variants {
856             layout::Variants::Single { .. } => bug!(),
857             layout::Variants::Tagged { .. } => raw_discr.to_bytes()?,
858             layout::Variants::NicheFilling {
859                 dataful_variant,
860                 ref niche_variants,
861                 niche_start,
862                 ..
863             } => {
864                 let variants_start = niche_variants.start as u128;
865                 let variants_end = niche_variants.end as u128;
866                 match raw_discr {
867                     PrimVal::Ptr(_) => {
868                         assert!(niche_start == 0);
869                         assert!(variants_start == variants_end);
870                         dataful_variant as u128
871                     },
872                     PrimVal::Bytes(raw_discr) => {
873                         let discr = raw_discr.wrapping_sub(niche_start)
874                             .wrapping_add(variants_start);
875                         if variants_start <= discr && discr <= variants_end {
876                             discr
877                         } else {
878                             dataful_variant as u128
879                         }
880                     },
881                     PrimVal::Undef => return err!(ReadUndefBytes),
882                 }
883             }
884         };
885
886         Ok(discr_val)
887     }
888
889
890     pub(crate) fn write_discriminant_value(
891         &mut self,
892         dest_ty: Ty<'tcx>,
893         dest: Place,
894         variant_index: usize,
895     ) -> EvalResult<'tcx> {
896         let layout = self.layout_of(dest_ty)?;
897
898         match layout.variants {
899             layout::Variants::Single { index } => {
900                 if index != variant_index {
901                     // If the layout of an enum is `Single`, all
902                     // other variants are necessarily uninhabited.
903                     assert_eq!(layout.for_variant(&self, variant_index).abi,
904                                layout::Abi::Uninhabited);
905                 }
906             }
907             layout::Variants::Tagged { .. } => {
908                 let discr_val = dest_ty.ty_adt_def().unwrap()
909                     .discriminant_for_variant(*self.tcx, variant_index)
910                     .val;
911
912                 let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?;
913                 self.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?;
914             }
915             layout::Variants::NicheFilling {
916                 dataful_variant,
917                 ref niche_variants,
918                 niche_start,
919                 ..
920             } => {
921                 if variant_index != dataful_variant {
922                     let (niche_dest, niche) =
923                         self.place_field(dest, mir::Field::new(0), layout)?;
924                     let niche_value = ((variant_index - niche_variants.start) as u128)
925                         .wrapping_add(niche_start);
926                     self.write_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?;
927                 }
928             }
929         }
930
931         Ok(())
932     }
933
934     pub fn read_global_as_value(&self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
935         if gid.promoted.is_none() {
936             let cached = self
937                 .tcx
938                 .interpret_interner
939                 .get_cached(gid.instance.def_id());
940             if let Some(alloc_id) = cached {
941                 let layout = self.layout_of(ty)?;
942                 let ptr = MemoryPointer::new(alloc_id, 0);
943                 return Ok(Value::ByRef(ptr.into(), layout.align))
944             }
945         }
946         let cv = self.const_eval(gid)?;
947         self.const_to_value(&cv.val, ty)
948     }
949
950     pub fn const_eval(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> {
951         let param_env = if self.tcx.is_static(gid.instance.def_id()).is_some() {
952             use rustc::traits;
953             ty::ParamEnv::empty(traits::Reveal::All)
954         } else {
955             self.param_env
956         };
957         self.tcx.const_eval(param_env.and(gid)).map_err(|err| match *err.kind {
958             ErrKind::Miri(ref err, _) => match err.kind {
959                 EvalErrorKind::TypeckError |
960                 EvalErrorKind::Layout(_) => EvalErrorKind::TypeckError.into(),
961                 _ => EvalErrorKind::ReferencedConstant.into(),
962             },
963             ErrKind::TypeckError => EvalErrorKind::TypeckError.into(),
964             ref other => bug!("const eval returned {:?}", other),
965         })
966     }
967
968     pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> {
969         let new_place = match place {
970             Place::Local { frame, local } => {
971                 // -1 since we don't store the return value
972                 match self.stack[frame].locals[local.index() - 1] {
973                     None => return err!(DeadLocal),
974                     Some(Value::ByRef(ptr, align)) => {
975                         Place::Ptr {
976                             ptr,
977                             align,
978                             extra: PlaceExtra::None,
979                         }
980                     }
981                     Some(val) => {
982                         let ty = self.stack[frame].mir.local_decls[local].ty;
983                         let ty = self.monomorphize(ty, self.stack[frame].instance.substs);
984                         let layout = self.layout_of(ty)?;
985                         let ptr = self.alloc_ptr(ty)?;
986                         self.stack[frame].locals[local.index() - 1] =
987                             Some(Value::ByRef(ptr.into(), layout.align)); // it stays live
988                         let place = Place::from_ptr(ptr, layout.align);
989                         self.write_value(ValTy { value: val, ty }, place)?;
990                         place
991                     }
992                 }
993             }
994             Place::Ptr { .. } => place,
995         };
996         Ok(new_place)
997     }
998
999     /// ensures this Value is not a ByRef
1000     pub fn follow_by_ref_value(
1001         &self,
1002         value: Value,
1003         ty: Ty<'tcx>,
1004     ) -> EvalResult<'tcx, Value> {
1005         match value {
1006             Value::ByRef(ptr, align) => {
1007                 self.read_value(ptr, align, ty)
1008             }
1009             other => Ok(other),
1010         }
1011     }
1012
1013     pub fn value_to_primval(
1014         &self,
1015         ValTy { value, ty } : ValTy<'tcx>,
1016     ) -> EvalResult<'tcx, PrimVal> {
1017         match self.follow_by_ref_value(value, ty)? {
1018             Value::ByRef { .. } => bug!("follow_by_ref_value can't result in `ByRef`"),
1019
1020             Value::ByVal(primval) => {
1021                 // TODO: Do we really want insta-UB here?
1022                 self.ensure_valid_value(primval, ty)?;
1023                 Ok(primval)
1024             }
1025
1026             Value::ByValPair(..) => bug!("value_to_primval can't work with fat pointers"),
1027         }
1028     }
1029
1030     pub fn write_ptr(&mut self, dest: Place, val: Pointer, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> {
1031         let valty = ValTy {
1032             value: val.to_value(),
1033             ty: dest_ty,
1034         };
1035         self.write_value(valty, dest)
1036     }
1037
1038     pub fn write_primval(
1039         &mut self,
1040         dest: Place,
1041         val: PrimVal,
1042         dest_ty: Ty<'tcx>,
1043     ) -> EvalResult<'tcx> {
1044         let valty = ValTy {
1045             value: Value::ByVal(val),
1046             ty: dest_ty,
1047         };
1048         self.write_value(valty, dest)
1049     }
1050
1051     pub fn write_value(
1052         &mut self,
1053         ValTy { value: src_val, ty: dest_ty } : ValTy<'tcx>,
1054         dest: Place,
1055     ) -> EvalResult<'tcx> {
1056         //trace!("Writing {:?} to {:?} at type {:?}", src_val, dest, dest_ty);
1057         // Note that it is really important that the type here is the right one, and matches the type things are read at.
1058         // In case `src_val` is a `ByValPair`, we don't do any magic here to handle padding properly, which is only
1059         // correct if we never look at this data with the wrong type.
1060
1061         match dest {
1062             Place::Ptr { ptr, align, extra } => {
1063                 assert_eq!(extra, PlaceExtra::None);
1064                 self.write_value_to_ptr(src_val, ptr, align, dest_ty)
1065             }
1066
1067             Place::Local { frame, local } => {
1068                 let dest = self.stack[frame].get_local(local)?;
1069                 self.write_value_possibly_by_val(
1070                     src_val,
1071                     |this, val| this.stack[frame].set_local(local, val),
1072                     dest,
1073                     dest_ty,
1074                 )
1075             }
1076         }
1077     }
1078
1079     // The cases here can be a bit subtle. Read carefully!
1080     fn write_value_possibly_by_val<F: FnOnce(&mut Self, Value) -> EvalResult<'tcx>>(
1081         &mut self,
1082         src_val: Value,
1083         write_dest: F,
1084         old_dest_val: Value,
1085         dest_ty: Ty<'tcx>,
1086     ) -> EvalResult<'tcx> {
1087         if let Value::ByRef(dest_ptr, align) = old_dest_val {
1088             // If the value is already `ByRef` (that is, backed by an `Allocation`),
1089             // then we must write the new value into this allocation, because there may be
1090             // other pointers into the allocation. These other pointers are logically
1091             // pointers into the local variable, and must be able to observe the change.
1092             //
1093             // Thus, it would be an error to replace the `ByRef` with a `ByVal`, unless we
1094             // knew for certain that there were no outstanding pointers to this allocation.
1095             self.write_value_to_ptr(src_val, dest_ptr, align, dest_ty)?;
1096         } else if let Value::ByRef(src_ptr, align) = src_val {
1097             // If the value is not `ByRef`, then we know there are no pointers to it
1098             // and we can simply overwrite the `Value` in the locals array directly.
1099             //
1100             // In this specific case, where the source value is `ByRef`, we must duplicate
1101             // the allocation, because this is a by-value operation. It would be incorrect
1102             // if they referred to the same allocation, since then a change to one would
1103             // implicitly change the other.
1104             //
1105             // It is a valid optimization to attempt reading a primitive value out of the
1106             // source and write that into the destination without making an allocation, so
1107             // we do so here.
1108             if let Ok(Some(src_val)) = self.try_read_value(src_ptr, align, dest_ty) {
1109                 write_dest(self, src_val)?;
1110             } else {
1111                 let dest_ptr = self.alloc_ptr(dest_ty)?.into();
1112                 let layout = self.layout_of(dest_ty)?;
1113                 self.memory.copy(src_ptr, align.min(layout.align), dest_ptr, layout.align, layout.size.bytes(), false)?;
1114                 write_dest(self, Value::ByRef(dest_ptr, layout.align))?;
1115             }
1116         } else {
1117             // Finally, we have the simple case where neither source nor destination are
1118             // `ByRef`. We may simply copy the source value over the the destintion.
1119             write_dest(self, src_val)?;
1120         }
1121         Ok(())
1122     }
1123
1124     pub fn write_value_to_ptr(
1125         &mut self,
1126         value: Value,
1127         dest: Pointer,
1128         dest_align: Align,
1129         dest_ty: Ty<'tcx>,
1130     ) -> EvalResult<'tcx> {
1131         let layout = self.layout_of(dest_ty)?;
1132         trace!("write_value_to_ptr: {:#?}, {}, {:#?}", value, dest_ty, layout);
1133         match value {
1134             Value::ByRef(ptr, align) => {
1135                 self.memory.copy(ptr, align.min(layout.align), dest, dest_align.min(layout.align), layout.size.bytes(), false)
1136             }
1137             Value::ByVal(primval) => {
1138                 let signed = match layout.abi {
1139                     layout::Abi::Scalar(ref scal) => match scal.value {
1140                         layout::Primitive::Int(_, signed) => signed,
1141                         _ => false,
1142                     },
1143                     _ if primval.is_undef() => false,
1144                     _ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout)
1145                 };
1146                 self.memory.write_primval(dest.to_ptr()?, dest_align, primval, layout.size.bytes(), signed)
1147             }
1148             Value::ByValPair(a_val, b_val) => {
1149                 let ptr = dest.to_ptr()?;
1150                 trace!("write_value_to_ptr valpair: {:#?}", layout);
1151                 let (a, b) = match layout.abi {
1152                     layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
1153                     _ => bug!("write_value_to_ptr: invalid ByValPair layout: {:#?}", layout)
1154                 };
1155                 let (a_size, b_size) = (a.size(&self), b.size(&self));
1156                 let a_ptr = ptr;
1157                 let b_offset = a_size.abi_align(b.align(&self));
1158                 let b_ptr = ptr.offset(b_offset.bytes(), &self)?.into();
1159                 // TODO: What about signedess?
1160                 self.memory.write_primval(a_ptr, dest_align, a_val, a_size.bytes(), false)?;
1161                 self.memory.write_primval(b_ptr, dest_align, b_val, b_size.bytes(), false)
1162             }
1163         }
1164     }
1165
1166     pub fn ty_to_primval_kind(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimValKind> {
1167         use syntax::ast::FloatTy;
1168
1169         let kind = match ty.sty {
1170             ty::TyBool => PrimValKind::Bool,
1171             ty::TyChar => PrimValKind::Char,
1172
1173             ty::TyInt(int_ty) => {
1174                 use syntax::ast::IntTy::*;
1175                 let size = match int_ty {
1176                     I8 => 1,
1177                     I16 => 2,
1178                     I32 => 4,
1179                     I64 => 8,
1180                     I128 => 16,
1181                     Isize => self.memory.pointer_size(),
1182                 };
1183                 PrimValKind::from_int_size(size)
1184             }
1185
1186             ty::TyUint(uint_ty) => {
1187                 use syntax::ast::UintTy::*;
1188                 let size = match uint_ty {
1189                     U8 => 1,
1190                     U16 => 2,
1191                     U32 => 4,
1192                     U64 => 8,
1193                     U128 => 16,
1194                     Usize => self.memory.pointer_size(),
1195                 };
1196                 PrimValKind::from_uint_size(size)
1197             }
1198
1199             ty::TyFloat(FloatTy::F32) => PrimValKind::F32,
1200             ty::TyFloat(FloatTy::F64) => PrimValKind::F64,
1201
1202             ty::TyFnPtr(_) => PrimValKind::FnPtr,
1203
1204             ty::TyRef(_, ref tam) |
1205             ty::TyRawPtr(ref tam) if self.type_is_sized(tam.ty) => PrimValKind::Ptr,
1206
1207             ty::TyAdt(def, _) if def.is_box() => PrimValKind::Ptr,
1208
1209             ty::TyAdt(..) => {
1210                 match self.layout_of(ty)?.abi {
1211                     layout::Abi::Scalar(ref scalar) => {
1212                         use rustc::ty::layout::Primitive::*;
1213                         match scalar.value {
1214                             Int(i, false) => PrimValKind::from_uint_size(i.size().bytes()),
1215                             Int(i, true) => PrimValKind::from_int_size(i.size().bytes()),
1216                             F32 => PrimValKind::F32,
1217                             F64 => PrimValKind::F64,
1218                             Pointer => PrimValKind::Ptr,
1219                         }
1220                     }
1221
1222                     _ => return err!(TypeNotPrimitive(ty)),
1223                 }
1224             }
1225
1226             _ => return err!(TypeNotPrimitive(ty)),
1227         };
1228
1229         Ok(kind)
1230     }
1231
1232     fn ensure_valid_value(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx> {
1233         match ty.sty {
1234             ty::TyBool if val.to_bytes()? > 1 => err!(InvalidBool),
1235
1236             ty::TyChar if ::std::char::from_u32(val.to_bytes()? as u32).is_none() => {
1237                 err!(InvalidChar(val.to_bytes()? as u32 as u128))
1238             }
1239
1240             _ => Ok(()),
1241         }
1242     }
1243
1244     pub fn read_value(&self, ptr: Pointer, align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
1245         if let Some(val) = self.try_read_value(ptr, align, ty)? {
1246             Ok(val)
1247         } else {
1248             bug!("primitive read failed for type: {:?}", ty);
1249         }
1250     }
1251
1252     pub(crate) fn read_ptr(
1253         &self,
1254         ptr: MemoryPointer,
1255         ptr_align: Align,
1256         pointee_ty: Ty<'tcx>,
1257     ) -> EvalResult<'tcx, Value> {
1258         let ptr_size = self.memory.pointer_size();
1259         let p: Pointer = self.memory.read_ptr_sized(ptr, ptr_align)?.into();
1260         if self.type_is_sized(pointee_ty) {
1261             Ok(p.to_value())
1262         } else {
1263             trace!("reading fat pointer extra of type {}", pointee_ty);
1264             let extra = ptr.offset(ptr_size, self)?;
1265             match self.tcx.struct_tail(pointee_ty).sty {
1266                 ty::TyDynamic(..) => Ok(p.to_value_with_vtable(
1267                     self.memory.read_ptr_sized(extra, ptr_align)?.to_ptr()?,
1268                 )),
1269                 ty::TySlice(..) | ty::TyStr => {
1270                     let len = self
1271                         .memory
1272                         .read_ptr_sized(extra, ptr_align)?
1273                         .to_bytes()?;
1274                     Ok(p.to_value_with_len(len as u64))
1275                 },
1276                 _ => bug!("unsized primval ptr read from {:?}", pointee_ty),
1277             }
1278         }
1279     }
1280
1281     pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
1282         use syntax::ast::FloatTy;
1283
1284         let ptr = ptr.to_ptr()?;
1285         let val = match ty.sty {
1286             ty::TyBool => {
1287                 let val = self.memory.read_primval(ptr, ptr_align, 1)?;
1288                 let val = match val {
1289                     PrimVal::Bytes(0) => false,
1290                     PrimVal::Bytes(1) => true,
1291                     // TODO: This seems a little overeager, should reading at bool type already be insta-UB?
1292                     _ => return err!(InvalidBool),
1293                 };
1294                 PrimVal::from_bool(val)
1295             }
1296             ty::TyChar => {
1297                 let c = self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()? as u32;
1298                 match ::std::char::from_u32(c) {
1299                     Some(ch) => PrimVal::from_char(ch),
1300                     None => return err!(InvalidChar(c as u128)),
1301                 }
1302             }
1303
1304             ty::TyInt(int_ty) => {
1305                 use syntax::ast::IntTy::*;
1306                 let size = match int_ty {
1307                     I8 => 1,
1308                     I16 => 2,
1309                     I32 => 4,
1310                     I64 => 8,
1311                     I128 => 16,
1312                     Isize => self.memory.pointer_size(),
1313                 };
1314                 self.memory.read_primval(ptr, ptr_align, size)?
1315             }
1316
1317             ty::TyUint(uint_ty) => {
1318                 use syntax::ast::UintTy::*;
1319                 let size = match uint_ty {
1320                     U8 => 1,
1321                     U16 => 2,
1322                     U32 => 4,
1323                     U64 => 8,
1324                     U128 => 16,
1325                     Usize => self.memory.pointer_size(),
1326                 };
1327                 self.memory.read_primval(ptr, ptr_align, size)?
1328             }
1329
1330             ty::TyFloat(FloatTy::F32) => {
1331                 PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()?)
1332             }
1333             ty::TyFloat(FloatTy::F64) => {
1334                 PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 8)?.to_bytes()?)
1335             }
1336
1337             ty::TyFnPtr(_) => self.memory.read_ptr_sized(ptr, ptr_align)?,
1338             ty::TyRef(_, ref tam) |
1339             ty::TyRawPtr(ref tam) => return self.read_ptr(ptr, ptr_align, tam.ty).map(Some),
1340
1341             ty::TyAdt(def, _) => {
1342                 if def.is_box() {
1343                     return self.read_ptr(ptr, ptr_align, ty.boxed_ty()).map(Some);
1344                 }
1345
1346                 if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi {
1347                     let size = scalar.value.size(self).bytes();
1348                     self.memory.read_primval(ptr, ptr_align, size)?
1349                 } else {
1350                     return Ok(None);
1351                 }
1352             }
1353
1354             _ => return Ok(None),
1355         };
1356
1357         Ok(Some(Value::ByVal(val)))
1358     }
1359
1360     pub fn frame(&self) -> &Frame<'mir, 'tcx> {
1361         self.stack.last().expect("no call frames exist")
1362     }
1363
1364     pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> {
1365         self.stack.last_mut().expect("no call frames exist")
1366     }
1367
1368     pub(super) fn mir(&self) -> &'mir mir::Mir<'tcx> {
1369         self.frame().mir
1370     }
1371
1372     pub fn substs(&self) -> &'tcx Substs<'tcx> {
1373         if let Some(frame) = self.stack.last() {
1374             frame.instance.substs
1375         } else {
1376             Substs::empty()
1377         }
1378     }
1379
1380     fn unsize_into_ptr(
1381         &mut self,
1382         src: Value,
1383         src_ty: Ty<'tcx>,
1384         dest: Place,
1385         dest_ty: Ty<'tcx>,
1386         sty: Ty<'tcx>,
1387         dty: Ty<'tcx>,
1388     ) -> EvalResult<'tcx> {
1389         // A<Struct> -> A<Trait> conversion
1390         let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty);
1391
1392         match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
1393             (&ty::TyArray(_, length), &ty::TySlice(_)) => {
1394                 let ptr = self.into_ptr(src)?;
1395                 // u64 cast is from usize to u64, which is always good
1396                 let valty = ValTy {
1397                     value: ptr.to_value_with_len(length.val.unwrap_u64() ),
1398                     ty: dest_ty,
1399                 };
1400                 self.write_value(valty, dest)
1401             }
1402             (&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
1403                 // For now, upcasts are limited to changes in marker
1404                 // traits, and hence never actually require an actual
1405                 // change to the vtable.
1406                 let valty = ValTy {
1407                     value: src,
1408                     ty: dest_ty,
1409                 };
1410                 self.write_value(valty, dest)
1411             }
1412             (_, &ty::TyDynamic(ref data, _)) => {
1413                 let trait_ref = data.principal().unwrap().with_self_ty(
1414                     *self.tcx,
1415                     src_pointee_ty,
1416                 );
1417                 let trait_ref = self.tcx.erase_regions(&trait_ref);
1418                 let vtable = self.get_vtable(src_pointee_ty, trait_ref)?;
1419                 let ptr = self.into_ptr(src)?;
1420                 let valty = ValTy {
1421                     value: ptr.to_value_with_vtable(vtable),
1422                     ty: dest_ty,
1423                 };
1424                 self.write_value(valty, dest)
1425             }
1426
1427             _ => bug!("invalid unsizing {:?} -> {:?}", src_ty, dest_ty),
1428         }
1429     }
1430
1431     fn unsize_into(
1432         &mut self,
1433         src: Value,
1434         src_layout: TyLayout<'tcx>,
1435         dst: Place,
1436         dst_layout: TyLayout<'tcx>,
1437     ) -> EvalResult<'tcx> {
1438         match (&src_layout.ty.sty, &dst_layout.ty.sty) {
1439             (&ty::TyRef(_, ref s), &ty::TyRef(_, ref d)) |
1440             (&ty::TyRef(_, ref s), &ty::TyRawPtr(ref d)) |
1441             (&ty::TyRawPtr(ref s), &ty::TyRawPtr(ref d)) => {
1442                 self.unsize_into_ptr(src, src_layout.ty, dst, dst_layout.ty, s.ty, d.ty)
1443             }
1444             (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => {
1445                 assert_eq!(def_a, def_b);
1446                 if def_a.is_box() || def_b.is_box() {
1447                     if !def_a.is_box() || !def_b.is_box() {
1448                         bug!("invalid unsizing between {:?} -> {:?}", src_layout, dst_layout);
1449                     }
1450                     return self.unsize_into_ptr(
1451                         src,
1452                         src_layout.ty,
1453                         dst,
1454                         dst_layout.ty,
1455                         src_layout.ty.boxed_ty(),
1456                         dst_layout.ty.boxed_ty(),
1457                     );
1458                 }
1459
1460                 // unsizing of generic struct with pointer fields
1461                 // Example: `Arc<T>` -> `Arc<Trait>`
1462                 // here we need to increase the size of every &T thin ptr field to a fat ptr
1463                 for i in 0..src_layout.fields.count() {
1464                     let (dst_f_place, dst_field) =
1465                         self.place_field(dst, mir::Field::new(i), dst_layout)?;
1466                     if dst_field.is_zst() {
1467                         continue;
1468                     }
1469                     let (src_f_value, src_field) = match src {
1470                         Value::ByRef(ptr, align) => {
1471                             let src_place = Place::from_primval_ptr(ptr, align);
1472                             let (src_f_place, src_field) =
1473                                 self.place_field(src_place, mir::Field::new(i), src_layout)?;
1474                             (self.read_place(src_f_place)?, src_field)
1475                         }
1476                         Value::ByVal(_) | Value::ByValPair(..) => {
1477                             let src_field = src_layout.field(&self, i)?;
1478                             assert_eq!(src_layout.fields.offset(i).bytes(), 0);
1479                             assert_eq!(src_field.size, src_layout.size);
1480                             (src, src_field)
1481                         }
1482                     };
1483                     if src_field.ty == dst_field.ty {
1484                         self.write_value(ValTy {
1485                             value: src_f_value,
1486                             ty: src_field.ty,
1487                         }, dst_f_place)?;
1488                     } else {
1489                         self.unsize_into(src_f_value, src_field, dst_f_place, dst_field)?;
1490                     }
1491                 }
1492                 Ok(())
1493             }
1494             _ => {
1495                 bug!(
1496                     "unsize_into: invalid conversion: {:?} -> {:?}",
1497                     src_layout,
1498                     dst_layout
1499                 )
1500             }
1501         }
1502     }
1503
1504     pub fn dump_local(&self, place: Place) {
1505         // Debug output
1506         match place {
1507             Place::Local { frame, local } => {
1508                 let mut allocs = Vec::new();
1509                 let mut msg = format!("{:?}", local);
1510                 if frame != self.cur_frame() {
1511                     write!(msg, " ({} frames up)", self.cur_frame() - frame).unwrap();
1512                 }
1513                 write!(msg, ":").unwrap();
1514
1515                 match self.stack[frame].get_local(local) {
1516                     Err(err) => {
1517                         if let EvalErrorKind::DeadLocal = err.kind {
1518                             write!(msg, " is dead").unwrap();
1519                         } else {
1520                             panic!("Failed to access local: {:?}", err);
1521                         }
1522                     }
1523                     Ok(Value::ByRef(ptr, align)) => {
1524                         match ptr.into_inner_primval() {
1525                             PrimVal::Ptr(ptr) => {
1526                                 write!(msg, " by align({}) ref:", align.abi()).unwrap();
1527                                 allocs.push(ptr.alloc_id);
1528                             }
1529                             ptr => write!(msg, " integral by ref: {:?}", ptr).unwrap(),
1530                         }
1531                     }
1532                     Ok(Value::ByVal(val)) => {
1533                         write!(msg, " {:?}", val).unwrap();
1534                         if let PrimVal::Ptr(ptr) = val {
1535                             allocs.push(ptr.alloc_id);
1536                         }
1537                     }
1538                     Ok(Value::ByValPair(val1, val2)) => {
1539                         write!(msg, " ({:?}, {:?})", val1, val2).unwrap();
1540                         if let PrimVal::Ptr(ptr) = val1 {
1541                             allocs.push(ptr.alloc_id);
1542                         }
1543                         if let PrimVal::Ptr(ptr) = val2 {
1544                             allocs.push(ptr.alloc_id);
1545                         }
1546                     }
1547                 }
1548
1549                 trace!("{}", msg);
1550                 self.memory.dump_allocs(allocs);
1551             }
1552             Place::Ptr { ptr, align, .. } => {
1553                 match ptr.into_inner_primval() {
1554                     PrimVal::Ptr(ptr) => {
1555                         trace!("by align({}) ref:", align.abi());
1556                         self.memory.dump_alloc(ptr.alloc_id);
1557                     }
1558                     ptr => trace!(" integral by ref: {:?}", ptr),
1559                 }
1560             }
1561         }
1562     }
1563
1564     /// Convenience function to ensure correct usage of locals
1565     pub fn modify_local<F>(&mut self, frame: usize, local: mir::Local, f: F) -> EvalResult<'tcx>
1566     where
1567         F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
1568     {
1569         let val = self.stack[frame].get_local(local)?;
1570         let new_val = f(self, val)?;
1571         self.stack[frame].set_local(local, new_val)?;
1572         // FIXME(solson): Run this when setting to Undef? (See previous version of this code.)
1573         // if let Value::ByRef(ptr) = self.stack[frame].get_local(local) {
1574         //     self.memory.deallocate(ptr)?;
1575         // }
1576         Ok(())
1577     }
1578
1579     pub fn generate_stacktrace(&self, explicit_span: Option<Span>) -> (Vec<FrameInfo>, Span) {
1580         let mut last_span = None;
1581         let mut frames = Vec::new();
1582         // skip 1 because the last frame is just the environment of the constant
1583         for &Frame { instance, span, .. } in self.stack().iter().skip(1).rev() {
1584             // make sure we don't emit frames that are duplicates of the previous
1585             if explicit_span == Some(span) {
1586                 last_span = Some(span);
1587                 continue;
1588             }
1589             if let Some(last) = last_span {
1590                 if last == span {
1591                     continue;
1592                 }
1593             } else {
1594                 last_span = Some(span);
1595             }
1596             let location = if self.tcx.def_key(instance.def_id()).disambiguated_data.data == DefPathData::ClosureExpr {
1597                 "closure".to_owned()
1598             } else {
1599                 instance.to_string()
1600             };
1601             frames.push(FrameInfo { span, location });
1602         }
1603         trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span);
1604         (frames, self.tcx.span)
1605     }
1606
1607     pub fn report(&self, e: &mut EvalError, as_err: bool, explicit_span: Option<Span>) {
1608         match e.kind {
1609             EvalErrorKind::Layout(_) |
1610             EvalErrorKind::TypeckError => return,
1611             _ => {},
1612         }
1613         if let Some(ref mut backtrace) = e.backtrace {
1614             let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
1615             backtrace.resolve();
1616             write!(trace_text, "backtrace frames: {}\n", backtrace.frames().len()).unwrap();
1617             'frames: for (i, frame) in backtrace.frames().iter().enumerate() {
1618                 if frame.symbols().is_empty() {
1619                     write!(trace_text, "{}: no symbols\n", i).unwrap();
1620                 }
1621                 for symbol in frame.symbols() {
1622                     write!(trace_text, "{}: ", i).unwrap();
1623                     if let Some(name) = symbol.name() {
1624                         write!(trace_text, "{}\n", name).unwrap();
1625                     } else {
1626                         write!(trace_text, "<unknown>\n").unwrap();
1627                     }
1628                     write!(trace_text, "\tat ").unwrap();
1629                     if let Some(file_path) = symbol.filename() {
1630                         write!(trace_text, "{}", file_path.display()).unwrap();
1631                     } else {
1632                         write!(trace_text, "<unknown_file>").unwrap();
1633                     }
1634                     if let Some(line) = symbol.lineno() {
1635                         write!(trace_text, ":{}\n", line).unwrap();
1636                     } else {
1637                         write!(trace_text, "\n").unwrap();
1638                     }
1639                 }
1640             }
1641             error!("{}", trace_text);
1642         }
1643         if let Some(frame) = self.stack().last() {
1644             let block = &frame.mir.basic_blocks()[frame.block];
1645             let span = explicit_span.unwrap_or_else(|| if frame.stmt < block.statements.len() {
1646                 block.statements[frame.stmt].source_info.span
1647             } else {
1648                 block.terminator().source_info.span
1649             });
1650             trace!("reporting const eval failure at {:?}", span);
1651             let mut err = if as_err {
1652                 ::rustc::middle::const_val::struct_error(*self.tcx, span, "constant evaluation error")
1653             } else {
1654                 let node_id = self
1655                     .stack()
1656                     .iter()
1657                     .rev()
1658                     .filter_map(|frame| self.tcx.hir.as_local_node_id(frame.instance.def_id()))
1659                     .next()
1660                     .expect("some part of a failing const eval must be local");
1661                 self.tcx.struct_span_lint_node(
1662                     ::rustc::lint::builtin::CONST_ERR,
1663                     node_id,
1664                     span,
1665                     "constant evaluation error",
1666                 )
1667             };
1668             let (frames, span) = self.generate_stacktrace(explicit_span);
1669             err.span_label(span, e.to_string());
1670             for FrameInfo { span, location } in frames {
1671                 err.span_note(span, &format!("inside call to `{}`", location));
1672             }
1673             err.emit();
1674         } else {
1675             self.tcx.sess.err(&e.to_string());
1676         }
1677     }
1678
1679     pub fn sign_extend(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
1680         let layout = self.layout_of(ty)?;
1681         let size = layout.size.bits();
1682         assert!(layout.abi.is_signed());
1683         // sign extend
1684         let amt = 128 - size;
1685         // shift the unsigned value to the left
1686         // and back to the right as signed (essentially fills with FF on the left)
1687         Ok((((value << amt) as i128) >> amt) as u128)
1688     }
1689
1690     pub fn truncate(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
1691         let size = self.layout_of(ty)?.size.bits();
1692         let amt = 128 - size;
1693         // truncate (shift left to drop out leftover values, shift right to fill with zeroes)
1694         Ok((value << amt) >> amt)
1695     }
1696 }
1697
1698 impl<'mir, 'tcx> Frame<'mir, 'tcx> {
1699     pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> {
1700         // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
1701         self.locals[local.index() - 1].ok_or(EvalErrorKind::DeadLocal.into())
1702     }
1703
1704     fn set_local(&mut self, local: mir::Local, value: Value) -> EvalResult<'tcx> {
1705         // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
1706         match self.locals[local.index() - 1] {
1707             None => err!(DeadLocal),
1708             Some(ref mut local) => {
1709                 *local = value;
1710                 Ok(())
1711             }
1712         }
1713     }
1714
1715     pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, Option<Value>> {
1716         trace!("{:?} is now live", local);
1717
1718         let old = self.locals[local.index() - 1];
1719         self.locals[local.index() - 1] = Some(Value::ByVal(PrimVal::Undef)); // StorageLive *always* kills the value that's currently stored
1720         return Ok(old);
1721     }
1722
1723     /// Returns the old value of the local
1724     pub fn storage_dead(&mut self, local: mir::Local) -> EvalResult<'tcx, Option<Value>> {
1725         trace!("{:?} is now dead", local);
1726
1727         let old = self.locals[local.index() - 1];
1728         self.locals[local.index() - 1] = None;
1729         return Ok(old);
1730     }
1731 }