summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_const_eval/src/const_eval
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_const_eval/src/const_eval')
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs8
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs40
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs117
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs21
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs35
5 files changed, 110 insertions, 111 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 322bfd5ce..09d53331b 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -9,13 +9,13 @@ use rustc_span::{Span, Symbol};
use super::InterpCx;
use crate::interpret::{
- struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType, UnsupportedOpInfo,
+ struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType,
+ UnsupportedOpInfo,
};
/// The CTFE machine has some custom error kinds.
#[derive(Clone, Debug)]
pub enum ConstEvalErrKind {
- NeedsRfc(String),
ConstAccessesStatic,
ModifiedGlobal,
AssertFailure(AssertKind<ConstInt>),
@@ -42,9 +42,6 @@ impl fmt::Display for ConstEvalErrKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::ConstEvalErrKind::*;
match *self {
- NeedsRfc(ref msg) => {
- write!(f, "\"{}\" needs an rfc before being allowed inside constants", msg)
- }
ConstAccessesStatic => write!(f, "constant accesses static"),
ModifiedGlobal => {
write!(f, "modifying a static's initial value from another static's initializer")
@@ -158,6 +155,7 @@ impl<'tcx> ConstEvalErr<'tcx> {
InterpError::Unsupported(
UnsupportedOpInfo::ReadPointerAsBytes
| UnsupportedOpInfo::PartialPointerOverwrite(_)
+ | UnsupportedOpInfo::PartialPointerCopy(_),
) => {
err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 975fb4b22..a2f14e753 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -2,8 +2,8 @@ use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr};
use crate::interpret::eval_nullary_intrinsic;
use crate::interpret::{
intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId,
- Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
- ScalarMaybeUninit, StackPopCleanup, InterpError,
+ Immediate, InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy,
+ RefTracking, StackPopCleanup,
};
use rustc_hir::def::DefKind;
@@ -74,14 +74,16 @@ fn eval_body_using_ecx<'mir, 'tcx>(
None => InternKind::Constant,
}
};
+ ecx.machine.check_alignment = false; // interning doesn't need to respect alignment
intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
+ // we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway
debug!("eval_body_using_ecx done: {:?}", *ret);
Ok(ret)
}
/// The `InterpCx` is only meant to be used to do field and index projections into constants for
-/// `simd_shuffle` and const patterns in match arms.
+/// `simd_shuffle` and const patterns in match arms. It never performs alignment checks.
///
/// The function containing the `match` that is currently being analyzed may have generic bounds
/// that inform us about the generic bounds of the constant. E.g., using an associated constant
@@ -98,7 +100,11 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
tcx,
root_span,
param_env,
- CompileTimeInterpreter::new(tcx.const_eval_limit(), can_access_statics),
+ CompileTimeInterpreter::new(
+ tcx.const_eval_limit(),
+ can_access_statics,
+ /*check_alignment:*/ false,
+ ),
)
}
@@ -166,10 +172,7 @@ pub(super) fn op_to_const<'tcx>(
// see comment on `let try_as_immediate` above
Err(imm) => match *imm {
_ if imm.layout.is_zst() => ConstValue::ZeroSized,
- Immediate::Scalar(x) => match x {
- ScalarMaybeUninit::Scalar(s) => ConstValue::Scalar(s),
- ScalarMaybeUninit::Uninit => to_const_value(&op.assert_mem_place()),
- },
+ Immediate::Scalar(x) => ConstValue::Scalar(x),
Immediate::ScalarPair(a, b) => {
debug!("ScalarPair(a: {:?}, b: {:?})", a, b);
// We know `offset` is relative to the allocation, so we can use `into_parts`.
@@ -194,7 +197,7 @@ pub(super) fn op_to_const<'tcx>(
}
}
-#[instrument(skip(tcx), level = "debug")]
+#[instrument(skip(tcx), level = "debug", ret)]
pub(crate) fn turn_into_const_value<'tcx>(
tcx: TyCtxt<'tcx>,
constant: ConstAlloc<'tcx>,
@@ -203,7 +206,13 @@ pub(crate) fn turn_into_const_value<'tcx>(
let cid = key.value;
let def_id = cid.instance.def.def_id();
let is_static = tcx.is_static(def_id);
- let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static);
+ // This is just accessing an already computed constant, so no need to check alginment here.
+ let ecx = mk_eval_cx(
+ tcx,
+ tcx.def_span(key.value.instance.def_id()),
+ key.param_env,
+ /*can_access_statics:*/ is_static,
+ );
let mplace = ecx.raw_const_to_mplace(constant).expect(
"can only fail if layout computation failed, \
@@ -215,10 +224,7 @@ pub(crate) fn turn_into_const_value<'tcx>(
);
// Turn this into a proper constant.
- let const_val = op_to_const(&ecx, &mplace.into());
- debug!(?const_val);
-
- const_val
+ op_to_const(&ecx, &mplace.into())
}
#[instrument(skip(tcx), level = "debug")]
@@ -300,7 +306,11 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
key.param_env,
// Statics (and promoteds inside statics) may access other statics, because unlike consts
// they do not have to behave "as if" they were evaluated at runtime.
- CompileTimeInterpreter::new(tcx.const_eval_limit(), /*can_access_statics:*/ is_static),
+ CompileTimeInterpreter::new(
+ tcx.const_eval_limit(),
+ /*can_access_statics:*/ is_static,
+ /*check_alignment:*/ tcx.sess.opts.unstable_opts.extra_const_ub_checks,
+ ),
);
let res = ecx.load_mir(cid.instance.def, cid.promoted);
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index fc2e6652a..e5acacd91 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -35,21 +35,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
// All `#[rustc_do_not_const_check]` functions should be hooked here.
let def_id = instance.def_id();
- if Some(def_id) == self.tcx.lang_items().const_eval_select() {
- // redirect to const_eval_select_ct
- if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() {
- return Ok(Some(
- ty::Instance::resolve(
- *self.tcx,
- ty::ParamEnv::reveal_all(),
- const_eval_select,
- instance.substs,
- )
- .unwrap()
- .unwrap(),
- ));
- }
- } else if Some(def_id) == self.tcx.lang_items().panic_display()
+ if Some(def_id) == self.tcx.lang_items().panic_display()
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
{
// &str or &&str
@@ -89,10 +75,10 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
/// exhaustion error.
///
/// Setting this to `0` disables the limit and allows the interpreter to run forever.
- pub steps_remaining: usize,
+ pub(super) steps_remaining: usize,
/// The virtual call stack.
- pub(crate) stack: Vec<Frame<'mir, 'tcx, AllocId, ()>>,
+ pub(super) stack: Vec<Frame<'mir, 'tcx, AllocId, ()>>,
/// We need to make sure consts never point to anything mutable, even recursively. That is
/// relied on for pattern matching on consts with references.
@@ -101,14 +87,22 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
/// * Pointers to allocations inside of statics can never leak outside, to a non-static global.
/// This boolean here controls the second part.
pub(super) can_access_statics: bool,
+
+ /// Whether to check alignment during evaluation.
+ pub(super) check_alignment: bool,
}
impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
- pub(crate) fn new(const_eval_limit: Limit, can_access_statics: bool) -> Self {
+ pub(crate) fn new(
+ const_eval_limit: Limit,
+ can_access_statics: bool,
+ check_alignment: bool,
+ ) -> Self {
CompileTimeInterpreter {
steps_remaining: const_eval_limit.0,
stack: Vec::new(),
can_access_statics,
+ check_alignment,
}
}
}
@@ -197,34 +191,35 @@ impl interpret::MayLeak for ! {
}
impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
- fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, bool> {
+ /// See documentation on the `ptr_guaranteed_cmp` intrinsic.
+ fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> {
Ok(match (a, b) {
// Comparisons between integers are always known.
- (Scalar::Int { .. }, Scalar::Int { .. }) => a == b,
- // Equality with integers can never be known for sure.
- (Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => false,
- // FIXME: return `true` for when both sides are the same pointer, *except* that
- // some things (like functions and vtables) do not have stable addresses
- // so we need to be careful around them (see e.g. #73722).
- (Scalar::Ptr(..), Scalar::Ptr(..)) => false,
- })
- }
-
- fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, bool> {
- Ok(match (a, b) {
- // Comparisons between integers are always known.
- (Scalar::Int(_), Scalar::Int(_)) => a != b,
+ (Scalar::Int { .. }, Scalar::Int { .. }) => {
+ if a == b {
+ 1
+ } else {
+ 0
+ }
+ }
// Comparisons of abstract pointers with null pointers are known if the pointer
// is in bounds, because if they are in bounds, the pointer can't be null.
// Inequality with integers other than null can never be known for sure.
(Scalar::Int(int), ptr @ Scalar::Ptr(..))
- | (ptr @ Scalar::Ptr(..), Scalar::Int(int)) => {
- int.is_null() && !self.scalar_may_be_null(ptr)?
+ | (ptr @ Scalar::Ptr(..), Scalar::Int(int))
+ if int.is_null() && !self.scalar_may_be_null(ptr)? =>
+ {
+ 0
}
- // FIXME: return `true` for at least some comparisons where we can reliably
+ // Equality with integers can never be known for sure.
+ (Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => 2,
+ // FIXME: return a `1` for when both sides are the same pointer, *except* that
+ // some things (like functions and vtables) do not have stable addresses
+ // so we need to be careful around them (see e.g. #73722).
+ // FIXME: return `0` for at least some comparisons where we can reliably
// determine the result of runtime inequality tests at compile-time.
// Examples include comparison of addresses in different static items.
- (Scalar::Ptr(..), Scalar::Ptr(..)) => false,
+ (Scalar::Ptr(..), Scalar::Ptr(..)) => 2,
})
}
}
@@ -236,6 +231,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
+ #[inline(always)]
+ fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+ ecx.machine.check_alignment
+ }
+
+ #[inline(always)]
+ fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+ ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
+ }
+
fn load_mir(
ecx: &InterpCx<'mir, 'tcx, Self>,
instance: ty::InstanceDef<'tcx>,
@@ -251,9 +256,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
);
throw_inval!(AlreadyReported(guar));
} else {
+ // `find_mir_or_eval_fn` checks that this is a const fn before even calling us,
+ // so this should be unreachable.
let path = ecx.tcx.def_path_str(def.did);
- Err(ConstEvalErrKind::NeedsRfc(format!("calling extern function `{}`", path))
- .into())
+ bug!("trying to call extern function `{path}` at compile-time");
}
}
_ => Ok(ecx.tcx.instance_mir(instance)),
@@ -321,22 +327,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
// CTFE-specific intrinsics.
let Some(ret) = target else {
- return Err(ConstEvalErrKind::NeedsRfc(format!(
- "calling intrinsic `{}`",
- intrinsic_name
- ))
- .into());
+ throw_unsup_format!("intrinsic `{intrinsic_name}` is not supported at compile-time");
};
match intrinsic_name {
- sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
- let a = ecx.read_immediate(&args[0])?.to_scalar()?;
- let b = ecx.read_immediate(&args[1])?.to_scalar()?;
- let cmp = if intrinsic_name == sym::ptr_guaranteed_eq {
- ecx.guaranteed_eq(a, b)?
- } else {
- ecx.guaranteed_ne(a, b)?
- };
- ecx.write_scalar(Scalar::from_bool(cmp), dest)?;
+ sym::ptr_guaranteed_cmp => {
+ let a = ecx.read_scalar(&args[0])?;
+ let b = ecx.read_scalar(&args[1])?;
+ let cmp = ecx.guaranteed_cmp(a, b)?;
+ ecx.write_scalar(Scalar::from_u8(cmp), dest)?;
}
sym::const_allocate => {
let size = ecx.read_scalar(&args[0])?.to_machine_usize(ecx)?;
@@ -382,11 +380,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
}
}
_ => {
- return Err(ConstEvalErrKind::NeedsRfc(format!(
- "calling intrinsic `{}`",
- intrinsic_name
- ))
- .into());
+ throw_unsup_format!(
+ "intrinsic `{intrinsic_name}` is not supported at compile-time"
+ );
}
}
@@ -429,7 +425,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
_left: &ImmTy<'tcx>,
_right: &ImmTy<'tcx>,
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
- Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into())
+ throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time");
}
fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
@@ -451,7 +447,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
_ptr: Pointer<AllocId>,
) -> InterpResult<'tcx> {
- Err(ConstEvalErrKind::NeedsRfc("exposing pointers".to_string()).into())
+ // This is only reachable with -Zunleash-the-miri-inside-of-you.
+ throw_unsup_format!("exposing pointers is not possible at compile-time")
}
#[inline(always)]
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index 948c33494..d9c4ae4d5 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -1,16 +1,16 @@
// Not in interpret to make sure we do not use private implementation details
+use crate::errors::MaxNumNodesInConstErr;
+use crate::interpret::{
+ intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta,
+ Scalar,
+};
use rustc_hir::Mutability;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
-use crate::interpret::{
- intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta,
- Scalar,
-};
-
mod error;
mod eval_queries;
mod fn_queries;
@@ -72,12 +72,17 @@ pub(crate) fn eval_to_valtree<'tcx>(
Ok(valtree) => Ok(Some(valtree)),
Err(err) => {
let did = cid.instance.def_id();
- let s = cid.display(tcx);
+ let global_const_id = cid.display(tcx);
match err {
ValTreeCreationError::NodesOverflow => {
- let msg = format!("maximum number of nodes exceeded in constant {}", &s);
+ let msg = format!(
+ "maximum number of nodes exceeded in constant {}",
+ &global_const_id
+ );
let mut diag = match tcx.hir().span_if_local(did) {
- Some(span) => tcx.sess.struct_span_err(span, &msg),
+ Some(span) => {
+ tcx.sess.create_err(MaxNumNodesInConstErr { span, global_const_id })
+ }
None => tcx.sess.struct_err(&msg),
};
diag.emit();
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 8fff4571d..a964fe846 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -3,7 +3,7 @@ use super::machine::CompileTimeEvalContext;
use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
use crate::interpret::{
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
- MemoryKind, PlaceTy, Scalar, ScalarMaybeUninit,
+ MemoryKind, PlaceTy, Scalar,
};
use crate::interpret::{MPlaceTy, Value};
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
@@ -90,14 +90,14 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
let Ok(val) = ecx.read_immediate(&place.into()) else {
return Err(ValTreeCreationError::Other);
};
- let val = val.to_scalar().unwrap();
+ let val = val.to_scalar();
*num_nodes += 1;
Ok(ty::ValTree::Leaf(val.assert_int()))
}
// Raw pointers are not allowed in type level constants, as we cannot properly test them for
- // equality at compile-time (see `ptr_guaranteed_eq`/`_ne`).
+ // equality at compile-time (see `ptr_guaranteed_cmp`).
// Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
// agree with runtime equality tests.
ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
@@ -204,7 +204,7 @@ fn get_info_on_unsized_field<'tcx>(
(unsized_inner_ty, num_elems)
}
-#[instrument(skip(ecx), level = "debug")]
+#[instrument(skip(ecx), level = "debug", ret)]
fn create_pointee_place<'tcx>(
ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
ty: Ty<'tcx>,
@@ -237,14 +237,11 @@ fn create_pointee_place<'tcx>(
let ptr = ecx.allocate_ptr(size, align, MemoryKind::Stack).unwrap();
debug!(?ptr);
- let place = MPlaceTy::from_aligned_ptr_with_meta(
+ MPlaceTy::from_aligned_ptr_with_meta(
ptr.into(),
layout,
MemPlaceMeta::Meta(Scalar::from_machine_usize(num_elems as u64, &tcx)),
- );
- debug!(?place);
-
- place
+ )
} else {
create_mplace_from_layout(ecx, ty)
}
@@ -253,7 +250,7 @@ fn create_pointee_place<'tcx>(
/// Converts a `ValTree` to a `ConstValue`, which is needed after mir
/// construction has finished.
// FIXME Merge `valtree_to_const_value` and `valtree_into_mplace` into one function
-#[instrument(skip(tcx), level = "debug")]
+#[instrument(skip(tcx), level = "debug", ret)]
pub fn valtree_to_const_value<'tcx>(
tcx: TyCtxt<'tcx>,
param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
@@ -294,7 +291,7 @@ pub fn valtree_to_const_value<'tcx>(
dump_place(&ecx, place.into());
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
- let const_val = match ty.kind() {
+ match ty.kind() {
ty::Ref(_, _, _) => {
let ref_place = place.to_ref(&tcx);
let imm =
@@ -303,10 +300,7 @@ pub fn valtree_to_const_value<'tcx>(
op_to_const(&ecx, &imm.into())
}
_ => op_to_const(&ecx, &place.into()),
- };
- debug!(?const_val);
-
- const_val
+ }
}
ty::Never
| ty::Error(_)
@@ -349,11 +343,7 @@ fn valtree_into_mplace<'tcx>(
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
let scalar_int = valtree.unwrap_leaf();
debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place);
- ecx.write_immediate(
- Immediate::Scalar(ScalarMaybeUninit::Scalar(scalar_int.into())),
- &place.into(),
- )
- .unwrap();
+ ecx.write_immediate(Immediate::Scalar(scalar_int.into()), &place.into()).unwrap();
}
ty::Ref(_, inner_ty, _) => {
let mut pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
@@ -366,11 +356,10 @@ fn valtree_into_mplace<'tcx>(
let imm = match inner_ty.kind() {
ty::Slice(_) | ty::Str => {
let len = valtree.unwrap_branch().len();
- let len_scalar =
- ScalarMaybeUninit::Scalar(Scalar::from_machine_usize(len as u64, &tcx));
+ let len_scalar = Scalar::from_machine_usize(len as u64, &tcx);
Immediate::ScalarPair(
- ScalarMaybeUninit::from_maybe_pointer((*pointee_place).ptr, &tcx),
+ Scalar::from_maybe_pointer((*pointee_place).ptr, &tcx),
len_scalar,
)
}