1
Fork 0

Auto merge of #66874 - RalfJung:miri-assert-panic, r=oli-obk

Miri engine: proper support for `Assert` MIR terminators

This puts down the basis for https://github.com/rust-lang/miri/issues/1070, and I also did some clean-up. The Miri side of this is at https://github.com/rust-lang/miri/pull/1084.

r? @oli-obk
This commit is contained in:
bors 2019-12-02 11:43:50 +00:00
commit 2da942f328
13 changed files with 195 additions and 118 deletions

View file

@ -471,6 +471,13 @@ impl<Tag> From<Scalar<Tag>> for ScalarMaybeUndef<Tag> {
}
}
impl<Tag> From<Pointer<Tag>> for ScalarMaybeUndef<Tag> {
#[inline(always)]
fn from(s: Pointer<Tag>) -> Self {
ScalarMaybeUndef::Scalar(s.into())
}
}
impl<Tag: fmt::Debug, Id: fmt::Debug> fmt::Debug for ScalarMaybeUndef<Tag, Id> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {

View file

@ -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<mir::BasicBlock>,
) -> 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,

View file

@ -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),
}

View file

@ -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<mir::SourceInfo> {
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<M::PointerTag> {
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<Span>) -> Vec<FrameInfo<'tcx>> {
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

View file

@ -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)?;
}

View file

@ -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)?;
location
}
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)?;
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,
)
}
}

View file

@ -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<mir::BasicBlock>,
) -> 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<mir::BasicBlock>,
) -> 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<MemoryKind<Self::MemoryKinds>>,
) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, 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,

View file

@ -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<M::PointerTag> {
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<M::MemoryKinds>,
) -> Pointer<M::PointerTag> {
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.

View file

@ -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<Tag> From<Scalar<Tag>> for Immediate<Tag> {
}
}
impl<Tag> From<Pointer<Tag>> for Immediate<Tag> {
#[inline(always)]
fn from(val: Pointer<Tag>) -> Self {
Immediate::Scalar(Scalar::from(val).into())
}
}
impl<'tcx, Tag> Immediate<Tag> {
pub fn new_slice(
val: Scalar<Tag>,
@ -60,14 +67,14 @@ impl<'tcx, Tag> Immediate<Tag> {
}
pub fn new_dyn_trait(val: Scalar<Tag>, vtable: Pointer<Tag>) -> Self {
Immediate::ScalarPair(val.into(), Scalar::Ptr(vtable).into())
Immediate::ScalarPair(val.into(), vtable.into())
}
#[inline]
pub fn to_scalar_or_undef(self) -> ScalarMaybeUndef<Tag> {
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>,

View file

@ -125,7 +125,7 @@ impl<Tag> MemPlace<Tag> {
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<Tag> {
@ -278,7 +278,7 @@ where
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag, M::AllocExtra>)>,
M::AllocExtra: AllocationExtra<Tag>,
{
/// 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
@ -694,6 +694,7 @@ where
}
/// Write a scalar to a place
#[inline(always)]
pub fn write_scalar(
&mut self,
val: impl Into<ScalarMaybeUndef<M::PointerTag>>,
@ -1041,6 +1042,24 @@ where
MPlaceTy::from_aligned_ptr(ptr, layout)
}
/// Returns a wide MPlace.
pub fn allocate_str(
&mut self,
str: &str,
kind: MemoryKind<M::MemoryKinds>,
) -> 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,

View file

@ -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(())

View file

@ -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())?;
}
}

View file

@ -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<rustc::mir::BasicBlock>,
) -> 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>,