Struct rustc_const_eval::interpret::eval_context::InterpCx
source · 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>>
impl<'mir, 'tcx: 'mir> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>
sourcefn hook_special_const_fn(
&mut self,
instance: Instance<'tcx>,
args: &[FnArg<'tcx>],
dest: &PlaceTy<'tcx>,
ret: Option<BasicBlock>
) -> InterpResult<'tcx, Option<Instance<'tcx>>>
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.
sourcefn align_offset(
&mut self,
instance: Instance<'tcx>,
args: &[OpTy<'tcx>],
dest: &PlaceTy<'tcx>,
ret: Option<BasicBlock>
) -> InterpResult<'tcx, ControlFlow<()>>
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.
sourcefn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8>
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>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
pub fn cast( &mut self, src: &OpTy<'tcx, M::Provenance>, cast_kind: CastKind, cast_ty: Ty<'tcx>, dest: &PlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx>
sourcepub fn int_to_int_or_float(
&self,
src: &ImmTy<'tcx, M::Provenance>,
cast_to: TyAndLayout<'tcx>
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>
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.
sourcepub fn float_to_float_or_int(
&self,
src: &ImmTy<'tcx, M::Provenance>,
cast_to: TyAndLayout<'tcx>
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>
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.
sourcepub fn ptr_to_ptr(
&self,
src: &ImmTy<'tcx, M::Provenance>,
cast_to: TyAndLayout<'tcx>
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>
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.
pub fn pointer_expose_address_cast( &mut self, src: &ImmTy<'tcx, M::Provenance>, cast_to: TyAndLayout<'tcx> ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>
pub fn pointer_from_exposed_address_cast( &self, src: &ImmTy<'tcx, M::Provenance>, cast_to: TyAndLayout<'tcx> ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>
sourcefn cast_from_int_like(
&self,
scalar: Scalar<M::Provenance>,
src_layout: TyAndLayout<'tcx>,
cast_ty: Ty<'tcx>
) -> InterpResult<'tcx, Scalar<M::Provenance>>
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.
sourcefn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance>where
F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>,
fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance>where F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>,
Low-level cast helper function. Converts an apfloat f
into int or float types.
sourcefn 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>
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
.
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>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
sourcepub fn write_discriminant(
&mut self,
variant_index: VariantIdx,
dest: &impl Writeable<'tcx, M::Provenance>
) -> InterpResult<'tcx>
pub fn write_discriminant( &mut self, variant_index: VariantIdx, dest: &impl Writeable<'tcx, M::Provenance> ) -> InterpResult<'tcx>
Writes the discriminant of the given variant.
sourcepub fn read_discriminant(
&self,
op: &impl Readable<'tcx, M::Provenance>
) -> InterpResult<'tcx, VariantIdx>
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)!
pub fn discriminant_for_variant( &self, layout: TyAndLayout<'tcx>, variant: VariantIdx ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>
source§impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
pub fn new( tcx: TyCtxt<'tcx>, root_span: Span, param_env: ParamEnv<'tcx>, machine: M ) -> Self
pub fn cur_span(&self) -> Span
sourcepub fn best_lint_scope(&self) -> HirId
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
sourcepub fn format_error(&self, e: InterpErrorInfo<'tcx>) -> String
pub fn format_error(&self, e: InterpErrorInfo<'tcx>) -> String
Turn the given error into a human-readable string. Expects the string to be printed, so if
RUSTC_CTFE_BACKTRACE
is set this will show a backtrace of the rustc internals that
triggered the error.
This is NOT the preferred way to render an error; use report
from const_eval
instead.
However, this is useful when error messages appear in ICEs.
pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>]
pub(crate) fn stack_mut( &mut self ) -> &mut Vec<Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>>
pub fn frame_idx(&self) -> usize
pub fn frame(&self) -> &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>
pub fn frame_mut( &mut self ) -> &mut Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>
pub fn body(&self) -> &'mir Body<'tcx>
pub fn sign_extend(&self, value: u128, ty: TyAndLayout<'_>) -> u128
pub fn truncate(&self, value: u128, ty: TyAndLayout<'_>) -> u128
pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool
pub fn load_mir( &self, instance: InstanceDef<'tcx>, promoted: Option<Promoted> ) -> InterpResult<'tcx, &'tcx Body<'tcx>>
sourcepub(super) fn subst_from_current_frame_and_normalize_erasing_regions<T: TypeFoldable<TyCtxt<'tcx>>>(
&self,
value: T
) -> Result<T, ErrorHandled>
pub(super) fn subst_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.
sourcepub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<TyCtxt<'tcx>>>(
&self,
frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
value: T
) -> Result<T, ErrorHandled>
pub(super) fn subst_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.
sourcepub(super) fn resolve(
&self,
def: DefId,
args: GenericArgsRef<'tcx>
) -> InterpResult<'tcx, Instance<'tcx>>
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).
pub fn layout_of_local( &self, frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, local: Local, layout: Option<TyAndLayout<'tcx>> ) -> InterpResult<'tcx, TyAndLayout<'tcx>>
sourcepub(super) fn size_and_align_of(
&self,
metadata: &MemPlaceMeta<M::Provenance>,
layout: &TyAndLayout<'tcx>
) -> InterpResult<'tcx, Option<(Size, Align)>>
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.
pub fn size_and_align_of_mplace( &self, mplace: &MPlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, Option<(Size, Align)>>
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>
sourcepub fn go_to_block(&mut self, target: BasicBlock)
pub fn go_to_block(&mut self, target: BasicBlock)
Jump to the given block.
sourcepub fn return_to_block(
&mut self,
target: Option<BasicBlock>
) -> InterpResult<'tcx>
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.
sourcepub fn unwind_to_block(&mut self, target: UnwindAction) -> InterpResult<'tcx>
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.
sourcepub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>
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.
sourcepub fn storage_live_for_always_live_locals(&mut self) -> InterpResult<'tcx>
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).
pub fn storage_live_dyn( &mut self, local: Local, meta: MemPlaceMeta<M::Provenance> ) -> InterpResult<'tcx>
sourcepub fn storage_live(&mut self, local: Local) -> InterpResult<'tcx>
pub fn storage_live(&mut self, local: Local) -> InterpResult<'tcx>
Mark a storage as live, killing the previous content.
pub fn storage_dead(&mut self, local: Local) -> InterpResult<'tcx>
fn deallocate_local( &mut self, local: LocalValue<M::Provenance> ) -> InterpResult<'tcx>
sourcepub fn ctfe_query<T>(
&self,
query: impl FnOnce(TyCtxtAt<'tcx>) -> Result<T, ErrorHandled>
) -> Result<T, ErrorHandled>
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.)
pub fn eval_global( &self, instance: Instance<'tcx> ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>
pub fn eval_mir_constant( &self, val: &Const<'tcx>, span: Option<Span>, layout: Option<TyAndLayout<'tcx>> ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>
pub fn dump_place( &self, place: &PlaceTy<'tcx, M::Provenance> ) -> PlacePrinter<'_, 'mir, 'tcx, M>
pub fn generate_stacktrace_from_stack( stack: &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] ) -> Vec<FrameInfo<'tcx>>
pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>>
source§impl<'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, !>> InterpCx<'mir, 'tcx, M>
impl<'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, !>> InterpCx<'mir, 'tcx, M>
sourcepub 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>
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>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
sourcepub(crate) fn find_closest_untracked_caller_location(&self) -> Span
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]
.
sourcepub(crate) fn alloc_caller_location(
&mut self,
filename: Symbol,
line: u32,
col: u32
) -> MPlaceTy<'tcx, M::Provenance>
pub(crate) fn alloc_caller_location( &mut self, filename: Symbol, line: u32, col: u32 ) -> MPlaceTy<'tcx, M::Provenance>
Allocate a const core::panic::Location
with the provided filename and line/column numbers.
pub(crate) fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32)
pub fn alloc_caller_location_for_span( &mut self, span: Span ) -> MPlaceTy<'tcx, M::Provenance>
source§impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
sourcepub fn emulate_intrinsic(
&mut self,
instance: Instance<'tcx>,
args: &[OpTy<'tcx, M::Provenance>],
dest: &PlaceTy<'tcx, M::Provenance>,
ret: Option<BasicBlock>
) -> InterpResult<'tcx, bool>
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.
pub(super) fn emulate_nondiverging_intrinsic( &mut self, intrinsic: &NonDivergingIntrinsic<'tcx> ) -> InterpResult<'tcx>
pub fn exact_div( &mut self, a: &ImmTy<'tcx, M::Provenance>, b: &ImmTy<'tcx, M::Provenance>, dest: &PlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx>
pub fn saturating_arith( &self, mir_op: BinOp, l: &ImmTy<'tcx, M::Provenance>, r: &ImmTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, Scalar<M::Provenance>>
sourcepub fn ptr_offset_inbounds(
&self,
ptr: Pointer<Option<M::Provenance>>,
pointee_ty: Ty<'tcx>,
offset_count: i64
) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>>
pub fn ptr_offset_inbounds( &self, ptr: Pointer<Option<M::Provenance>>, pointee_ty: Ty<'tcx>, offset_count: 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.
sourcepub(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>
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
.
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>
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>>
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>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
sourcepub fn global_base_pointer(
&self,
ptr: Pointer<AllocId>
) -> InterpResult<'tcx, Pointer<M::Provenance>>
pub fn global_base_pointer( &self, ptr: Pointer<AllocId> ) -> 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
.
pub fn fn_ptr( &mut self, fn_val: FnVal<'tcx, M::ExtraFnVal> ) -> Pointer<M::Provenance>
pub fn allocate_ptr( &mut self, size: Size, align: Align, kind: MemoryKind<M::MemoryKind> ) -> InterpResult<'tcx, Pointer<M::Provenance>>
pub fn allocate_bytes_ptr( &mut self, bytes: &[u8], align: Align, kind: MemoryKind<M::MemoryKind>, mutability: Mutability ) -> InterpResult<'tcx, Pointer<M::Provenance>>
sourcepub fn allocate_raw_ptr(
&mut self,
alloc: Allocation,
kind: MemoryKind<M::MemoryKind>
) -> InterpResult<'tcx, Pointer<M::Provenance>>
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.
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>>
pub fn deallocate_ptr( &mut self, ptr: Pointer<Option<M::Provenance>>, old_size_and_align: Option<(Size, Align)>, kind: MemoryKind<M::MemoryKind> ) -> InterpResult<'tcx>
sourcefn get_ptr_access(
&self,
ptr: Pointer<Option<M::Provenance>>,
size: Size,
align: Align
) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>>
fn get_ptr_access( &self, ptr: Pointer<Option<M::Provenance>>, size: Size, align: Align ) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>>
Internal helper function to determine the allocation and offset of a pointer (if any).
sourcepub fn check_ptr_access_align(
&self,
ptr: Pointer<Option<M::Provenance>>,
size: Size,
align: Align,
msg: CheckInAllocMsg
) -> InterpResult<'tcx>
pub fn check_ptr_access_align( &self, ptr: Pointer<Option<M::Provenance>>, size: Size, align: Align, msg: CheckInAllocMsg ) -> InterpResult<'tcx>
Check if the given pointer points to live memory of given size
and align
(ignoring M::enforce_alignment
). The caller can control the error message for the
out-of-bounds case.
sourcefn check_and_deref_ptr<T>(
&self,
ptr: Pointer<Option<M::Provenance>>,
size: Size,
align: Align,
check: CheckAlignment,
msg: CheckInAllocMsg,
alloc_size: impl FnOnce(AllocId, Size, M::ProvenanceExtra) -> InterpResult<'tcx, (Size, Align, T)>
) -> InterpResult<'tcx, Option<T>>
fn check_and_deref_ptr<T>( &self, ptr: Pointer<Option<M::Provenance>>, size: Size, align: Align, check: CheckAlignment, 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. align
defines whether and which alignment check
is done.
If this returns None
, the size is 0; it can however return Some
even for size 0.
fn check_offset_align( &self, offset: u64, align: Align, check: CheckAlignment ) -> InterpResult<'tcx>
source§impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
Allocation accessors
sourcefn get_global_alloc(
&self,
id: AllocId,
is_write: bool
) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::Provenance, M::AllocExtra, M::Bytes>>>
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
.
sourcepub fn alloc_base_addr(&self, id: AllocId) -> InterpResult<'tcx, *const u8>
pub fn alloc_base_addr(&self, id: AllocId) -> InterpResult<'tcx, *const u8>
Get the base address for the bytes in an Allocation
specified by the
AllocID
passed in; error if no such allocation exists.
It is up to the caller to take sufficient care when using this address: there could be provenance or uninit memory in there, and other memory accesses could invalidate the exposed pointer.
sourcefn get_alloc_raw(
&self,
id: AllocId
) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra, M::Bytes>>
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.
sourcepub fn get_ptr_alloc<'a>(
&'a self,
ptr: Pointer<Option<M::Provenance>>,
size: Size,
align: Align
) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
pub fn get_ptr_alloc<'a>( &'a self, ptr: Pointer<Option<M::Provenance>>, size: Size, align: Align ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
“Safe” (bounds and align-checked) allocation access.
sourcepub fn get_alloc_extra<'a>(
&'a self,
id: AllocId
) -> InterpResult<'tcx, &'a M::AllocExtra>
pub fn get_alloc_extra<'a>( &'a self, id: AllocId ) -> InterpResult<'tcx, &'a M::AllocExtra>
Return the extra
field of the given allocation.
sourcepub fn get_alloc_mutability<'a>(
&'a self,
id: AllocId
) -> InterpResult<'tcx, Mutability>
pub fn get_alloc_mutability<'a>( &'a self, id: AllocId ) -> InterpResult<'tcx, Mutability>
Return the mutability
field of the given allocation.
sourcefn get_alloc_raw_mut(
&mut self,
id: AllocId
) -> InterpResult<'tcx, (&mut Allocation<M::Provenance, M::AllocExtra, M::Bytes>, &mut M)>
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.
sourcepub fn get_ptr_alloc_mut<'a>(
&'a mut self,
ptr: Pointer<Option<M::Provenance>>,
size: Size,
align: Align
) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
pub fn get_ptr_alloc_mut<'a>( &'a mut self, ptr: Pointer<Option<M::Provenance>>, size: Size, align: Align ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
“Safe” (bounds and align-checked) allocation access.
sourcepub fn get_alloc_extra_mut<'a>(
&'a mut self,
id: AllocId
) -> InterpResult<'tcx, (&'a mut M::AllocExtra, &'a mut M)>
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.
sourcepub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind)
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.
sourcefn get_live_alloc_size_and_align(
&self,
id: AllocId,
msg: CheckInAllocMsg
) -> InterpResult<'tcx, (Size, Align)>
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.
fn get_fn_alloc(&self, id: AllocId) -> Option<FnVal<'tcx, M::ExtraFnVal>>
pub fn get_ptr_fn( &self, ptr: Pointer<Option<M::Provenance>> ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>>
pub fn get_ptr_vtable( &self, ptr: Pointer<Option<M::Provenance>> ) -> InterpResult<'tcx, (Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>)>
pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx>
sourcepub fn dump_alloc<'a>(&'a self, id: AllocId) -> DumpAllocs<'a, 'mir, 'tcx, M>
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.
sourcepub fn dump_allocs<'a>(
&'a self,
allocs: Vec<AllocId>
) -> DumpAllocs<'a, 'mir, 'tcx, M>
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.
sourcepub fn find_leaked_allocations(
&self,
static_roots: &[AllocId]
) -> Vec<(AllocId, MemoryKind<M::MemoryKind>, Allocation<M::Provenance, M::AllocExtra, M::Bytes>)>
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>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
sourcepub fn read_bytes_ptr_strip_provenance(
&self,
ptr: Pointer<Option<M::Provenance>>,
size: Size
) -> InterpResult<'tcx, &[u8]>
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.
sourcepub fn write_bytes_ptr(
&mut self,
ptr: Pointer<Option<M::Provenance>>,
src: impl IntoIterator<Item = u8>
) -> InterpResult<'tcx>
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.
pub fn mem_copy( &mut self, src: Pointer<Option<M::Provenance>>, src_align: Align, dest: Pointer<Option<M::Provenance>>, dest_align: Align, size: Size, nonoverlapping: bool ) -> InterpResult<'tcx>
pub fn mem_copy_repeatedly( &mut self, src: Pointer<Option<M::Provenance>>, src_align: Align, dest: Pointer<Option<M::Provenance>>, dest_align: Align, size: Size, num_copies: u64, nonoverlapping: bool ) -> InterpResult<'tcx>
source§impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
Machine pointer introspection.
sourcepub fn scalar_may_be_null(
&self,
scalar: Scalar<M::Provenance>
) -> InterpResult<'tcx, bool>
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.
sourcepub fn ptr_try_get_alloc_id(
&self,
ptr: Pointer<Option<M::Provenance>>
) -> Result<(AllocId, Size, M::ProvenanceExtra), u64>
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.
sourcepub fn ptr_get_alloc_id(
&self,
ptr: Pointer<Option<M::Provenance>>
) -> InterpResult<'tcx, (AllocId, Size, M::ProvenanceExtra)>
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).
source§impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
sourcefn read_immediate_from_mplace_raw(
&self,
mplace: &MPlaceTy<'tcx, M::Provenance>
) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::Provenance>>>
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.
sourcepub fn read_immediate_raw(
&self,
src: &impl Readable<'tcx, M::Provenance>
) -> InterpResult<'tcx, Either<MPlaceTy<'tcx, M::Provenance>, ImmTy<'tcx, M::Provenance>>>
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.
sourcepub fn read_immediate(
&self,
op: &impl Readable<'tcx, M::Provenance>
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>
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
.
sourcepub fn read_scalar(
&self,
op: &impl Readable<'tcx, M::Provenance>
) -> InterpResult<'tcx, Scalar<M::Provenance>>
pub fn read_scalar( &self, op: &impl Readable<'tcx, M::Provenance> ) -> InterpResult<'tcx, Scalar<M::Provenance>>
Read a scalar from a place
sourcepub fn read_pointer(
&self,
op: &impl Readable<'tcx, M::Provenance>
) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>>
pub fn read_pointer( &self, op: &impl Readable<'tcx, M::Provenance> ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>>
Read a pointer from a place.
sourcepub fn read_target_usize(
&self,
op: &impl Readable<'tcx, M::Provenance>
) -> InterpResult<'tcx, u64>
pub fn read_target_usize( &self, op: &impl Readable<'tcx, M::Provenance> ) -> InterpResult<'tcx, u64>
Read a pointer-sized unsigned integer from a place.
sourcepub fn read_target_isize(
&self,
op: &impl Readable<'tcx, M::Provenance>
) -> InterpResult<'tcx, i64>
pub fn read_target_isize( &self, op: &impl Readable<'tcx, M::Provenance> ) -> InterpResult<'tcx, i64>
Read a pointer-sized signed integer from a place.
sourcepub fn read_str(
&self,
mplace: &MPlaceTy<'tcx, M::Provenance>
) -> InterpResult<'tcx, &str>
pub fn read_str( &self, mplace: &MPlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, &str>
Turn the wide MPlace into a string (must already be dereferenced!)
sourcepub fn operand_to_simd(
&self,
op: &OpTy<'tcx, M::Provenance>
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)>
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.
sourcepub 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>>
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.
sourcepub fn place_to_op(
&self,
place: &PlaceTy<'tcx, M::Provenance>
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>
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.
sourcepub fn eval_place_to_op(
&self,
mir_place: Place<'tcx>,
layout: Option<TyAndLayout<'tcx>>
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>
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.
sourcepub fn eval_operand(
&self,
mir_op: &Operand<'tcx>,
layout: Option<TyAndLayout<'tcx>>
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>
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.
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>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
sourcepub 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>
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.
sourcepub 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>
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>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
fn binary_char_op( &self, bin_op: BinOp, l: char, r: char ) -> (ImmTy<'tcx, M::Provenance>, bool)
fn binary_bool_op( &self, bin_op: BinOp, l: bool, r: bool ) -> (ImmTy<'tcx, M::Provenance>, bool)
fn binary_float_op<F: Float + Into<Scalar<M::Provenance>>>( &self, bin_op: BinOp, layout: TyAndLayout<'tcx>, l: F, r: F ) -> (ImmTy<'tcx, M::Provenance>, bool)
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)>
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)>
sourcepub 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)>
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.
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>>
sourcepub fn overflowing_unary_op(
&self,
un_op: UnOp,
val: &ImmTy<'tcx, M::Provenance>
) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)>
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.
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>,
impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M>where Prov: Provenance, M: Machine<'mir, 'tcx, Provenance = Prov>,
sourcepub fn ref_to_mplace(
&self,
val: &ImmTy<'tcx, M::Provenance>
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>
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
.
sourcepub fn mplace_to_ref(
&self,
mplace: &MPlaceTy<'tcx, M::Provenance>
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>>
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
.
sourcepub fn deref_pointer(
&self,
src: &impl Readable<'tcx, M::Provenance>
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>
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.
pub(super) fn get_place_alloc( &self, mplace: &MPlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
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>>>
sourcepub fn check_mplace(
&self,
mplace: &MPlaceTy<'tcx, M::Provenance>
) -> InterpResult<'tcx>
pub fn check_mplace( &self, mplace: &MPlaceTy<'tcx, M::Provenance> ) -> InterpResult<'tcx>
Check if this mplace is dereferenceable and sufficiently aligned.
sourcepub fn mplace_to_simd(
&self,
mplace: &MPlaceTy<'tcx, M::Provenance>
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)>
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.
sourcepub fn place_to_simd(
&mut self,
place: &PlaceTy<'tcx, M::Provenance>
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)>
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.
pub fn local_to_place( &self, frame: usize, local: Local ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>>
sourcepub fn eval_place(
&self,
mir_place: Place<'tcx>
) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>>
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
.
sourcepub fn write_immediate(
&mut self,
src: Immediate<M::Provenance>,
dest: &impl Writeable<'tcx, M::Provenance>
) -> InterpResult<'tcx>
pub fn write_immediate( &mut self, src: Immediate<M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance> ) -> InterpResult<'tcx>
Write an immediate to a place
sourcepub fn write_scalar(
&mut self,
val: impl Into<Scalar<M::Provenance>>,
dest: &impl Writeable<'tcx, M::Provenance>
) -> InterpResult<'tcx>
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
sourcepub fn write_pointer(
&mut self,
ptr: impl Into<Pointer<Option<M::Provenance>>>,
dest: &impl Writeable<'tcx, M::Provenance>
) -> InterpResult<'tcx>
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
sourcefn write_immediate_no_validate(
&mut self,
src: Immediate<M::Provenance>,
dest: &impl Writeable<'tcx, M::Provenance>
) -> InterpResult<'tcx>
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.
sourcefn write_immediate_to_mplace_no_validate(
&mut self,
value: Immediate<M::Provenance>,
layout: TyAndLayout<'tcx>,
align: Align,
dest: MemPlace<M::Provenance>
) -> InterpResult<'tcx>
fn write_immediate_to_mplace_no_validate( &mut self, value: Immediate<M::Provenance>, layout: TyAndLayout<'tcx>, align: Align, 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.
pub fn write_uninit( &mut self, dest: &impl Writeable<'tcx, M::Provenance> ) -> InterpResult<'tcx>
sourcepub fn copy_op(
&mut self,
src: &impl Readable<'tcx, M::Provenance>,
dest: &impl Writeable<'tcx, M::Provenance>,
allow_transmute: bool
) -> InterpResult<'tcx>
pub fn copy_op( &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.
sourcefn copy_op_no_validate(
&mut self,
src: &impl Readable<'tcx, M::Provenance>,
dest: &impl Writeable<'tcx, M::Provenance>,
allow_transmute: bool
) -> InterpResult<'tcx>
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.
sourcepub fn force_allocation(
&mut self,
place: &PlaceTy<'tcx, M::Provenance>
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>
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
.
pub fn allocate_dyn( &mut self, layout: TyAndLayout<'tcx>, kind: MemoryKind<M::MemoryKind>, meta: MemPlaceMeta<M::Provenance> ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>
pub fn allocate( &mut self, layout: TyAndLayout<'tcx>, kind: MemoryKind<M::MemoryKind> ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>
sourcepub fn allocate_str(
&mut self,
str: &str,
kind: MemoryKind<M::MemoryKind>,
mutbl: Mutability
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>
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 &'static [mut] str
to a new 1-aligned allocation.
sourcepub fn write_aggregate(
&mut self,
kind: &AggregateKind<'tcx>,
operands: &IndexSlice<FieldIdx, Operand<'tcx>>,
dest: &PlaceTy<'tcx, M::Provenance>
) -> InterpResult<'tcx>
pub 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.
pub fn raw_const_to_mplace( &self, raw: ConstAlloc<'tcx> ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>>
sourcepub(super) fn unpack_dyn_trait(
&self,
mplace: &MPlaceTy<'tcx, M::Provenance>
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, Pointer<Option<M::Provenance>>)>
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.
sourcepub(super) fn unpack_dyn_star<P: Projectable<'tcx, M::Provenance>>(
&self,
val: &P
) -> InterpResult<'tcx, (P, Pointer<Option<M::Provenance>>)>
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>,
impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M>where Prov: Provenance, M: Machine<'mir, 'tcx, Provenance = Prov>,
sourcepub fn project_field<P: Projectable<'tcx, M::Provenance>>(
&self,
base: &P,
field: usize
) -> InterpResult<'tcx, P>
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
.
sourcepub fn project_downcast<P: Projectable<'tcx, M::Provenance>>(
&self,
base: &P,
variant: VariantIdx
) -> InterpResult<'tcx, P>
pub fn project_downcast<P: Projectable<'tcx, M::Provenance>>( &self, base: &P, variant: VariantIdx ) -> InterpResult<'tcx, P>
Downcasting to an enum variant.
sourcepub fn project_index<P: Projectable<'tcx, M::Provenance>>(
&self,
base: &P,
index: u64
) -> InterpResult<'tcx, P>
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.
fn project_constant_index<P: Projectable<'tcx, M::Provenance>>( &self, base: &P, offset: u64, min_length: u64, from_end: bool ) -> InterpResult<'tcx, P>
sourcepub fn project_array_fields<'a, P: Projectable<'tcx, M::Provenance>>(
&self,
base: &'a P
) -> InterpResult<'tcx, ArrayIterator<'tcx, 'a, M::Provenance, P>>
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 operand_index
.
sourcefn project_subslice<P: Projectable<'tcx, M::Provenance>>(
&self,
base: &P,
from: u64,
to: u64,
from_end: bool
) -> InterpResult<'tcx, P>
fn project_subslice<P: Projectable<'tcx, M::Provenance>>( &self, base: &P, from: u64, to: u64, from_end: bool ) -> InterpResult<'tcx, P>
Subslicing
sourcepub 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,
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>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
sourcepub fn step(&mut self) -> InterpResult<'tcx, bool>
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
sourcepub fn statement(&mut self, stmt: &Statement<'tcx>) -> InterpResult<'tcx>
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!
sourcepub fn eval_rvalue_into_place(
&mut self,
rvalue: &Rvalue<'tcx>,
place: Place<'tcx>
) -> InterpResult<'tcx>
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.
sourcefn terminator(&mut self, terminator: &Terminator<'tcx>) -> InterpResult<'tcx>
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>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
sourcepub fn copy_fn_arg(
&self,
arg: &FnArg<'tcx, M::Provenance>
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>
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.
sourcepub fn copy_fn_args(
&self,
args: &[FnArg<'tcx, M::Provenance>]
) -> InterpResult<'tcx, Vec<OpTy<'tcx, M::Provenance>>>
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.
pub fn fn_arg_field( &self, arg: &FnArg<'tcx, M::Provenance>, field: usize ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>>
pub(super) fn eval_terminator( &mut self, terminator: &Terminator<'tcx> ) -> InterpResult<'tcx>
sourcepub(super) fn eval_fn_call_arguments(
&self,
ops: &[Operand<'tcx>]
) -> InterpResult<'tcx, Vec<FnArg<'tcx, M::Provenance>>>
pub(super) fn eval_fn_call_arguments( &self, ops: &[Operand<'tcx>] ) -> InterpResult<'tcx, Vec<FnArg<'tcx, M::Provenance>>>
Evaluate the arguments of a function call
sourcefn unfold_transparent(
&self,
layout: TyAndLayout<'tcx>,
may_unfold: impl Fn(AdtDef<'tcx>) -> bool
) -> TyAndLayout<'tcx>
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.
sourcefn unfold_npo(
&self,
layout: TyAndLayout<'tcx>
) -> InterpResult<'tcx, TyAndLayout<'tcx>>
fn unfold_npo( &self, layout: TyAndLayout<'tcx> ) -> InterpResult<'tcx, TyAndLayout<'tcx>>
Unwrap types that are guaranteed a null-pointer-optimization
sourcefn layout_compat(
&self,
caller: TyAndLayout<'tcx>,
callee: TyAndLayout<'tcx>
) -> InterpResult<'tcx, bool>
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.)
fn check_argument_compat( &self, caller_abi: &ArgAbi<'tcx, Ty<'tcx>>, callee_abi: &ArgAbi<'tcx, Ty<'tcx>> ) -> InterpResult<'tcx, bool>
sourcefn 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,
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.
sourcepub(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>
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.
fn check_fn_target_features( &self, instance: Instance<'tcx> ) -> InterpResult<'tcx, ()>
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>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
sourcepub fn get_vtable_ptr(
&self,
ty: Ty<'tcx>,
poly_trait_ref: Option<PolyExistentialTraitRef<'tcx>>
) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>>
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).
sourcepub fn get_vtable_entries(
&self,
vtable: Pointer<Option<M::Provenance>>
) -> InterpResult<'tcx, &'tcx [VtblEntry<'tcx>]>
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.
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>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M>
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>
sourcepub 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>
pub 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
.
sourcepub fn validate_operand(
&self,
op: &OpTy<'tcx, M::Provenance>
) -> InterpResult<'tcx>
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>
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>>
type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpErrorInfo<'tcx>>
&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>
fn handle_fn_abi_err( &self, err: FnAbiError<'tcx>, _span: Span, _fn_abi_request: FnAbiRequest<'tcx> ) -> InterpErrorInfo<'tcx>
fn_abi_of_*
, to adapt tcx.fn_abi_of_*(...)
into a
Self::FnAbiOfResult
(which does not need to be a Result<...>
). Read moresource§impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M>
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M>
fn data_layout(&self) -> &TargetDataLayout
source§impl<'mir, 'tcx, M> HasParamEnv<'tcx> for InterpCx<'mir, 'tcx, M>where
M: Machine<'mir, 'tcx>,
impl<'mir, 'tcx, M> HasParamEnv<'tcx> for InterpCx<'mir, 'tcx, M>where M: Machine<'mir, 'tcx>,
source§impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'mir, 'tcx, M>
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'mir, 'tcx, M>
§type LayoutOfResult = Result<TyAndLayout<'tcx, Ty<'tcx>>, InterpErrorInfo<'tcx>>
type LayoutOfResult = Result<TyAndLayout<'tcx, Ty<'tcx>>, InterpErrorInfo<'tcx>>
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
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>
fn handle_layout_err( &self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx> ) -> InterpErrorInfo<'tcx>
layout_of
, to adapt tcx.layout_of(...)
into a
Self::LayoutOfResult
(which does not need to be a Result<...>
). Read moreAuto Trait Implementations§
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> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> PointerArithmetic for Twhere
T: HasDataLayout,
impl<T> PointerArithmetic for Twhere T: HasDataLayout,
fn pointer_size(&self) -> Size
fn max_size_of_val(&self) -> Size
fn target_usize_max(&self) -> u64
fn target_isize_min(&self) -> i64
fn target_isize_max(&self) -> i64
fn target_usize_to_isize(&self, val: u64) -> i64
source§fn truncate_to_ptr(&self, _: (u64, bool)) -> (u64, bool)
fn truncate_to_ptr(&self, _: (u64, bool)) -> (u64, bool)
fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool)
fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool)
fn offset<'tcx>(&self, val: u64, i: u64) -> Result<u64, InterpErrorInfo<'tcx>>
fn signed_offset<'tcx>( &self, val: u64, i: i64 ) -> Result<u64, InterpErrorInfo<'tcx>>
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.