diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index f82af62c5f39d..a038ca23ae92d 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -471,6 +471,13 @@ impl From> for ScalarMaybeUndef { } } +impl From> for ScalarMaybeUndef { + #[inline(always)] + fn from(s: Pointer) -> Self { + ScalarMaybeUndef::Scalar(s.into()) + } +} + impl fmt::Debug for ScalarMaybeUndef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 0967b25788557..ff0cf6f4fdd21 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -23,7 +23,7 @@ use syntax::{source_map::{Span, DUMMY_SP}, symbol::Symbol}; use crate::interpret::{self, PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar, Pointer, RawConst, ConstValue, Machine, - InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup, + InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup, AssertMessage, Allocation, AllocId, MemoryKind, Memory, snapshot, RefTracking, intern_const_alloc_recursive, }; @@ -395,6 +395,40 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ) } + fn assert_panic( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + _span: Span, + msg: &AssertMessage<'tcx>, + _unwind: Option, + ) -> InterpResult<'tcx> { + use rustc::mir::interpret::PanicInfo::*; + Err(match msg { + BoundsCheck { ref len, ref index } => { + let len = ecx + .read_immediate(ecx.eval_operand(len, None)?) + .expect("can't eval len") + .to_scalar()? + .to_machine_usize(&*ecx)?; + let index = ecx + .read_immediate(ecx.eval_operand(index, None)?) + .expect("can't eval index") + .to_scalar()? + .to_machine_usize(&*ecx)?; + err_panic!(BoundsCheck { len, index }) + } + Overflow(op) => err_panic!(Overflow(*op)), + OverflowNeg => err_panic!(OverflowNeg), + DivisionByZero => err_panic!(DivisionByZero), + RemainderByZero => err_panic!(RemainderByZero), + ResumedAfterReturn(generator_kind) + => err_panic!(ResumedAfterReturn(*generator_kind)), + ResumedAfterPanic(generator_kind) + => err_panic!(ResumedAfterPanic(*generator_kind)), + Panic { .. } => bug!("`Panic` variant cannot occur in MIR"), + } + .into()) + } + fn ptr_to_int( _mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer, @@ -423,7 +457,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } #[inline(always)] - fn tag_allocation<'b>( + fn init_allocation_extra<'b>( _memory_extra: &(), _id: AllocId, alloc: Cow<'b, Allocation>, @@ -518,7 +552,7 @@ pub fn const_caller_location<'tcx>( tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None)) .subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())), ); - let loc_place = ecx.alloc_caller_location(file, line, col).unwrap(); + let loc_place = ecx.alloc_caller_location(file, line, col); intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap(); let loc_const = ty::Const { ty: loc_ty, diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 1fb8b3ca63fcf..e9602ecfa4c72 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -55,7 +55,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ).ok_or_else(|| err_inval!(TooGeneric))?; let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); - self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?; + self.write_scalar(fn_ptr, dest)?; } _ => bug!("reify fn pointer on {:?}", src.layout.ty), } @@ -88,8 +88,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ClosureKind::FnOnce, ); let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); - let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into()); - self.write_immediate(val, dest)?; + self.write_scalar(fn_ptr, dest)?; } _ => bug!("closure fn pointer on {:?}", src.layout.ty), } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 6c16c4f221928..8250cadb01d44 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -164,6 +164,20 @@ impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> { } } +impl<'mir, 'tcx, Tag, Extra> Frame<'mir, 'tcx, Tag, Extra> { + /// Return the `SourceInfo` of the current instruction. + pub fn current_source_info(&self) -> Option { + self.block.map(|block| { + let block = &self.body.basic_blocks()[block]; + if self.stmt < block.statements.len() { + block.statements[self.stmt].source_info + } else { + block.terminator().source_info + } + }) + } +} + impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M> { #[inline] fn data_layout(&self) -> &layout::TargetDataLayout { @@ -236,6 +250,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.memory.force_bits(scalar, size) } + /// Call this to turn untagged "global" pointers (obtained via `tcx`) into + /// the *canonical* machine pointer to the allocation. Must never be used + /// for any other pointers! + /// + /// This represents a *direct* access to that memory, as opposed to access + /// through a pointer that was created by the program. #[inline(always)] pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer { self.memory.tag_static_base_pointer(ptr) @@ -828,34 +848,28 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn generate_stacktrace(&self, explicit_span: Option) -> Vec> { let mut last_span = None; let mut frames = Vec::new(); - for &Frame { instance, span, body, block, stmt, .. } in self.stack().iter().rev() { + for frame in self.stack().iter().rev() { // make sure we don't emit frames that are duplicates of the previous - if explicit_span == Some(span) { - last_span = Some(span); + if explicit_span == Some(frame.span) { + last_span = Some(frame.span); continue; } if let Some(last) = last_span { - if last == span { + if last == frame.span { continue; } } else { - last_span = Some(span); + last_span = Some(frame.span); } - let lint_root = block.and_then(|block| { - let block = &body.basic_blocks()[block]; - let source_info = if stmt < block.statements.len() { - block.statements[stmt].source_info - } else { - block.terminator().source_info - }; - match &body.source_scopes[source_info.scope].local_data { + let lint_root = frame.current_source_info().and_then(|source_info| { + match &frame.body.source_scopes[source_info.scope].local_data { mir::ClearCrossCrate::Set(data) => Some(data.lint_root), mir::ClearCrossCrate::Clear => None, } }); - frames.push(FrameInfo { call_site: span, instance, lint_root }); + frames.push(FrameInfo { call_site: frame.span, instance: frame.instance, lint_root }); } trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span); frames diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 7bcf84a7b2dd6..118dfcb3d9a01 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -110,13 +110,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match intrinsic_name { "caller_location" => { - let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); - let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); - let location = self.alloc_caller_location( - Symbol::intern(&caller.file.name.to_string()), - caller.line as u32, - caller.col_display as u32 + 1, - )?; + let location = self.alloc_caller_location_for_span(span); self.write_scalar(location.ptr, dest)?; } diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs index 9e07a3f1072c1..ecf4b7a39b726 100644 --- a/src/librustc_mir/interpret/intrinsics/caller_location.rs +++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs @@ -1,50 +1,48 @@ use rustc::middle::lang_items::PanicLocationLangItem; -use rustc::mir::interpret::{Pointer, PointerArithmetic, Scalar}; use rustc::ty::subst::Subst; -use rustc_target::abi::{LayoutOf, Size}; -use syntax_pos::Symbol; +use rustc_target::abi::LayoutOf; +use syntax_pos::{Symbol, Span}; -use crate::interpret::{MemoryKind, MPlaceTy, intrinsics::{InterpCx, InterpResult, Machine}}; +use crate::interpret::{Scalar, MemoryKind, MPlaceTy, intrinsics::{InterpCx, Machine}}; impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - pub fn alloc_caller_location( + crate fn alloc_caller_location( &mut self, filename: Symbol, line: u32, col: u32, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> MPlaceTy<'tcx, M::PointerTag> { + let file = self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation); let line = Scalar::from_u32(line); let col = Scalar::from_u32(col); - let ptr_size = self.pointer_size(); - let u32_size = Size::from_bits(32); - + // Allocate memory for `CallerLocation` struct. let loc_ty = self.tcx.type_of(self.tcx.require_lang_item(PanicLocationLangItem, None)) .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_static.into()].iter())); - let loc_layout = self.layout_of(loc_ty)?; - - let file_alloc = self.tcx.allocate_bytes(filename.as_str().as_bytes()); - let file_ptr = Pointer::new(file_alloc, Size::ZERO); - let file = Scalar::Ptr(self.tag_static_base_pointer(file_ptr)); - let file_len = Scalar::from_uint(filename.as_str().len() as u128, ptr_size); - + let loc_layout = self.layout_of(loc_ty).unwrap(); let location = self.allocate(loc_layout, MemoryKind::CallerLocation); - let file_out = self.mplace_field(location, 0)?; - let file_ptr_out = self.force_ptr(self.mplace_field(file_out, 0)?.ptr)?; - let file_len_out = self.force_ptr(self.mplace_field(file_out, 1)?.ptr)?; - let line_out = self.force_ptr(self.mplace_field(location, 1)?.ptr)?; - let col_out = self.force_ptr(self.mplace_field(location, 2)?.ptr)?; + // Initialize fields. + self.write_immediate(file.to_ref(), self.mplace_field(location, 0).unwrap().into()) + .expect("writing to memory we just allocated cannot fail"); + self.write_scalar(line, self.mplace_field(location, 1).unwrap().into()) + .expect("writing to memory we just allocated cannot fail"); + self.write_scalar(col, self.mplace_field(location, 2).unwrap().into()) + .expect("writing to memory we just allocated cannot fail"); - let layout = &self.tcx.data_layout; - // We just allocated this, so we can skip the bounds checks. - let alloc = self.memory.get_raw_mut(file_ptr_out.alloc_id)?; - - alloc.write_scalar(layout, file_ptr_out, file.into(), ptr_size)?; - alloc.write_scalar(layout, file_len_out, file_len.into(), ptr_size)?; - alloc.write_scalar(layout, line_out, line.into(), u32_size)?; - alloc.write_scalar(layout, col_out, col.into(), u32_size)?; + location + } - Ok(location) + pub fn alloc_caller_location_for_span( + &mut self, + span: Span, + ) -> MPlaceTy<'tcx, M::PointerTag> { + let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); + let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); + self.alloc_caller_location( + Symbol::intern(&caller.file.name.to_string()), + caller.line as u32, + caller.col_display as u32 + 1, + ) } } diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index b7cde626415a7..2ecc8d88ad398 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -11,7 +11,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use syntax_pos::Span; use super::{ - Allocation, AllocId, InterpResult, Scalar, AllocationExtra, + Allocation, AllocId, InterpResult, Scalar, AllocationExtra, AssertMessage, InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory, Frame, Operand, }; @@ -175,6 +175,14 @@ pub trait Machine<'mir, 'tcx>: Sized { unwind: Option, ) -> InterpResult<'tcx>; + /// Called to evaluate `Assert` MIR terminators that trigger a panic. + fn assert_panic( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + span: Span, + msg: &AssertMessage<'tcx>, + unwind: Option, + ) -> InterpResult<'tcx>; + /// Called for read access to a foreign static item. /// /// This will only be called once per static and machine; the result is cached in @@ -233,20 +241,19 @@ pub trait Machine<'mir, 'tcx>: Sized { /// cache the result. (This relies on `AllocMap::get_or` being able to add the /// owned allocation to the map even when the map is shared.) /// - /// For static allocations, the tag returned must be the same as the one returned by - /// `tag_static_base_pointer`. - fn tag_allocation<'b>( + /// Also return the "base" tag to use for this allocation: the one that is used for direct + /// accesses to this allocation. If `kind == STATIC_KIND`, this tag must be consistent + /// with `tag_static_base_pointer`. + fn init_allocation_extra<'b>( memory_extra: &Self::MemoryExtra, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, ) -> (Cow<'b, Allocation>, Self::PointerTag); - /// Return the "base" tag for the given static allocation: the one that is used for direct - /// accesses to this static/const/fn allocation. - /// - /// Be aware that requesting the `Allocation` for that `id` will lead to cycles - /// for cyclic statics! + /// Return the "base" tag for the given *static* allocation: the one that is used for direct + /// accesses to this static/const/fn allocation. If `id` is not a static allocation, + /// this will return an unusable tag (i.e., accesses will be UB)! fn tag_static_base_pointer( memory_extra: &Self::MemoryExtra, id: AllocId, diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index a8011f7abb14f..ee7fb18fd05a5 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -143,6 +143,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } } + /// Call this to turn untagged "global" pointers (obtained via `tcx`) into + /// the *canonical* machine pointer to the allocation. Must never be used + /// for any other pointers! + /// + /// This represents a *direct* access to that memory, as opposed to access + /// through a pointer that was created by the program. #[inline] pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer { ptr.with_tag(M::tag_static_base_pointer(&self.extra, ptr.alloc_id)) @@ -191,7 +197,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { kind: MemoryKind, ) -> Pointer { let id = self.tcx.alloc_map.lock().reserve(); - let (alloc, tag) = M::tag_allocation(&self.extra, id, Cow::Owned(alloc), Some(kind)); + debug_assert_ne!(Some(kind), M::STATIC_KIND.map(MemoryKind::Machine), + "dynamically allocating static memory"); + let (alloc, tag) = M::init_allocation_extra(&self.extra, id, Cow::Owned(alloc), Some(kind)); self.alloc_map.insert(id, (kind, alloc.into_owned())); Pointer::from(id).with_tag(tag) } @@ -350,7 +358,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { sptr } else { // A "real" access, we must get a pointer. - Scalar::Ptr(self.force_ptr(sptr)?) + Scalar::from(self.force_ptr(sptr)?) }; Ok(match normalized.to_bits_or_ptr(self.pointer_size(), self) { Ok(bits) => { @@ -473,14 +481,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } } }; - // We got tcx memory. Let the machine figure out whether and how to - // turn that into memory with the right pointer tag. - Ok(M::tag_allocation( + // We got tcx memory. Let the machine initialize its "extra" stuff. + let (alloc, tag) = M::init_allocation_extra( memory_extra, id, // always use the ID we got as input, not the "hidden" one. alloc, M::STATIC_KIND.map(MemoryKind::Machine), - ).0) + ); + debug_assert_eq!(tag, M::tag_static_base_pointer(memory_extra, id)); + Ok(alloc) } /// Gives raw access to the `Allocation`, without bounds or alignment checks. diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 8dd5807f7cfbf..9e94ae2c16081 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -24,7 +24,7 @@ use rustc_macros::HashStable; /// /// For optimization of a few very common cases, there is also a representation for a pair of /// primitive values (`ScalarPair`). It allows Miri to avoid making allocations for checked binary -/// operations and fat pointers. This idea was taken from rustc's codegen. +/// operations and wide pointers. This idea was taken from rustc's codegen. /// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely /// defined on `Immediate`, and do not have to work with a `Place`. #[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, Hash)] @@ -47,6 +47,13 @@ impl From> for Immediate { } } +impl From> for Immediate { + #[inline(always)] + fn from(val: Pointer) -> Self { + Immediate::Scalar(Scalar::from(val).into()) + } +} + impl<'tcx, Tag> Immediate { pub fn new_slice( val: Scalar, @@ -60,14 +67,14 @@ impl<'tcx, Tag> Immediate { } pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self { - Immediate::ScalarPair(val.into(), Scalar::Ptr(vtable).into()) + Immediate::ScalarPair(val.into(), vtable.into()) } #[inline] pub fn to_scalar_or_undef(self) -> ScalarMaybeUndef { match self { Immediate::Scalar(val) => val, - Immediate::ScalarPair(..) => bug!("Got a fat pointer where a scalar was expected"), + Immediate::ScalarPair(..) => bug!("Got a wide pointer where a scalar was expected"), } } @@ -324,7 +331,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(self.read_immediate(op)?.to_scalar_or_undef()) } - // Turn the MPlace into a string (must already be dereferenced!) + // Turn the wide MPlace into a string (must already be dereferenced!) pub fn read_str( &self, mplace: MPlaceTy<'tcx, M::PointerTag>, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 5b263f7680131..8da20a4bba288 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -125,7 +125,7 @@ impl MemPlace { Self::from_scalar_ptr(ptr.into(), align) } - /// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space. + /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space. /// This is the inverse of `ref_to_mplace`. #[inline(always)] pub fn to_ref(self) -> Immediate { @@ -278,7 +278,7 @@ where M::MemoryMap: AllocMap, Allocation)>, M::AllocExtra: AllocationExtra, { - /// Take a value, which represents a (thin or fat) reference, and make it a place. + /// Take a value, which represents a (thin or wide) reference, and make it a place. /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. /// /// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not @@ -686,6 +686,7 @@ where } /// Write a scalar to a place + #[inline(always)] pub fn write_scalar( &mut self, val: impl Into>, @@ -1033,6 +1034,24 @@ where MPlaceTy::from_aligned_ptr(ptr, layout) } + /// Returns a wide MPlace. + pub fn allocate_str( + &mut self, + str: &str, + kind: MemoryKind, + ) -> MPlaceTy<'tcx, M::PointerTag> { + let ptr = self.memory.allocate_static_bytes(str.as_bytes(), kind); + let meta = Scalar::from_uint(str.len() as u128, self.pointer_size()); + let mplace = MemPlace { + ptr: ptr.into(), + align: Align::from_bytes(1).unwrap(), + meta: Some(meta), + }; + + let layout = self.layout_of(self.tcx.mk_static_str()).unwrap(); + MPlaceTy { mplace, layout } + } + pub fn write_discriminant_index( &mut self, variant_index: VariantIdx, diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 50cd318851077..06c3969fbc542 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -7,8 +7,8 @@ use syntax::source_map::Span; use rustc_target::spec::abi::Abi; use super::{ - GlobalId, InterpResult, PointerArithmetic, - InterpCx, Machine, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal, + GlobalId, InterpResult, InterpCx, Machine, + OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal, }; impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { @@ -115,40 +115,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { expected, ref msg, target, - .. + cleanup, } => { let cond_val = self.read_immediate(self.eval_operand(cond, None)?)? .to_scalar()?.to_bool()?; if expected == cond_val { self.go_to_block(target); } else { - // Compute error message - use rustc::mir::interpret::PanicInfo::*; - return Err(match msg { - BoundsCheck { ref len, ref index } => { - let len = self - .read_immediate(self.eval_operand(len, None)?) - .expect("can't eval len") - .to_scalar()? - .to_bits(self.memory.pointer_size())? as u64; - let index = self - .read_immediate(self.eval_operand(index, None)?) - .expect("can't eval index") - .to_scalar()? - .to_bits(self.memory.pointer_size())? as u64; - err_panic!(BoundsCheck { len, index }) - } - Overflow(op) => err_panic!(Overflow(*op)), - OverflowNeg => err_panic!(OverflowNeg), - DivisionByZero => err_panic!(DivisionByZero), - RemainderByZero => err_panic!(RemainderByZero), - ResumedAfterReturn(generator_kind) - => err_panic!(ResumedAfterReturn(*generator_kind)), - ResumedAfterPanic(generator_kind) - => err_panic!(ResumedAfterPanic(*generator_kind)), - Panic { .. } => bug!("`Panic` variant cannot occur in MIR"), - } - .into()); + M::assert_panic(self, terminator.source_info.span, msg, cleanup)?; } } @@ -164,15 +138,21 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(()) }, + // It is UB to ever encounter this. + Unreachable => throw_ub!(Unreachable), + + // These should never occur for MIR we actually run. + DropAndReplace { .. } | + FalseEdges { .. } | + FalseUnwind { .. } => + bug!("{:#?} should have been eliminated by MIR pass", terminator.kind), + + // These are not (yet) supported. It is unclear if they even can occur in + // MIR that we actually run. Yield { .. } | GeneratorDrop | - DropAndReplace { .. } | - Abort => unimplemented!("{:#?}", terminator.kind), - FalseEdges { .. } => bug!("should have been eliminated by\ - `simplify_branches` mir pass"), - FalseUnwind { .. } => bug!("should have been eliminated by\ - `simplify_branches` mir pass"), - Unreachable => throw_ub!(Unreachable), + Abort => + throw_unsup_format!("Unsupported terminator kind: {:#?}", terminator.kind), } Ok(()) diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 3a7f47a2aaca9..efa0d266cbc21 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -67,7 +67,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // allocation is correctly aligned as we created it above. Also we're only offsetting by // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`. let vtable_alloc = self.memory.get_raw_mut(vtable.alloc_id)?; - vtable_alloc.write_ptr_sized(tcx, vtable, Scalar::Ptr(drop).into())?; + vtable_alloc.write_ptr_sized(tcx, vtable, drop.into())?; let size_ptr = vtable.offset(ptr_size, tcx)?; vtable_alloc.write_ptr_sized(tcx, size_ptr, Scalar::from_uint(size, ptr_size).into())?; @@ -87,7 +87,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // We cannot use `vtable_allic` as we are creating fn ptrs in this loop. let method_ptr = vtable.offset(ptr_size * (3 + i as u64), tcx)?; self.memory.get_raw_mut(vtable.alloc_id)? - .write_ptr_sized(tcx, method_ptr, Scalar::Ptr(fn_ptr).into())?; + .write_ptr_sized(tcx, method_ptr, fn_ptr.into())?; } } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 67958af3460fc..bbbaac145f559 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -156,6 +156,15 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { throw_unsup!(ConstPropUnsupported("calling intrinsics isn't supported in ConstProp")); } + fn assert_panic( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _span: Span, + _msg: &rustc::mir::interpret::AssertMessage<'tcx>, + _unwind: Option, + ) -> InterpResult<'tcx> { + bug!("panics terminators are not evaluated in ConstProp"); + } + fn ptr_to_int( _mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer, @@ -182,7 +191,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { } #[inline(always)] - fn tag_allocation<'b>( + fn init_allocation_extra<'b>( _memory_extra: &(), _id: AllocId, alloc: Cow<'b, Allocation>,