pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
    pub machine: M,
    pub tcx: TyCtxtAt<'tcx>,
    pub(crate) param_env: ParamEnv<'tcx>,
    pub memory: Memory<'mir, 'tcx, M>,
    pub recursion_limit: Limit,
}

Fields§

§machine: M

Stores the Machine instance.

Note: the stack is provided by the machine.

§tcx: TyCtxtAt<'tcx>

The results of the type checker, from rustc. The span in this is the “root” of the evaluation, i.e., the const we are evaluating (if this is CTFE).

§param_env: ParamEnv<'tcx>

Bounds in scope for polymorphic evaluations.

§memory: Memory<'mir, 'tcx, M>

The virtual memory system.

§recursion_limit: Limit

The recursion limit (cached from tcx.recursion_limit(()))

Implementations§

source§

impl<'mir, 'tcx: 'mir> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>

source

fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32)

source

fn hook_special_const_fn( &mut self, instance: Instance<'tcx>, args: &[FnArg<'tcx>], dest: &PlaceTy<'tcx>, ret: Option<BasicBlock> ) -> InterpResult<'tcx, Option<Instance<'tcx>>>

“Intercept” a function call, because we have something special to do for it. All #[rustc_do_not_const_check] functions should be hooked here. If this returns Some function, which may be instance or a different function with compatible arguments, then evaluation should continue with that function. If this returns None, the function call has been handled and the function has returned.

source

fn align_offset( &mut self, instance: Instance<'tcx>, args: &[OpTy<'tcx>], dest: &PlaceTy<'tcx>, ret: Option<BasicBlock> ) -> InterpResult<'tcx, ControlFlow<()>>

align_offset(ptr, target_align) needs special handling in const eval, because the pointer may not have an address.

If ptr does have a known address, then we return Continue(()) and the function call should proceed as normal.

If ptr doesn’t have an address, but its underlying allocation’s alignment is at most target_align, then we call the function again with an dummy address relative to the allocation.

If ptr doesn’t have an address and target_align is stricter than the underlying allocation’s alignment, then we return usize::MAX immediately.

source

fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8>

See documentation on the ptr_guaranteed_cmp intrinsic.

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

source

