]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/eval_context.rs
Auto merge of #52712 - oli-obk:const_eval_cleanups, r=RalfJung
[rust.git] / src / librustc_mir / interpret / eval_context.rs
1 use std::fmt::Write;
2 use std::hash::{Hash, Hasher};
3 use std::mem;
4
5 use rustc::hir::def_id::DefId;
6 use rustc::hir::def::Def;
7 use rustc::hir::map::definitions::DefPathData;
8 use rustc::mir;
9 use rustc::ty::layout::{self, Size, Align, HasDataLayout, IntegerExt, LayoutOf, TyLayout, Primitive};
10 use rustc::ty::subst::{Subst, Substs};
11 use rustc::ty::{self, Ty, TyCtxt, TypeAndMut};
12 use rustc::ty::query::TyCtxtAt;
13 use rustc_data_structures::fx::{FxHashSet, FxHasher};
14 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
15 use rustc::mir::interpret::{
16     GlobalId, Value, Scalar, FrameInfo, AllocType,
17     EvalResult, EvalErrorKind, Pointer, ConstValue,
18     ScalarMaybeUndef,
19 };
20
21 use syntax::codemap::{self, Span};
22 use syntax::ast::Mutability;
23
24 use super::{Place, PlaceExtra, Memory,
25             HasMemory, MemoryKind,
26             Machine};
27
28 macro_rules! validation_failure{
29     ($what:expr, $where:expr, $details:expr) => {{
30         let where_ = if $where.is_empty() {
31             String::new()
32         } else {
33             format!(" at {}", $where)
34         };
35         err!(ValidationFailure(format!(
36             "encountered {}{}, but expected {}",
37             $what, where_, $details,
38         )))
39     }};
40     ($what:expr, $where:expr) => {{
41         let where_ = if $where.is_empty() {
42             String::new()
43         } else {
44             format!(" at {}", $where)
45         };
46         err!(ValidationFailure(format!(
47             "encountered {}{}",
48             $what, where_,
49         )))
50     }};
51 }
52
53 pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
54     /// Stores the `Machine` instance.
55     pub machine: M,
56
57     /// The results of the type checker, from rustc.
58     pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
59
60     /// Bounds in scope for polymorphic evaluations.
61     pub param_env: ty::ParamEnv<'tcx>,
62
63     /// The virtual memory system.
64     pub memory: Memory<'a, 'mir, 'tcx, M>,
65
66     /// The virtual call stack.
67     pub(crate) stack: Vec<Frame<'mir, 'tcx>>,
68
69     /// The maximum number of stack frames allowed
70     pub(crate) stack_limit: usize,
71
72     /// When this value is negative, it indicates the number of interpreter
73     /// steps *until* the loop detector is enabled. When it is positive, it is
74     /// the number of steps after the detector has been enabled modulo the loop
75     /// detector period.
76     pub(crate) steps_since_detector_enabled: isize,
77
78     pub(crate) loop_detector: InfiniteLoopDetector<'a, 'mir, 'tcx, M>,
79 }
80
81 /// A stack frame.
82 #[derive(Clone)]
83 pub struct Frame<'mir, 'tcx: 'mir> {
84     ////////////////////////////////////////////////////////////////////////////////
85     // Function and callsite information
86     ////////////////////////////////////////////////////////////////////////////////
87     /// The MIR for the function called on this frame.
88     pub mir: &'mir mir::Mir<'tcx>,
89
90     /// The def_id and substs of the current function
91     pub instance: ty::Instance<'tcx>,
92
93     /// The span of the call site.
94     pub span: codemap::Span,
95
96     ////////////////////////////////////////////////////////////////////////////////
97     // Return place and locals
98     ////////////////////////////////////////////////////////////////////////////////
99     /// The block to return to when returning from the current stack frame
100     pub return_to_block: StackPopCleanup,
101
102     /// The location where the result of the current stack frame should be written to.
103     pub return_place: Place,
104
105     /// The list of locals for this stack frame, stored in order as
106     /// `[return_ptr, arguments..., variables..., temporaries...]`. The locals are stored as `Option<Value>`s.
107     /// `None` represents a local that is currently dead, while a live local
108     /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
109     pub locals: IndexVec<mir::Local, LocalValue>,
110
111     ////////////////////////////////////////////////////////////////////////////////
112     // Current position within the function
113     ////////////////////////////////////////////////////////////////////////////////
114     /// The block that is currently executed (or will be executed after the above call stacks
115     /// return).
116     pub block: mir::BasicBlock,
117
118     /// The index of the currently evaluated statement.
119     pub stmt: usize,
120 }
121
122 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
123 pub enum LocalValue {
124     Dead,
125     Live(Value),
126 }
127
128 impl LocalValue {
129     pub fn access(self) -> EvalResult<'static, Value> {
130         match self {
131             LocalValue::Dead => err!(DeadLocal),
132             LocalValue::Live(val) => Ok(val),
133         }
134     }
135 }
136
137 impl<'mir, 'tcx: 'mir> Eq for Frame<'mir, 'tcx> {}
138
139 impl<'mir, 'tcx: 'mir> PartialEq for Frame<'mir, 'tcx> {
140     fn eq(&self, other: &Self) -> bool {
141         let Frame {
142             mir: _,
143             instance,
144             span: _,
145             return_to_block,
146             return_place,
147             locals,
148             block,
149             stmt,
150         } = self;
151
152         // Some of these are constant during evaluation, but are included
153         // anyways for correctness.
154         *instance == other.instance
155             && *return_to_block == other.return_to_block
156             && *return_place == other.return_place
157             && *locals == other.locals
158             && *block == other.block
159             && *stmt == other.stmt
160     }
161 }
162
163 impl<'mir, 'tcx: 'mir> Hash for Frame<'mir, 'tcx> {
164     fn hash<H: Hasher>(&self, state: &mut H) {
165         let Frame {
166             mir: _,
167             instance,
168             span: _,
169             return_to_block,
170             return_place,
171             locals,
172             block,
173             stmt,
174         } = self;
175
176         instance.hash(state);
177         return_to_block.hash(state);
178         return_place.hash(state);
179         locals.hash(state);
180         block.hash(state);
181         stmt.hash(state);
182     }
183 }
184
185 /// The virtual machine state during const-evaluation at a given point in time.
186 type EvalSnapshot<'a, 'mir, 'tcx, M>
187     = (M, Vec<Frame<'mir, 'tcx>>, Memory<'a, 'mir, 'tcx, M>);
188
189 pub(crate) struct InfiniteLoopDetector<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
190     /// The set of all `EvalSnapshot` *hashes* observed by this detector.
191     ///
192     /// When a collision occurs in this table, we store the full snapshot in
193     /// `snapshots`.
194     hashes: FxHashSet<u64>,
195
196     /// The set of all `EvalSnapshot`s observed by this detector.
197     ///
198     /// An `EvalSnapshot` will only be fully cloned once it has caused a
199     /// collision in `hashes`. As a result, the detector must observe at least
200     /// *two* full cycles of an infinite loop before it triggers.
201     snapshots: FxHashSet<EvalSnapshot<'a, 'mir, 'tcx, M>>,
202 }
203
204 impl<'a, 'mir, 'tcx, M> Default for InfiniteLoopDetector<'a, 'mir, 'tcx, M>
205     where M: Machine<'mir, 'tcx>,
206           'tcx: 'a + 'mir,
207 {
208     fn default() -> Self {
209         InfiniteLoopDetector {
210             hashes: FxHashSet::default(),
211             snapshots: FxHashSet::default(),
212         }
213     }
214 }
215
216 impl<'a, 'mir, 'tcx, M> InfiniteLoopDetector<'a, 'mir, 'tcx, M>
217     where M: Machine<'mir, 'tcx>,
218           'tcx: 'a + 'mir,
219 {
220     /// Returns `true` if the loop detector has not yet observed a snapshot.
221     pub fn is_empty(&self) -> bool {
222         self.hashes.is_empty()
223     }
224
225     pub fn observe_and_analyze(
226         &mut self,
227         machine: &M,
228         stack: &Vec<Frame<'mir, 'tcx>>,
229         memory: &Memory<'a, 'mir, 'tcx, M>,
230     ) -> EvalResult<'tcx, ()> {
231         let snapshot = (machine, stack, memory);
232
233         let mut fx = FxHasher::default();
234         snapshot.hash(&mut fx);
235         let hash = fx.finish();
236
237         if self.hashes.insert(hash) {
238             // No collision
239             return Ok(())
240         }
241
242         if self.snapshots.insert((machine.clone(), stack.clone(), memory.clone())) {
243             // Spurious collision or first cycle
244             return Ok(())
245         }
246
247         // Second cycle
248         Err(EvalErrorKind::InfiniteLoop.into())
249     }
250 }
251
252 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
253 pub enum StackPopCleanup {
254     /// The stackframe existed to compute the initial value of a static/constant, make sure it
255     /// isn't modifyable afterwards in case of constants.
256     /// In case of `static mut`, mark the memory to ensure it's never marked as immutable through
257     /// references or deallocated
258     MarkStatic(Mutability),
259     /// A regular stackframe added due to a function call will need to get forwarded to the next
260     /// block
261     Goto(mir::BasicBlock),
262     /// The main function and diverging functions have nowhere to return to
263     None,
264 }
265
266 #[derive(Copy, Clone, Debug)]
267 pub struct TyAndPacked<'tcx> {
268     pub ty: Ty<'tcx>,
269     pub packed: bool,
270 }
271
272 #[derive(Copy, Clone, Debug)]
273 pub struct ValTy<'tcx> {
274     pub value: Value,
275     pub ty: Ty<'tcx>,
276 }
277
278 impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
279     type Target = Value;
280     fn deref(&self) -> &Value {
281         &self.value
282     }
283 }
284
285 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for &'a EvalContext<'a, 'mir, 'tcx, M> {
286     #[inline]
287     fn data_layout(&self) -> &layout::TargetDataLayout {
288         &self.tcx.data_layout
289     }
290 }
291
292 impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout
293     for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
294     #[inline]
295     fn data_layout(&self) -> &layout::TargetDataLayout {
296         &self.tcx.data_layout
297     }
298 }
299
300 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'mir, 'tcx, M> {
301     #[inline]
302     fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
303         *self.tcx
304     }
305 }
306
307 impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx>
308     for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
309     #[inline]
310     fn tcx<'d>(&'d self) -> TyCtxt<'d, 'tcx, 'tcx> {
311         *self.tcx
312     }
313 }
314
315 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for &'a EvalContext<'a, 'mir, 'tcx, M> {
316     type Ty = Ty<'tcx>;
317     type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
318
319     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
320         self.tcx.layout_of(self.param_env.and(ty))
321             .map_err(|layout| EvalErrorKind::Layout(layout).into())
322     }
323 }
324
325 impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf
326     for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
327     type Ty = Ty<'tcx>;
328     type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
329
330     #[inline]
331     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
332         (&**self).layout_of(ty)
333     }
334 }
335
336 const STEPS_UNTIL_DETECTOR_ENABLED: isize = 1_000_000;
337
338 impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
339     pub fn new(
340         tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
341         param_env: ty::ParamEnv<'tcx>,
342         machine: M,
343         memory_data: M::MemoryData,
344     ) -> Self {
345         EvalContext {
346             machine,
347             tcx,
348             param_env,
349             memory: Memory::new(tcx, memory_data),
350             stack: Vec::new(),
351             stack_limit: tcx.sess.const_eval_stack_frame_limit,
352             loop_detector: Default::default(),
353             steps_since_detector_enabled: -STEPS_UNTIL_DETECTOR_ENABLED,
354         }
355     }
356
357     pub(crate) fn with_fresh_body<F: FnOnce(&mut Self) -> R, R>(&mut self, f: F) -> R {
358         let stack = mem::replace(&mut self.stack, Vec::new());
359         let steps = mem::replace(&mut self.steps_since_detector_enabled, -STEPS_UNTIL_DETECTOR_ENABLED);
360         let r = f(self);
361         self.stack = stack;
362         self.steps_since_detector_enabled = steps;
363         r
364     }
365
366     pub fn alloc_ptr(&mut self, layout: TyLayout<'tcx>) -> EvalResult<'tcx, Pointer> {
367         assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
368
369         self.memory.allocate(layout.size, layout.align, MemoryKind::Stack)
370     }
371
372     pub fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
373         &self.memory
374     }
375
376     pub fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
377         &mut self.memory
378     }
379
380     pub fn stack(&self) -> &[Frame<'mir, 'tcx>] {
381         &self.stack
382     }
383
384     #[inline]
385     pub fn cur_frame(&self) -> usize {
386         assert!(self.stack.len() > 0);
387         self.stack.len() - 1
388     }
389
390     pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
391         let ptr = self.memory.allocate_bytes(s.as_bytes());
392         Ok(Scalar::Ptr(ptr).to_value_with_len(s.len() as u64, self.tcx.tcx))
393     }
394
395     pub fn const_to_value(
396         &mut self,
397         val: ConstValue<'tcx>,
398     ) -> EvalResult<'tcx, Value> {
399         match val {
400             ConstValue::Unevaluated(def_id, substs) => {
401                 let instance = self.resolve(def_id, substs)?;
402                 self.read_global_as_value(GlobalId {
403                     instance,
404                     promoted: None,
405                 })
406             }
407             ConstValue::ByRef(alloc, offset) => {
408                 // FIXME: Allocate new AllocId for all constants inside
409                 let id = self.memory.allocate_value(alloc.clone(), MemoryKind::Stack)?;
410                 Ok(Value::ByRef(Pointer::new(id, offset).into(), alloc.align))
411             },
412             ConstValue::ScalarPair(a, b) => Ok(Value::ScalarPair(a.into(), b.into())),
413             ConstValue::Scalar(val) => Ok(Value::Scalar(val.into())),
414         }
415     }
416
417     pub(super) fn resolve(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, ty::Instance<'tcx>> {
418         trace!("resolve: {:?}, {:#?}", def_id, substs);
419         trace!("substs: {:#?}", self.substs());
420         trace!("param_env: {:#?}", self.param_env);
421         let substs = self.tcx.subst_and_normalize_erasing_regions(
422             self.substs(),
423             self.param_env,
424             &substs,
425         );
426         ty::Instance::resolve(
427             *self.tcx,
428             self.param_env,
429             def_id,
430             substs,
431         ).ok_or_else(|| EvalErrorKind::TooGeneric.into())
432     }
433
434     pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
435         ty.is_sized(self.tcx, self.param_env)
436     }
437
438     pub fn load_mir(
439         &self,
440         instance: ty::InstanceDef<'tcx>,
441     ) -> EvalResult<'tcx, &'tcx mir::Mir<'tcx>> {
442         // do not continue if typeck errors occurred (can only occur in local crate)
443         let did = instance.def_id();
444         if did.is_local() && self.tcx.has_typeck_tables(did) && self.tcx.typeck_tables_of(did).tainted_by_errors {
445             return err!(TypeckError);
446         }
447         trace!("load mir {:?}", instance);
448         match instance {
449             ty::InstanceDef::Item(def_id) => {
450                 self.tcx.maybe_optimized_mir(def_id).ok_or_else(||
451                     EvalErrorKind::NoMirFor(self.tcx.item_path_str(def_id)).into()
452                 )
453             }
454             _ => Ok(self.tcx.instance_mir(instance)),
455         }
456     }
457
458     pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
459         // miri doesn't care about lifetimes, and will choke on some crazy ones
460         // let's simply get rid of them
461         let substituted = ty.subst(*self.tcx, substs);
462         self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted)
463     }
464
465     /// Return the size and aligment of the value at the given type.
466     /// Note that the value does not matter if the type is sized. For unsized types,
467     /// the value has to be a fat pointer, and we only care about the "extra" data in it.
468     pub fn size_and_align_of_dst(
469         &self,
470         ty: Ty<'tcx>,
471         value: Value,
472     ) -> EvalResult<'tcx, (Size, Align)> {
473         let layout = self.layout_of(ty)?;
474         if !layout.is_unsized() {
475             Ok(layout.size_and_align())
476         } else {
477             match ty.sty {
478                 ty::TyAdt(..) | ty::TyTuple(..) => {
479                     // First get the size of all statically known fields.
480                     // Don't use type_of::sizing_type_of because that expects t to be sized,
481                     // and it also rounds up to alignment, which we want to avoid,
482                     // as the unsized field's alignment could be smaller.
483                     assert!(!ty.is_simd());
484                     debug!("DST {} layout: {:?}", ty, layout);
485
486                     let sized_size = layout.fields.offset(layout.fields.count() - 1);
487                     let sized_align = layout.align;
488                     debug!(
489                         "DST {} statically sized prefix size: {:?} align: {:?}",
490                         ty,
491                         sized_size,
492                         sized_align
493                     );
494
495                     // Recurse to get the size of the dynamically sized field (must be
496                     // the last field).
497                     let field_ty = layout.field(self, layout.fields.count() - 1)?.ty;
498                     let (unsized_size, unsized_align) =
499                         self.size_and_align_of_dst(field_ty, value)?;
500
501                     // FIXME (#26403, #27023): We should be adding padding
502                     // to `sized_size` (to accommodate the `unsized_align`
503                     // required of the unsized field that follows) before
504                     // summing it with `sized_size`. (Note that since #26403
505                     // is unfixed, we do not yet add the necessary padding
506                     // here. But this is where the add would go.)
507
508                     // Return the sum of sizes and max of aligns.
509                     let size = sized_size + unsized_size;
510
511                     // Choose max of two known alignments (combined value must
512                     // be aligned according to more restrictive of the two).
513                     let align = sized_align.max(unsized_align);
514
515                     // Issue #27023: must add any necessary padding to `size`
516                     // (to make it a multiple of `align`) before returning it.
517                     //
518                     // Namely, the returned size should be, in C notation:
519                     //
520                     //   `size + ((size & (align-1)) ? align : 0)`
521                     //
522                     // emulated via the semi-standard fast bit trick:
523                     //
524                     //   `(size + (align-1)) & -align`
525
526                     Ok((size.abi_align(align), align))
527                 }
528                 ty::TyDynamic(..) => {
529                     let (_, vtable) = self.into_ptr_vtable_pair(value)?;
530                     // the second entry in the vtable is the dynamic size of the object.
531                     self.read_size_and_align_from_vtable(vtable)
532                 }
533
534                 ty::TySlice(_) | ty::TyStr => {
535                     let (elem_size, align) = layout.field(self, 0)?.size_and_align();
536                     let (_, len) = self.into_slice(value)?;
537                     Ok((elem_size * len, align))
538                 }
539
540                 _ => bug!("size_of_val::<{:?}>", ty),
541             }
542         }
543     }
544
545     pub fn push_stack_frame(
546         &mut self,
547         instance: ty::Instance<'tcx>,
548         span: codemap::Span,
549         mir: &'mir mir::Mir<'tcx>,
550         return_place: Place,
551         return_to_block: StackPopCleanup,
552     ) -> EvalResult<'tcx> {
553         ::log_settings::settings().indentation += 1;
554
555         // first push a stack frame so we have access to the local substs
556         self.stack.push(Frame {
557             mir,
558             block: mir::START_BLOCK,
559             return_to_block,
560             return_place,
561             // empty local array, we fill it in below, after we are inside the stack frame and
562             // all methods actually know about the frame
563             locals: IndexVec::new(),
564             span,
565             instance,
566             stmt: 0,
567         });
568
569         // don't allocate at all for trivial constants
570         if mir.local_decls.len() > 1 {
571             let mut locals = IndexVec::from_elem(LocalValue::Dead, &mir.local_decls);
572             for (local, decl) in locals.iter_mut().zip(mir.local_decls.iter()) {
573                 *local = LocalValue::Live(self.init_value(decl.ty)?);
574             }
575             match self.tcx.describe_def(instance.def_id()) {
576                 // statics and constants don't have `Storage*` statements, no need to look for them
577                 Some(Def::Static(..)) | Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {},
578                 _ => {
579                     trace!("push_stack_frame: {:?}: num_bbs: {}", span, mir.basic_blocks().len());
580                     for block in mir.basic_blocks() {
581                         for stmt in block.statements.iter() {
582                             use rustc::mir::StatementKind::{StorageDead, StorageLive};
583                             match stmt.kind {
584                                 StorageLive(local) |
585                                 StorageDead(local) => locals[local] = LocalValue::Dead,
586                                 _ => {}
587                             }
588                         }
589                     }
590                 },
591             }
592             self.frame_mut().locals = locals;
593         }
594
595         self.memory.cur_frame = self.cur_frame();
596
597         if self.stack.len() > self.stack_limit {
598             err!(StackFrameLimitReached)
599         } else {
600             Ok(())
601         }
602     }
603
604     pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
605         ::log_settings::settings().indentation -= 1;
606         M::end_region(self, None)?;
607         let frame = self.stack.pop().expect(
608             "tried to pop a stack frame, but there were none",
609         );
610         if !self.stack.is_empty() {
611             // TODO: Is this the correct time to start considering these accesses as originating from the returned-to stack frame?
612             self.memory.cur_frame = self.cur_frame();
613         }
614         match frame.return_to_block {
615             StackPopCleanup::MarkStatic(mutable) => {
616                 if let Place::Ptr { ptr, .. } = frame.return_place {
617                     // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
618                     self.memory.mark_static_initialized(
619                         ptr.unwrap_or_err()?.to_ptr()?.alloc_id,
620                         mutable,
621                     )?
622                 } else {
623                     bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_place);
624                 }
625             }
626             StackPopCleanup::Goto(target) => self.goto_block(target),
627             StackPopCleanup::None => {}
628         }
629         // deallocate all locals that are backed by an allocation
630         for local in frame.locals {
631             self.deallocate_local(local)?;
632         }
633
634         Ok(())
635     }
636
637     pub fn deallocate_local(&mut self, local: LocalValue) -> EvalResult<'tcx> {
638         // FIXME: should we tell the user that there was a local which was never written to?
639         if let LocalValue::Live(Value::ByRef(ptr, _align)) = local {
640             trace!("deallocating local");
641             let ptr = ptr.to_ptr()?;
642             self.memory.dump_alloc(ptr.alloc_id);
643             self.memory.deallocate_local(ptr)?;
644         };
645         Ok(())
646     }
647
648     /// Evaluate an assignment statement.
649     ///
650     /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
651     /// type writes its results directly into the memory specified by the place.
652     pub(super) fn eval_rvalue_into_place(
653         &mut self,
654         rvalue: &mir::Rvalue<'tcx>,
655         place: &mir::Place<'tcx>,
656     ) -> EvalResult<'tcx> {
657         let dest = self.eval_place(place)?;
658         let dest_ty = self.place_ty(place);
659         let dest_layout = self.layout_of(dest_ty)?;
660
661         use rustc::mir::Rvalue::*;
662         match *rvalue {
663             Use(ref operand) => {
664                 let value = self.eval_operand(operand)?.value;
665                 let valty = ValTy {
666                     value,
667                     ty: dest_ty,
668                 };
669                 self.write_value(valty, dest)?;
670             }
671
672             BinaryOp(bin_op, ref left, ref right) => {
673                 let left = self.eval_operand(left)?;
674                 let right = self.eval_operand(right)?;
675                 self.intrinsic_overflowing(
676                     bin_op,
677                     left,
678                     right,
679                     dest,
680                     dest_ty,
681                 )?;
682             }
683
684             CheckedBinaryOp(bin_op, ref left, ref right) => {
685                 let left = self.eval_operand(left)?;
686                 let right = self.eval_operand(right)?;
687                 self.intrinsic_with_overflow(
688                     bin_op,
689                     left,
690                     right,
691                     dest,
692                     dest_ty,
693                 )?;
694             }
695
696             UnaryOp(un_op, ref operand) => {
697                 let val = self.eval_operand_to_scalar(operand)?;
698                 let val = self.unary_op(un_op, val, dest_layout)?;
699                 self.write_scalar(
700                     dest,
701                     val,
702                     dest_ty,
703                 )?;
704             }
705
706             Aggregate(ref kind, ref operands) => {
707                 let (dest, active_field_index) = match **kind {
708                     mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
709                         self.write_discriminant_value(dest_ty, dest, variant_index)?;
710                         if adt_def.is_enum() {
711                             (self.place_downcast(dest, variant_index)?, active_field_index)
712                         } else {
713                             (dest, active_field_index)
714                         }
715                     }
716                     _ => (dest, None)
717                 };
718
719                 let layout = self.layout_of(dest_ty)?;
720                 for (i, operand) in operands.iter().enumerate() {
721                     let value = self.eval_operand(operand)?;
722                     // Ignore zero-sized fields.
723                     if !self.layout_of(value.ty)?.is_zst() {
724                         let field_index = active_field_index.unwrap_or(i);
725                         let (field_dest, _) = self.place_field(dest, mir::Field::new(field_index), layout)?;
726                         self.write_value(value, field_dest)?;
727                     }
728                 }
729             }
730
731             Repeat(ref operand, _) => {
732                 let (elem_ty, length) = match dest_ty.sty {
733                     ty::TyArray(elem_ty, n) => (elem_ty, n.unwrap_usize(self.tcx.tcx)),
734                     _ => {
735                         bug!(
736                             "tried to assign array-repeat to non-array type {:?}",
737                             dest_ty
738                         )
739                     }
740                 };
741                 let elem_size = self.layout_of(elem_ty)?.size;
742                 let value = self.eval_operand(operand)?.value;
743
744                 let (dest, dest_align) = self.force_allocation(dest)?.to_ptr_align();
745
746                 if length > 0 {
747                     let dest = dest.unwrap_or_err()?;
748                     //write the first value
749                     self.write_value_to_ptr(value, dest, dest_align, elem_ty)?;
750
751                     if length > 1 {
752                         let rest = dest.ptr_offset(elem_size * 1 as u64, &self)?;
753                         self.memory.copy_repeatedly(dest, dest_align, rest, dest_align, elem_size, length - 1, false)?;
754                     }
755                 }
756             }
757
758             Len(ref place) => {
759                 // FIXME(CTFE): don't allow computing the length of arrays in const eval
760                 let src = self.eval_place(place)?;
761                 let ty = self.place_ty(place);
762                 let (_, len) = src.elem_ty_and_len(ty, self.tcx.tcx);
763                 let size = self.memory.pointer_size().bytes() as u8;
764                 self.write_scalar(
765                     dest,
766                     Scalar::Bits {
767                         bits: len as u128,
768                         size,
769                     },
770                     dest_ty,
771                 )?;
772             }
773
774             Ref(_, _, ref place) => {
775                 let src = self.eval_place(place)?;
776                 // We ignore the alignment of the place here -- special handling for packed structs ends
777                 // at the `&` operator.
778                 let (ptr, _align, extra) = self.force_allocation(src)?.to_ptr_align_extra();
779
780                 let val = match extra {
781                     PlaceExtra::None => Value::Scalar(ptr),
782                     PlaceExtra::Length(len) => ptr.to_value_with_len(len, self.tcx.tcx),
783                     PlaceExtra::Vtable(vtable) => ptr.to_value_with_vtable(vtable),
784                     PlaceExtra::DowncastVariant(..) => {
785                         bug!("attempted to take a reference to an enum downcast place")
786                     }
787                 };
788                 let valty = ValTy {
789                     value: val,
790                     ty: dest_ty,
791                 };
792                 self.write_value(valty, dest)?;
793             }
794
795             NullaryOp(mir::NullOp::Box, ty) => {
796                 let ty = self.monomorphize(ty, self.substs());
797                 M::box_alloc(self, ty, dest)?;
798             }
799
800             NullaryOp(mir::NullOp::SizeOf, ty) => {
801                 let ty = self.monomorphize(ty, self.substs());
802                 let layout = self.layout_of(ty)?;
803                 assert!(!layout.is_unsized(),
804                         "SizeOf nullary MIR operator called for unsized type");
805                 let size = self.memory.pointer_size().bytes() as u8;
806                 self.write_scalar(
807                     dest,
808                     Scalar::Bits {
809                         bits: layout.size.bytes() as u128,
810                         size,
811                     },
812                     dest_ty,
813                 )?;
814             }
815
816             Cast(kind, ref operand, cast_ty) => {
817                 debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest_ty);
818                 let src = self.eval_operand(operand)?;
819                 self.cast(src, kind, dest_ty, dest)?;
820             }
821
822             Discriminant(ref place) => {
823                 let ty = self.place_ty(place);
824                 let layout = self.layout_of(ty)?;
825                 let place = self.eval_place(place)?;
826                 let discr_val = self.read_discriminant_value(place, layout)?;
827                 let size = self.layout_of(dest_ty).unwrap().size.bytes() as u8;
828                 self.write_scalar(dest, Scalar::Bits {
829                     bits: discr_val,
830                     size,
831                 }, dest_ty)?;
832             }
833         }
834
835         self.dump_local(dest);
836
837         Ok(())
838     }
839
840     pub(super) fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
841         match ty.sty {
842             ty::TyRawPtr(ty::TypeAndMut { ty, .. }) |
843             ty::TyRef(_, ty, _) => !self.type_is_sized(ty),
844             ty::TyAdt(def, _) if def.is_box() => !self.type_is_sized(ty.boxed_ty()),
845             _ => false,
846         }
847     }
848
849     pub(super) fn eval_operand_to_scalar(
850         &mut self,
851         op: &mir::Operand<'tcx>,
852     ) -> EvalResult<'tcx, Scalar> {
853         let valty = self.eval_operand(op)?;
854         self.value_to_scalar(valty)
855     }
856
857     pub(crate) fn operands_to_args(
858         &mut self,
859         ops: &[mir::Operand<'tcx>],
860     ) -> EvalResult<'tcx, Vec<ValTy<'tcx>>> {
861         ops.into_iter()
862             .map(|op| self.eval_operand(op))
863             .collect()
864     }
865
866     pub fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> {
867         use rustc::mir::Operand::*;
868         let ty = self.monomorphize(op.ty(self.mir(), *self.tcx), self.substs());
869         match *op {
870             // FIXME: do some more logic on `move` to invalidate the old location
871             Copy(ref place) |
872             Move(ref place) => {
873                 Ok(ValTy {
874                     value: self.eval_and_read_place(place)?,
875                     ty
876                 })
877             },
878
879             Constant(ref constant) => {
880                 let value = self.const_to_value(constant.literal.val)?;
881
882                 Ok(ValTy {
883                     value,
884                     ty,
885                 })
886             }
887         }
888     }
889
890     /// reads a tag and produces the corresponding variant index
891     pub fn read_discriminant_as_variant_index(
892         &self,
893         place: Place,
894         layout: TyLayout<'tcx>,
895     ) -> EvalResult<'tcx, usize> {
896         match layout.variants {
897             ty::layout::Variants::Single { index } => Ok(index),
898             ty::layout::Variants::Tagged { .. } => {
899                 let discr_val = self.read_discriminant_value(place, layout)?;
900                 layout
901                     .ty
902                     .ty_adt_def()
903                     .expect("tagged layout for non adt")
904                     .discriminants(self.tcx.tcx)
905                     .position(|var| var.val == discr_val)
906                     .ok_or_else(|| EvalErrorKind::InvalidDiscriminant.into())
907             }
908             ty::layout::Variants::NicheFilling { .. } => {
909                 let discr_val = self.read_discriminant_value(place, layout)?;
910                 assert_eq!(discr_val as usize as u128, discr_val);
911                 Ok(discr_val as usize)
912             },
913         }
914     }
915
916     pub fn read_discriminant_value(
917         &self,
918         place: Place,
919         layout: TyLayout<'tcx>,
920     ) -> EvalResult<'tcx, u128> {
921         trace!("read_discriminant_value {:#?}", layout);
922         if layout.abi == layout::Abi::Uninhabited {
923             return Ok(0);
924         }
925
926         match layout.variants {
927             layout::Variants::Single { index } => {
928                 let discr_val = layout.ty.ty_adt_def().map_or(
929                     index as u128,
930                     |def| def.discriminant_for_variant(*self.tcx, index).val);
931                 return Ok(discr_val);
932             }
933             layout::Variants::Tagged { .. } |
934             layout::Variants::NicheFilling { .. } => {},
935         }
936         let discr_place_val = self.read_place(place)?;
937         let (discr_val, discr) = self.read_field(discr_place_val, None, mir::Field::new(0), layout)?;
938         trace!("discr value: {:?}, {:?}", discr_val, discr);
939         let raw_discr = self.value_to_scalar(ValTy {
940             value: discr_val,
941             ty: discr.ty
942         })?;
943         let discr_val = match layout.variants {
944             layout::Variants::Single { .. } => bug!(),
945             // FIXME: should we catch invalid discriminants here?
946             layout::Variants::Tagged { .. } => {
947                 if discr.ty.is_signed() {
948                     let i = raw_discr.to_bits(discr.size)? as i128;
949                     // going from layout tag type to typeck discriminant type
950                     // requires first sign extending with the layout discriminant
951                     let shift = 128 - discr.size.bits();
952                     let sexted = (i << shift) >> shift;
953                     // and then zeroing with the typeck discriminant type
954                     let discr_ty = layout
955                         .ty
956                         .ty_adt_def().expect("tagged layout corresponds to adt")
957                         .repr
958                         .discr_type();
959                     let discr_ty = layout::Integer::from_attr(self.tcx.tcx, discr_ty);
960                     let shift = 128 - discr_ty.size().bits();
961                     let truncatee = sexted as u128;
962                     (truncatee << shift) >> shift
963                 } else {
964                     raw_discr.to_bits(discr.size)?
965                 }
966             },
967             layout::Variants::NicheFilling {
968                 dataful_variant,
969                 ref niche_variants,
970                 niche_start,
971                 ..
972             } => {
973                 let variants_start = *niche_variants.start() as u128;
974                 let variants_end = *niche_variants.end() as u128;
975                 match raw_discr {
976                     Scalar::Ptr(_) => {
977                         assert!(niche_start == 0);
978                         assert!(variants_start == variants_end);
979                         dataful_variant as u128
980                     },
981                     Scalar::Bits { bits: raw_discr, size } => {
982                         assert_eq!(size as u64, discr.size.bytes());
983                         let discr = raw_discr.wrapping_sub(niche_start)
984                             .wrapping_add(variants_start);
985                         if variants_start <= discr && discr <= variants_end {
986                             discr
987                         } else {
988                             dataful_variant as u128
989                         }
990                     },
991                 }
992             }
993         };
994
995         Ok(discr_val)
996     }
997
998
999     pub fn write_discriminant_value(
1000         &mut self,
1001         dest_ty: Ty<'tcx>,
1002         dest: Place,
1003         variant_index: usize,
1004     ) -> EvalResult<'tcx> {
1005         let layout = self.layout_of(dest_ty)?;
1006
1007         match layout.variants {
1008             layout::Variants::Single { index } => {
1009                 if index != variant_index {
1010                     // If the layout of an enum is `Single`, all
1011                     // other variants are necessarily uninhabited.
1012                     assert_eq!(layout.for_variant(&self, variant_index).abi,
1013                                layout::Abi::Uninhabited);
1014                 }
1015             }
1016             layout::Variants::Tagged { ref tag, .. } => {
1017                 let discr_val = dest_ty.ty_adt_def().unwrap()
1018                     .discriminant_for_variant(*self.tcx, variant_index)
1019                     .val;
1020
1021                 // raw discriminants for enums are isize or bigger during
1022                 // their computation, but the in-memory tag is the smallest possible
1023                 // representation
1024                 let size = tag.value.size(self.tcx.tcx);
1025                 let shift = 128 - size.bits();
1026                 let discr_val = (discr_val << shift) >> shift;
1027
1028                 let (discr_dest, tag) = self.place_field(dest, mir::Field::new(0), layout)?;
1029                 self.write_scalar(discr_dest, Scalar::Bits {
1030                     bits: discr_val,
1031                     size: size.bytes() as u8,
1032                 }, tag.ty)?;
1033             }
1034             layout::Variants::NicheFilling {
1035                 dataful_variant,
1036                 ref niche_variants,
1037                 niche_start,
1038                 ..
1039             } => {
1040                 if variant_index != dataful_variant {
1041                     let (niche_dest, niche) =
1042                         self.place_field(dest, mir::Field::new(0), layout)?;
1043                     let niche_value = ((variant_index - niche_variants.start()) as u128)
1044                         .wrapping_add(niche_start);
1045                     self.write_scalar(niche_dest, Scalar::Bits {
1046                         bits: niche_value,
1047                         size: niche.size.bytes() as u8,
1048                     }, niche.ty)?;
1049                 }
1050             }
1051         }
1052
1053         Ok(())
1054     }
1055
1056     pub fn read_global_as_value(&mut self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, Value> {
1057         let cv = self.const_eval(gid)?;
1058         self.const_to_value(cv.val)
1059     }
1060
1061     pub fn const_eval(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> {
1062         let param_env = if self.tcx.is_static(gid.instance.def_id()).is_some() {
1063             ty::ParamEnv::reveal_all()
1064         } else {
1065             self.param_env
1066         };
1067         self.tcx.const_eval(param_env.and(gid)).map_err(|err| EvalErrorKind::ReferencedConstant(err).into())
1068     }
1069
1070     pub fn allocate_place_for_value(
1071         &mut self,
1072         value: Value,
1073         layout: TyLayout<'tcx>,
1074         variant: Option<usize>,
1075     ) -> EvalResult<'tcx, Place> {
1076         let (ptr, align) = match value {
1077             Value::ByRef(ptr, align) => (ptr, align),
1078             Value::ScalarPair(..) | Value::Scalar(_) => {
1079                 let ptr = self.alloc_ptr(layout)?.into();
1080                 self.write_value_to_ptr(value, ptr, layout.align, layout.ty)?;
1081                 (ptr, layout.align)
1082             },
1083         };
1084         Ok(Place::Ptr {
1085             ptr: ptr.into(),
1086             align,
1087             extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant),
1088         })
1089     }
1090
1091     pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> {
1092         let new_place = match place {
1093             Place::Local { frame, local } => {
1094                 match self.stack[frame].locals[local].access()? {
1095                     Value::ByRef(ptr, align) => {
1096                         Place::Ptr {
1097                             ptr: ptr.into(),
1098                             align,
1099                             extra: PlaceExtra::None,
1100                         }
1101                     }
1102                     val => {
1103                         let ty = self.stack[frame].mir.local_decls[local].ty;
1104                         let ty = self.monomorphize(ty, self.stack[frame].instance.substs);
1105                         let layout = self.layout_of(ty)?;
1106                         let ptr = self.alloc_ptr(layout)?;
1107                         self.stack[frame].locals[local] =
1108                             LocalValue::Live(Value::ByRef(ptr.into(), layout.align)); // it stays live
1109
1110                         let place = Place::from_ptr(ptr, layout.align);
1111                         self.write_value(ValTy { value: val, ty }, place)?;
1112                         place
1113                     }
1114                 }
1115             }
1116             Place::Ptr { .. } => place,
1117         };
1118         Ok(new_place)
1119     }
1120
1121     /// ensures this Value is not a ByRef
1122     pub fn follow_by_ref_value(
1123         &self,
1124         value: Value,
1125         ty: Ty<'tcx>,
1126     ) -> EvalResult<'tcx, Value> {
1127         match value {
1128             Value::ByRef(ptr, align) => {
1129                 self.read_value(ptr, align, ty)
1130             }
1131             other => Ok(other),
1132         }
1133     }
1134
1135     pub fn value_to_scalar(
1136         &self,
1137         ValTy { value, ty } : ValTy<'tcx>,
1138     ) -> EvalResult<'tcx, Scalar> {
1139         match self.follow_by_ref_value(value, ty)? {
1140             Value::ByRef { .. } => bug!("follow_by_ref_value can't result in `ByRef`"),
1141
1142             Value::Scalar(scalar) => scalar.unwrap_or_err(),
1143
1144             Value::ScalarPair(..) => bug!("value_to_scalar can't work with fat pointers"),
1145         }
1146     }
1147
1148     pub fn write_ptr(&mut self, dest: Place, val: Scalar, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> {
1149         let valty = ValTy {
1150             value: val.to_value(),
1151             ty: dest_ty,
1152         };
1153         self.write_value(valty, dest)
1154     }
1155
1156     pub fn write_scalar(
1157         &mut self,
1158         dest: Place,
1159         val: impl Into<ScalarMaybeUndef>,
1160         dest_ty: Ty<'tcx>,
1161     ) -> EvalResult<'tcx> {
1162         let valty = ValTy {
1163             value: Value::Scalar(val.into()),
1164             ty: dest_ty,
1165         };
1166         self.write_value(valty, dest)
1167     }
1168
1169     pub fn write_value(
1170         &mut self,
1171         ValTy { value: src_val, ty: dest_ty } : ValTy<'tcx>,
1172         dest: Place,
1173     ) -> EvalResult<'tcx> {
1174         //trace!("Writing {:?} to {:?} at type {:?}", src_val, dest, dest_ty);
1175         // Note that it is really important that the type here is the right one, and matches the type things are read at.
1176         // In case `src_val` is a `ScalarPair`, we don't do any magic here to handle padding properly, which is only
1177         // correct if we never look at this data with the wrong type.
1178
1179         match dest {
1180             Place::Ptr { ptr, align, extra } => {
1181                 assert_eq!(extra, PlaceExtra::None);
1182                 self.write_value_to_ptr(src_val, ptr.unwrap_or_err()?, align, dest_ty)
1183             }
1184
1185             Place::Local { frame, local } => {
1186                 let old_val = self.stack[frame].locals[local].access()?;
1187                 self.write_value_possibly_by_val(
1188                     src_val,
1189                     |this, val| this.stack[frame].set_local(local, val),
1190                     old_val,
1191                     dest_ty,
1192                 )
1193             }
1194         }
1195     }
1196
1197     // The cases here can be a bit subtle. Read carefully!
1198     fn write_value_possibly_by_val<F: FnOnce(&mut Self, Value) -> EvalResult<'tcx>>(
1199         &mut self,
1200         src_val: Value,
1201         write_dest: F,
1202         old_dest_val: Value,
1203         dest_ty: Ty<'tcx>,
1204     ) -> EvalResult<'tcx> {
1205         // FIXME: this should be a layout check, not underlying value
1206         if let Value::ByRef(dest_ptr, align) = old_dest_val {
1207             // If the value is already `ByRef` (that is, backed by an `Allocation`),
1208             // then we must write the new value into this allocation, because there may be
1209             // other pointers into the allocation. These other pointers are logically
1210             // pointers into the local variable, and must be able to observe the change.
1211             //
1212             // Thus, it would be an error to replace the `ByRef` with a `ByVal`, unless we
1213             // knew for certain that there were no outstanding pointers to this allocation.
1214             self.write_value_to_ptr(src_val, dest_ptr, align, dest_ty)?;
1215         } else if let Value::ByRef(src_ptr, align) = src_val {
1216             // If the value is not `ByRef`, then we know there are no pointers to it
1217             // and we can simply overwrite the `Value` in the locals array directly.
1218             //
1219             // In this specific case, where the source value is `ByRef`, we must duplicate
1220             // the allocation, because this is a by-value operation. It would be incorrect
1221             // if they referred to the same allocation, since then a change to one would
1222             // implicitly change the other.
1223             //
1224             // It is a valid optimization to attempt reading a primitive value out of the
1225             // source and write that into the destination without making an allocation, so
1226             // we do so here.
1227             if let Ok(Some(src_val)) = self.try_read_value(src_ptr, align, dest_ty) {
1228                 write_dest(self, src_val)?;
1229             } else {
1230                 let layout = self.layout_of(dest_ty)?;
1231                 let dest_ptr = self.alloc_ptr(layout)?.into();
1232                 self.memory.copy(src_ptr, align.min(layout.align), dest_ptr, layout.align, layout.size, false)?;
1233                 write_dest(self, Value::ByRef(dest_ptr, layout.align))?;
1234             }
1235         } else {
1236             // Finally, we have the simple case where neither source nor destination are
1237             // `ByRef`. We may simply copy the source value over the the destintion.
1238             write_dest(self, src_val)?;
1239         }
1240         Ok(())
1241     }
1242
1243     pub fn write_value_to_ptr(
1244         &mut self,
1245         value: Value,
1246         dest: Scalar,
1247         dest_align: Align,
1248         dest_ty: Ty<'tcx>,
1249     ) -> EvalResult<'tcx> {
1250         let layout = self.layout_of(dest_ty)?;
1251         trace!("write_value_to_ptr: {:#?}, {}, {:#?}", value, dest_ty, layout);
1252         match value {
1253             Value::ByRef(ptr, align) => {
1254                 self.memory.copy(ptr, align.min(layout.align), dest, dest_align.min(layout.align), layout.size, false)
1255             }
1256             Value::Scalar(scalar) => {
1257                 let signed = match layout.abi {
1258                     layout::Abi::Scalar(ref scal) => match scal.value {
1259                         layout::Primitive::Int(_, signed) => signed,
1260                         _ => false,
1261                     },
1262                     _ => false,
1263                 };
1264                 self.memory.write_scalar(dest, dest_align, scalar, layout.size, layout.align, signed)
1265             }
1266             Value::ScalarPair(a_val, b_val) => {
1267                 trace!("write_value_to_ptr valpair: {:#?}", layout);
1268                 let (a, b) = match layout.abi {
1269                     layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
1270                     _ => bug!("write_value_to_ptr: invalid ScalarPair layout: {:#?}", layout)
1271                 };
1272                 let (a_size, b_size) = (a.size(&self), b.size(&self));
1273                 let (a_align, b_align) = (a.align(&self), b.align(&self));
1274                 let a_ptr = dest;
1275                 let b_offset = a_size.abi_align(b_align);
1276                 let b_ptr = dest.ptr_offset(b_offset, &self)?.into();
1277                 // TODO: What about signedess?
1278                 self.memory.write_scalar(a_ptr, dest_align, a_val, a_size, a_align, false)?;
1279                 self.memory.write_scalar(b_ptr, dest_align, b_val, b_size, b_align, false)
1280             }
1281         }
1282     }
1283
1284     pub fn read_value(&self, ptr: Scalar, align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
1285         if let Some(val) = self.try_read_value(ptr, align, ty)? {
1286             Ok(val)
1287         } else {
1288             bug!("primitive read failed for type: {:?}", ty);
1289         }
1290     }
1291
1292     fn validate_scalar(
1293         &self,
1294         value: ScalarMaybeUndef,
1295         size: Size,
1296         scalar: &layout::Scalar,
1297         path: &str,
1298         ty: Ty,
1299     ) -> EvalResult<'tcx> {
1300         trace!("validate scalar: {:#?}, {:#?}, {:#?}, {}", value, size, scalar, ty);
1301         let (lo, hi) = scalar.valid_range.clone().into_inner();
1302
1303         let value = match value {
1304             ScalarMaybeUndef::Scalar(scalar) => scalar,
1305             ScalarMaybeUndef::Undef => return validation_failure!("undefined bytes", path),
1306         };
1307
1308         let bits = match value {
1309             Scalar::Bits { bits, size: value_size } => {
1310                 assert_eq!(value_size as u64, size.bytes());
1311                 bits
1312             },
1313             Scalar::Ptr(_) => {
1314                 let ptr_size = self.memory.pointer_size();
1315                 let ptr_max = u128::max_value() >> (128 - ptr_size.bits());
1316                 return if lo > hi {
1317                     if lo - hi == 1 {
1318                         // no gap, all values are ok
1319                         Ok(())
1320                     } else if hi < ptr_max || lo > 1 {
1321                         let max = u128::max_value() >> (128 - size.bits());
1322                         validation_failure!(
1323                             "pointer",
1324                             path,
1325                             format!("something in the range {:?} or {:?}", 0..=lo, hi..=max)
1326                         )
1327                     } else {
1328                         Ok(())
1329                     }
1330                 } else if hi < ptr_max || lo > 1 {
1331                     validation_failure!(
1332                         "pointer",
1333                         path,
1334                         format!("something in the range {:?}", scalar.valid_range)
1335                     )
1336                 } else {
1337                     Ok(())
1338                 };
1339             },
1340         };
1341
1342         // char gets a special treatment, because its number space is not contiguous so `TyLayout`
1343         // has no special checks for chars
1344         match ty.sty {
1345             ty::TyChar => {
1346                 debug_assert_eq!(size.bytes(), 4);
1347                 if ::std::char::from_u32(bits as u32).is_none() {
1348                     return err!(InvalidChar(bits));
1349                 }
1350             }
1351             _ => {},
1352         }
1353
1354         use std::ops::RangeInclusive;
1355         let in_range = |bound: RangeInclusive<u128>| bound.contains(&bits);
1356         if lo > hi {
1357             if in_range(0..=hi) || in_range(lo..=u128::max_value()) {
1358                 Ok(())
1359             } else {
1360                 validation_failure!(
1361                     bits,
1362                     path,
1363                     format!("something in the range {:?} or {:?}", ..=hi, lo..)
1364                 )
1365             }
1366         } else {
1367             if in_range(scalar.valid_range.clone()) {
1368                 Ok(())
1369             } else {
1370                 validation_failure!(
1371                     bits,
1372                     path,
1373                     format!("something in the range {:?}", scalar.valid_range)
1374                 )
1375             }
1376         }
1377     }
1378
1379     /// This function checks the memory where `ptr` points to.
1380     /// It will error if the bits at the destination do not match the ones described by the layout.
1381     pub fn validate_ptr_target(
1382         &self,
1383         ptr: Pointer,
1384         ptr_align: Align,
1385         mut layout: TyLayout<'tcx>,
1386         path: String,
1387         seen: &mut FxHashSet<(Pointer, Ty<'tcx>)>,
1388         todo: &mut Vec<(Pointer, Ty<'tcx>, String)>,
1389     ) -> EvalResult<'tcx> {
1390         self.memory.dump_alloc(ptr.alloc_id);
1391         trace!("validate_ptr_target: {:?}, {:#?}", ptr, layout);
1392
1393         let variant;
1394         match layout.variants {
1395             layout::Variants::NicheFilling { niche: ref tag, .. } |
1396             layout::Variants::Tagged { ref tag, .. } => {
1397                 let size = tag.value.size(self);
1398                 let (tag_value, tag_layout) = self.read_field(
1399                     Value::ByRef(ptr.into(), ptr_align),
1400                     None,
1401                     mir::Field::new(0),
1402                     layout,
1403                 )?;
1404                 let tag_value = match self.follow_by_ref_value(tag_value, tag_layout.ty)? {
1405                     Value::Scalar(val) => val,
1406                     _ => bug!("tag must be scalar"),
1407                 };
1408                 let path = format!("{}.TAG", path);
1409                 self.validate_scalar(tag_value, size, tag, &path, tag_layout.ty)?;
1410                 let variant_index = self.read_discriminant_as_variant_index(
1411                     Place::from_ptr(ptr, ptr_align),
1412                     layout,
1413                 )?;
1414                 variant = variant_index;
1415                 layout = layout.for_variant(self, variant_index);
1416                 trace!("variant layout: {:#?}", layout);
1417             },
1418             layout::Variants::Single { index } => variant = index,
1419         }
1420         match layout.fields {
1421             // primitives are unions with zero fields
1422             layout::FieldPlacement::Union(0) => {
1423                 match layout.abi {
1424                     // nothing to do, whatever the pointer points to, it is never going to be read
1425                     layout::Abi::Uninhabited => validation_failure!("a value of an uninhabited type", path),
1426                     // check that the scalar is a valid pointer or that its bit range matches the
1427                     // expectation.
1428                     layout::Abi::Scalar(ref scalar) => {
1429                         let size = scalar.value.size(self);
1430                         let value = self.memory.read_scalar(ptr, ptr_align, size)?;
1431                         self.validate_scalar(value, size, scalar, &path, layout.ty)?;
1432                         if scalar.value == Primitive::Pointer {
1433                             // ignore integer pointers, we can't reason about the final hardware
1434                             if let Scalar::Ptr(ptr) = value.unwrap_or_err()? {
1435                                 let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
1436                                 if let Some(AllocType::Static(did)) = alloc_kind {
1437                                     // statics from other crates are already checked
1438                                     // extern statics should not be validated as they have no body
1439                                     if !did.is_local() || self.tcx.is_foreign_item(did) {
1440                                         return Ok(());
1441                                     }
1442                                 }
1443                                 if let Some(tam) = layout.ty.builtin_deref(false) {
1444                                     // we have not encountered this pointer+layout combination before
1445                                     if seen.insert((ptr, tam.ty)) {
1446                                         todo.push((ptr, tam.ty, format!("(*{})", path)))
1447                                     }
1448                                 }
1449                             }
1450                         }
1451                         Ok(())
1452                     },
1453                     _ => bug!("bad abi for FieldPlacement::Union(0): {:#?}", layout.abi),
1454                 }
1455             }
1456             layout::FieldPlacement::Union(_) => {
1457                 // We can't check unions, their bits are allowed to be anything.
1458                 // The fields don't need to correspond to any bit pattern of the union's fields.
1459                 // See https://github.com/rust-lang/rust/issues/32836#issuecomment-406875389
1460                 Ok(())
1461             },
1462             layout::FieldPlacement::Array { stride, count } => {
1463                 let elem_layout = layout.field(self, 0)?;
1464                 for i in 0..count {
1465                     let mut path = path.clone();
1466                     self.write_field_name(&mut path, layout.ty, i as usize, variant).unwrap();
1467                     self.validate_ptr_target(ptr.offset(stride * i, self)?, ptr_align, elem_layout, path, seen, todo)?;
1468                 }
1469                 Ok(())
1470             },
1471             layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
1472
1473                 // check length field and vtable field
1474                 match layout.ty.builtin_deref(false).map(|tam| &tam.ty.sty) {
1475                     | Some(ty::TyStr)
1476                     | Some(ty::TySlice(_)) => {
1477                         let (len, len_layout) = self.read_field(
1478                             Value::ByRef(ptr.into(), ptr_align),
1479                             None,
1480                             mir::Field::new(1),
1481                             layout,
1482                         )?;
1483                         let len = self.value_to_scalar(ValTy { value: len, ty: len_layout.ty })?;
1484                         if len.to_bits(len_layout.size).is_err() {
1485                             return validation_failure!("length is not a valid integer", path);
1486                         }
1487                     },
1488                     Some(ty::TyDynamic(..)) => {
1489                         let (vtable, vtable_layout) = self.read_field(
1490                             Value::ByRef(ptr.into(), ptr_align),
1491                             None,
1492                             mir::Field::new(1),
1493                             layout,
1494                         )?;
1495                         let vtable = self.value_to_scalar(ValTy { value: vtable, ty: vtable_layout.ty })?;
1496                         if vtable.to_ptr().is_err() {
1497                             return validation_failure!("vtable address is not a pointer", path);
1498                         }
1499                     }
1500                     _ => {},
1501                 }
1502                 for (i, &offset) in offsets.iter().enumerate() {
1503                     let field_layout = layout.field(self, i)?;
1504                     let mut path = path.clone();
1505                     self.write_field_name(&mut path, layout.ty, i, variant).unwrap();
1506                     self.validate_ptr_target(ptr.offset(offset, self)?, ptr_align, field_layout, path, seen, todo)?;
1507                 }
1508                 Ok(())
1509             }
1510         }
1511     }
1512
1513     pub fn try_read_by_ref(&self, mut val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
1514         // Convert to ByVal or ScalarPair if possible
1515         if let Value::ByRef(ptr, align) = val {
1516             if let Some(read_val) = self.try_read_value(ptr, align, ty)? {
1517                 val = read_val;
1518             }
1519         }
1520         Ok(val)
1521     }
1522
1523     pub fn try_read_value(&self, ptr: Scalar, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
1524         let layout = self.layout_of(ty)?;
1525         self.memory.check_align(ptr, ptr_align)?;
1526
1527         if layout.size.bytes() == 0 {
1528             return Ok(Some(Value::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { bits: 0, size: 0 }))));
1529         }
1530
1531         let ptr = ptr.to_ptr()?;
1532
1533         match layout.abi {
1534             layout::Abi::Scalar(..) => {
1535                 let scalar = self.memory.read_scalar(ptr, ptr_align, layout.size)?;
1536                 Ok(Some(Value::Scalar(scalar)))
1537             }
1538             layout::Abi::ScalarPair(ref a, ref b) => {
1539                 let (a, b) = (&a.value, &b.value);
1540                 let (a_size, b_size) = (a.size(self), b.size(self));
1541                 let a_ptr = ptr;
1542                 let b_offset = a_size.abi_align(b.align(self));
1543                 let b_ptr = ptr.offset(b_offset, self)?.into();
1544                 let a_val = self.memory.read_scalar(a_ptr, ptr_align, a_size)?;
1545                 let b_val = self.memory.read_scalar(b_ptr, ptr_align, b_size)?;
1546                 Ok(Some(Value::ScalarPair(a_val, b_val)))
1547             }
1548             _ => Ok(None),
1549         }
1550     }
1551
1552     pub fn frame(&self) -> &Frame<'mir, 'tcx> {
1553         self.stack.last().expect("no call frames exist")
1554     }
1555
1556     pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> {
1557         self.stack.last_mut().expect("no call frames exist")
1558     }
1559
1560     pub(super) fn mir(&self) -> &'mir mir::Mir<'tcx> {
1561         self.frame().mir
1562     }
1563
1564     pub fn substs(&self) -> &'tcx Substs<'tcx> {
1565         if let Some(frame) = self.stack.last() {
1566             frame.instance.substs
1567         } else {
1568             Substs::empty()
1569         }
1570     }
1571
1572     fn unsize_into_ptr(
1573         &mut self,
1574         src: Value,
1575         src_ty: Ty<'tcx>,
1576         dest: Place,
1577         dest_ty: Ty<'tcx>,
1578         sty: Ty<'tcx>,
1579         dty: Ty<'tcx>,
1580     ) -> EvalResult<'tcx> {
1581         // A<Struct> -> A<Trait> conversion
1582         let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty);
1583
1584         match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
1585             (&ty::TyArray(_, length), &ty::TySlice(_)) => {
1586                 let ptr = self.into_ptr(src)?;
1587                 // u64 cast is from usize to u64, which is always good
1588                 let valty = ValTy {
1589                     value: ptr.to_value_with_len(length.unwrap_usize(self.tcx.tcx), self.tcx.tcx),
1590                     ty: dest_ty,
1591                 };
1592                 self.write_value(valty, dest)
1593             }
1594             (&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
1595                 // For now, upcasts are limited to changes in marker
1596                 // traits, and hence never actually require an actual
1597                 // change to the vtable.
1598                 let valty = ValTy {
1599                     value: src,
1600                     ty: dest_ty,
1601                 };
1602                 self.write_value(valty, dest)
1603             }
1604             (_, &ty::TyDynamic(ref data, _)) => {
1605                 let trait_ref = data.principal().unwrap().with_self_ty(
1606                     *self.tcx,
1607                     src_pointee_ty,
1608                 );
1609                 let trait_ref = self.tcx.erase_regions(&trait_ref);
1610                 let vtable = self.get_vtable(src_pointee_ty, trait_ref)?;
1611                 let ptr = self.into_ptr(src)?;
1612                 let valty = ValTy {
1613                     value: ptr.to_value_with_vtable(vtable),
1614                     ty: dest_ty,
1615                 };
1616                 self.write_value(valty, dest)
1617             }
1618
1619             _ => bug!("invalid unsizing {:?} -> {:?}", src_ty, dest_ty),
1620         }
1621     }
1622
1623     crate fn unsize_into(
1624         &mut self,
1625         src: Value,
1626         src_layout: TyLayout<'tcx>,
1627         dst: Place,
1628         dst_layout: TyLayout<'tcx>,
1629     ) -> EvalResult<'tcx> {
1630         match (&src_layout.ty.sty, &dst_layout.ty.sty) {
1631             (&ty::TyRef(_, s, _), &ty::TyRef(_, d, _)) |
1632             (&ty::TyRef(_, s, _), &ty::TyRawPtr(TypeAndMut { ty: d, .. })) |
1633             (&ty::TyRawPtr(TypeAndMut { ty: s, .. }),
1634              &ty::TyRawPtr(TypeAndMut { ty: d, .. })) => {
1635                 self.unsize_into_ptr(src, src_layout.ty, dst, dst_layout.ty, s, d)
1636             }
1637             (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => {
1638                 assert_eq!(def_a, def_b);
1639                 if def_a.is_box() || def_b.is_box() {
1640                     if !def_a.is_box() || !def_b.is_box() {
1641                         bug!("invalid unsizing between {:?} -> {:?}", src_layout, dst_layout);
1642                     }
1643                     return self.unsize_into_ptr(
1644                         src,
1645                         src_layout.ty,
1646                         dst,
1647                         dst_layout.ty,
1648                         src_layout.ty.boxed_ty(),
1649                         dst_layout.ty.boxed_ty(),
1650                     );
1651                 }
1652
1653                 // unsizing of generic struct with pointer fields
1654                 // Example: `Arc<T>` -> `Arc<Trait>`
1655                 // here we need to increase the size of every &T thin ptr field to a fat ptr
1656                 for i in 0..src_layout.fields.count() {
1657                     let (dst_f_place, dst_field) =
1658                         self.place_field(dst, mir::Field::new(i), dst_layout)?;
1659                     if dst_field.is_zst() {
1660                         continue;
1661                     }
1662                     let (src_f_value, src_field) = match src {
1663                         Value::ByRef(ptr, align) => {
1664                             let src_place = Place::from_scalar_ptr(ptr.into(), align);
1665                             let (src_f_place, src_field) =
1666                                 self.place_field(src_place, mir::Field::new(i), src_layout)?;
1667                             (self.read_place(src_f_place)?, src_field)
1668                         }
1669                         Value::Scalar(_) | Value::ScalarPair(..) => {
1670                             let src_field = src_layout.field(&self, i)?;
1671                             assert_eq!(src_layout.fields.offset(i).bytes(), 0);
1672                             assert_eq!(src_field.size, src_layout.size);
1673                             (src, src_field)
1674                         }
1675                     };
1676                     if src_field.ty == dst_field.ty {
1677                         self.write_value(ValTy {
1678                             value: src_f_value,
1679                             ty: src_field.ty,
1680                         }, dst_f_place)?;
1681                     } else {
1682                         self.unsize_into(src_f_value, src_field, dst_f_place, dst_field)?;
1683                     }
1684                 }
1685                 Ok(())
1686             }
1687             _ => {
1688                 bug!(
1689                     "unsize_into: invalid conversion: {:?} -> {:?}",
1690                     src_layout,
1691                     dst_layout
1692                 )
1693             }
1694         }
1695     }
1696
1697     pub fn dump_local(&self, place: Place) {
1698         // Debug output
1699         if !log_enabled!(::log::Level::Trace) {
1700             return;
1701         }
1702         match place {
1703             Place::Local { frame, local } => {
1704                 let mut allocs = Vec::new();
1705                 let mut msg = format!("{:?}", local);
1706                 if frame != self.cur_frame() {
1707                     write!(msg, " ({} frames up)", self.cur_frame() - frame).unwrap();
1708                 }
1709                 write!(msg, ":").unwrap();
1710
1711                 match self.stack[frame].locals[local].access() {
1712                     Err(err) => {
1713                         if let EvalErrorKind::DeadLocal = err.kind {
1714                             write!(msg, " is dead").unwrap();
1715                         } else {
1716                             panic!("Failed to access local: {:?}", err);
1717                         }
1718                     }
1719                     Ok(Value::ByRef(ptr, align)) => {
1720                         match ptr {
1721                             Scalar::Ptr(ptr) => {
1722                                 write!(msg, " by align({}) ref:", align.abi()).unwrap();
1723                                 allocs.push(ptr.alloc_id);
1724                             }
1725                             ptr => write!(msg, " integral by ref: {:?}", ptr).unwrap(),
1726                         }
1727                     }
1728                     Ok(Value::Scalar(val)) => {
1729                         write!(msg, " {:?}", val).unwrap();
1730                         if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val {
1731                             allocs.push(ptr.alloc_id);
1732                         }
1733                     }
1734                     Ok(Value::ScalarPair(val1, val2)) => {
1735                         write!(msg, " ({:?}, {:?})", val1, val2).unwrap();
1736                         if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val1 {
1737                             allocs.push(ptr.alloc_id);
1738                         }
1739                         if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val2 {
1740                             allocs.push(ptr.alloc_id);
1741                         }
1742                     }
1743                 }
1744
1745                 trace!("{}", msg);
1746                 self.memory.dump_allocs(allocs);
1747             }
1748             Place::Ptr { ptr, align, .. } => {
1749                 match ptr {
1750                     ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) => {
1751                         trace!("by align({}) ref:", align.abi());
1752                         self.memory.dump_alloc(ptr.alloc_id);
1753                     }
1754                     ptr => trace!(" integral by ref: {:?}", ptr),
1755                 }
1756             }
1757         }
1758     }
1759
1760     pub fn generate_stacktrace(&self, explicit_span: Option<Span>) -> (Vec<FrameInfo>, Span) {
1761         let mut last_span = None;
1762         let mut frames = Vec::new();
1763         // skip 1 because the last frame is just the environment of the constant
1764         for &Frame { instance, span, mir, block, stmt, .. } in self.stack().iter().skip(1).rev() {
1765             // make sure we don't emit frames that are duplicates of the previous
1766             if explicit_span == Some(span) {
1767                 last_span = Some(span);
1768                 continue;
1769             }
1770             if let Some(last) = last_span {
1771                 if last == span {
1772                     continue;
1773                 }
1774             } else {
1775                 last_span = Some(span);
1776             }
1777             let location = if self.tcx.def_key(instance.def_id()).disambiguated_data.data == DefPathData::ClosureExpr {
1778                 "closure".to_owned()
1779             } else {
1780                 instance.to_string()
1781             };
1782             let block = &mir.basic_blocks()[block];
1783             let source_info = if stmt < block.statements.len() {
1784                 block.statements[stmt].source_info
1785             } else {
1786                 block.terminator().source_info
1787             };
1788             let lint_root = match mir.source_scope_local_data {
1789                 mir::ClearCrossCrate::Set(ref ivs) => Some(ivs[source_info.scope].lint_root),
1790                 mir::ClearCrossCrate::Clear => None,
1791             };
1792             frames.push(FrameInfo { span, location, lint_root });
1793         }
1794         trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span);
1795         (frames, self.tcx.span)
1796     }
1797
1798     pub fn sign_extend(&self, value: u128, ty: TyLayout<'_>) -> u128 {
1799         super::sign_extend(value, ty)
1800     }
1801
1802     pub fn truncate(&self, value: u128, ty: TyLayout<'_>) -> u128 {
1803         super::truncate(value, ty)
1804     }
1805
1806     fn write_field_name(&self, s: &mut String, ty: Ty<'tcx>, i: usize, variant: usize) -> ::std::fmt::Result {
1807         match ty.sty {
1808             ty::TyBool |
1809             ty::TyChar |
1810             ty::TyInt(_) |
1811             ty::TyUint(_) |
1812             ty::TyFloat(_) |
1813             ty::TyFnPtr(_) |
1814             ty::TyNever |
1815             ty::TyFnDef(..) |
1816             ty::TyGeneratorWitness(..) |
1817             ty::TyForeign(..) |
1818             ty::TyDynamic(..) => {
1819                 bug!("field_name({:?}): not applicable", ty)
1820             }
1821
1822             // Potentially-fat pointers.
1823             ty::TyRef(_, pointee, _) |
1824             ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
1825                 assert!(i < 2);
1826
1827                 // Reuse the fat *T type as its own thin pointer data field.
1828                 // This provides information about e.g. DST struct pointees
1829                 // (which may have no non-DST form), and will work as long
1830                 // as the `Abi` or `FieldPlacement` is checked by users.
1831                 if i == 0 {
1832                     return write!(s, ".data_ptr");
1833                 }
1834
1835                 match self.tcx.struct_tail(pointee).sty {
1836                     ty::TySlice(_) |
1837                     ty::TyStr => write!(s, ".len"),
1838                     ty::TyDynamic(..) => write!(s, ".vtable_ptr"),
1839                     _ => bug!("field_name({:?}): not applicable", ty)
1840                 }
1841             }
1842
1843             // Arrays and slices.
1844             ty::TyArray(_, _) |
1845             ty::TySlice(_) |
1846             ty::TyStr => write!(s, "[{}]", i),
1847
1848             // generators and closures.
1849             ty::TyClosure(def_id, _) | ty::TyGenerator(def_id, _, _) => {
1850                 let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
1851                 let freevar = self.tcx.with_freevars(node_id, |fv| fv[i]);
1852                 write!(s, ".upvar({})", self.tcx.hir.name(freevar.var_id()))
1853             }
1854
1855             ty::TyTuple(_) => write!(s, ".{}", i),
1856
1857             // enums
1858             ty::TyAdt(def, ..) if def.is_enum() => {
1859                 let variant = &def.variants[variant];
1860                 write!(s, ".{}::{}", variant.name, variant.fields[i].ident)
1861             }
1862
1863             // other ADTs.
1864             ty::TyAdt(def, _) => write!(s, ".{}", def.non_enum_variant().fields[i].ident),
1865
1866             ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
1867             ty::TyInfer(_) | ty::TyError => {
1868                 bug!("write_field_name: unexpected type `{}`", ty)
1869             }
1870         }
1871     }
1872
1873     pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, LocalValue> {
1874         trace!("{:?} is now live", local);
1875
1876         let ty = self.frame().mir.local_decls[local].ty;
1877         let init = self.init_value(ty)?;
1878         // StorageLive *always* kills the value that's currently stored
1879         Ok(mem::replace(&mut self.frame_mut().locals[local], LocalValue::Live(init)))
1880     }
1881
1882     fn init_value(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
1883         let ty = self.monomorphize(ty, self.substs());
1884         let layout = self.layout_of(ty)?;
1885         Ok(match layout.abi {
1886             layout::Abi::Scalar(..) => Value::Scalar(ScalarMaybeUndef::Undef),
1887             layout::Abi::ScalarPair(..) => Value::ScalarPair(
1888                 ScalarMaybeUndef::Undef,
1889                 ScalarMaybeUndef::Undef,
1890             ),
1891             _ => Value::ByRef(self.alloc_ptr(layout)?.into(), layout.align),
1892         })
1893     }
1894 }
1895
1896 impl<'mir, 'tcx> Frame<'mir, 'tcx> {
1897     fn set_local(&mut self, local: mir::Local, value: Value) -> EvalResult<'tcx> {
1898         match self.locals[local] {
1899             LocalValue::Dead => err!(DeadLocal),
1900             LocalValue::Live(ref mut local) => {
1901                 *local = value;
1902                 Ok(())
1903             }
1904         }
1905     }
1906
1907     /// Returns the old value of the local
1908     pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue {
1909         trace!("{:?} is now dead", local);
1910
1911         mem::replace(&mut self.locals[local], LocalValue::Dead)
1912     }
1913 }