From b1aa3cac5b7f5ac3e527f32431fa82e1c7d00c52 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 09:59:52 +0100 Subject: [PATCH 1/9] Miri: add machine hook for MIR-level assertion panics --- src/librustc_mir/const_eval.rs | 35 ++++++++++++++- src/librustc_mir/interpret/machine.rs | 9 +++- src/librustc_mir/interpret/terminator.rs | 54 ++++++++---------------- src/librustc_mir/transform/const_prop.rs | 8 ++++ 4 files changed, 67 insertions(+), 39 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 0967b25788557..18b965f4c3466 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,39 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ) } + fn assert_panic( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + 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, diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index b7cde626415a7..42d5140e34843 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,13 @@ 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>, + 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 diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 50cd318851077..a47482524039a 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, 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/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 67958af3460fc..1fb254fb69fdf 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -156,6 +156,14 @@ 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>, + _msg: &rustc::mir::interpret::AssertMessage<'tcx>, + _unwind: Option, + ) -> InterpResult<'tcx> { + throw_unsup_format!("panics are not supported in ConstProp"); + } + fn ptr_to_int( _mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer, From a8eea623f5f44332be284af26180136f898f4832 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 10:13:40 +0100 Subject: [PATCH 2/9] expose span to M::assert_panic, and provide helper to turn that into CallerLocation --- src/librustc_mir/const_eval.rs | 1 + src/librustc_mir/interpret/intrinsics.rs | 8 +------- .../interpret/intrinsics/caller_location.rs | 17 +++++++++++++++-- src/librustc_mir/interpret/machine.rs | 1 + src/librustc_mir/interpret/terminator.rs | 2 +- src/librustc_mir/transform/const_prop.rs | 1 + 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 18b965f4c3466..4b009111bf7ce 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -397,6 +397,7 @@ 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> { diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 7bcf84a7b2dd6..ea8bc968ccf37 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..649fc65f64234 100644 --- a/src/librustc_mir/interpret/intrinsics/caller_location.rs +++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs @@ -2,12 +2,12 @@ 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 syntax_pos::{Symbol, Span}; use crate::interpret::{MemoryKind, MPlaceTy, intrinsics::{InterpCx, InterpResult, 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, @@ -47,4 +47,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(location) } + + pub fn alloc_caller_location_for_span( + &mut self, + span: Span, + ) -> InterpResult<'tcx, 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 42d5140e34843..81ea62d380691 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -178,6 +178,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// 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>; diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index a47482524039a..06c3969fbc542 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -122,7 +122,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if expected == cond_val { self.go_to_block(target); } else { - M::assert_panic(self, msg, cleanup)?; + M::assert_panic(self, terminator.source_info.span, msg, cleanup)?; } } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 1fb254fb69fdf..64dc86734efe4 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -158,6 +158,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { fn assert_panic( _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _span: Span, _msg: &rustc::mir::interpret::AssertMessage<'tcx>, _unwind: Option, ) -> InterpResult<'tcx> { From cde17d915867d75169e8f7e8845ce705006c2ebb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 11:09:26 +0100 Subject: [PATCH 3/9] Add From instances for Pointer -> ScalarMaybeUndef and Pointer -> Immediate --- src/librustc/mir/interpret/value.rs | 7 +++++++ src/librustc_mir/interpret/cast.rs | 5 ++--- src/librustc_mir/interpret/memory.rs | 2 +- src/librustc_mir/interpret/operand.rs | 9 ++++++++- src/librustc_mir/interpret/place.rs | 1 + src/librustc_mir/interpret/traits.rs | 4 ++-- 6 files changed, 21 insertions(+), 7 deletions(-) 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/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/memory.rs b/src/librustc_mir/interpret/memory.rs index a8011f7abb14f..1035a93a1e964 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -350,7 +350,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) => { diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 8dd5807f7cfbf..96bad0deafe1b 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -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,7 +67,7 @@ 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] diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 5b263f7680131..11caf20acc532 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -686,6 +686,7 @@ where } /// Write a scalar to a place + #[inline(always)] pub fn write_scalar( &mut self, val: impl Into>, 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())?; } } From 56356a0745fe6b040400ebfaa636b8197395afc1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 11:29:30 +0100 Subject: [PATCH 4/9] Miri: add helper fn to allocate string; simplify alloc_caller_location --- src/librustc_mir/const_eval.rs | 2 +- src/librustc_mir/interpret/intrinsics.rs | 2 +- .../interpret/intrinsics/caller_location.rs | 45 +++++++------------ src/librustc_mir/interpret/operand.rs | 2 +- src/librustc_mir/interpret/place.rs | 18 ++++++++ 5 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 4b009111bf7ce..010738c5a052e 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -552,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/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index ea8bc968ccf37..118dfcb3d9a01 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -110,7 +110,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match intrinsic_name { "caller_location" => { - let location = self.alloc_caller_location_for_span(span)?; + 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 649fc65f64234..ecf4b7a39b726 100644 --- a/src/librustc_mir/interpret/intrinsics/caller_location.rs +++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs @@ -1,10 +1,9 @@ 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 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> { crate fn alloc_caller_location( @@ -12,46 +11,32 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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)?; - - 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)?; + // 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"); - Ok(location) + location } pub fn alloc_caller_location_for_span( &mut self, span: Span, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> 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( diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 96bad0deafe1b..2ec1613bce27a 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -331,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 fat 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 11caf20acc532..ea7b53b3dda2c 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -1034,6 +1034,24 @@ where MPlaceTy::from_aligned_ptr(ptr, layout) } + /// Returns a fat 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, From c8743dbe51ca28f1d77cc310178f75af072e97be Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 11:48:37 +0100 Subject: [PATCH 5/9] add and use helper method to get SourceInfo of current instruction in frame --- src/librustc_mir/interpret/eval_context.rs | 36 +++++++++++++--------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 6c16c4f221928..36f17688e8e9d 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 { @@ -828,34 +842,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 From 96ea142c89ad34c00d803d91ee0b08689599c65d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 19:42:37 +0100 Subject: [PATCH 6/9] make alloc_extra machine hook a bit nicer --- src/librustc_mir/const_eval.rs | 6 +++--- src/librustc_mir/interpret/eval_context.rs | 4 ++++ src/librustc_mir/interpret/machine.rs | 7 ++----- src/librustc_mir/interpret/memory.rs | 15 +++++++++------ src/librustc_mir/transform/const_prop.rs | 6 +++--- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 010738c5a052e..ef6e34c3dd0af 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -457,14 +457,14 @@ 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>, _kind: Option>, - ) -> (Cow<'b, Allocation>, Self::PointerTag) { + ) -> Cow<'b, Allocation> { // We do not use a tag so we can just cheaply forward the allocation - (alloc, ()) + alloc } #[inline(always)] diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 36f17688e8e9d..16ebf2a34a0bf 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -250,6 +250,10 @@ 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. This represents a *direct* + /// access to that memory, as opposed to access through a pointer that was created + /// by the program. Must never be used for derived (program-created) pointers! #[inline(always)] pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer { self.memory.tag_static_base_pointer(ptr) diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 81ea62d380691..0bdb217203420 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -240,15 +240,12 @@ pub trait Machine<'mir, 'tcx>: Sized { /// allocation (because a copy had to be done to add tags or metadata), machine memory will /// 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>( + fn init_allocation_extra<'b>( memory_extra: &Self::MemoryExtra, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> (Cow<'b, Allocation>, Self::PointerTag); + ) -> Cow<'b, Allocation>; /// Return the "base" tag for the given static allocation: the one that is used for direct /// accesses to this static/const/fn allocation. diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 1035a93a1e964..8aaaa2c22fe77 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -143,6 +143,10 @@ 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. This represents a *direct* + /// access to that memory, as opposed to access through a pointer that was created + /// by the program. Must never be used for derived (program-created) pointers! #[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,9 +195,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)); + let alloc = 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) + self.tag_static_base_pointer(Pointer::from(id)) } pub fn reallocate( @@ -473,14 +477,13 @@ 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. + Ok(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) + )) } /// Gives raw access to the `Allocation`, without bounds or alignment checks. diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 64dc86734efe4..aa3897efb9e78 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -191,14 +191,14 @@ 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>, _kind: Option>, - ) -> (Cow<'b, Allocation>, Self::PointerTag) { + ) -> Cow<'b, Allocation> { // We do not use a tag so we can just cheaply forward the allocation - (alloc, ()) + alloc } #[inline(always)] From 386a2bb3a0cf22c895dfd9ba21f92cde3b47aae0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2019 10:28:01 +0100 Subject: [PATCH 7/9] fat -> wide --- src/librustc_mir/interpret/operand.rs | 6 +++--- src/librustc_mir/interpret/place.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 2ec1613bce27a..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)] @@ -74,7 +74,7 @@ impl<'tcx, Tag> Immediate { 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"), } } @@ -331,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 fat 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 ea7b53b3dda2c..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 @@ -1034,7 +1034,7 @@ where MPlaceTy::from_aligned_ptr(ptr, layout) } - /// Returns a fat MPlace. + /// Returns a wide MPlace. pub fn allocate_str( &mut self, str: &str, From 9a52543aaebe0cd426debd8ba748d171547ec500 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2019 14:21:41 +0100 Subject: [PATCH 8/9] Assert terminator is never executed in ConstProp --- src/librustc_mir/transform/const_prop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index aa3897efb9e78..03c352bbd7d1d 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -162,7 +162,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _msg: &rustc::mir::interpret::AssertMessage<'tcx>, _unwind: Option, ) -> InterpResult<'tcx> { - throw_unsup_format!("panics are not supported in ConstProp"); + bug!("panics terminators are not evaluated in ConstProp"); } fn ptr_to_int( From 5e51a153f97b141dfeef795d22ec9e47967764f2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 10:02:41 +0100 Subject: [PATCH 9/9] fix init_allocation_extra --- src/librustc_mir/const_eval.rs | 4 ++-- src/librustc_mir/interpret/eval_context.rs | 8 +++++--- src/librustc_mir/interpret/machine.rs | 14 ++++++++------ src/librustc_mir/interpret/memory.rs | 20 +++++++++++++------- src/librustc_mir/transform/const_prop.rs | 4 ++-- 5 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index ef6e34c3dd0af..ff0cf6f4fdd21 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -462,9 +462,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, _id: AllocId, alloc: Cow<'b, Allocation>, _kind: Option>, - ) -> Cow<'b, Allocation> { + ) -> (Cow<'b, Allocation>, Self::PointerTag) { // We do not use a tag so we can just cheaply forward the allocation - alloc + (alloc, ()) } #[inline(always)] diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 16ebf2a34a0bf..8250cadb01d44 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -251,9 +251,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } /// Call this to turn untagged "global" pointers (obtained via `tcx`) into - /// the *canonical* machine pointer to the allocation. This represents a *direct* - /// access to that memory, as opposed to access through a pointer that was created - /// by the program. Must never be used for derived (program-created) pointers! + /// 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) diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 0bdb217203420..2ecc8d88ad398 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -240,18 +240,20 @@ pub trait Machine<'mir, 'tcx>: Sized { /// allocation (because a copy had to be done to add tags or metadata), machine memory will /// 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.) + /// + /// 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>; + ) -> (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 8aaaa2c22fe77..ee7fb18fd05a5 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -144,9 +144,11 @@ 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. This represents a *direct* - /// access to that memory, as opposed to access through a pointer that was created - /// by the program. Must never be used for derived (program-created) pointers! + /// 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)) @@ -195,9 +197,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { kind: MemoryKind, ) -> Pointer { let id = self.tcx.alloc_map.lock().reserve(); - let alloc = M::init_allocation_extra(&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())); - self.tag_static_base_pointer(Pointer::from(id)) + Pointer::from(id).with_tag(tag) } pub fn reallocate( @@ -478,12 +482,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } }; // We got tcx memory. Let the machine initialize its "extra" stuff. - Ok(M::init_allocation_extra( + 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), - )) + ); + 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/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 03c352bbd7d1d..bbbaac145f559 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -196,9 +196,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { _id: AllocId, alloc: Cow<'b, Allocation>, _kind: Option>, - ) -> Cow<'b, Allocation> { + ) -> (Cow<'b, Allocation>, Self::PointerTag) { // We do not use a tag so we can just cheaply forward the allocation - alloc + (alloc, ()) } #[inline(always)]