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    CtfeProvenance
bool
!
crate::const_eval::MemoryKind
rustc_data_structures::fx::FxIndexMap<AllocId,
(MemoryKind<Self::MemoryKind>, Allocation)>
Option<Self::MemoryKind>
None
()
()
Box<[u8]>
&InterpCx<'tcx, Self>
_ecx
bool
false;
&mut InterpCx<'tcx, Self>
_ecx
mir::UnwindTerminateReason
_reason
InterpResult<'tcx>
{
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("unwinding cannot happen during compile-time evaluation")));
}
&InterpCx<'tcx, Self>
_ecx
ty::Instance<'tcx>
_instance
InterpResult<'tcx>
interp_ok(());
&mut InterpCx<'tcx, Self>
_ecx
!
fn_val
&FnAbi<'tcx, Ty<'tcx>>
_abi
&[FnArg<'tcx>]
_args
&PlaceTy<'tcx, Self::Provenance>
_destination
Option<mir::BasicBlock>
_target
mir::UnwindAction
_unwind
InterpResult<'tcx>
match fn_val {}
&InterpCx<'tcx, Self>
_ecx
bool
true;
&InterpCx<'tcx, Self>
_ecx
AllocId
_id
&'b Allocation
alloc
InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance>>>
interp_ok(Cow::Borrowed(alloc));
&InterpCx<'tcx, Self>
_ecx
AllocId
_id
MemoryKind<Self::MemoryKind>
_kind
Size
_size
Align
_align
InterpResult<'tcx, Self::AllocExtra>
interp_ok(());
&InterpCx<'tcx, Self>
ecx
DefId
def_id
InterpResult<'tcx, Pointer>
interp_ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id).into(),
        Size::ZERO));
&InterpCx<'tcx, Self>
_ecx
Pointer<CtfeProvenance>
ptr
Option<MemoryKind<Self::MemoryKind>>
_kind
InterpResult<'tcx, Pointer<CtfeProvenance>>
interp_ok(ptr);
&InterpCx<'tcx, Self>
_ecx
u64
addr
InterpResult<'tcx, Pointer<Option<CtfeProvenance>>>
interp_ok(Pointer::without_provenance(addr));
&InterpCx<'tcx, Self>
_ecx
Pointer<CtfeProvenance>
ptr
i64
_size
Option<(AllocId, Size, Self::ProvenanceExtra)>
let (prov, offset) = ptr.prov_and_relative_offset();
Some((prov.alloc_id(), offset, prov.immutable()));
&InterpCx<'tcx, Self>
_ecx
Option<ty::Instance<'tcx>>
_instance
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 assert_panic(
109        _ecx: &mut InterpCx<'tcx, Self>,
110        _msg: &rustc_middle::mir::AssertMessage<'tcx>,
111        _unwind: UnwindAction,
112    ) -> interpret::InterpResult<'tcx> {
113        ::core::panicking::panic("not implemented")unimplemented!()
114    }
115
116    #[inline(always)]
117    fn runtime_checks(_ecx: &InterpCx<'tcx, Self>, r: RuntimeChecks) -> InterpResult<'tcx, bool> {
118        // Runtime checks have different value depending on the crate they are codegenned in.
119        // Verify we aren't trying to evaluate them in mir-optimizations.
120        {
    ::core::panicking::panic_fmt(format_args!("compiletime machine evaluated {0:?}",
            r));
}panic!("compiletime machine evaluated {r:?}")
121    }
122
123    fn binary_ptr_op(
124        ecx: &InterpCx<'tcx, Self>,
125        bin_op: BinOp,
126        left: &interpret::ImmTy<'tcx, Self::Provenance>,
127        right: &interpret::ImmTy<'tcx, Self::Provenance>,
128    ) -> interpret::InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> {
129        use rustc_middle::mir::BinOp::*;
130        interp_ok(match bin_op {
131            Eq | Ne | Lt | Le | Gt | Ge => {
132                // Types can differ, e.g. fn ptrs with different `for`.
133                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);
134                let size = ecx.pointer_size();
135                // Just compare the bits. ScalarPairs are compared lexicographically.
136                // We thus always compare pairs and simply fill scalars up with 0.
137                // If the pointer has provenance, `to_bits` will return `Err` and we bail out.
138                let left = match **left {
139                    Immediate::Scalar(l) => (l.to_bits(size)?, 0),
140                    Immediate::ScalarPair(l1, l2) => (l1.to_bits(size)?, l2.to_bits(size)?),
141                    Immediate::Uninit => {
    ::core::panicking::panic_fmt(format_args!("we should never see uninit data here"));
}panic!("we should never see uninit data here"),
142                };
143                let right = match **right {
144                    Immediate::Scalar(r) => (r.to_bits(size)?, 0),
145                    Immediate::ScalarPair(r1, r2) => (r1.to_bits(size)?, r2.to_bits(size)?),
146                    Immediate::Uninit => {
    ::core::panicking::panic_fmt(format_args!("we should never see uninit data here"));
}panic!("we should never see uninit data here"),
147                };
148                let res = match bin_op {
149                    Eq => left == right,
150                    Ne => left != right,
151                    Lt => left < right,
152                    Le => left <= right,
153                    Gt => left > right,
154                    Ge => left >= right,
155                    _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
156                };
157                ImmTy::from_bool(res, *ecx.tcx)
158            }
159
160            // Some more operations are possible with atomics.
161            // The return value always has the provenance of the *left* operand.
162            Add | Sub | BitOr | BitAnd | BitXor => {
163                {
    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")
164            }
165
166            _ => ::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),
167        })
168    }
169
170    fn expose_provenance(
171        _ecx: &InterpCx<'tcx, Self>,
172        _provenance: Self::Provenance,
173    ) -> interpret::InterpResult<'tcx> {
174        ::core::panicking::panic("not implemented")unimplemented!()
175    }
176
177    fn init_frame(
178        _ecx: &mut InterpCx<'tcx, Self>,
179        _frame: interpret::Frame<'tcx, Self::Provenance>,
180    ) -> interpret::InterpResult<'tcx, interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>>
181    {
182        ::core::panicking::panic("not implemented")unimplemented!()
183    }
184
185    fn stack<'a>(
186        _ecx: &'a InterpCx<'tcx, Self>,
187    ) -> &'a [interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>] {
188        // Return an empty stack instead of panicking, as `cur_span` uses it to evaluate constants.
189        &[]
190    }
191
192    fn stack_mut<'a>(
193        _ecx: &'a mut InterpCx<'tcx, Self>,
194    ) -> &'a mut Vec<interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>> {
195        ::core::panicking::panic("not implemented")unimplemented!()
196    }
197
198    fn get_default_alloc_params(
199        &self,
200    ) -> <Self::Bytes as rustc_middle::mir::interpret::AllocBytes>::AllocParams {
201    }
202}