3 use rustc::hir::def_id::DefId;
4 use rustc::hir::def::Def;
5 use rustc::hir::map::definitions::DefPathData;
7 use rustc::ty::layout::{self, Size, Align, HasDataLayout, IntegerExt, LayoutOf, TyLayout};
8 use rustc::ty::subst::{Subst, Substs};
9 use rustc::ty::{self, Ty, TyCtxt, TypeAndMut};
10 use rustc::ty::query::TyCtxtAt;
11 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
12 use rustc::mir::interpret::FrameInfo;
13 use syntax::codemap::{self, Span};
14 use syntax::ast::Mutability;
15 use rustc::mir::interpret::{
16 GlobalId, Value, Scalar,
17 EvalResult, EvalErrorKind, Pointer, ConstValue,
21 use super::{Place, PlaceExtra, Memory,
22 HasMemory, MemoryKind,
25 pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
26 /// Stores the `Machine` instance.
29 /// The results of the type checker, from rustc.
30 pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
32 /// Bounds in scope for polymorphic evaluations.
33 pub param_env: ty::ParamEnv<'tcx>,
35 /// The virtual memory system.
36 pub memory: Memory<'a, 'mir, 'tcx, M>,
38 /// The virtual call stack.
39 pub(crate) stack: Vec<Frame<'mir, 'tcx>>,
41 /// The maximum number of stack frames allowed
42 pub(crate) stack_limit: usize,
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) terminators_remaining: usize,
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>,
58 /// The def_id and substs of the current function
59 pub instance: ty::Instance<'tcx>,
61 /// The span of the call site.
62 pub span: codemap::Span,
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,
70 /// The location where the result of the current stack frame should be written to.
71 pub return_place: Place,
73 /// The list of locals for this stack frame, stored in order as
74 /// `[return_ptr, 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 `Scalar` or refer to some part of an `Allocation`.
78 /// Before being initialized, arguments are `Value::Scalar(Scalar::undef())` and other locals are `None`.
79 pub locals: IndexVec<mir::Local, Option<Value>>,
81 ////////////////////////////////////////////////////////////////////////////////
82 // Current position within the function
83 ////////////////////////////////////////////////////////////////////////////////
84 /// The block that is currently executed (or will be executed after the above call stacks
86 pub block: mir::BasicBlock,
88 /// The index of the currently evaluated statement.
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
101 Goto(mir::BasicBlock),
102 /// The main function and diverging functions have nowhere to return to
106 #[derive(Copy, Clone, Debug)]
107 pub struct TyAndPacked<'tcx> {
112 #[derive(Copy, Clone, Debug)]
113 pub struct ValTy<'tcx> {
118 impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
120 fn deref(&self) -> &Value {
125 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for &'a EvalContext<'a, 'mir, 'tcx, M> {
127 fn data_layout(&self) -> &layout::TargetDataLayout {
128 &self.tcx.data_layout
132 impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout
133 for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
135 fn data_layout(&self) -> &layout::TargetDataLayout {
136 &self.tcx.data_layout
140 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'mir, 'tcx, M> {
142 fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
147 impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx>
148 for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
150 fn tcx<'d>(&'d self) -> TyCtxt<'d, 'tcx, 'tcx> {
155 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for &'a EvalContext<'a, 'mir, 'tcx, M> {
157 type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
159 fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
160 self.tcx.layout_of(self.param_env.and(ty))
161 .map_err(|layout| EvalErrorKind::Layout(layout).into())
165 impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf
166 for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
168 type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
171 fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
172 (&**self).layout_of(ty)
176 const MAX_TERMINATORS: usize = 1_000_000;
178 impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
180 tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
181 param_env: ty::ParamEnv<'tcx>,
183 memory_data: M::MemoryData,
189 memory: Memory::new(tcx, memory_data),
191 stack_limit: tcx.sess.const_eval_stack_frame_limit,
192 terminators_remaining: MAX_TERMINATORS,
196 pub(crate) fn with_fresh_body<F: FnOnce(&mut Self) -> R, R>(&mut self, f: F) -> R {
197 let stack = mem::replace(&mut self.stack, Vec::new());
198 let terminators_remaining = mem::replace(&mut self.terminators_remaining, MAX_TERMINATORS);
201 self.terminators_remaining = terminators_remaining;
205 pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, Pointer> {
206 let layout = self.layout_of(ty)?;
207 assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
209 self.memory.allocate(layout.size, layout.align, Some(MemoryKind::Stack))
212 pub fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
216 pub fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
220 pub fn stack(&self) -> &[Frame<'mir, 'tcx>] {
225 pub fn cur_frame(&self) -> usize {
226 assert!(self.stack.len() > 0);
230 pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
231 let ptr = self.memory.allocate_bytes(s.as_bytes());
232 Ok(Scalar::Ptr(ptr).to_value_with_len(s.len() as u64, self.tcx.tcx))
235 pub fn const_to_value(
237 val: ConstValue<'tcx>,
238 ) -> EvalResult<'tcx, Value> {
240 ConstValue::Unevaluated(def_id, substs) => {
241 let instance = self.resolve(def_id, substs)?;
242 self.read_global_as_value(GlobalId {
247 ConstValue::ByRef(alloc, offset) => {
248 // FIXME: Allocate new AllocId for all constants inside
249 let id = self.memory.allocate_value(alloc.clone(), Some(MemoryKind::Stack))?;
250 Ok(Value::ByRef(Pointer::new(id, offset).into(), alloc.align))
252 ConstValue::ScalarPair(a, b) => Ok(Value::ScalarPair(a, b)),
253 ConstValue::Scalar(val) => Ok(Value::Scalar(val)),
257 pub(super) fn resolve(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, ty::Instance<'tcx>> {
258 trace!("resolve: {:?}, {:#?}", def_id, substs);
259 trace!("substs: {:#?}", self.substs());
260 trace!("param_env: {:#?}", self.param_env);
261 let substs = self.tcx.subst_and_normalize_erasing_regions(
266 ty::Instance::resolve(
271 ).ok_or_else(|| EvalErrorKind::TooGeneric.into())
274 pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
275 ty.is_sized(self.tcx, self.param_env)
280 instance: ty::InstanceDef<'tcx>,
281 ) -> EvalResult<'tcx, &'tcx mir::Mir<'tcx>> {
282 // do not continue if typeck errors occurred (can only occur in local crate)
283 let did = instance.def_id();
284 if did.is_local() && self.tcx.has_typeck_tables(did) && self.tcx.typeck_tables_of(did).tainted_by_errors {
285 return err!(TypeckError);
287 trace!("load mir {:?}", instance);
289 ty::InstanceDef::Item(def_id) => {
290 self.tcx.maybe_optimized_mir(def_id).ok_or_else(||
291 EvalErrorKind::NoMirFor(self.tcx.item_path_str(def_id)).into()
294 _ => Ok(self.tcx.instance_mir(instance)),
298 pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
299 // miri doesn't care about lifetimes, and will choke on some crazy ones
300 // let's simply get rid of them
301 let substituted = ty.subst(*self.tcx, substs);
302 self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted)
305 /// Return the size and aligment of the value at the given type.
306 /// Note that the value does not matter if the type is sized. For unsized types,
307 /// the value has to be a fat pointer, and we only care about the "extra" data in it.
308 pub fn size_and_align_of_dst(
312 ) -> EvalResult<'tcx, (Size, Align)> {
313 let layout = self.layout_of(ty)?;
314 if !layout.is_unsized() {
315 Ok(layout.size_and_align())
318 ty::TyAdt(..) | ty::TyTuple(..) => {
319 // First get the size of all statically known fields.
320 // Don't use type_of::sizing_type_of because that expects t to be sized,
321 // and it also rounds up to alignment, which we want to avoid,
322 // as the unsized field's alignment could be smaller.
323 assert!(!ty.is_simd());
324 debug!("DST {} layout: {:?}", ty, layout);
326 let sized_size = layout.fields.offset(layout.fields.count() - 1);
327 let sized_align = layout.align;
329 "DST {} statically sized prefix size: {:?} align: {:?}",
335 // Recurse to get the size of the dynamically sized field (must be
337 let field_ty = layout.field(&self, layout.fields.count() - 1)?.ty;
338 let (unsized_size, unsized_align) =
339 self.size_and_align_of_dst(field_ty, value)?;
341 // FIXME (#26403, #27023): We should be adding padding
342 // to `sized_size` (to accommodate the `unsized_align`
343 // required of the unsized field that follows) before
344 // summing it with `sized_size`. (Note that since #26403
345 // is unfixed, we do not yet add the necessary padding
346 // here. But this is where the add would go.)
348 // Return the sum of sizes and max of aligns.
349 let size = sized_size + unsized_size;
351 // Choose max of two known alignments (combined value must
352 // be aligned according to more restrictive of the two).
353 let align = sized_align.max(unsized_align);
355 // Issue #27023: must add any necessary padding to `size`
356 // (to make it a multiple of `align`) before returning it.
358 // Namely, the returned size should be, in C notation:
360 // `size + ((size & (align-1)) ? align : 0)`
362 // emulated via the semi-standard fast bit trick:
364 // `(size + (align-1)) & -align`
366 Ok((size.abi_align(align), align))
368 ty::TyDynamic(..) => {
369 let (_, vtable) = self.into_ptr_vtable_pair(value)?;
370 // the second entry in the vtable is the dynamic size of the object.
371 self.read_size_and_align_from_vtable(vtable)
374 ty::TySlice(_) | ty::TyStr => {
375 let (elem_size, align) = layout.field(&self, 0)?.size_and_align();
376 let (_, len) = self.into_slice(value)?;
377 Ok((elem_size * len, align))
380 _ => bug!("size_of_val::<{:?}>", ty),
385 pub fn push_stack_frame(
387 instance: ty::Instance<'tcx>,
389 mir: &'mir mir::Mir<'tcx>,
391 return_to_block: StackPopCleanup,
392 ) -> EvalResult<'tcx> {
393 ::log_settings::settings().indentation += 1;
395 let locals = if mir.local_decls.len() > 1 {
396 let mut locals = IndexVec::from_elem(Some(Value::Scalar(Scalar::undef())), &mir.local_decls);
397 match self.tcx.describe_def(instance.def_id()) {
398 // statics and constants don't have `Storage*` statements, no need to look for them
399 Some(Def::Static(..)) | Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {},
401 trace!("push_stack_frame: {:?}: num_bbs: {}", span, mir.basic_blocks().len());
402 for block in mir.basic_blocks() {
403 for stmt in block.statements.iter() {
404 use rustc::mir::StatementKind::{StorageDead, StorageLive};
407 StorageDead(local) => locals[local] = None,
416 // don't allocate at all for trivial constants
420 self.stack.push(Frame {
422 block: mir::START_BLOCK,
431 self.memory.cur_frame = self.cur_frame();
433 if self.stack.len() > self.stack_limit {
434 err!(StackFrameLimitReached)
440 pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
441 ::log_settings::settings().indentation -= 1;
442 M::end_region(self, None)?;
443 let frame = self.stack.pop().expect(
444 "tried to pop a stack frame, but there were none",
446 if !self.stack.is_empty() {
447 // TODO: Is this the correct time to start considering these accesses as originating from the returned-to stack frame?
448 self.memory.cur_frame = self.cur_frame();
450 match frame.return_to_block {
451 StackPopCleanup::MarkStatic(mutable) => {
452 if let Place::Ptr { ptr, .. } = frame.return_place {
453 // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
454 self.memory.mark_static_initialized(
455 ptr.to_ptr()?.alloc_id,
459 bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_place);
462 StackPopCleanup::Goto(target) => self.goto_block(target),
463 StackPopCleanup::None => {}
465 // deallocate all locals that are backed by an allocation
466 for local in frame.locals {
467 self.deallocate_local(local)?;
473 pub fn deallocate_local(&mut self, local: Option<Value>) -> EvalResult<'tcx> {
474 if let Some(Value::ByRef(ptr, _align)) = local {
475 trace!("deallocating local");
476 let ptr = ptr.to_ptr()?;
477 self.memory.dump_alloc(ptr.alloc_id);
478 self.memory.deallocate_local(ptr)?;
483 /// Evaluate an assignment statement.
485 /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
486 /// type writes its results directly into the memory specified by the place.
487 pub(super) fn eval_rvalue_into_place(
489 rvalue: &mir::Rvalue<'tcx>,
490 place: &mir::Place<'tcx>,
491 ) -> EvalResult<'tcx> {
492 let dest = self.eval_place(place)?;
493 let dest_ty = self.place_ty(place);
495 use rustc::mir::Rvalue::*;
497 Use(ref operand) => {
498 let value = self.eval_operand(operand)?.value;
503 self.write_value(valty, dest)?;
506 BinaryOp(bin_op, ref left, ref right) => {
507 let left = self.eval_operand(left)?;
508 let right = self.eval_operand(right)?;
509 self.intrinsic_overflowing(
518 CheckedBinaryOp(bin_op, ref left, ref right) => {
519 let left = self.eval_operand(left)?;
520 let right = self.eval_operand(right)?;
521 self.intrinsic_with_overflow(
530 UnaryOp(un_op, ref operand) => {
531 let val = self.eval_operand_to_scalar(operand)?;
532 let val = self.unary_op(un_op, val, dest_ty)?;
540 Aggregate(ref kind, ref operands) => {
541 self.inc_step_counter_and_check_limit(operands.len());
543 let (dest, active_field_index) = match **kind {
544 mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
545 self.write_discriminant_value(dest_ty, dest, variant_index)?;
546 if adt_def.is_enum() {
547 (self.place_downcast(dest, variant_index)?, active_field_index)
549 (dest, active_field_index)
555 let layout = self.layout_of(dest_ty)?;
556 for (i, operand) in operands.iter().enumerate() {
557 let value = self.eval_operand(operand)?;
558 // Ignore zero-sized fields.
559 if !self.layout_of(value.ty)?.is_zst() {
560 let field_index = active_field_index.unwrap_or(i);
561 let (field_dest, _) = self.place_field(dest, mir::Field::new(field_index), layout)?;
562 self.write_value(value, field_dest)?;
567 Repeat(ref operand, _) => {
568 let (elem_ty, length) = match dest_ty.sty {
569 ty::TyArray(elem_ty, n) => (elem_ty, n.unwrap_usize(self.tcx.tcx)),
572 "tried to assign array-repeat to non-array type {:?}",
577 let elem_size = self.layout_of(elem_ty)?.size;
578 let value = self.eval_operand(operand)?.value;
580 let (dest, dest_align) = self.force_allocation(dest)?.to_ptr_align();
583 //write the first value
584 self.write_value_to_ptr(value, dest, dest_align, elem_ty)?;
587 let rest = dest.ptr_offset(elem_size * 1 as u64, &self)?;
588 self.memory.copy_repeatedly(dest, dest_align, rest, dest_align, elem_size, length - 1, false)?;
594 // FIXME(CTFE): don't allow computing the length of arrays in const eval
595 let src = self.eval_place(place)?;
596 let ty = self.place_ty(place);
597 let (_, len) = src.elem_ty_and_len(ty, self.tcx.tcx);
598 let defined = self.memory.pointer_size().bits() as u8;
609 Ref(_, _, ref place) => {
610 let src = self.eval_place(place)?;
611 // We ignore the alignment of the place here -- special handling for packed structs ends
612 // at the `&` operator.
613 let (ptr, _align, extra) = self.force_allocation(src)?.to_ptr_align_extra();
615 let val = match extra {
616 PlaceExtra::None => ptr.to_value(),
617 PlaceExtra::Length(len) => ptr.to_value_with_len(len, self.tcx.tcx),
618 PlaceExtra::Vtable(vtable) => ptr.to_value_with_vtable(vtable),
619 PlaceExtra::DowncastVariant(..) => {
620 bug!("attempted to take a reference to an enum downcast place")
627 self.write_value(valty, dest)?;
630 NullaryOp(mir::NullOp::Box, ty) => {
631 let ty = self.monomorphize(ty, self.substs());
632 M::box_alloc(self, ty, dest)?;
635 NullaryOp(mir::NullOp::SizeOf, ty) => {
636 let ty = self.monomorphize(ty, self.substs());
637 let layout = self.layout_of(ty)?;
638 assert!(!layout.is_unsized(),
639 "SizeOf nullary MIR operator called for unsized type");
640 let defined = self.memory.pointer_size().bits() as u8;
644 bits: layout.size.bytes() as u128,
651 Cast(kind, ref operand, cast_ty) => {
652 debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest_ty);
653 use rustc::mir::CastKind::*;
656 let src = self.eval_operand(operand)?;
657 let src_layout = self.layout_of(src.ty)?;
658 let dst_layout = self.layout_of(dest_ty)?;
659 self.unsize_into(src.value, src_layout, dest, dst_layout)?;
663 let src = self.eval_operand(operand)?;
664 if self.type_is_fat_ptr(src.ty) {
665 match (src.value, self.type_is_fat_ptr(dest_ty)) {
666 (Value::ByRef { .. }, _) |
667 // pointers to extern types
668 (Value::Scalar(_),_) |
669 // slices and trait objects to other slices/trait objects
670 (Value::ScalarPair(..), true) => {
675 self.write_value(valty, dest)?;
677 // slices and trait objects to thin pointers (dropping the metadata)
678 (Value::ScalarPair(data, _), false) => {
680 value: Value::Scalar(data),
683 self.write_value(valty, dest)?;
687 let src_layout = self.layout_of(src.ty)?;
688 match src_layout.variants {
689 layout::Variants::Single { index } => {
690 if let Some(def) = src.ty.ty_adt_def() {
692 .discriminant_for_variant(*self.tcx, index)
699 return self.write_scalar(
708 layout::Variants::Tagged { .. } |
709 layout::Variants::NicheFilling { .. } => {},
712 let src_val = self.value_to_scalar(src)?;
713 let dest_val = self.cast_scalar(src_val, src.ty, dest_ty)?;
715 value: Value::Scalar(dest_val),
718 self.write_value(valty, dest)?;
723 match self.eval_operand(operand)?.ty.sty {
724 ty::TyFnDef(def_id, substs) => {
725 if self.tcx.has_attr(def_id, "rustc_args_required_const") {
726 bug!("reifying a fn ptr that requires \
729 let instance: EvalResult<'tcx, _> = ty::Instance::resolve(
734 ).ok_or_else(|| EvalErrorKind::TooGeneric.into());
735 let fn_ptr = self.memory.create_fn_alloc(instance?);
737 value: Value::Scalar(fn_ptr.into()),
740 self.write_value(valty, dest)?;
742 ref other => bug!("reify fn pointer on {:?}", other),
749 let mut src = self.eval_operand(operand)?;
751 self.write_value(src, dest)?;
753 ref other => bug!("fn to unsafe fn cast on {:?}", other),
757 ClosureFnPointer => {
758 match self.eval_operand(operand)?.ty.sty {
759 ty::TyClosure(def_id, substs) => {
760 let substs = self.tcx.subst_and_normalize_erasing_regions(
762 ty::ParamEnv::reveal_all(),
765 let instance = ty::Instance::resolve_closure(
769 ty::ClosureKind::FnOnce,
771 let fn_ptr = self.memory.create_fn_alloc(instance);
773 value: Value::Scalar(fn_ptr.into()),
776 self.write_value(valty, dest)?;
778 ref other => bug!("closure fn pointer on {:?}", other),
784 Discriminant(ref place) => {
785 let ty = self.place_ty(place);
786 let place = self.eval_place(place)?;
787 let discr_val = self.read_discriminant_value(place, ty)?;
788 let defined = self.layout_of(dest_ty).unwrap().size.bits() as u8;
789 self.write_scalar(dest, Scalar::Bits {
796 self.dump_local(dest);
801 pub(super) fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
803 ty::TyRawPtr(ty::TypeAndMut { ty, .. }) |
804 ty::TyRef(_, ty, _) => !self.type_is_sized(ty),
805 ty::TyAdt(def, _) if def.is_box() => !self.type_is_sized(ty.boxed_ty()),
810 pub(super) fn eval_operand_to_scalar(
812 op: &mir::Operand<'tcx>,
813 ) -> EvalResult<'tcx, Scalar> {
814 let valty = self.eval_operand(op)?;
815 self.value_to_scalar(valty)
818 pub(crate) fn operands_to_args(
820 ops: &[mir::Operand<'tcx>],
821 ) -> EvalResult<'tcx, Vec<ValTy<'tcx>>> {
823 .map(|op| self.eval_operand(op))
827 pub fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> {
828 use rustc::mir::Operand::*;
829 let ty = self.monomorphize(op.ty(self.mir(), *self.tcx), self.substs());
831 // FIXME: do some more logic on `move` to invalidate the old location
835 value: self.eval_and_read_place(place)?,
840 Constant(ref constant) => {
841 use rustc::mir::Literal;
842 let mir::Constant { ref literal, .. } = **constant;
843 let value = match *literal {
844 Literal::Value { ref value } => self.const_to_value(value.val)?,
846 Literal::Promoted { index } => {
847 let instance = self.frame().instance;
848 self.read_global_as_value(GlobalId {
850 promoted: Some(index),
863 /// reads a tag and produces the corresponding variant index
864 pub fn read_discriminant_as_variant_index(
868 ) -> EvalResult<'tcx, usize> {
869 let layout = self.layout_of(ty)?;
870 match layout.variants {
871 ty::layout::Variants::Single { index } => Ok(index),
872 ty::layout::Variants::Tagged { .. } => {
873 let discr_val = self.read_discriminant_value(place, ty)?;
876 .expect("tagged layout for non adt")
877 .discriminants(self.tcx.tcx)
878 .position(|var| var.val == discr_val)
879 .ok_or_else(|| EvalErrorKind::InvalidDiscriminant.into())
881 ty::layout::Variants::NicheFilling { .. } => {
882 let discr_val = self.read_discriminant_value(place, ty)?;
883 assert_eq!(discr_val as usize as u128, discr_val);
884 Ok(discr_val as usize)
889 pub fn read_discriminant_value(
893 ) -> EvalResult<'tcx, u128> {
894 let layout = self.layout_of(ty)?;
895 trace!("read_discriminant_value {:#?}", layout);
896 if layout.abi == layout::Abi::Uninhabited {
900 match layout.variants {
901 layout::Variants::Single { index } => {
902 let discr_val = ty.ty_adt_def().map_or(
904 |def| def.discriminant_for_variant(*self.tcx, index).val);
905 return Ok(discr_val);
907 layout::Variants::Tagged { .. } |
908 layout::Variants::NicheFilling { .. } => {},
911 let (discr_place, discr) = self.place_field(place, mir::Field::new(0), layout)?;
912 trace!("discr place: {:?}, {:?}", discr_place, discr);
913 let raw_discr = self.value_to_scalar(ValTy {
914 value: self.read_place(discr_place)?,
917 let discr_val = match layout.variants {
918 layout::Variants::Single { .. } => bug!(),
919 // FIXME: should we catch invalid discriminants here?
920 layout::Variants::Tagged { .. } => {
921 if discr.ty.is_signed() {
922 let i = raw_discr.to_bits(discr.size)? as i128;
923 // going from layout tag type to typeck discriminant type
924 // requires first sign extending with the layout discriminant
925 let shift = 128 - discr.size.bits();
926 let sexted = (i << shift) >> shift;
927 // and then zeroing with the typeck discriminant type
929 .ty_adt_def().expect("tagged layout corresponds to adt")
932 let discr_ty = layout::Integer::from_attr(self.tcx.tcx, discr_ty);
933 let shift = 128 - discr_ty.size().bits();
934 let truncatee = sexted as u128;
935 (truncatee << shift) >> shift
937 raw_discr.to_bits(discr.size)?
940 layout::Variants::NicheFilling {
946 let variants_start = *niche_variants.start() as u128;
947 let variants_end = *niche_variants.end() as u128;
950 assert!(niche_start == 0);
951 assert!(variants_start == variants_end);
952 dataful_variant as u128
954 Scalar::Bits { bits: raw_discr, defined } => {
955 if defined < discr.size.bits() as u8 {
956 return err!(ReadUndefBytes);
958 let discr = raw_discr.wrapping_sub(niche_start)
959 .wrapping_add(variants_start);
960 if variants_start <= discr && discr <= variants_end {
963 dataful_variant as u128
974 pub fn write_discriminant_value(
978 variant_index: usize,
979 ) -> EvalResult<'tcx> {
980 let layout = self.layout_of(dest_ty)?;
982 match layout.variants {
983 layout::Variants::Single { index } => {
984 if index != variant_index {
985 // If the layout of an enum is `Single`, all
986 // other variants are necessarily uninhabited.
987 assert_eq!(layout.for_variant(&self, variant_index).abi,
988 layout::Abi::Uninhabited);
991 layout::Variants::Tagged { ref tag, .. } => {
992 let discr_val = dest_ty.ty_adt_def().unwrap()
993 .discriminant_for_variant(*self.tcx, variant_index)
996 // raw discriminants for enums are isize or bigger during
997 // their computation, but the in-memory tag is the smallest possible
999 let size = tag.value.size(self.tcx.tcx).bits();
1000 let shift = 128 - size;
1001 let discr_val = (discr_val << shift) >> shift;
1003 let (discr_dest, tag) = self.place_field(dest, mir::Field::new(0), layout)?;
1004 self.write_scalar(discr_dest, Scalar::Bits {
1006 defined: size as u8,
1009 layout::Variants::NicheFilling {
1015 if variant_index != dataful_variant {
1016 let (niche_dest, niche) =
1017 self.place_field(dest, mir::Field::new(0), layout)?;
1018 let niche_value = ((variant_index - niche_variants.start()) as u128)
1019 .wrapping_add(niche_start);
1020 self.write_scalar(niche_dest, Scalar::Bits {
1022 defined: niche.size.bits() as u8,
1031 pub fn read_global_as_value(&mut self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, Value> {
1032 let cv = self.const_eval(gid)?;
1033 self.const_to_value(cv.val)
1036 pub fn const_eval(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> {
1037 let param_env = if self.tcx.is_static(gid.instance.def_id()).is_some() {
1038 ty::ParamEnv::reveal_all()
1042 self.tcx.const_eval(param_env.and(gid)).map_err(|err| EvalErrorKind::ReferencedConstant(err).into())
1045 pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> {
1046 let new_place = match place {
1047 Place::Local { frame, local } => {
1048 match self.stack[frame].locals[local] {
1049 None => return err!(DeadLocal),
1050 Some(Value::ByRef(ptr, align)) => {
1054 extra: PlaceExtra::None,
1058 let ty = self.stack[frame].mir.local_decls[local].ty;
1059 let ty = self.monomorphize(ty, self.stack[frame].instance.substs);
1060 let layout = self.layout_of(ty)?;
1061 let ptr = self.alloc_ptr(ty)?;
1062 self.stack[frame].locals[local] =
1063 Some(Value::ByRef(ptr.into(), layout.align)); // it stays live
1064 let place = Place::from_ptr(ptr, layout.align);
1065 self.write_value(ValTy { value: val, ty }, place)?;
1070 Place::Ptr { .. } => place,
1075 /// ensures this Value is not a ByRef
1076 pub fn follow_by_ref_value(
1080 ) -> EvalResult<'tcx, Value> {
1082 Value::ByRef(ptr, align) => {
1083 self.read_value(ptr, align, ty)
1089 pub fn value_to_scalar(
1091 ValTy { value, ty } : ValTy<'tcx>,
1092 ) -> EvalResult<'tcx, Scalar> {
1093 match self.follow_by_ref_value(value, ty)? {
1094 Value::ByRef { .. } => bug!("follow_by_ref_value can't result in `ByRef`"),
1096 Value::Scalar(scalar) => {
1097 // TODO: Do we really want insta-UB here?
1098 self.ensure_valid_value(scalar, ty)?;
1102 Value::ScalarPair(..) => bug!("value_to_scalar can't work with fat pointers"),
1106 pub fn write_ptr(&mut self, dest: Place, val: Scalar, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> {
1108 value: val.to_value(),
1111 self.write_value(valty, dest)
1114 pub fn write_scalar(
1119 ) -> EvalResult<'tcx> {
1121 value: Value::Scalar(val),
1124 self.write_value(valty, dest)
1129 ValTy { value: src_val, ty: dest_ty } : ValTy<'tcx>,
1131 ) -> EvalResult<'tcx> {
1132 //trace!("Writing {:?} to {:?} at type {:?}", src_val, dest, dest_ty);
1133 // Note that it is really important that the type here is the right one, and matches the type things are read at.
1134 // In case `src_val` is a `ScalarPair`, we don't do any magic here to handle padding properly, which is only
1135 // correct if we never look at this data with the wrong type.
1138 Place::Ptr { ptr, align, extra } => {
1139 assert_eq!(extra, PlaceExtra::None);
1140 self.write_value_to_ptr(src_val, ptr, align, dest_ty)
1143 Place::Local { frame, local } => {
1144 let dest = self.stack[frame].get_local(local)?;
1145 self.write_value_possibly_by_val(
1147 |this, val| this.stack[frame].set_local(local, val),
1155 // The cases here can be a bit subtle. Read carefully!
1156 fn write_value_possibly_by_val<F: FnOnce(&mut Self, Value) -> EvalResult<'tcx>>(
1160 old_dest_val: Value,
1162 ) -> EvalResult<'tcx> {
1163 if let Value::ByRef(dest_ptr, align) = old_dest_val {
1164 // If the value is already `ByRef` (that is, backed by an `Allocation`),
1165 // then we must write the new value into this allocation, because there may be
1166 // other pointers into the allocation. These other pointers are logically
1167 // pointers into the local variable, and must be able to observe the change.
1169 // Thus, it would be an error to replace the `ByRef` with a `ByVal`, unless we
1170 // knew for certain that there were no outstanding pointers to this allocation.
1171 self.write_value_to_ptr(src_val, dest_ptr, align, dest_ty)?;
1172 } else if let Value::ByRef(src_ptr, align) = src_val {
1173 // If the value is not `ByRef`, then we know there are no pointers to it
1174 // and we can simply overwrite the `Value` in the locals array directly.
1176 // In this specific case, where the source value is `ByRef`, we must duplicate
1177 // the allocation, because this is a by-value operation. It would be incorrect
1178 // if they referred to the same allocation, since then a change to one would
1179 // implicitly change the other.
1181 // It is a valid optimization to attempt reading a primitive value out of the
1182 // source and write that into the destination without making an allocation, so
1184 if let Ok(Some(src_val)) = self.try_read_value(src_ptr, align, dest_ty) {
1185 write_dest(self, src_val)?;
1187 let dest_ptr = self.alloc_ptr(dest_ty)?.into();
1188 let layout = self.layout_of(dest_ty)?;
1189 self.memory.copy(src_ptr, align.min(layout.align), dest_ptr, layout.align, layout.size, false)?;
1190 write_dest(self, Value::ByRef(dest_ptr, layout.align))?;
1193 // Finally, we have the simple case where neither source nor destination are
1194 // `ByRef`. We may simply copy the source value over the the destintion.
1195 write_dest(self, src_val)?;
1200 pub fn write_value_to_ptr(
1206 ) -> EvalResult<'tcx> {
1207 let layout = self.layout_of(dest_ty)?;
1208 trace!("write_value_to_ptr: {:#?}, {}, {:#?}", value, dest_ty, layout);
1210 Value::ByRef(ptr, align) => {
1211 self.memory.copy(ptr, align.min(layout.align), dest, dest_align.min(layout.align), layout.size, false)
1213 Value::Scalar(scalar) => {
1214 let signed = match layout.abi {
1215 layout::Abi::Scalar(ref scal) => match scal.value {
1216 layout::Primitive::Int(_, signed) => signed,
1220 Scalar::Bits { defined: 0, .. } => false,
1221 _ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout),
1224 self.memory.write_scalar(dest, dest_align, scalar, layout.size, signed)
1226 Value::ScalarPair(a_val, b_val) => {
1227 trace!("write_value_to_ptr valpair: {:#?}", layout);
1228 let (a, b) = match layout.abi {
1229 layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
1230 _ => bug!("write_value_to_ptr: invalid ScalarPair layout: {:#?}", layout)
1232 let (a_size, b_size) = (a.size(&self), b.size(&self));
1234 let b_offset = a_size.abi_align(b.align(&self));
1235 let b_ptr = dest.ptr_offset(b_offset, &self)?.into();
1236 // TODO: What about signedess?
1237 self.memory.write_scalar(a_ptr, dest_align, a_val, a_size, false)?;
1238 self.memory.write_scalar(b_ptr, dest_align, b_val, b_size, false)
1243 fn ensure_valid_value(&self, val: Scalar, ty: Ty<'tcx>) -> EvalResult<'tcx> {
1245 ty::TyBool => val.to_bool().map(|_| ()),
1247 ty::TyChar if ::std::char::from_u32(val.to_bits(Size::from_bytes(4))? as u32).is_none() => {
1248 err!(InvalidChar(val.to_bits(Size::from_bytes(4))? as u32 as u128))
1255 pub fn read_value(&self, ptr: Scalar, align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
1256 if let Some(val) = self.try_read_value(ptr, align, ty)? {
1259 bug!("primitive read failed for type: {:?}", ty);
1263 pub(crate) fn read_ptr(
1267 pointee_ty: Ty<'tcx>,
1268 ) -> EvalResult<'tcx, Value> {
1269 let ptr_size = self.memory.pointer_size();
1270 let p: Scalar = self.memory.read_ptr_sized(ptr, ptr_align)?.into();
1271 if self.type_is_sized(pointee_ty) {
1274 trace!("reading fat pointer extra of type {}", pointee_ty);
1275 let extra = ptr.offset(ptr_size, self)?;
1276 match self.tcx.struct_tail(pointee_ty).sty {
1277 ty::TyDynamic(..) => Ok(p.to_value_with_vtable(
1278 self.memory.read_ptr_sized(extra, ptr_align)?.to_ptr()?,
1280 ty::TySlice(..) | ty::TyStr => {
1283 .read_ptr_sized(extra, ptr_align)?
1284 .to_bits(ptr_size)?;
1285 Ok(p.to_value_with_len(len as u64, self.tcx.tcx))
1287 _ => bug!("unsized scalar ptr read from {:?}", pointee_ty),
1292 pub fn validate_ptr_target(
1297 ) -> EvalResult<'tcx> {
1300 self.memory.read_scalar(ptr, ptr_align, Size::from_bytes(1))?.to_bool()?;
1303 let c = self.memory.read_scalar(ptr, ptr_align, Size::from_bytes(4))?.to_bits(Size::from_bytes(4))? as u32;
1304 match ::std::char::from_u32(c) {
1306 None => return err!(InvalidChar(c as u128)),
1311 self.memory.read_ptr_sized(ptr, ptr_align)?;
1313 ty::TyRef(_, rty, _) |
1314 ty::TyRawPtr(ty::TypeAndMut { ty: rty, .. }) => {
1315 self.read_ptr(ptr, ptr_align, rty)?;
1318 ty::TyAdt(def, _) => {
1320 self.read_ptr(ptr, ptr_align, ty.boxed_ty())?;
1324 if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi {
1325 let size = scalar.value.size(self);
1326 self.memory.read_scalar(ptr, ptr_align, size)?;
1335 pub fn try_read_by_ref(&self, mut val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
1336 // Convert to ByVal or ScalarPair if possible
1337 if let Value::ByRef(ptr, align) = val {
1338 if let Some(read_val) = self.try_read_value(ptr, align, ty)? {
1345 pub fn try_read_value(&self, ptr: Scalar, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
1346 let layout = self.layout_of(ty)?;
1347 self.memory.check_align(ptr, ptr_align)?;
1349 if layout.size.bytes() == 0 {
1350 return Ok(Some(Value::Scalar(Scalar::undef())));
1353 let ptr = ptr.to_ptr()?;
1355 // Not the right place to do this
1356 //self.validate_ptr_target(ptr, ptr_align, ty)?;
1359 layout::Abi::Scalar(..) => {
1360 let scalar = self.memory.read_scalar(ptr, ptr_align, layout.size)?;
1361 Ok(Some(Value::Scalar(scalar)))
1363 layout::Abi::ScalarPair(ref a, ref b) => {
1364 let (a, b) = (&a.value, &b.value);
1365 let (a_size, b_size) = (a.size(self), b.size(self));
1367 let b_offset = a_size.abi_align(b.align(self));
1368 let b_ptr = ptr.offset(b_offset, self)?.into();
1369 let a_val = self.memory.read_scalar(a_ptr, ptr_align, a_size)?;
1370 let b_val = self.memory.read_scalar(b_ptr, ptr_align, b_size)?;
1371 Ok(Some(Value::ScalarPair(a_val, b_val)))
1377 pub fn frame(&self) -> &Frame<'mir, 'tcx> {
1378 self.stack.last().expect("no call frames exist")
1381 pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> {
1382 self.stack.last_mut().expect("no call frames exist")
1385 pub(super) fn mir(&self) -> &'mir mir::Mir<'tcx> {
1389 pub fn substs(&self) -> &'tcx Substs<'tcx> {
1390 if let Some(frame) = self.stack.last() {
1391 frame.instance.substs
1405 ) -> EvalResult<'tcx> {
1406 // A<Struct> -> A<Trait> conversion
1407 let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty);
1409 match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
1410 (&ty::TyArray(_, length), &ty::TySlice(_)) => {
1411 let ptr = self.into_ptr(src)?;
1412 // u64 cast is from usize to u64, which is always good
1414 value: ptr.to_value_with_len(length.unwrap_usize(self.tcx.tcx), self.tcx.tcx),
1417 self.write_value(valty, dest)
1419 (&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
1420 // For now, upcasts are limited to changes in marker
1421 // traits, and hence never actually require an actual
1422 // change to the vtable.
1427 self.write_value(valty, dest)
1429 (_, &ty::TyDynamic(ref data, _)) => {
1430 let trait_ref = data.principal().unwrap().with_self_ty(
1434 let trait_ref = self.tcx.erase_regions(&trait_ref);
1435 let vtable = self.get_vtable(src_pointee_ty, trait_ref)?;
1436 let ptr = self.into_ptr(src)?;
1438 value: ptr.to_value_with_vtable(vtable),
1441 self.write_value(valty, dest)
1444 _ => bug!("invalid unsizing {:?} -> {:?}", src_ty, dest_ty),
1451 src_layout: TyLayout<'tcx>,
1453 dst_layout: TyLayout<'tcx>,
1454 ) -> EvalResult<'tcx> {
1455 match (&src_layout.ty.sty, &dst_layout.ty.sty) {
1456 (&ty::TyRef(_, s, _), &ty::TyRef(_, d, _)) |
1457 (&ty::TyRef(_, s, _), &ty::TyRawPtr(TypeAndMut { ty: d, .. })) |
1458 (&ty::TyRawPtr(TypeAndMut { ty: s, .. }),
1459 &ty::TyRawPtr(TypeAndMut { ty: d, .. })) => {
1460 self.unsize_into_ptr(src, src_layout.ty, dst, dst_layout.ty, s, d)
1462 (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => {
1463 assert_eq!(def_a, def_b);
1464 if def_a.is_box() || def_b.is_box() {
1465 if !def_a.is_box() || !def_b.is_box() {
1466 bug!("invalid unsizing between {:?} -> {:?}", src_layout, dst_layout);
1468 return self.unsize_into_ptr(
1473 src_layout.ty.boxed_ty(),
1474 dst_layout.ty.boxed_ty(),
1478 // unsizing of generic struct with pointer fields
1479 // Example: `Arc<T>` -> `Arc<Trait>`
1480 // here we need to increase the size of every &T thin ptr field to a fat ptr
1481 for i in 0..src_layout.fields.count() {
1482 let (dst_f_place, dst_field) =
1483 self.place_field(dst, mir::Field::new(i), dst_layout)?;
1484 if dst_field.is_zst() {
1487 let (src_f_value, src_field) = match src {
1488 Value::ByRef(ptr, align) => {
1489 let src_place = Place::from_scalar_ptr(ptr, align);
1490 let (src_f_place, src_field) =
1491 self.place_field(src_place, mir::Field::new(i), src_layout)?;
1492 (self.read_place(src_f_place)?, src_field)
1494 Value::Scalar(_) | Value::ScalarPair(..) => {
1495 let src_field = src_layout.field(&self, i)?;
1496 assert_eq!(src_layout.fields.offset(i).bytes(), 0);
1497 assert_eq!(src_field.size, src_layout.size);
1501 if src_field.ty == dst_field.ty {
1502 self.write_value(ValTy {
1507 self.unsize_into(src_f_value, src_field, dst_f_place, dst_field)?;
1514 "unsize_into: invalid conversion: {:?} -> {:?}",
1522 pub fn dump_local(&self, place: Place) {
1524 if !log_enabled!(::log::Level::Trace) {
1528 Place::Local { frame, local } => {
1529 let mut allocs = Vec::new();
1530 let mut msg = format!("{:?}", local);
1531 if frame != self.cur_frame() {
1532 write!(msg, " ({} frames up)", self.cur_frame() - frame).unwrap();
1534 write!(msg, ":").unwrap();
1536 match self.stack[frame].get_local(local) {
1538 if let EvalErrorKind::DeadLocal = err.kind {
1539 write!(msg, " is dead").unwrap();
1541 panic!("Failed to access local: {:?}", err);
1544 Ok(Value::ByRef(ptr, align)) => {
1546 Scalar::Ptr(ptr) => {
1547 write!(msg, " by align({}) ref:", align.abi()).unwrap();
1548 allocs.push(ptr.alloc_id);
1550 ptr => write!(msg, " integral by ref: {:?}", ptr).unwrap(),
1553 Ok(Value::Scalar(val)) => {
1554 write!(msg, " {:?}", val).unwrap();
1555 if let Scalar::Ptr(ptr) = val {
1556 allocs.push(ptr.alloc_id);
1559 Ok(Value::ScalarPair(val1, val2)) => {
1560 write!(msg, " ({:?}, {:?})", val1, val2).unwrap();
1561 if let Scalar::Ptr(ptr) = val1 {
1562 allocs.push(ptr.alloc_id);
1564 if let Scalar::Ptr(ptr) = val2 {
1565 allocs.push(ptr.alloc_id);
1571 self.memory.dump_allocs(allocs);
1573 Place::Ptr { ptr, align, .. } => {
1575 Scalar::Ptr(ptr) => {
1576 trace!("by align({}) ref:", align.abi());
1577 self.memory.dump_alloc(ptr.alloc_id);
1579 ptr => trace!(" integral by ref: {:?}", ptr),
1585 /// Convenience function to ensure correct usage of locals
1586 pub fn modify_local<F>(&mut self, frame: usize, local: mir::Local, f: F) -> EvalResult<'tcx>
1588 F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
1590 let val = self.stack[frame].get_local(local)?;
1591 let new_val = f(self, val)?;
1592 self.stack[frame].set_local(local, new_val)?;
1593 // FIXME(solson): Run this when setting to Undef? (See previous version of this code.)
1594 // if let Value::ByRef(ptr) = self.stack[frame].get_local(local) {
1595 // self.memory.deallocate(ptr)?;
1600 pub fn generate_stacktrace(&self, explicit_span: Option<Span>) -> (Vec<FrameInfo>, Span) {
1601 let mut last_span = None;
1602 let mut frames = Vec::new();
1603 // skip 1 because the last frame is just the environment of the constant
1604 for &Frame { instance, span, mir, block, stmt, .. } in self.stack().iter().skip(1).rev() {
1605 // make sure we don't emit frames that are duplicates of the previous
1606 if explicit_span == Some(span) {
1607 last_span = Some(span);
1610 if let Some(last) = last_span {
1615 last_span = Some(span);
1617 let location = if self.tcx.def_key(instance.def_id()).disambiguated_data.data == DefPathData::ClosureExpr {
1618 "closure".to_owned()
1620 instance.to_string()
1622 let block = &mir.basic_blocks()[block];
1623 let source_info = if stmt < block.statements.len() {
1624 block.statements[stmt].source_info
1626 block.terminator().source_info
1628 let lint_root = match mir.source_scope_local_data {
1629 mir::ClearCrossCrate::Set(ref ivs) => Some(ivs[source_info.scope].lint_root),
1630 mir::ClearCrossCrate::Clear => None,
1632 frames.push(FrameInfo { span, location, lint_root });
1634 trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span);
1635 (frames, self.tcx.span)
1638 pub fn sign_extend(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
1639 super::sign_extend(self.tcx.tcx, value, ty)
1642 pub fn truncate(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
1643 super::truncate(self.tcx.tcx, value, ty)
1647 impl<'mir, 'tcx> Frame<'mir, 'tcx> {
1648 pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> {
1649 self.locals[local].ok_or_else(|| EvalErrorKind::DeadLocal.into())
1652 fn set_local(&mut self, local: mir::Local, value: Value) -> EvalResult<'tcx> {
1653 match self.locals[local] {
1654 None => err!(DeadLocal),
1655 Some(ref mut local) => {
1662 pub fn storage_live(&mut self, local: mir::Local) -> Option<Value> {
1663 trace!("{:?} is now live", local);
1665 // StorageLive *always* kills the value that's currently stored
1666 mem::replace(&mut self.locals[local], Some(Value::Scalar(Scalar::undef())))
1669 /// Returns the old value of the local
1670 pub fn storage_dead(&mut self, local: mir::Local) -> Option<Value> {
1671 trace!("{:?} is now dead", local);
1673 self.locals[local].take()