rustc_const_eval/const_eval/
dummy_machine.rs

1use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult};
2use rustc_middle::mir::*;
3use rustc_middle::query::TyCtxtAt;
4use rustc_middle::ty::Ty;
5use rustc_middle::ty::layout::TyAndLayout;
6use rustc_middle::{bug, span_bug, ty};
7use rustc_span::def_id::DefId;
8use rustc_target::callconv::FnAbi;
9
10use crate::interpret::{
11    self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic, interp_ok,
12    throw_machine_stop,
13};
14
15/// Macro for machine-specific `InterpError` without allocation.
16/// (These will never be shown to the user, but they help diagnose ICEs.)
17pub macro throw_machine_stop_str($($tt:tt)*) {{
18    // We make a new local type for it. The type itself does not carry any information,
19    // but its vtable (for the `MachineStopType` trait) does.
20    #[derive(Debug)]
21    struct Zst;
22    // Printing this type shows the desired string.
23    impl std::fmt::Display for Zst {
24        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25            write!(f, $($tt)*)
26        }
27    }
28
29    impl rustc_middle::mir::interpret::MachineStopType for Zst {
30        fn diagnostic_message(&self) -> rustc_errors::DiagMessage {
31            self.to_string().into()
32        }
33
34        fn add_args(
35            self: Box<Self>,
36            _: &mut dyn FnMut(rustc_errors::DiagArgName, rustc_errors::DiagArgValue),
37        ) {}
38    }
39    throw_machine_stop!(Zst)
40}}
41
42pub struct DummyMachine;
43
44impl HasStaticRootDefId for DummyMachine {
45    fn static_def_id(&self) -> Option<rustc_hir::def_id::LocalDefId> {
46        None
47    }
48}
49
50impl<'tcx> interpret::Machine<'tcx> for DummyMachine {
51    interpret::compile_time_machine!(<'tcx>);
52    type MemoryKind = !;
53    const PANIC_ON_ALLOC_FAIL: bool = true;
54
55    // We want to just eval random consts in the program, so `eval_mir_const` can fail.
56    const ALL_CONSTS_ARE_PRECHECKED: bool = false;
57
58    #[inline(always)]
59    fn enforce_alignment(_ecx: &InterpCx<'tcx, Self>) -> bool {
60        false // no reason to enforce alignment
61    }
62
63    fn enforce_validity(_ecx: &InterpCx<'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
64        false
65    }
66
67    fn before_access_global(
68        _tcx: TyCtxtAt<'tcx>,
69        _machine: &Self,
70        _alloc_id: AllocId,
71        alloc: ConstAllocation<'tcx>,
72        _static_def_id: Option<DefId>,
73        is_write: bool,
74    ) -> InterpResult<'tcx> {
75        if is_write {
76            throw_machine_stop_str!("can't write to global");
77        }
78
79        // If the static allocation is mutable, then we can't const prop it as its content
80        // might be different at runtime.
81        if alloc.inner().mutability.is_mut() {
82            throw_machine_stop_str!("can't access mutable globals in ConstProp");
83        }
84
85        interp_ok(())
86    }
87
88    fn find_mir_or_eval_fn(
89        _ecx: &mut InterpCx<'tcx, Self>,
90        _instance: ty::Instance<'tcx>,
91        _abi: &FnAbi<'tcx, Ty<'tcx>>,
92        _args: &[interpret::FnArg<'tcx, Self::Provenance>],
93        _destination: &interpret::MPlaceTy<'tcx, Self::Provenance>,
94        _target: Option<BasicBlock>,
95        _unwind: UnwindAction,
96    ) -> interpret::InterpResult<'tcx, Option<(&'tcx Body<'tcx>, ty::Instance<'tcx>)>> {
97        unimplemented!()
98    }
99
100    fn panic_nounwind(
101        _ecx: &mut InterpCx<'tcx, Self>,
102        _msg: &str,
103    ) -> interpret::InterpResult<'tcx> {
104        unimplemented!()
105    }
106
107    fn call_intrinsic(
108        _ecx: &mut InterpCx<'tcx, Self>,
109        _instance: ty::Instance<'tcx>,
110        _args: &[interpret::OpTy<'tcx, Self::Provenance>],
111        _destination: &interpret::MPlaceTy<'tcx, Self::Provenance>,
112        _target: Option<BasicBlock>,
113        _unwind: UnwindAction,
114    ) -> interpret::InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
115        unimplemented!()
116    }
117
118    fn assert_panic(
119        _ecx: &mut InterpCx<'tcx, Self>,
120        _msg: &rustc_middle::mir::AssertMessage<'tcx>,
121        _unwind: UnwindAction,
122    ) -> interpret::InterpResult<'tcx> {
123        unimplemented!()
124    }
125
126    fn binary_ptr_op(
127        ecx: &InterpCx<'tcx, Self>,
128        bin_op: BinOp,
129        left: &interpret::ImmTy<'tcx, Self::Provenance>,
130        right: &interpret::ImmTy<'tcx, Self::Provenance>,
131    ) -> interpret::InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> {
132        use rustc_middle::mir::BinOp::*;
133        interp_ok(match bin_op {
134            Eq | Ne | Lt | Le | Gt | Ge => {
135                // Types can differ, e.g. fn ptrs with different `for`.
136                assert_eq!(left.layout.backend_repr, right.layout.backend_repr);
137                let size = ecx.pointer_size();
138                // Just compare the bits. ScalarPairs are compared lexicographically.
139                // We thus always compare pairs and simply fill scalars up with 0.
140                // If the pointer has provenance, `to_bits` will return `Err` and we bail out.
141                let left = match **left {
142                    Immediate::Scalar(l) => (l.to_bits(size)?, 0),
143                    Immediate::ScalarPair(l1, l2) => (l1.to_bits(size)?, l2.to_bits(size)?),
144                    Immediate::Uninit => panic!("we should never see uninit data here"),
145                };
146                let right = match **right {
147                    Immediate::Scalar(r) => (r.to_bits(size)?, 0),
148                    Immediate::ScalarPair(r1, r2) => (r1.to_bits(size)?, r2.to_bits(size)?),
149                    Immediate::Uninit => panic!("we should never see uninit data here"),
150                };
151                let res = match bin_op {
152                    Eq => left == right,
153                    Ne => left != right,
154                    Lt => left < right,
155                    Le => left <= right,
156                    Gt => left > right,
157                    Ge => left >= right,
158                    _ => bug!(),
159                };
160                ImmTy::from_bool(res, *ecx.tcx)
161            }
162
163            // Some more operations are possible with atomics.
164            // The return value always has the provenance of the *left* operand.
165            Add | Sub | BitOr | BitAnd | BitXor => {
166                throw_machine_stop_str!("pointer arithmetic is not handled")
167            }
168
169            _ => span_bug!(ecx.cur_span(), "Invalid operator on pointers: {:?}", bin_op),
170        })
171    }
172
173    fn expose_provenance(
174        _ecx: &InterpCx<'tcx, Self>,
175        _provenance: Self::Provenance,
176    ) -> interpret::InterpResult<'tcx> {
177        unimplemented!()
178    }
179
180    fn init_frame(
181        _ecx: &mut InterpCx<'tcx, Self>,
182        _frame: interpret::Frame<'tcx, Self::Provenance>,
183    ) -> interpret::InterpResult<'tcx, interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>>
184    {
185        unimplemented!()
186    }
187
188    fn stack<'a>(
189        _ecx: &'a InterpCx<'tcx, Self>,
190    ) -> &'a [interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>] {
191        // Return an empty stack instead of panicking, as `cur_span` uses it to evaluate constants.
192        &[]
193    }
194
195    fn stack_mut<'a>(
196        _ecx: &'a mut InterpCx<'tcx, Self>,
197    ) -> &'a mut Vec<interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>> {
198        unimplemented!()
199    }
200}