| use crate::interpret::{self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic}; |
| use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult}; |
| use rustc_middle::mir::*; |
| use rustc_middle::query::TyCtxtAt; |
| use rustc_middle::ty; |
| use rustc_middle::ty::layout::TyAndLayout; |
| use rustc_span::def_id::DefId; |
| |
| /// Macro for machine-specific `InterpError` without allocation. |
| /// (These will never be shown to the user, but they help diagnose ICEs.) |
| pub macro throw_machine_stop_str($($tt:tt)*) {{ |
| // We make a new local type for it. The type itself does not carry any information, |
| // but its vtable (for the `MachineStopType` trait) does. |
| #[derive(Debug)] |
| struct Zst; |
| // Printing this type shows the desired string. |
| impl std::fmt::Display for Zst { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| write!(f, $($tt)*) |
| } |
| } |
| |
| impl rustc_middle::mir::interpret::MachineStopType for Zst { |
| fn diagnostic_message(&self) -> rustc_errors::DiagMessage { |
| self.to_string().into() |
| } |
| |
| fn add_args( |
| self: Box<Self>, |
| _: &mut dyn FnMut(rustc_errors::DiagArgName, rustc_errors::DiagArgValue), |
| ) {} |
| } |
| throw_machine_stop!(Zst) |
| }} |
| |
| pub struct DummyMachine; |
| |
| impl HasStaticRootDefId for DummyMachine { |
| fn static_def_id(&self) -> Option<rustc_hir::def_id::LocalDefId> { |
| None |
| } |
| } |
| |
| impl<'mir, 'tcx: 'mir> interpret::Machine<'mir, 'tcx> for DummyMachine { |
| interpret::compile_time_machine!(<'mir, 'tcx>); |
| type MemoryKind = !; |
| const PANIC_ON_ALLOC_FAIL: bool = true; |
| |
| #[inline(always)] |
| fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { |
| false // no reason to enforce alignment |
| } |
| |
| fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool { |
| false |
| } |
| |
| fn before_access_global( |
| _tcx: TyCtxtAt<'tcx>, |
| _machine: &Self, |
| _alloc_id: AllocId, |
| alloc: ConstAllocation<'tcx>, |
| _static_def_id: Option<DefId>, |
| is_write: bool, |
| ) -> InterpResult<'tcx> { |
| if is_write { |
| throw_machine_stop_str!("can't write to global"); |
| } |
| |
| // If the static allocation is mutable, then we can't const prop it as its content |
| // might be different at runtime. |
| if alloc.inner().mutability.is_mut() { |
| throw_machine_stop_str!("can't access mutable globals in ConstProp"); |
| } |
| |
| Ok(()) |
| } |
| |
| fn find_mir_or_eval_fn( |
| _ecx: &mut InterpCx<'mir, 'tcx, Self>, |
| _instance: ty::Instance<'tcx>, |
| _abi: rustc_target::spec::abi::Abi, |
| _args: &[interpret::FnArg<'tcx, Self::Provenance>], |
| _destination: &interpret::MPlaceTy<'tcx, Self::Provenance>, |
| _target: Option<BasicBlock>, |
| _unwind: UnwindAction, |
| ) -> interpret::InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> { |
| unimplemented!() |
| } |
| |
| fn panic_nounwind( |
| _ecx: &mut InterpCx<'mir, 'tcx, Self>, |
| _msg: &str, |
| ) -> interpret::InterpResult<'tcx> { |
| unimplemented!() |
| } |
| |
| fn call_intrinsic( |
| _ecx: &mut InterpCx<'mir, 'tcx, Self>, |
| _instance: ty::Instance<'tcx>, |
| _args: &[interpret::OpTy<'tcx, Self::Provenance>], |
| _destination: &interpret::MPlaceTy<'tcx, Self::Provenance>, |
| _target: Option<BasicBlock>, |
| _unwind: UnwindAction, |
| ) -> interpret::InterpResult<'tcx> { |
| unimplemented!() |
| } |
| |
| fn assert_panic( |
| _ecx: &mut InterpCx<'mir, 'tcx, Self>, |
| _msg: &rustc_middle::mir::AssertMessage<'tcx>, |
| _unwind: UnwindAction, |
| ) -> interpret::InterpResult<'tcx> { |
| unimplemented!() |
| } |
| |
| fn binary_ptr_op( |
| ecx: &InterpCx<'mir, 'tcx, Self>, |
| bin_op: BinOp, |
| left: &interpret::ImmTy<'tcx, Self::Provenance>, |
| right: &interpret::ImmTy<'tcx, Self::Provenance>, |
| ) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> { |
| use rustc_middle::mir::BinOp::*; |
| Ok(match bin_op { |
| Eq | Ne | Lt | Le | Gt | Ge => { |
| // Types can differ, e.g. fn ptrs with different `for`. |
| assert_eq!(left.layout.abi, right.layout.abi); |
| let size = ecx.pointer_size(); |
| // Just compare the bits. ScalarPairs are compared lexicographically. |
| // We thus always compare pairs and simply fill scalars up with 0. |
| // If the pointer has provenance, `to_bits` will return `Err` and we bail out. |
| let left = match **left { |
| Immediate::Scalar(l) => (l.to_bits(size)?, 0), |
| Immediate::ScalarPair(l1, l2) => (l1.to_bits(size)?, l2.to_bits(size)?), |
| Immediate::Uninit => panic!("we should never see uninit data here"), |
| }; |
| let right = match **right { |
| Immediate::Scalar(r) => (r.to_bits(size)?, 0), |
| Immediate::ScalarPair(r1, r2) => (r1.to_bits(size)?, r2.to_bits(size)?), |
| Immediate::Uninit => panic!("we should never see uninit data here"), |
| }; |
| let res = match bin_op { |
| Eq => left == right, |
| Ne => left != right, |
| Lt => left < right, |
| Le => left <= right, |
| Gt => left > right, |
| Ge => left >= right, |
| _ => bug!(), |
| }; |
| (ImmTy::from_bool(res, *ecx.tcx), false) |
| } |
| |
| // Some more operations are possible with atomics. |
| // The return value always has the provenance of the *left* operand. |
| Add | Sub | BitOr | BitAnd | BitXor => { |
| throw_machine_stop_str!("pointer arithmetic is not handled") |
| } |
| |
| _ => span_bug!(ecx.cur_span(), "Invalid operator on pointers: {:?}", bin_op), |
| }) |
| } |
| |
| fn expose_ptr( |
| _ecx: &mut InterpCx<'mir, 'tcx, Self>, |
| _ptr: interpret::Pointer<Self::Provenance>, |
| ) -> interpret::InterpResult<'tcx> { |
| unimplemented!() |
| } |
| |
| fn init_frame_extra( |
| _ecx: &mut InterpCx<'mir, 'tcx, Self>, |
| _frame: interpret::Frame<'mir, 'tcx, Self::Provenance>, |
| ) -> interpret::InterpResult< |
| 'tcx, |
| interpret::Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, |
| > { |
| unimplemented!() |
| } |
| |
| fn stack<'a>( |
| _ecx: &'a InterpCx<'mir, 'tcx, Self>, |
| ) -> &'a [interpret::Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] { |
| // Return an empty stack instead of panicking, as `cur_span` uses it to evaluate constants. |
| &[] |
| } |
| |
| fn stack_mut<'a>( |
| _ecx: &'a mut InterpCx<'mir, 'tcx, Self>, |
| ) -> &'a mut Vec<interpret::Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> { |
| unimplemented!() |
| } |
| } |