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