Skip to main content

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    impl rustc_middle::mir::interpret::MachineStopType for Zst {}
29
30    throw_machine_stop!(Zst)
31}}
32
33pub struct DummyMachine;
34
35impl HasStaticRootDefId for DummyMachine {
36    fn static_def_id(&self) -> Option<rustc_hir::def_id::LocalDefId> {
37        None
38    }
39}
40
41impl<'tcx> interpret::Machine<'tcx> for DummyMachine {
42    type Provenance = CtfeProvenance;
type ProvenanceExtra = bool;
type ExtraFnVal = !;
type MemoryKind = crate::const_eval::MemoryKind;
type MemoryMap =
    rustc_data_structures::fx::FxIndexMap<AllocId,
    (MemoryKind<Self::MemoryKind>, Allocation)>;
const GLOBAL_KIND: Option<Self::MemoryKind> = None;
type AllocExtra = ();
type FrameExtra = ();
type Bytes = Box<[u8]>;
#[inline(always)]
fn ignore_optional_overflow_checks(_ecx: &InterpCx<'tcx, Self>) -> bool {
    false
}
#[inline(always)]
fn unwind_terminate(_ecx: &mut InterpCx<'tcx, Self>,
    _reason: mir::UnwindTerminateReason) -> InterpResult<'tcx> {
    {
        ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
                format_args!("unwinding cannot happen during compile-time evaluation")));
    }
}
#[inline(always)]
fn check_fn_target_features(_ecx: &InterpCx<'tcx, Self>,
    _instance: ty::Instance<'tcx>) -> InterpResult<'tcx> {
    interp_ok(())
}
#[inline(always)]
fn call_extra_fn(_ecx: &mut InterpCx<'tcx, Self>, fn_val: !,
    _abi: &FnAbi<'tcx, Ty<'tcx>>, _args: &[FnArg<'tcx>],
    _destination: &PlaceTy<'tcx, Self::Provenance>,
    _target: Option<mir::BasicBlock>, _unwind: mir::UnwindAction)
    -> InterpResult<'tcx> {
    match fn_val {}
}
#[inline(always)]
fn float_fuse_mul_add(_ecx: &InterpCx<'tcx, Self>) -> bool { true }
#[inline(always)]
fn adjust_global_allocation<'b>(_ecx: &InterpCx<'tcx, Self>, _id: AllocId,
    alloc: &'b Allocation)
    -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance>>> {
    interp_ok(Cow::Borrowed(alloc))
}
fn init_local_allocation(_ecx: &InterpCx<'tcx, Self>, _id: AllocId,
    _kind: MemoryKind<Self::MemoryKind>, _size: Size, _align: Align)
    -> InterpResult<'tcx, Self::AllocExtra> {
    interp_ok(())
}
fn extern_static_pointer(ecx: &InterpCx<'tcx, Self>, def_id: DefId)
    -> InterpResult<'tcx, Pointer> {
    interp_ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id).into(),
            Size::ZERO))
}
#[inline(always)]
fn adjust_alloc_root_pointer(_ecx: &InterpCx<'tcx, Self>,
    ptr: Pointer<CtfeProvenance>, _kind: Option<MemoryKind<Self::MemoryKind>>)
    -> InterpResult<'tcx, Pointer<CtfeProvenance>> {
    interp_ok(ptr)
}
#[inline(always)]
fn ptr_from_addr_cast(_ecx: &InterpCx<'tcx, Self>, addr: u64)
    -> InterpResult<'tcx, Pointer<Option<CtfeProvenance>>> {
    interp_ok(Pointer::without_provenance(addr))
}
#[inline(always)]
fn ptr_get_alloc(_ecx: &InterpCx<'tcx, Self>, ptr: Pointer<CtfeProvenance>,
    _size: i64) -> Option<(AllocId, Size, Self::ProvenanceExtra)> {
    let (prov, offset) = ptr.prov_and_relative_offset();
    Some((prov.alloc_id(), offset, prov.immutable()))
}
#[inline(always)]
fn get_global_alloc_salt(_ecx: &InterpCx<'tcx, Self>,
    _instance: Option<ty::Instance<'tcx>>) -> usize {
    CTFE_ALLOC_SALT
}interpret::compile_time_machine!(<'tcx>);
43    const PANIC_ON_ALLOC_FAIL: bool = true;
44
45    // We want to just eval random consts in the program, so `eval_mir_const` can fail.
46    const ALL_CONSTS_ARE_PRECHECKED: bool = false;
47
48    #[inline(always)]
49    fn enforce_alignment(_ecx: &InterpCx<'tcx, Self>) -> bool {
50        false // no reason to enforce alignment
51    }
52
53    fn enforce_validity(_ecx: &InterpCx<'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
54        false
55    }
56
57    fn before_access_global(
58        _tcx: TyCtxtAt<'tcx>,
59        _machine: &Self,
60        _alloc_id: AllocId,
61        alloc: ConstAllocation<'tcx>,
62        _static_def_id: Option<DefId>,
63        is_write: bool,
64    ) -> InterpResult<'tcx> {
65        if is_write {
66            {
    struct Zst;
    #[automatically_derived]
    impl ::core::fmt::Debug for Zst {
        #[inline]
        fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
            ::core::fmt::Formatter::write_str(f, "Zst")
        }
    }
    impl std::fmt::Display for Zst {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            f.write_fmt(format_args!("can\'t write to global"))
        }
    }
    impl rustc_middle::mir::interpret::MachineStopType for Zst {}
    do yeet ::rustc_middle::mir::interpret::InterpErrorKind::MachineStop(Box::new(Zst))
};throw_machine_stop_str!("can't write to global");
67        }
68
69        // If the static allocation is mutable, then we can't const prop it as its content
70        // might be different at runtime.
71        if alloc.inner().mutability.is_mut() {
72            {
    struct Zst;
    #[automatically_derived]
    impl ::core::fmt::Debug for Zst {
        #[inline]
        fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
            ::core::fmt::Formatter::write_str(f, "Zst")
        }
    }
    impl std::fmt::Display for Zst {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            f.write_fmt(format_args!("can\'t access mutable globals in ConstProp"))
        }
    }
    impl rustc_middle::mir::interpret::MachineStopType for Zst {}
    do yeet ::rustc_middle::mir::interpret::InterpErrorKind::MachineStop(Box::new(Zst))
};throw_machine_stop_str!("can't access mutable globals in ConstProp");
73        }
74
75        interp_ok(())
76    }
77
78    fn find_mir_or_eval_fn(
79        _ecx: &mut InterpCx<'tcx, Self>,
80        _instance: ty::Instance<'tcx>,
81        _abi: &FnAbi<'tcx, Ty<'tcx>>,
82        _args: &[interpret::FnArg<'tcx, Self::Provenance>],
83        _destination: &interpret::PlaceTy<'tcx, Self::Provenance>,
84        _target: Option<BasicBlock>,
85        _unwind: UnwindAction,
86    ) -> interpret::InterpResult<'tcx, Option<(&'tcx Body<'tcx>, ty::Instance<'tcx>)>> {
87        ::core::panicking::panic("not implemented")unimplemented!()
88    }
89
90    fn panic_nounwind(
91        _ecx: &mut InterpCx<'tcx, Self>,
92        _msg: &str,
93    ) -> interpret::InterpResult<'tcx> {
94        ::core::panicking::panic("not implemented")unimplemented!()
95    }
96
97    fn call_intrinsic(
98        _ecx: &mut InterpCx<'tcx, Self>,
99        _instance: ty::Instance<'tcx>,
100        _args: &[interpret::OpTy<'tcx, Self::Provenance>],
101        _destination: &interpret::PlaceTy<'tcx, Self::Provenance>,
102        _target: Option<BasicBlock>,
103        _unwind: UnwindAction,
104    ) -> interpret::InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
105        ::core::panicking::panic("not implemented")unimplemented!()
106    }
107
108    fn call_llvm_intrinsic(
109        _ecx: &mut InterpCx<'tcx, Self>,
110        _instance: ty::Instance<'tcx>,
111        _args: &[interpret::OpTy<'tcx, Self::Provenance>],
112        _destination: &interpret::PlaceTy<'tcx, Self::Provenance>,
113        _target: Option<BasicBlock>,
114    ) -> interpret::InterpResult<'tcx> {
115        ::core::panicking::panic("not implemented")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        ::core::panicking::panic("not implemented")unimplemented!()
124    }
125
126    #[inline(always)]
127    fn runtime_checks(_ecx: &InterpCx<'tcx, Self>, r: RuntimeChecks) -> InterpResult<'tcx, bool> {
128        // Runtime checks have different value depending on the crate they are codegenned in.
129        // Verify we aren't trying to evaluate them in mir-optimizations.
130        {
    ::core::panicking::panic_fmt(format_args!("compiletime machine evaluated {0:?}",
            r));
}panic!("compiletime machine evaluated {r:?}")
131    }
132
133    fn binary_ptr_op(
134        ecx: &InterpCx<'tcx, Self>,
135        bin_op: BinOp,
136        left: &interpret::ImmTy<'tcx, Self::Provenance>,
137        right: &interpret::ImmTy<'tcx, Self::Provenance>,
138    ) -> interpret::InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> {
139        use rustc_middle::mir::BinOp::*;
140        interp_ok(match bin_op {
141            Eq | Ne | Lt | Le | Gt | Ge => {
142                // Types can differ, e.g. fn ptrs with different `for`.
143                {
    match (&left.layout.backend_repr, &right.layout.backend_repr) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(left.layout.backend_repr, right.layout.backend_repr);
144                let size = ecx.pointer_size();
145                // Just compare the bits. ScalarPairs are compared lexicographically.
146                // We thus always compare pairs and simply fill scalars up with 0.
147                // If the pointer has provenance, `to_bits` will return `Err` and we bail out.
148                let left = match **left {
149                    Immediate::Scalar(l) => (l.to_bits(size)?, 0),
150                    Immediate::ScalarPair(l1, l2) => (l1.to_bits(size)?, l2.to_bits(size)?),
151                    Immediate::Uninit => {
    ::core::panicking::panic_fmt(format_args!("we should never see uninit data here"));
}panic!("we should never see uninit data here"),
152                };
153                let right = match **right {
154                    Immediate::Scalar(r) => (r.to_bits(size)?, 0),
155                    Immediate::ScalarPair(r1, r2) => (r1.to_bits(size)?, r2.to_bits(size)?),
156                    Immediate::Uninit => {
    ::core::panicking::panic_fmt(format_args!("we should never see uninit data here"));
}panic!("we should never see uninit data here"),
157                };
158                let res = match bin_op {
159                    Eq => left == right,
160                    Ne => left != right,
161                    Lt => left < right,
162                    Le => left <= right,
163                    Gt => left > right,
164                    Ge => left >= right,
165                    _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
166                };
167                ImmTy::from_bool(res, *ecx.tcx)
168            }
169
170            // Some more operations are possible with atomics.
171            // The return value always has the provenance of the *left* operand.
172            Add | Sub | BitOr | BitAnd | BitXor => {
173                {
    struct Zst;
    #[automatically_derived]
    impl ::core::fmt::Debug for Zst {
        #[inline]
        fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
            ::core::fmt::Formatter::write_str(f, "Zst")
        }
    }
    impl std::fmt::Display for Zst {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            f.write_fmt(format_args!("pointer arithmetic is not handled"))
        }
    }
    impl rustc_middle::mir::interpret::MachineStopType for Zst {}
    do yeet ::rustc_middle::mir::interpret::InterpErrorKind::MachineStop(Box::new(Zst))
}throw_machine_stop_str!("pointer arithmetic is not handled")
174            }
175
176            _ => ::rustc_middle::util::bug::span_bug_fmt(ecx.cur_span(),
    format_args!("Invalid operator on pointers: {0:?}", bin_op))span_bug!(ecx.cur_span(), "Invalid operator on pointers: {:?}", bin_op),
177        })
178    }
179
180    fn expose_provenance(
181        _ecx: &InterpCx<'tcx, Self>,
182        _provenance: Self::Provenance,
183    ) -> interpret::InterpResult<'tcx> {
184        ::core::panicking::panic("not implemented")unimplemented!()
185    }
186
187    fn init_frame(
188        _ecx: &mut InterpCx<'tcx, Self>,
189        _frame: interpret::Frame<'tcx, Self::Provenance>,
190    ) -> interpret::InterpResult<'tcx, interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>>
191    {
192        ::core::panicking::panic("not implemented")unimplemented!()
193    }
194
195    fn stack<'a>(
196        _ecx: &'a InterpCx<'tcx, Self>,
197    ) -> &'a [interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>] {
198        // Return an empty stack instead of panicking, as `cur_span` uses it to evaluate constants.
199        &[]
200    }
201
202    fn stack_mut<'a>(
203        _ecx: &'a mut InterpCx<'tcx, Self>,
204    ) -> &'a mut Vec<interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>> {
205        ::core::panicking::panic("not implemented")unimplemented!()
206    }
207
208    fn get_default_alloc_params(
209        &self,
210    ) -> <Self::Bytes as rustc_middle::mir::interpret::AllocBytes>::AllocParams {
211    }
212}