]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/eval_context.rs
8ae0345e07a34a5da3fae486c8b1c56b35fefcf3
[rust.git] / src / librustc_mir / interpret / eval_context.rs
1 // Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use std::fmt::Write;
12 use std::mem;
13
14 use syntax::source_map::{self, Span, DUMMY_SP};
15 use rustc::hir::def_id::DefId;
16 use rustc::hir::def::Def;
17 use rustc::mir;
18 use rustc::ty::layout::{
19     self, Size, Align, HasDataLayout, LayoutOf, TyLayout
20 };
21 use rustc::ty::subst::{Subst, Substs};
22 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
23 use rustc::ty::query::TyCtxtAt;
24 use rustc_data_structures::indexed_vec::IndexVec;
25 use rustc::mir::interpret::{
26     ErrorHandled,
27     GlobalId, Scalar, FrameInfo, AllocId,
28     EvalResult, EvalErrorKind,
29     truncate, sign_extend,
30 };
31 use rustc_data_structures::fx::FxHashMap;
32
33 use super::{
34     Immediate, Operand, MemPlace, MPlaceTy, Place, PlaceTy, ScalarMaybeUndef,
35     Memory, Machine
36 };
37
38 pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> {
39     /// Stores the `Machine` instance.
40     pub machine: M,
41
42     /// The results of the type checker, from rustc.
43     pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
44
45     /// Bounds in scope for polymorphic evaluations.
46     pub(crate) param_env: ty::ParamEnv<'tcx>,
47
48     /// The virtual memory system.
49     pub(crate) memory: Memory<'a, 'mir, 'tcx, M>,
50
51     /// The virtual call stack.
52     pub(crate) stack: Vec<Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>>,
53
54     /// A cache for deduplicating vtables
55     pub(super) vtables: FxHashMap<(Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>), AllocId>,
56 }
57
58 /// A stack frame.
59 #[derive(Clone)]
60 pub struct Frame<'mir, 'tcx: 'mir, Tag=(), Extra=()> {
61     ////////////////////////////////////////////////////////////////////////////////
62     // Function and callsite information
63     ////////////////////////////////////////////////////////////////////////////////
64     /// The MIR for the function called on this frame.
65     pub mir: &'mir mir::Mir<'tcx>,
66
67     /// The def_id and substs of the current function
68     pub instance: ty::Instance<'tcx>,
69
70     /// The span of the call site.
71     pub span: source_map::Span,
72
73     ////////////////////////////////////////////////////////////////////////////////
74     // Return place and locals
75     ////////////////////////////////////////////////////////////////////////////////
76     /// Work to perform when returning from this function
77     pub return_to_block: StackPopCleanup,
78
79     /// The location where the result of the current stack frame should be written to,
80     /// and its layout in the caller.
81     pub return_place: Option<PlaceTy<'tcx, Tag>>,
82
83     /// The list of locals for this stack frame, stored in order as
84     /// `[return_ptr, arguments..., variables..., temporaries...]`.
85     /// The locals are stored as `Option<Value>`s.
86     /// `None` represents a local that is currently dead, while a live local
87     /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
88     pub locals: IndexVec<mir::Local, LocalValue<Tag>>,
89
90     ////////////////////////////////////////////////////////////////////////////////
91     // Current position within the function
92     ////////////////////////////////////////////////////////////////////////////////
93     /// The block that is currently executed (or will be executed after the above call stacks
94     /// return).
95     pub block: mir::BasicBlock,
96
97     /// The index of the currently evaluated statement.
98     pub stmt: usize,
99
100     /// Extra data for the machine
101     pub extra: Extra,
102 }
103
104 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
105 pub enum StackPopCleanup {
106     /// Jump to the next block in the caller, or cause UB if None (that's a function
107     /// that may never return). Also store layout of return place so
108     /// we can validate it at that layout.
109     Goto(Option<mir::BasicBlock>),
110     /// Just do nohing: Used by Main and for the box_alloc hook in miri.
111     /// `cleanup` says whether locals are deallocated.  Static computation
112     /// wants them leaked to intern what they need (and just throw away
113     /// the entire `ecx` when it is done).
114     None { cleanup: bool },
115 }
116
117 // State of a local variable
118 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
119 pub enum LocalValue<Tag=(), Id=AllocId> {
120     Dead,
121     // Mostly for convenience, we re-use the `Operand` type here.
122     // This is an optimization over just always having a pointer here;
123     // we can thus avoid doing an allocation when the local just stores
124     // immediate values *and* never has its address taken.
125     Live(Operand<Tag, Id>),
126 }
127
128 impl<'tcx, Tag> LocalValue<Tag> {
129     pub fn access(&self) -> EvalResult<'tcx, &Operand<Tag>> {
130         match self {
131             LocalValue::Dead => err!(DeadLocal),
132             LocalValue::Live(ref val) => Ok(val),
133         }
134     }
135
136     pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand<Tag>> {
137         match self {
138             LocalValue::Dead => err!(DeadLocal),
139             LocalValue::Live(ref mut val) => Ok(val),
140         }
141     }
142 }
143
144 impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> HasDataLayout
145     for EvalContext<'a, 'mir, 'tcx, M>
146 {
147     #[inline]
148     fn data_layout(&self) -> &layout::TargetDataLayout {
149         &self.tcx.data_layout
150     }
151 }
152
153 impl<'a, 'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for EvalContext<'a, 'mir, 'tcx, M>
154     where M: Machine<'a, 'mir, 'tcx>
155 {
156     #[inline]
157     fn tcx<'d>(&'d self) -> TyCtxt<'d, 'tcx, 'tcx> {
158         *self.tcx
159     }
160 }
161
162 impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> LayoutOf
163     for EvalContext<'a, 'mir, 'tcx, M>
164 {
165     type Ty = Ty<'tcx>;
166     type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
167
168     #[inline]
169     fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
170         self.tcx.layout_of(self.param_env.and(ty))
171             .map_err(|layout| EvalErrorKind::Layout(layout).into())
172     }
173 }
174
175 impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
176     pub fn new(
177         tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
178         param_env: ty::ParamEnv<'tcx>,
179         machine: M,
180     ) -> Self {
181         EvalContext {
182             machine,
183             tcx,
184             param_env,
185             memory: Memory::new(tcx),
186             stack: Vec::new(),
187             vtables: FxHashMap::default(),
188         }
189     }
190
191     #[inline(always)]
192     pub fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
193         &self.memory
194     }
195
196     #[inline(always)]
197     pub fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
198         &mut self.memory
199     }
200
201     #[inline(always)]
202     pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] {
203         &self.stack
204     }
205
206     #[inline(always)]
207     pub fn cur_frame(&self) -> usize {
208         assert!(self.stack.len() > 0);
209         self.stack.len() - 1
210     }
211
212     #[inline(always)]
213     pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> {
214         self.stack.last().expect("no call frames exist")
215     }
216
217     #[inline(always)]
218     pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> {
219         self.stack.last_mut().expect("no call frames exist")
220     }
221
222     #[inline(always)]
223     pub(super) fn mir(&self) -> &'mir mir::Mir<'tcx> {
224         self.frame().mir
225     }
226
227     pub fn substs(&self) -> &'tcx Substs<'tcx> {
228         if let Some(frame) = self.stack.last() {
229             frame.instance.substs
230         } else {
231             Substs::empty()
232         }
233     }
234
235     pub(super) fn resolve(
236         &self,
237         def_id: DefId,
238         substs: &'tcx Substs<'tcx>
239     ) -> EvalResult<'tcx, ty::Instance<'tcx>> {
240         trace!("resolve: {:?}, {:#?}", def_id, substs);
241         trace!("substs: {:#?}", self.substs());
242         trace!("param_env: {:#?}", self.param_env);
243         let substs = self.tcx.subst_and_normalize_erasing_regions(
244             self.substs(),
245             self.param_env,
246             &substs,
247         );
248         ty::Instance::resolve(
249             *self.tcx,
250             self.param_env,
251             def_id,
252             substs,
253         ).ok_or_else(|| EvalErrorKind::TooGeneric.into())
254     }
255
256     pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
257         ty.is_sized(self.tcx, self.param_env)
258     }
259
260     pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
261         ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP)
262     }
263
264     pub fn load_mir(
265         &self,
266         instance: ty::InstanceDef<'tcx>,
267     ) -> EvalResult<'tcx, &'tcx mir::Mir<'tcx>> {
268         // do not continue if typeck errors occurred (can only occur in local crate)
269         let did = instance.def_id();
270         if did.is_local()
271             && self.tcx.has_typeck_tables(did)
272             && self.tcx.typeck_tables_of(did).tainted_by_errors
273         {
274             return err!(TypeckError);
275         }
276         trace!("load mir {:?}", instance);
277         match instance {
278             ty::InstanceDef::Item(def_id) => {
279                 self.tcx.maybe_optimized_mir(def_id).ok_or_else(||
280                     EvalErrorKind::NoMirFor(self.tcx.item_path_str(def_id)).into()
281                 )
282             }
283             _ => Ok(self.tcx.instance_mir(instance)),
284         }
285     }
286
287     pub fn monomorphize<T: TypeFoldable<'tcx> + Subst<'tcx>>(
288         &self,
289         t: T,
290         substs: &'tcx Substs<'tcx>
291     ) -> T {
292         // miri doesn't care about lifetimes, and will choke on some crazy ones
293         // let's simply get rid of them
294         let substituted = t.subst(*self.tcx, substs);
295         self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted)
296     }
297
298     pub fn layout_of_local(
299         &self,
300         frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
301         local: mir::Local
302     ) -> EvalResult<'tcx, TyLayout<'tcx>> {
303         let local_ty = frame.mir.local_decls[local].ty;
304         let local_ty = self.monomorphize(local_ty, frame.instance.substs);
305         self.layout_of(local_ty)
306     }
307
308     pub fn str_to_immediate(&mut self, s: &str) -> EvalResult<'tcx, Immediate<M::PointerTag>> {
309         let ptr = self.memory.allocate_static_bytes(s.as_bytes()).with_default_tag();
310         Ok(Immediate::new_slice(Scalar::Ptr(ptr), s.len() as u64, self))
311     }
312
313     /// Return the actual dynamic size and alignment of the place at the given type.
314     /// Only the "meta" (metadata) part of the place matters.
315     /// This can fail to provide an answer for extern types.
316     pub(super) fn size_and_align_of(
317         &self,
318         metadata: Option<Scalar<M::PointerTag>>,
319         layout: TyLayout<'tcx>,
320     ) -> EvalResult<'tcx, Option<(Size, Align)>> {
321         if !layout.is_unsized() {
322             return Ok(Some((layout.size, layout.align.abi)));
323         }
324         match layout.ty.sty {
325             ty::Adt(..) | ty::Tuple(..) => {
326                 // First get the size of all statically known fields.
327                 // Don't use type_of::sizing_type_of because that expects t to be sized,
328                 // and it also rounds up to alignment, which we want to avoid,
329                 // as the unsized field's alignment could be smaller.
330                 assert!(!layout.ty.is_simd());
331                 trace!("DST layout: {:?}", layout);
332
333                 let sized_size = layout.fields.offset(layout.fields.count() - 1);
334                 let sized_align = layout.align.abi;
335                 trace!(
336                     "DST {} statically sized prefix size: {:?} align: {:?}",
337                     layout.ty,
338                     sized_size,
339                     sized_align
340                 );
341
342                 // Recurse to get the size of the dynamically sized field (must be
343                 // the last field).  Can't have foreign types here, how would we
344                 // adjust alignment and size for them?
345                 let field = layout.field(self, layout.fields.count() - 1)?;
346                 let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? {
347                     Some(size_and_align) => size_and_align,
348                     None => {
349                         // A field with extern type.  If this field is at offset 0, we behave
350                         // like the underlying extern type.
351                         // FIXME: Once we have made decisions for how to handle size and alignment
352                         // of `extern type`, this should be adapted.  It is just a temporary hack
353                         // to get some code to work that probably ought to work.
354                         if sized_size == Size::ZERO {
355                             return Ok(None)
356                         } else {
357                             bug!("Fields cannot be extern types, unless they are at offset 0")
358                         }
359                     }
360                 };
361
362                 // FIXME (#26403, #27023): We should be adding padding
363                 // to `sized_size` (to accommodate the `unsized_align`
364                 // required of the unsized field that follows) before
365                 // summing it with `sized_size`. (Note that since #26403
366                 // is unfixed, we do not yet add the necessary padding
367                 // here. But this is where the add would go.)
368
369                 // Return the sum of sizes and max of aligns.
370                 let size = sized_size + unsized_size;
371
372                 // Choose max of two known alignments (combined value must
373                 // be aligned according to more restrictive of the two).
374                 let align = sized_align.max(unsized_align);
375
376                 // Issue #27023: must add any necessary padding to `size`
377                 // (to make it a multiple of `align`) before returning it.
378                 //
379                 // Namely, the returned size should be, in C notation:
380                 //
381                 //   `size + ((size & (align-1)) ? align : 0)`
382                 //
383                 // emulated via the semi-standard fast bit trick:
384                 //
385                 //   `(size + (align-1)) & -align`
386
387                 Ok(Some((size.align_to(align), align)))
388             }
389             ty::Dynamic(..) => {
390                 let vtable = metadata.expect("dyn trait fat ptr must have vtable").to_ptr()?;
391                 // the second entry in the vtable is the dynamic size of the object.
392                 Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
393             }
394
395             ty::Slice(_) | ty::Str => {
396                 let len = metadata.expect("slice fat ptr must have vtable").to_usize(self)?;
397                 let elem = layout.field(self, 0)?;
398                 Ok(Some((elem.size * len, elem.align.abi)))
399             }
400
401             ty::Foreign(_) => {
402                 Ok(None)
403             }
404
405             _ => bug!("size_and_align_of::<{:?}> not supported", layout.ty),
406         }
407     }
408     #[inline]
409     pub fn size_and_align_of_mplace(
410         &self,
411         mplace: MPlaceTy<'tcx, M::PointerTag>
412     ) -> EvalResult<'tcx, Option<(Size, Align)>> {
413         self.size_and_align_of(mplace.meta, mplace.layout)
414     }
415
416     pub fn push_stack_frame(
417         &mut self,
418         instance: ty::Instance<'tcx>,
419         span: source_map::Span,
420         mir: &'mir mir::Mir<'tcx>,
421         return_place: Option<PlaceTy<'tcx, M::PointerTag>>,
422         return_to_block: StackPopCleanup,
423     ) -> EvalResult<'tcx> {
424         if self.stack.len() > 1 { // FIXME should be "> 0", printing topmost frame crashes rustc...
425             info!("PAUSING({}) {}", self.cur_frame(), self.frame().instance);
426         }
427         ::log_settings::settings().indentation += 1;
428
429         // first push a stack frame so we have access to the local substs
430         let extra = M::stack_push(self)?;
431         self.stack.push(Frame {
432             mir,
433             block: mir::START_BLOCK,
434             return_to_block,
435             return_place,
436             // empty local array, we fill it in below, after we are inside the stack frame and
437             // all methods actually know about the frame
438             locals: IndexVec::new(),
439             span,
440             instance,
441             stmt: 0,
442             extra,
443         });
444
445         // don't allocate at all for trivial constants
446         if mir.local_decls.len() > 1 {
447             // We put some marker immediate into the locals that we later want to initialize.
448             // This can be anything except for LocalValue::Dead -- because *that* is the
449             // value we use for things that we know are initially dead.
450             let dummy =
451                 LocalValue::Live(Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef)));
452             let mut locals = IndexVec::from_elem(dummy, &mir.local_decls);
453             // Return place is handled specially by the `eval_place` functions, and the
454             // entry in `locals` should never be used. Make it dead, to be sure.
455             locals[mir::RETURN_PLACE] = LocalValue::Dead;
456             // Now mark those locals as dead that we do not want to initialize
457             match self.tcx.describe_def(instance.def_id()) {
458                 // statics and constants don't have `Storage*` statements, no need to look for them
459                 Some(Def::Static(..)) | Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {},
460                 _ => {
461                     trace!("push_stack_frame: {:?}: num_bbs: {}", span, mir.basic_blocks().len());
462                     for block in mir.basic_blocks() {
463                         for stmt in block.statements.iter() {
464                             use rustc::mir::StatementKind::{StorageDead, StorageLive};
465                             match stmt.kind {
466                                 StorageLive(local) |
467                                 StorageDead(local) => {
468                                     locals[local] = LocalValue::Dead;
469                                 }
470                                 _ => {}
471                             }
472                         }
473                     }
474                 },
475             }
476             // Finally, properly initialize all those that still have the dummy value
477             for (local, decl) in locals.iter_mut().zip(mir.local_decls.iter()) {
478                 match *local {
479                     LocalValue::Live(_) => {
480                         // This needs to be peoperly initialized.
481                         let layout = self.layout_of(self.monomorphize(decl.ty, instance.substs))?;
482                         *local = LocalValue::Live(self.uninit_operand(layout)?);
483                     }
484                     LocalValue::Dead => {
485                         // Nothing to do
486                     }
487                 }
488             }
489             // done
490             self.frame_mut().locals = locals;
491         }
492
493         if self.stack.len() > 1 { // FIXME no check should be needed, but some instances ICE
494             info!("ENTERING({}) {}", self.cur_frame(), self.frame().instance);
495         }
496
497         if self.stack.len() > self.tcx.sess.const_eval_stack_frame_limit {
498             err!(StackFrameLimitReached)
499         } else {
500             Ok(())
501         }
502     }
503
504     pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
505         if self.stack.len() > 1 { // FIXME no check should be needed, but some instances ICE
506             info!("LEAVING({}) {}", self.cur_frame(), self.frame().instance);
507         }
508         ::log_settings::settings().indentation -= 1;
509         let frame = self.stack.pop().expect(
510             "tried to pop a stack frame, but there were none",
511         );
512         M::stack_pop(self, frame.extra)?;
513         // Abort early if we do not want to clean up: We also avoid validation in that case,
514         // because this is CTFE and the final value will be thoroughly validated anyway.
515         match frame.return_to_block {
516             StackPopCleanup::Goto(_) => {},
517             StackPopCleanup::None { cleanup } => {
518                 if !cleanup {
519                     assert!(self.stack.is_empty(), "only the topmost frame should ever be leaked");
520                     // Leak the locals, skip validation.
521                     return Ok(());
522                 }
523             }
524         }
525         // Deallocate all locals that are backed by an allocation.
526         for local in frame.locals {
527             self.deallocate_local(local)?;
528         }
529         // Validate the return value. Do this after deallocating so that we catch dangling
530         // references.
531         if let Some(return_place) = frame.return_place {
532             if M::enforce_validity(self) {
533                 // Data got changed, better make sure it matches the type!
534                 // It is still possible that the return place held invalid data while
535                 // the function is running, but that's okay because nobody could have
536                 // accessed that same data from the "outside" to observe any broken
537                 // invariant -- that is, unless a function somehow has a ptr to
538                 // its return place... but the way MIR is currently generated, the
539                 // return place is always a local and then this cannot happen.
540                 self.validate_operand(
541                     self.place_to_op(return_place)?,
542                     vec![],
543                     None,
544                     /*const_mode*/false,
545                 )?;
546             }
547         } else {
548             // Uh, that shouldn't happen... the function did not intend to return
549             return err!(Unreachable);
550         }
551         // Jump to new block -- *after* validation so that the spans make more sense.
552         match frame.return_to_block {
553             StackPopCleanup::Goto(block) => {
554                 self.goto_block(block)?;
555             }
556             StackPopCleanup::None { .. } => {}
557         }
558
559         if self.stack.len() > 1 { // FIXME should be "> 0", printing topmost frame crashes rustc...
560             info!("CONTINUING({}) {}", self.cur_frame(), self.frame().instance);
561         }
562
563         Ok(())
564     }
565
566     /// Mark a storage as live, killing the previous content and returning it.
567     /// Remember to deallocate that!
568     pub fn storage_live(
569         &mut self,
570         local: mir::Local
571     ) -> EvalResult<'tcx, LocalValue<M::PointerTag>> {
572         assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
573         trace!("{:?} is now live", local);
574
575         let layout = self.layout_of_local(self.frame(), local)?;
576         let init = LocalValue::Live(self.uninit_operand(layout)?);
577         // StorageLive *always* kills the value that's currently stored
578         Ok(mem::replace(&mut self.frame_mut().locals[local], init))
579     }
580
581     /// Returns the old value of the local.
582     /// Remember to deallocate that!
583     pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue<M::PointerTag> {
584         assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
585         trace!("{:?} is now dead", local);
586
587         mem::replace(&mut self.frame_mut().locals[local], LocalValue::Dead)
588     }
589
590     pub(super) fn deallocate_local(
591         &mut self,
592         local: LocalValue<M::PointerTag>,
593     ) -> EvalResult<'tcx> {
594         // FIXME: should we tell the user that there was a local which was never written to?
595         if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
596             trace!("deallocating local");
597             let ptr = ptr.to_ptr()?;
598             self.memory.dump_alloc(ptr.alloc_id);
599             self.memory.deallocate_local(ptr)?;
600         };
601         Ok(())
602     }
603
604     pub fn const_eval_raw(
605         &self,
606         gid: GlobalId<'tcx>,
607     ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
608         let param_env = if self.tcx.is_static(gid.instance.def_id()).is_some() {
609             ty::ParamEnv::reveal_all()
610         } else {
611             self.param_env
612         };
613         // We use `const_eval_raw` here, and get an unvalidated result.  That is okay:
614         // Our result will later be validated anyway, and there seems no good reason
615         // to have to fail early here.  This is also more consistent with
616         // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles.
617         let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| {
618             match err {
619                 ErrorHandled::Reported => EvalErrorKind::ReferencedConstant,
620                 ErrorHandled::TooGeneric => EvalErrorKind::TooGeneric,
621             }
622         })?;
623         self.raw_const_to_mplace(val)
624     }
625
626     pub fn dump_place(&self, place: Place<M::PointerTag>) {
627         // Debug output
628         if !log_enabled!(::log::Level::Trace) {
629             return;
630         }
631         match place {
632             Place::Local { frame, local } => {
633                 let mut allocs = Vec::new();
634                 let mut msg = format!("{:?}", local);
635                 if frame != self.cur_frame() {
636                     write!(msg, " ({} frames up)", self.cur_frame() - frame).unwrap();
637                 }
638                 write!(msg, ":").unwrap();
639
640                 match self.stack[frame].locals[local].access() {
641                     Err(err) => {
642                         if let EvalErrorKind::DeadLocal = err.kind {
643                             write!(msg, " is dead").unwrap();
644                         } else {
645                             panic!("Failed to access local: {:?}", err);
646                         }
647                     }
648                     Ok(Operand::Indirect(mplace)) => {
649                         let (ptr, align) = mplace.to_scalar_ptr_align();
650                         match ptr {
651                             Scalar::Ptr(ptr) => {
652                                 write!(msg, " by align({}) ref:", align.bytes()).unwrap();
653                                 allocs.push(ptr.alloc_id);
654                             }
655                             ptr => write!(msg, " by integral ref: {:?}", ptr).unwrap(),
656                         }
657                     }
658                     Ok(Operand::Immediate(Immediate::Scalar(val))) => {
659                         write!(msg, " {:?}", val).unwrap();
660                         if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val {
661                             allocs.push(ptr.alloc_id);
662                         }
663                     }
664                     Ok(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
665                         write!(msg, " ({:?}, {:?})", val1, val2).unwrap();
666                         if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val1 {
667                             allocs.push(ptr.alloc_id);
668                         }
669                         if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val2 {
670                             allocs.push(ptr.alloc_id);
671                         }
672                     }
673                 }
674
675                 trace!("{}", msg);
676                 self.memory.dump_allocs(allocs);
677             }
678             Place::Ptr(mplace) => {
679                 match mplace.ptr {
680                     Scalar::Ptr(ptr) => {
681                         trace!("by align({}) ref:", mplace.align.bytes());
682                         self.memory.dump_alloc(ptr.alloc_id);
683                     }
684                     ptr => trace!(" integral by ref: {:?}", ptr),
685                 }
686             }
687         }
688     }
689
690     pub fn generate_stacktrace(&self, explicit_span: Option<Span>) -> Vec<FrameInfo<'tcx>> {
691         let mut last_span = None;
692         let mut frames = Vec::new();
693         for &Frame { instance, span, mir, block, stmt, .. } in self.stack().iter().rev() {
694             // make sure we don't emit frames that are duplicates of the previous
695             if explicit_span == Some(span) {
696                 last_span = Some(span);
697                 continue;
698             }
699             if let Some(last) = last_span {
700                 if last == span {
701                     continue;
702                 }
703             } else {
704                 last_span = Some(span);
705             }
706             let block = &mir.basic_blocks()[block];
707             let source_info = if stmt < block.statements.len() {
708                 block.statements[stmt].source_info
709             } else {
710                 block.terminator().source_info
711             };
712             let lint_root = match mir.source_scope_local_data {
713                 mir::ClearCrossCrate::Set(ref ivs) => Some(ivs[source_info.scope].lint_root),
714                 mir::ClearCrossCrate::Clear => None,
715             };
716             frames.push(FrameInfo { call_site: span, instance, lint_root });
717         }
718         trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span);
719         frames
720     }
721
722     #[inline(always)]
723     pub fn sign_extend(&self, value: u128, ty: TyLayout<'_>) -> u128 {
724         assert!(ty.abi.is_signed());
725         sign_extend(value, ty.size)
726     }
727
728     #[inline(always)]
729     pub fn truncate(&self, value: u128, ty: TyLayout<'_>) -> u128 {
730         truncate(value, ty.size)
731     }
732 }