pub fn cast( &mut self, src: &OpTy<'tcx, M::Provenance>, cast_kind: CastKind, cast_ty: Ty<'tcx>, dest: &PlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx>

source

pub fn int_to_int_or_float( &self, src: &ImmTy<'tcx, M::Provenance>, cast_to: TyAndLayout<'tcx> ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>

Handles ‘IntToInt’ and ‘IntToFloat’ casts.

source

pub fn float_to_float_or_int( &self, src: &ImmTy<'tcx, M::Provenance>, cast_to: TyAndLayout<'tcx> ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>

Handles ‘FloatToFloat’ and ‘FloatToInt’ casts.

source

pub fn ptr_to_ptr( &self, src: &ImmTy<'tcx, M::Provenance>, cast_to: TyAndLayout<'tcx> ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>

Handles ‘FnPtrToPtr’ and ‘PtrToPtr’ casts.

source

pub fn pointer_expose_address_cast( &mut self, src: &ImmTy<'tcx, M::Provenance>, cast_to: TyAndLayout<'tcx> ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>

source

pub fn pointer_from_exposed_address_cast( &self, src: &ImmTy<'tcx, M::Provenance>, cast_to: TyAndLayout<'tcx> ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>

source

fn cast_from_int_like( &self, scalar: Scalar<M::Provenance>, src_layout: TyAndLayout<'tcx>, cast_ty: Ty<'tcx> ) -> InterpResult<'tcx, Scalar<M::Provenance>>

Low-level cast helper function. This works directly on scalars and can take ‘int-like’ input type (basically everything with a scalar layout) to int/float/char types.

source

fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance>

Low-level cast helper function. Converts an apfloat f into int or float types.

source

fn unsize_into_ptr( &mut self, src: &OpTy<'tcx, M::Provenance>, dest: &PlaceTy<'tcx, M::Provenance>, source_ty: Ty<'tcx>, cast_ty: Ty<'tcx> ) -> InterpResult<'tcx>

src is a pointer to a source_ty, and in dest we should store a pointer to th same data at type cast_ty.

source

pub fn unsize_into( &mut self, src: &OpTy<'tcx, M::Provenance>, cast_ty: TyAndLayout<'tcx>, dest: &PlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx>

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

source

pub fn write_discriminant( &mut self, variant_index: VariantIdx, dest: &impl Writeable<'tcx, M::Provenance> ) -> InterpResult<'tcx>

Writes the discriminant of the given variant.

source

pub fn read_discriminant( &self, op: &impl Readable<'tcx, M::Provenance> ) -> InterpResult<'tcx, VariantIdx>

Read discriminant, return the runtime value as well as the variant index. Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)!

source

pub fn discriminant_for_variant( &self, ty: Ty<'tcx>, variant: VariantIdx ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

source

pub fn new( tcx: TyCtxt<'tcx>, root_span: Span, param_env: ParamEnv<'tcx>, machine: M ) -> Self

source

pub fn cur_span(&self) -> Span

source

pub fn best_lint_scope(&self) -> HirId

Find the first stack frame that is within the current crate, if any, otherwise return the crate’s HirId

source

pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>]

source

pub(crate) fn stack_mut( &mut self ) -> &mut Vec<Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>>

source

pub fn frame_idx(&self) -> usize

source

pub fn frame(&self) -> &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>

source

pub fn frame_mut( &mut self ) -> &mut Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>

source

pub fn body(&self) -> &'mir Body<'tcx>

source

pub fn sign_extend(&self, value: u128, ty: TyAndLayout<'_>) -> u128

source

pub fn truncate(&self, value: u128, ty: TyAndLayout<'_>) -> u128

source

pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool

source

pub fn load_mir( &self, instance: InstanceDef<'tcx>, promoted: Option<Promoted> ) -> InterpResult<'tcx, &'tcx Body<'tcx>>

source

pub(super) fn instantiate_from_current_frame_and_normalize_erasing_regions<T: TypeFoldable<TyCtxt<'tcx>>>( &self, value: T ) -> Result<T, ErrorHandled>

Call this on things you got out of the MIR (so it is as generic as the current stack frame), to bring it into the proper environment for this interpreter.

source

pub(super) fn instantiate_from_frame_and_normalize_erasing_regions<T: TypeFoldable<TyCtxt<'tcx>>>( &self, frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, value: T ) -> Result<T, ErrorHandled>

Call this on things you got out of the MIR (so it is as generic as the provided stack frame), to bring it into the proper environment for this interpreter.

source

pub(super) fn resolve( &self, def: DefId, args: GenericArgsRef<'tcx> ) -> InterpResult<'tcx, Instance<'tcx>>

The args are assumed to already be in our interpreter “universe” (param_env).

source

pub(crate) fn find_closest_untracked_caller_location(&self) -> Span

Walks up the callstack from the intrinsic’s callsite, searching for the first callsite in a frame which is not #[track_caller]. This is the fancy version of cur_span.

source

pub fn layout_of_local( &self, frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, local: Local, layout: Option<TyAndLayout<'tcx>> ) -> InterpResult<'tcx, TyAndLayout<'tcx>>

source

pub(super) fn size_and_align_of( &self, metadata: &MemPlaceMeta<M::Provenance>, layout: &TyAndLayout<'tcx> ) -> InterpResult<'tcx, Option<(Size, Align)>>

Returns the actual dynamic size and alignment of the place at the given type. Only the “meta” (metadata) part of the place matters. This can fail to provide an answer for extern types.

source

pub fn size_and_align_of_mplace( &self, mplace: &MPlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, Option<(Size, Align)>>

source

pub fn push_stack_frame( &mut self, instance: Instance<'tcx>, body: &'mir Body<'tcx>, return_place: &PlaceTy<'tcx, M::Provenance>, return_to_block: StackPopCleanup ) -> InterpResult<'tcx>

source

pub fn go_to_block(&mut self, target: BasicBlock)

Jump to the given block.

source

pub fn return_to_block( &mut self, target: Option<BasicBlock> ) -> InterpResult<'tcx>

Return to the given target basic block. Do not use for unwinding! Use unwind_to_block instead.

If target is None, that indicates the function cannot return, so we raise UB.

source

pub fn unwind_to_block(&mut self, target: UnwindAction) -> InterpResult<'tcx>

Unwind to the given target basic block. Do not use for returning! Use return_to_block instead.

If target is UnwindAction::Continue, that indicates the function does not need cleanup during unwinding, and we will just keep propagating that upwards.

If target is UnwindAction::Unreachable, that indicates the function does not allow unwinding, and doing so is UB.

source

pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>

Pops the current frame from the stack, deallocating the memory for allocated locals.

If unwinding is false, then we are performing a normal return from a function. In this case, we jump back into the frame of the caller, and continue execution as normal.

If unwinding is true, then we are in the middle of a panic, and need to unwind this frame. In this case, we jump to the cleanup block for the function, which is responsible for running Drop impls for any locals that have been initialized at this point. The cleanup block ends with a special Resume terminator, which will cause us to continue unwinding.

source

pub fn storage_live_for_always_live_locals(&mut self) -> InterpResult<'tcx>

In the current stack frame, mark all locals as live that are not arguments and don’t have Storage* annotations (this includes the return place).

source

pub fn storage_live_dyn( &mut self, local: Local, meta: MemPlaceMeta<M::Provenance> ) -> InterpResult<'tcx>

source

pub fn storage_live(&mut self, local: Local) -> InterpResult<'tcx>

Mark a storage as live, killing the previous content.

source

pub fn storage_dead(&mut self, local: Local) -> InterpResult<'tcx>

source

fn deallocate_local( &mut self, local: LocalValue<M::Provenance> ) -> InterpResult<'tcx>

source

pub fn ctfe_query<T>( &self, query: impl FnOnce(TyCtxtAt<'tcx>) -> Result<T, ErrorHandled> ) -> Result<T, ErrorHandled>

Call a query that can return ErrorHandled. Should be used for statics and other globals. (mir::Const/ty::Const have eval methods that can be used directly instead.)

source

pub fn eval_global( &self, instance: Instance<'tcx> ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>

source

pub fn eval_mir_constant( &self, val: &Const<'tcx>, span: Option<Span>, layout: Option<TyAndLayout<'tcx>> ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>

source

pub fn dump_place( &self, place: &PlaceTy<'tcx, M::Provenance> ) -> PlacePrinter<'_, 'mir, 'tcx, M>

source

pub fn generate_stacktrace_from_stack( stack: &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] ) -> Vec<FrameInfo<'tcx>>

source

pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>>

source§

impl<'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, !>> InterpCx<'mir, 'tcx, M>

source

pub fn intern_with_temp_alloc( &mut self, layout: TyAndLayout<'tcx>, f: impl FnOnce(&mut InterpCx<'mir, 'tcx, M>, &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx, ()> ) -> InterpResult<'tcx, AllocId>

A helper function that allocates memory for the layout given and gives you access to mutate it. Once your own mutation code is done, the backing Allocation is removed from the current Memory and interned as read-only into the global memory.

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

source

pub fn emulate_intrinsic( &mut self, instance: Instance<'tcx>, args: &[OpTy<'tcx, M::Provenance>], dest: &PlaceTy<'tcx, M::Provenance>, ret: Option<BasicBlock> ) -> InterpResult<'tcx, bool>

Returns true if emulation happened. Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own intrinsic handling.

source

pub(super) fn emulate_nondiverging_intrinsic( &mut self, intrinsic: &NonDivergingIntrinsic<'tcx> ) -> InterpResult<'tcx>

source

pub fn numeric_intrinsic( &self, name: Symbol, val: Scalar<M::Provenance>, layout: TyAndLayout<'tcx> ) -> InterpResult<'tcx, Scalar<M::Provenance>>

source

pub fn exact_div( &mut self, a: &ImmTy<'tcx, M::Provenance>, b: &ImmTy<'tcx, M::Provenance>, dest: &PlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx>

source

pub fn saturating_arith( &self, mir_op: BinOp, l: &ImmTy<'tcx, M::Provenance>, r: &ImmTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, Scalar<M::Provenance>>

source

pub fn ptr_offset_inbounds( &self, ptr: Pointer<Option<M::Provenance>>, offset_bytes: i64 ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>>

Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its allocation. For integer pointers, we consider each of them their own tiny allocation of size 0, so offset-by-0 (and only 0) is okay – except that null cannot be offset by any value.

source

pub(crate) fn copy_intrinsic( &mut self, src: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, nonoverlapping: bool ) -> InterpResult<'tcx>

Copy count*size_of::<T>() many bytes from *src to *dst.

source

pub(crate) fn write_bytes_intrinsic( &mut self, dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, byte: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance> ) -> InterpResult<'tcx>

source

pub(crate) fn compare_bytes_intrinsic( &mut self, left: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, right: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, byte_count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance> ) -> InterpResult<'tcx, Scalar<M::Provenance>>

source

pub(crate) fn raw_eq_intrinsic( &mut self, lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, rhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance> ) -> InterpResult<'tcx, Scalar<M::Provenance>>

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

source

pub fn global_base_pointer( &self, ptr: Pointer<CtfeProvenance> ) -> InterpResult<'tcx, Pointer<M::Provenance>>

Call this to turn untagged “global” pointers (obtained via tcx) into the machine pointer to the allocation. Must never be used for any other pointers, nor for TLS statics.

Using the resulting pointer represents a direct access to that memory (e.g. by directly using a static), as opposed to access through a pointer that was created by the program.

This function can fail only if ptr points to an extern static.

source

pub fn fn_ptr( &mut self, fn_val: FnVal<'tcx, M::ExtraFnVal> ) -> Pointer<M::Provenance>

source

pub fn allocate_ptr( &mut self, size: Size, align: Align, kind: MemoryKind<M::MemoryKind> ) -> InterpResult<'tcx, Pointer<M::Provenance>>

source

pub fn allocate_bytes_ptr( &mut self, bytes: &[u8], align: Align, kind: MemoryKind<M::MemoryKind>, mutability: Mutability ) -> InterpResult<'tcx, Pointer<M::Provenance>>

source

pub fn allocate_raw_ptr( &mut self, alloc: Allocation, kind: MemoryKind<M::MemoryKind> ) -> InterpResult<'tcx, Pointer<M::Provenance>>

This can fail only if alloc contains provenance.

source

pub fn reallocate_ptr( &mut self, ptr: Pointer<Option<M::Provenance>>, old_size_and_align: Option<(Size, Align)>, new_size: Size, new_align: Align, kind: MemoryKind<M::MemoryKind> ) -> InterpResult<'tcx, Pointer<M::Provenance>>

source

pub fn deallocate_ptr( &mut self, ptr: Pointer<Option<M::Provenance>>, old_size_and_align: Option<(Size, Align)>, kind: MemoryKind<M::MemoryKind> ) -> InterpResult<'tcx>

source

fn get_ptr_access( &self, ptr: Pointer<Option<M::Provenance>>, size: Size ) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>>

Internal helper function to determine the allocation and offset of a pointer (if any).

source

pub fn check_ptr_access( &self, ptr: Pointer<Option<M::Provenance>>, size: Size, msg: CheckInAllocMsg ) -> InterpResult<'tcx>

Check if the given pointer points to live memory of the given size. The caller can control the error message for the out-of-bounds case.

source

fn check_and_deref_ptr<T>( &self, ptr: Pointer<Option<M::Provenance>>, size: Size, msg: CheckInAllocMsg, alloc_size: impl FnOnce(AllocId, Size, M::ProvenanceExtra) -> InterpResult<'tcx, (Size, Align, T)> ) -> InterpResult<'tcx, Option<T>>

Low-level helper function to check if a ptr is in-bounds and potentially return a reference to the allocation it points to. Supports both shared and mutable references, as the actual checking is offloaded to a helper closure.

Returns None if and only if the size is 0.

source

pub(super) fn check_misalign( &self, misaligned: Option<Misalignment>, msg: CheckAlignMsg ) -> InterpResult<'tcx>

source

pub(super) fn is_ptr_misaligned( &self, ptr: Pointer<Option<M::Provenance>>, align: Align ) -> Option<Misalignment>

source

pub fn check_ptr_align( &self, ptr: Pointer<Option<M::Provenance>>, align: Align ) -> InterpResult<'tcx>

Checks a pointer for misalignment.

The error assumes this is checking the pointer used directly for an access.

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

source

pub fn remove_unreachable_allocs( &mut self, reachable_allocs: &FxHashSet<AllocId> )

This function is used by Miri’s provenance GC to remove unreachable entries from the dead_alloc_map.

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

Allocation accessors

source

fn get_global_alloc( &self, id: AllocId, is_write: bool ) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::Provenance, M::AllocExtra, M::Bytes>>>

Helper function to obtain a global (tcx) allocation. This attempts to return a reference to an existing allocation if one can be found in tcx. That, however, is only possible if tcx and this machine use the same pointer provenance, so it is indirected through M::adjust_allocation.

source

fn get_alloc_raw( &self, id: AllocId ) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra, M::Bytes>>

Gives raw access to the Allocation, without bounds or alignment checks. The caller is responsible for calling the access hooks!

You almost certainly want to use get_ptr_alloc/get_ptr_alloc_mut instead.

source

pub fn get_ptr_alloc<'a>( &'a self, ptr: Pointer<Option<M::Provenance>>, size: Size ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>

Bounds-checked but not align-checked allocation access.

source

pub fn get_alloc_extra<'a>( &'a self, id: AllocId ) -> InterpResult<'tcx, &'a M::AllocExtra>

Return the extra field of the given allocation.

source

pub fn get_alloc_mutability<'a>( &'a self, id: AllocId ) -> InterpResult<'tcx, Mutability>

Return the mutability field of the given allocation.

source

fn get_alloc_raw_mut( &mut self, id: AllocId ) -> InterpResult<'tcx, (&mut Allocation<M::Provenance, M::AllocExtra, M::Bytes>, &mut M)>

Gives raw mutable access to the Allocation, without bounds or alignment checks. The caller is responsible for calling the access hooks!

Also returns a ptr to self.extra so that the caller can use it in parallel with the allocation.

source

pub fn get_ptr_alloc_mut<'a>( &'a mut self, ptr: Pointer<Option<M::Provenance>>, size: Size ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>

Bounds-checked but not align-checked allocation access.

source

pub fn get_alloc_extra_mut<'a>( &'a mut self, id: AllocId ) -> InterpResult<'tcx, (&'a mut M::AllocExtra, &'a mut M)>

Return the extra field of the given allocation.

source

pub fn is_alloc_live(&self, id: AllocId) -> bool

Check whether an allocation is live. This is faster than calling InterpCx::get_alloc_info if all you need to check is whether the kind is AllocKind::Dead because it doesn’t have to look up the type and layout of statics.

source

pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind)

Obtain the size and alignment of an allocation, even if that allocation has been deallocated.

source

fn get_live_alloc_size_and_align( &self, id: AllocId, msg: CheckInAllocMsg ) -> InterpResult<'tcx, (Size, Align)>

Obtain the size and alignment of a live allocation.

source

fn get_fn_alloc(&self, id: AllocId) -> Option<FnVal<'tcx, M::ExtraFnVal>>

source

pub fn get_ptr_fn( &self, ptr: Pointer<Option<M::Provenance>> ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>>

source

pub fn get_ptr_vtable( &self, ptr: Pointer<Option<M::Provenance>> ) -> InterpResult<'tcx, (Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>)>

source

pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx>

source

pub fn dump_alloc<'a>(&'a self, id: AllocId) -> DumpAllocs<'a, 'mir, 'tcx, M>

Create a lazy debug printer that prints the given allocation and all allocations it points to, recursively.

source

pub fn dump_allocs<'a>( &'a self, allocs: Vec<AllocId> ) -> DumpAllocs<'a, 'mir, 'tcx, M>

Create a lazy debug printer for a list of allocations and all allocations they point to, recursively.

source

pub fn print_alloc_bytes_for_diagnostics(&self, id: AllocId) -> String

Print the allocation’s bytes, without any nested allocations.

source

pub fn find_leaked_allocations( &self, static_roots: &[AllocId] ) -> Vec<(AllocId, MemoryKind<M::MemoryKind>, Allocation<M::Provenance, M::AllocExtra, M::Bytes>)>

Find leaked allocations. Allocations reachable from static_roots or a Global allocation are not considered leaked, as well as leaks whose kind’s may_leak() returns true.

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

source

pub fn read_bytes_ptr_strip_provenance( &self, ptr: Pointer<Option<M::Provenance>>, size: Size ) -> InterpResult<'tcx, &[u8]>

Reads the given number of bytes from memory, and strips their provenance if possible. Returns them as a slice.

Performs appropriate bounds checks.

source

pub fn write_bytes_ptr( &mut self, ptr: Pointer<Option<M::Provenance>>, src: impl IntoIterator<Item = u8> ) -> InterpResult<'tcx>

Writes the given stream of bytes into memory.

Performs appropriate bounds checks.

source

pub fn mem_copy( &mut self, src: Pointer<Option<M::Provenance>>, dest: Pointer<Option<M::Provenance>>, size: Size, nonoverlapping: bool ) -> InterpResult<'tcx>

source

pub fn mem_copy_repeatedly( &mut self, src: Pointer<Option<M::Provenance>>, dest: Pointer<Option<M::Provenance>>, size: Size, num_copies: u64, nonoverlapping: bool ) -> InterpResult<'tcx>

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

Machine pointer introspection.

source

pub fn scalar_may_be_null( &self, scalar: Scalar<M::Provenance> ) -> InterpResult<'tcx, bool>

Test if this value might be null. If the machine does not support ptr-to-int casts, this is conservative.

source

pub fn ptr_try_get_alloc_id( &self, ptr: Pointer<Option<M::Provenance>> ) -> Result<(AllocId, Size, M::ProvenanceExtra), u64>

Turning a “maybe pointer” into a proper pointer (and some information about where it points), or an absolute address.

The result must be used immediately; it is not allowed to convert the returned data back into a Pointer and store that in machine state. (In fact that’s not even possible since M::ProvenanceExtra is generic and we don’t have an operation to turn it back into M::Provenance.)

source

pub fn ptr_get_alloc_id( &self, ptr: Pointer<Option<M::Provenance>> ) -> InterpResult<'tcx, (AllocId, Size, M::ProvenanceExtra)>

Turning a “maybe pointer” into a proper pointer (and some information about where it points).

The result must be used immediately; it is not allowed to convert the returned data back into a Pointer and store that in machine state. (In fact that’s not even possible since M::ProvenanceExtra is generic and we don’t have an operation to turn it back into M::Provenance.)

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

source

fn read_immediate_from_mplace_raw( &self, mplace: &MPlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::Provenance>>>

Try reading an immediate in memory; this is interesting particularly for ScalarPair. Returns None if the layout does not permit loading this as a value.

This is an internal function; call read_immediate instead.

source

pub fn read_immediate_raw( &self, src: &impl Readable<'tcx, M::Provenance> ) -> InterpResult<'tcx, Either<MPlaceTy<'tcx, M::Provenance>, ImmTy<'tcx, M::Provenance>>>

Try returning an immediate for the operand. If the layout does not permit loading this as an immediate, return where in memory we can find the data. Note that for a given layout, this operation will either always return Left or Right! succeed! Whether it returns Left depends on whether the layout can be represented in an Immediate, not on which data is stored there currently.

This is an internal function that should not usually be used; call read_immediate instead. ConstProp needs it, though.

source

pub fn read_immediate( &self, op: &impl Readable<'tcx, M::Provenance> ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>

Read an immediate from a place, asserting that that is possible with the given layout.

If this succeeds, the ImmTy is never Uninit.

source

pub fn read_scalar( &self, op: &impl Readable<'tcx, M::Provenance> ) -> InterpResult<'tcx, Scalar<M::Provenance>>

Read a scalar from a place

source

pub fn read_pointer( &self, op: &impl Readable<'tcx, M::Provenance> ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>>

Read a pointer from a place.

source

pub fn read_target_usize( &self, op: &impl Readable<'tcx, M::Provenance> ) -> InterpResult<'tcx, u64>

Read a pointer-sized unsigned integer from a place.

source

pub fn read_target_isize( &self, op: &impl Readable<'tcx, M::Provenance> ) -> InterpResult<'tcx, i64>

Read a pointer-sized signed integer from a place.

source

pub fn read_str( &self, mplace: &MPlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, &str>

Turn the wide MPlace into a string (must already be dereferenced!)

source

pub fn operand_to_simd( &self, op: &OpTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)>

Converts a repr(simd) operand into an operand where place_index accesses the SIMD elements. Also returns the number of elements.

Can (but does not always) trigger UB if op is uninitialized.

source

pub fn local_to_op( &self, frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, local: Local, layout: Option<TyAndLayout<'tcx>> ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>

Read from a local. Will not access memory, instead an indirect Operand is returned.

This is public because it is used by priroda to get an OpTy from a local.

source

pub fn place_to_op( &self, place: &PlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>

Every place can be read from, so we can turn them into an operand. This will definitely return Indirect if the place is a Ptr, i.e., this will never actually read from memory.

source

pub fn eval_place_to_op( &self, mir_place: Place<'tcx>, layout: Option<TyAndLayout<'tcx>> ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>

Evaluate a place with the goal of reading from it. This lets us sometimes avoid allocations.

source

pub fn eval_operand( &self, mir_op: &Operand<'tcx>, layout: Option<TyAndLayout<'tcx>> ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>

Evaluate the operand, returning a place where you can then find the data. If you already know the layout, you can save two table lookups by passing it in here.

source

pub(crate) fn const_val_to_op( &self, val_val: ConstValue<'tcx>, ty: Ty<'tcx>, layout: Option<TyAndLayout<'tcx>> ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

source

pub fn binop_with_overflow( &mut self, op: BinOp, left: &ImmTy<'tcx, M::Provenance>, right: &ImmTy<'tcx, M::Provenance>, dest: &PlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx>

Applies the binary operation op to the two operands and writes a tuple of the result and a boolean signifying the potential overflow to the destination.

source

pub fn binop_ignore_overflow( &mut self, op: BinOp, left: &ImmTy<'tcx, M::Provenance>, right: &ImmTy<'tcx, M::Provenance>, dest: &PlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx>

Applies the binary operation op to the arguments and writes the result to the destination.

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

source

fn binary_char_op( &self, bin_op: BinOp, l: char, r: char ) -> (ImmTy<'tcx, M::Provenance>, bool)

source

fn binary_bool_op( &self, bin_op: BinOp, l: bool, r: bool ) -> (ImmTy<'tcx, M::Provenance>, bool)

source

fn binary_float_op<F: Float + FloatConvert<F> + Into<Scalar<M::Provenance>>>( &self, bin_op: BinOp, layout: TyAndLayout<'tcx>, l: F, r: F ) -> (ImmTy<'tcx, M::Provenance>, bool)

source

fn binary_int_op( &self, bin_op: BinOp, l: u128, left_layout: TyAndLayout<'tcx>, r: u128, right_layout: TyAndLayout<'tcx> ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)>

source

fn binary_ptr_op( &self, bin_op: BinOp, left: &ImmTy<'tcx, M::Provenance>, right: &ImmTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)>

source

pub fn overflowing_binary_op( &self, bin_op: BinOp, left: &ImmTy<'tcx, M::Provenance>, right: &ImmTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)>

Returns the result of the specified operation, and whether it overflowed.

source

pub fn wrapping_binary_op( &self, bin_op: BinOp, left: &ImmTy<'tcx, M::Provenance>, right: &ImmTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>

source

pub fn overflowing_unary_op( &self, un_op: UnOp, val: &ImmTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)>

Returns the result of the specified operation, whether it overflowed, and the result type.

source

pub fn wrapping_unary_op( &self, un_op: UnOp, val: &ImmTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>

source§

impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M>
where Prov: Provenance, M: Machine<'mir, 'tcx, Provenance = Prov>,

source

pub fn ptr_with_meta_to_mplace( &self, ptr: Pointer<Option<M::Provenance>>, meta: MemPlaceMeta<M::Provenance>, layout: TyAndLayout<'tcx> ) -> MPlaceTy<'tcx, M::Provenance>

source

pub fn ptr_to_mplace( &self, ptr: Pointer<Option<M::Provenance>>, layout: TyAndLayout<'tcx> ) -> MPlaceTy<'tcx, M::Provenance>

source

pub fn ref_to_mplace( &self, val: &ImmTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>

Take a value, which represents a (thin or wide) reference, and make it a place. Alignment is just based on the type. This is the inverse of mplace_to_ref().

Only call this if you are sure the place is “valid” (aligned and inbounds), or do not want to ever use the place for memory access! Generally prefer deref_pointer.

source

pub fn mplace_to_ref( &self, mplace: &MPlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>

Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space. align information is lost! This is the inverse of ref_to_mplace.

source

pub fn deref_pointer( &self, src: &impl Readable<'tcx, M::Provenance> ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>

Take an operand, representing a pointer, and dereference it to a place. Corresponds to the * operator in Rust.

source

pub(super) fn get_place_alloc( &self, mplace: &MPlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>

source

pub(super) fn get_place_alloc_mut( &mut self, mplace: &MPlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>

source

pub fn mplace_to_simd( &self, mplace: &MPlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)>

Converts a repr(simd) place into a place where place_index accesses the SIMD elements. Also returns the number of elements.

source

pub fn place_to_simd( &mut self, place: &PlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)>

Converts a repr(simd) place into a place where place_index accesses the SIMD elements. Also returns the number of elements.

source

pub fn local_to_place( &self, frame: usize, local: Local ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>>

source

pub fn eval_place( &self, mir_place: Place<'tcx> ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>>

Computes a place. You should only use this if you intend to write into this place; for reading, a more efficient alternative is eval_place_to_op.

source

pub fn write_immediate( &mut self, src: Immediate<M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance> ) -> InterpResult<'tcx>

Write an immediate to a place

source

pub fn write_scalar( &mut self, val: impl Into<Scalar<M::Provenance>>, dest: &impl Writeable<'tcx, M::Provenance> ) -> InterpResult<'tcx>

Write a scalar to a place

source

pub fn write_pointer( &mut self, ptr: impl Into<Pointer<Option<M::Provenance>>>, dest: &impl Writeable<'tcx, M::Provenance> ) -> InterpResult<'tcx>

Write a pointer to a place

source

fn write_immediate_no_validate( &mut self, src: Immediate<M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance> ) -> InterpResult<'tcx>

Write an immediate to a place. If you use this you are responsible for validating that things got copied at the right type.

source

fn write_immediate_to_mplace_no_validate( &mut self, value: Immediate<M::Provenance>, layout: TyAndLayout<'tcx>, dest: MemPlace<M::Provenance> ) -> InterpResult<'tcx>

Write an immediate to memory. If you use this you are responsible for validating that things got copied at the right layout.

source

pub fn write_uninit( &mut self, dest: &impl Writeable<'tcx, M::Provenance> ) -> InterpResult<'tcx>

source

pub(super) fn copy_op_no_dest_validation( &mut self, src: &impl Readable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance> ) -> InterpResult<'tcx>

Copies the data from an operand to a place. The layouts of the src and dest may disagree. Does not perform validation of the destination. The only known use case for this function is checking the return value of a static during stack frame popping.

source

pub fn copy_op_allow_transmute( &mut self, src: &impl Readable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance> ) -> InterpResult<'tcx>

Copies the data from an operand to a place. The layouts of the src and dest may disagree.

source

pub fn copy_op( &mut self, src: &impl Readable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance> ) -> InterpResult<'tcx>

Copies the data from an operand to a place. src and dest must have the same layout and the copied value will be validated.

source

fn copy_op_inner( &mut self, src: &impl Readable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>, allow_transmute: bool, validate_dest: bool ) -> InterpResult<'tcx>

Copies the data from an operand to a place. allow_transmute indicates whether the layouts may disagree.

source

fn copy_op_no_validate( &mut self, src: &impl Readable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>, allow_transmute: bool ) -> InterpResult<'tcx>

Copies the data from an operand to a place. allow_transmute indicates whether the layouts may disagree. Also, if you use this you are responsible for validating that things get copied at the right type.

source

pub fn force_allocation( &mut self, place: &PlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>

Ensures that a place is in memory, and returns where it is. If the place currently refers to a local that doesn’t yet have a matching allocation, create such an allocation. This is essentially force_to_memplace.

source

pub fn allocate_dyn( &mut self, layout: TyAndLayout<'tcx>, kind: MemoryKind<M::MemoryKind>, meta: MemPlaceMeta<M::Provenance> ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>

source

pub fn allocate( &mut self, layout: TyAndLayout<'tcx>, kind: MemoryKind<M::MemoryKind> ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>

source

pub fn allocate_str( &mut self, str: &str, kind: MemoryKind<M::MemoryKind>, mutbl: Mutability ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>

Returns a wide MPlace of type str to a new 1-aligned allocation.

source

pub fn raw_const_to_mplace( &self, raw: ConstAlloc<'tcx> ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>

source

pub(super) fn unpack_dyn_trait( &self, mplace: &MPlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, Pointer<Option<M::Provenance>>)>

Turn a place with a dyn Trait type into a place with the actual dynamic type. Aso returns the vtable.

source

pub(super) fn unpack_dyn_star<P: Projectable<'tcx, M::Provenance>>( &self, val: &P ) -> InterpResult<'tcx, (P, Pointer<Option<M::Provenance>>)>

Turn a dyn* Trait type into an value with the actual dynamic type. Also returns the vtable.

source§

impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M>
where Prov: Provenance, M: Machine<'mir, 'tcx, Provenance = Prov>,

source

pub fn project_field<P: Projectable<'tcx, M::Provenance>>( &self, base: &P, field: usize ) -> InterpResult<'tcx, P>

Offset a pointer to project to a field of a struct/union. Unlike place_field, this is always possible without allocating, so it can take &self. Also return the field’s layout. This supports both struct and array fields, but not slices!

This also works for arrays, but then the usize index type is restricting. For indexing into arrays, use mplace_index.

source

pub fn project_downcast<P: Projectable<'tcx, M::Provenance>>( &self, base: &P, variant: VariantIdx ) -> InterpResult<'tcx, P>

Downcasting to an enum variant.

source

pub fn project_index<P: Projectable<'tcx, M::Provenance>>( &self, base: &P, index: u64 ) -> InterpResult<'tcx, P>

Compute the offset and field layout for accessing the given index.

source

fn project_constant_index<P: Projectable<'tcx, M::Provenance>>( &self, base: &P, offset: u64, min_length: u64, from_end: bool ) -> InterpResult<'tcx, P>

source

pub fn project_array_fields<'a, P: Projectable<'tcx, M::Provenance>>( &self, base: &'a P ) -> InterpResult<'tcx, ArrayIterator<'tcx, 'a, M::Provenance, P>>

Iterates over all fields of an array. Much more efficient than doing the same by repeatedly calling project_index.

source

fn project_subslice<P: Projectable<'tcx, M::Provenance>>( &self, base: &P, from: u64, to: u64, from_end: bool ) -> InterpResult<'tcx, P>

Subslicing

source

pub fn project<P>( &self, base: &P, proj_elem: PlaceElem<'tcx> ) -> InterpResult<'tcx, P>
where P: Projectable<'tcx, M::Provenance> + From<MPlaceTy<'tcx, M::Provenance>> + Debug,

Applying a general projection

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

source

pub fn step(&mut self) -> InterpResult<'tcx, bool>

Returns true as long as there are more things to do.

This is used by priroda

This is marked #inline(always) to work around adversarial codegen when opt-level = 3

source

pub fn statement(&mut self, stmt: &Statement<'tcx>) -> InterpResult<'tcx>

Runs the interpretation logic for the given mir::Statement at the current frame and statement counter.

This does NOT move the statement counter forward, the caller has to do that!

source

pub fn eval_rvalue_into_place( &mut self, rvalue: &Rvalue<'tcx>, place: Place<'tcx> ) -> InterpResult<'tcx>

Evaluate an assignment statement.

There is no separate eval_rvalue function. Instead, the code for handling each rvalue type writes its results directly into the memory specified by the place.

source

fn write_aggregate( &mut self, kind: &AggregateKind<'tcx>, operands: &IndexSlice<FieldIdx, Operand<'tcx>>, dest: &PlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx>

Writes the aggregate to the destination.

source

fn write_repeat( &mut self, operand: &Operand<'tcx>, dest: &PlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx>

Repeats operand into the destination. dest must have array type, and that type determines how often operand is repeated.

source

fn terminator(&mut self, terminator: &Terminator<'tcx>) -> InterpResult<'tcx>

Evaluate the given terminator. Will also adjust the stack frame and statement position accordingly.

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

source

pub fn copy_fn_arg( &self, arg: &FnArg<'tcx, M::Provenance> ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>

Make a copy of the given fn_arg. Any InPlace are degenerated to copies, no protection of the original memory occurs.

source

pub fn copy_fn_args( &self, args: &[FnArg<'tcx, M::Provenance>] ) -> InterpResult<'tcx, Vec<OpTy<'tcx, M::Provenance>>>

Make a copy of the given fn_args. Any InPlace are degenerated to copies, no protection of the original memory occurs.

source

pub fn fn_arg_field( &self, arg: &FnArg<'tcx, M::Provenance>, field: usize ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>>

source

pub(super) fn eval_terminator( &mut self, terminator: &Terminator<'tcx> ) -> InterpResult<'tcx>

source

pub(super) fn eval_fn_call_arguments( &self, ops: &[Spanned<Operand<'tcx>>] ) -> InterpResult<'tcx, Vec<FnArg<'tcx, M::Provenance>>>

Evaluate the arguments of a function call

source

fn unfold_transparent( &self, layout: TyAndLayout<'tcx>, may_unfold: impl Fn(AdtDef<'tcx>) -> bool ) -> TyAndLayout<'tcx>

Find the wrapped inner type of a transparent wrapper. Must not be called on 1-ZST (as they don’t have a uniquely defined “wrapped field”).

We work with TyAndLayout here since that makes it much easier to iterate over all fields.

source

fn unfold_npo( &self, layout: TyAndLayout<'tcx> ) -> InterpResult<'tcx, TyAndLayout<'tcx>>

Unwrap types that are guaranteed a null-pointer-optimization

source

fn layout_compat( &self, caller: TyAndLayout<'tcx>, callee: TyAndLayout<'tcx> ) -> InterpResult<'tcx, bool>

Check if these two layouts look like they are fn-ABI-compatible. (We also compare the PassMode, so this doesn’t have to check everything. But it turns out that only checking the PassMode is insufficient.)

source

fn check_argument_compat( &self, caller_abi: &ArgAbi<'tcx, Ty<'tcx>>, callee_abi: &ArgAbi<'tcx, Ty<'tcx>> ) -> InterpResult<'tcx, bool>

source

fn pass_argument<'x, 'y>( &mut self, caller_args: &mut impl Iterator<Item = (&'x FnArg<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>)>, callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, callee_arg: &Place<'tcx>, callee_ty: Ty<'tcx>, already_live: bool ) -> InterpResult<'tcx>
where 'tcx: 'x + 'y,

Initialize a single callee argument, checking the types for compatibility.

source

pub(crate) fn eval_fn_call( &mut self, fn_val: FnVal<'tcx, M::ExtraFnVal>, (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>), args: &[FnArg<'tcx, M::Provenance>], with_caller_location: bool, destination: &PlaceTy<'tcx, M::Provenance>, target: Option<BasicBlock>, unwind: UnwindAction ) -> InterpResult<'tcx>

Call this function – pushing the stack frame and initializing the arguments.

caller_fn_abi is used to determine if all the arguments are passed the proper way. However, we also need caller_abi to determine if we need to do untupling of arguments.

with_caller_location indicates whether the caller passed a caller location. Miri implements caller locations without argument passing, but to match FnAbi we need to know when those arguments are present.

source

fn check_fn_target_features( &self, instance: Instance<'tcx> ) -> InterpResult<'tcx, ()>

source

fn drop_in_place( &mut self, place: &PlaceTy<'tcx, M::Provenance>, instance: Instance<'tcx>, target: BasicBlock, unwind: UnwindAction ) -> InterpResult<'tcx>

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

source

pub fn get_vtable_ptr( &self, ty: Ty<'tcx>, poly_trait_ref: Option<PolyExistentialTraitRef<'tcx>> ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>>

Creates a dynamic vtable for the given type and vtable origin. This is used only for objects.

The trait_ref encodes the erased self type. Hence, if we are making an object Foo<Trait> from a value of type Foo<T>, then trait_ref would map T: Trait. None here means that this is an auto trait without any methods, so we only need the basic vtable (drop, size, align).

source

pub fn get_vtable_entries( &self, vtable: Pointer<Option<M::Provenance>> ) -> InterpResult<'tcx, &'tcx [VtblEntry<'tcx>]>

Returns a high-level representation of the entries of the given vtable.

source

pub fn get_vtable_size_and_align( &self, vtable: Pointer<Option<M::Provenance>> ) -> InterpResult<'tcx, (Size, Align)>

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>

source

fn validate_operand_internal( &self, op: &OpTy<'tcx, M::Provenance>, path: Vec<PathElem>, ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>>, ctfe_mode: Option<CtfeValidationMode> ) -> InterpResult<'tcx>

source

pub(crate) fn const_validate_operand( &self, op: &OpTy<'tcx, M::Provenance>, path: Vec<PathElem>, ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>, ctfe_mode: CtfeValidationMode ) -> InterpResult<'tcx>

This function checks the data at op to be const-valid. op is assumed to cover valid memory if it is an indirect operand. It will error if the bits at the destination do not match the ones described by the layout.

ref_tracking is used to record references that we encounter so that they can be checked recursively by an outside driving loop.

constant controls whether this must satisfy the rules for constants:

  • no pointers to statics.
  • no UnsafeCell or non-ZST &mut.
source

pub fn validate_operand( &self, op: &OpTy<'tcx, M::Provenance> ) -> InterpResult<'tcx>

This function checks the data at op to be runtime-valid. op is assumed to cover valid memory if it is an indirect operand. It will error if the bits at the destination do not match the ones described by the layout.

Trait Implementations§

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'mir, 'tcx, M>

§

type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpErrorInfo<'tcx>>

The &FnAbi-wrapping type (or &FnAbi itself), which will be returned from fn_abi_of_* (see also handle_fn_abi_err).
source§

fn handle_fn_abi_err( &self, err: FnAbiError<'tcx>, _span: Span, _fn_abi_request: FnAbiRequest<'tcx> ) -> InterpErrorInfo<'tcx>

Helper used for fn_abi_of_*, to adapt tcx.fn_abi_of_*(...) into a Self::FnAbiOfResult (which does not need to be a Result<...>). Read more
source§

impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M>

source§

impl<'mir, 'tcx, M> HasParamEnv<'tcx> for InterpCx<'mir, 'tcx, M>
where M: Machine<'mir, 'tcx>,

source§

fn param_env(&self) -> ParamEnv<'tcx>

source§

impl<'mir, 'tcx, M> HasTyCtxt<'tcx> for InterpCx<'mir, 'tcx, M>
where M: Machine<'mir, 'tcx>,

source§

fn tcx(&self) -> TyCtxt<'tcx>

source§

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'mir, 'tcx, M>

§

type LayoutOfResult = Result<TyAndLayout<'tcx, Ty<'tcx>>, InterpErrorInfo<'tcx>>

The TyAndLayout-wrapping type (or TyAndLayout itself), which will be returned from layout_of (see also handle_layout_err).
source§

fn layout_tcx_at_span(&self) -> Span

Span to use for tcx.at(span), from layout_of.
source§

fn handle_layout_err( &self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx> ) -> InterpErrorInfo<'tcx>

Helper used for layout_of, to adapt tcx.layout_of(...) into a Self::LayoutOfResult (which does not need to be a Result<...>). Read more

Auto Trait Implementations§

§

impl<'mir, 'tcx, M> DynSend for InterpCx<'mir, 'tcx, M>
where M: DynSend, <M as Machine<'mir, 'tcx>>::ExtraFnVal: DynSend, <M as Machine<'mir, 'tcx>>::MemoryMap: DynSend,

§

impl<'mir, 'tcx, M> DynSync for InterpCx<'mir, 'tcx, M>
where M: DynSync, <M as Machine<'mir, 'tcx>>::ExtraFnVal: DynSync, <M as Machine<'mir, 'tcx>>::MemoryMap: DynSync,

§

impl<'mir, 'tcx, M> !RefUnwindSafe for InterpCx<'mir, 'tcx, M>

§

impl<'mir, 'tcx, M> !Send for InterpCx<'mir, 'tcx, M>

§

impl<'mir, 'tcx, M> !Sync for InterpCx<'mir, 'tcx, M>

§

impl<'mir, 'tcx, M> Unpin for InterpCx<'mir, 'tcx, M>
where M: Unpin, <M as Machine<'mir, 'tcx>>::ExtraFnVal: Unpin, <M as Machine<'mir, 'tcx>>::MemoryMap: Unpin,

§

impl<'mir, 'tcx, M> !UnwindSafe for InterpCx<'mir, 'tcx, M>

Blanket Implementations§

source§

impl<T> Aligned for T

source§

const ALIGN: Alignment = _

Alignment of Self.
source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T, R> CollectAndApply<T, R> for T

source§

fn collect_and_apply<I, F>(iter: I, f: F) -> R
where I: Iterator<Item = T>, F: FnOnce(&[T]) -> R,

Equivalent to f(&iter.collect::<Vec<_>>()).

§

type Output = R

§

impl<T> Filterable for T

§

fn filterable( self, filter_name: &'static str ) -> RequestFilterDataProvider<T, fn(_: DataRequest<'_>) -> bool>

Creates a filterable data provider with the given name for debugging. Read more
source§

impl<'tcx, C> FnAbiOf<'tcx> for C
where C: FnAbiOfHelpers<'tcx>,

source§

fn fn_abi_of_fn_ptr( &self, sig: Binder<'tcx, FnSig<'tcx>>, extra_args: &'tcx List<Ty<'tcx>> ) -> Self::FnAbiOfResult

Compute a FnAbi suitable for indirect calls, i.e. to fn pointers. Read more
source§

fn fn_abi_of_instance( &self, instance: Instance<'tcx>, extra_args: &'tcx List<Ty<'tcx>> ) -> Self::FnAbiOfResult

Compute a FnAbi suitable for declaring/defining an fn instance, and for direct calls to an fn. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<P> IntoQueryParam<P> for P

source§

impl<'tcx, C> LayoutOf<'tcx> for C
where C: LayoutOfHelpers<'tcx>,

source§

fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult

Computes the layout of a type. Note that this implicitly executes in “reveal all” mode, and will normalize the input type.
source§

fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::LayoutOfResult

Computes the layout of a type, at span. Note that this implicitly executes in “reveal all” mode, and will normalize the input type.
source§

impl<T> MaybeResult<T> for T

§

type Error = !

source§

fn from(_: Result<T, <T as MaybeResult<T>>::Error>) -> T

source§

fn to_result(self) -> Result<T, <T as MaybeResult<T>>::Error>

§

impl<T> Pointable for T

§

const ALIGN: usize = _

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<T> PointerArithmetic for T
where T: HasDataLayout,

source§

fn pointer_size(&self) -> Size

source§

fn max_size_of_val(&self) -> Size

source§

fn target_usize_max(&self) -> u64

source§

fn target_isize_min(&self) -> i64

source§

fn target_isize_max(&self) -> i64

source§

fn target_usize_to_isize(&self, val: u64) -> i64

source§

fn truncate_to_ptr(&self, _: (u64, bool)) -> (u64, bool)

Helper function: truncate given value-“overflowed flag” pair to pointer size and update “overflowed flag” if there was an overflow. This should be called by all the other methods before returning!
source§

fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool)

source§

fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool)

source§

fn offset<'tcx>(&self, val: u64, i: u64) -> Result<u64, InterpErrorInfo<'tcx>>

source§

fn signed_offset<'tcx>( &self, val: u64, i: i64 ) -> Result<u64, InterpErrorInfo<'tcx>>

source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<'tcx, T> ToPredicate<'tcx, T> for T

source§

fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> T

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<Tcx, T> Value<Tcx> for T
where Tcx: DepContext,

source§

default fn from_cycle_error( tcx: Tcx, cycle_error: &CycleError, _guar: ErrorGuaranteed ) -> T

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

impl<'a, T> Captures<'a> for T
where T: ?Sized,

§

impl<T> ErasedDestructor for T
where T: 'static,

Layout§

Note: Unable to compute type layout, possibly due to this type having generic parameters. Layout can only be computed for concrete, fully-instantiated types.