summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_const_eval/src/interpret/intrinsics
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs118
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs11
2 files changed, 53 insertions, 76 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index cc7b6c91b..a29cdade0 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -11,7 +11,7 @@ use rustc_middle::mir::{
BinOp, NonDivergingIntrinsic,
};
use rustc_middle::ty;
-use rustc_middle::ty::layout::LayoutOf as _;
+use rustc_middle::ty::layout::{LayoutOf as _, ValidityRequirement};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{Ty, TyCtxt};
use rustc_span::symbol::{sym, Symbol};
@@ -45,7 +45,7 @@ fn numeric_intrinsic<Prov>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<
pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
let path = crate::util::type_name(tcx, ty);
let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
- tcx.intern_const_alloc(alloc)
+ tcx.mk_const_alloc(alloc)
}
/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated
@@ -71,7 +71,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
sym::pref_align_of => {
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
- ConstValue::from_machine_usize(layout.align.pref.bytes(), &tcx)
+ ConstValue::from_target_usize(layout.align.pref.bytes(), &tcx)
}
sym::type_id => {
ensure_monomorphic_enough(tcx, tp_ty)?;
@@ -79,7 +79,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
}
sym::variant_count => match tp_ty.kind() {
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
- ty::Adt(adt, _) => ConstValue::from_machine_usize(adt.variants().len() as u64, &tcx),
+ ty::Adt(adt, _) => ConstValue::from_target_usize(adt.variants().len() as u64, &tcx),
ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
throw_inval!(TooGeneric)
}
@@ -101,9 +101,10 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
| ty::Closure(_, _)
| ty::Generator(_, _, _)
| ty::GeneratorWitness(_)
+ | ty::GeneratorWitnessMIR(_, _)
| ty::Never
| ty::Tuple(_)
- | ty::Error(_) => ConstValue::from_machine_usize(0u64, &tcx),
+ | ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx),
},
other => bug!("`{}` is not a zero arg intrinsic", other),
})
@@ -155,7 +156,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
_ => bug!(),
};
- self.write_scalar(Scalar::from_machine_usize(result, self), dest)?;
+ self.write_scalar(Scalar::from_target_usize(result, self), dest)?;
}
sym::pref_align_of
@@ -209,19 +210,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let out_val = numeric_intrinsic(intrinsic_name, bits, kind);
self.write_scalar(out_val, dest)?;
}
- sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
- let lhs = self.read_immediate(&args[0])?;
- let rhs = self.read_immediate(&args[1])?;
- let bin_op = match intrinsic_name {
- sym::add_with_overflow => BinOp::Add,
- sym::sub_with_overflow => BinOp::Sub,
- sym::mul_with_overflow => BinOp::Mul,
- _ => bug!(),
- };
- self.binop_with_overflow(
- bin_op, /*force_overflow_checks*/ true, &lhs, &rhs, dest,
- )?;
- }
sym::saturating_add | sym::saturating_sub => {
let l = self.read_immediate(&args[0])?;
let r = self.read_immediate(&args[1])?;
@@ -301,7 +289,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
sym::offset => {
let ptr = self.read_pointer(&args[0])?;
- let offset_count = self.read_machine_isize(&args[1])?;
+ let offset_count = self.read_target_isize(&args[1])?;
let pointee_ty = substs.type_at(0);
let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?;
@@ -309,7 +297,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
sym::arith_offset => {
let ptr = self.read_pointer(&args[0])?;
- let offset_count = self.read_machine_isize(&args[1])?;
+ let offset_count = self.read_target_isize(&args[1])?;
let pointee_ty = substs.type_at(0);
let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
@@ -375,7 +363,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// The signed form of the intrinsic allows this. If we interpret the
// difference as isize, we'll get the proper signed difference. If that
// seems *positive*, they were more than isize::MAX apart.
- let dist = val.to_machine_isize(self)?;
+ let dist = val.to_target_isize(self)?;
if dist >= 0 {
throw_ub_format!(
"`{}` called when first pointer is too far before second",
@@ -385,7 +373,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
dist
} else {
// b >= a
- let dist = val.to_machine_isize(self)?;
+ let dist = val.to_target_isize(self)?;
// If converting to isize produced a *negative* result, we had an overflow
// because they were more than isize::MAX apart.
if dist < 0 {
@@ -410,10 +398,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Perform division by size to compute return value.
let ret_layout = if intrinsic_name == sym::ptr_offset_from_unsigned {
- assert!(0 <= dist && dist <= self.machine_isize_max());
+ assert!(0 <= dist && dist <= self.target_isize_max());
usize_layout
} else {
- assert!(self.machine_isize_min() <= dist && dist <= self.machine_isize_max());
+ assert!(self.target_isize_min() <= dist && dist <= self.target_isize_max());
isize_layout
};
let pointee_layout = self.layout_of(substs.type_at(0))?;
@@ -430,48 +418,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
| sym::assert_zero_valid
| sym::assert_mem_uninitialized_valid => {
let ty = instance.substs.type_at(0);
- let layout = self.layout_of(ty)?;
-
- // For *all* intrinsics we first check `is_uninhabited` to give a more specific
- // error message.
- if layout.abi.is_uninhabited() {
- // The run-time intrinsic panics just to get a good backtrace; here we abort
- // since there is no problem showing a backtrace even for aborts.
- M::abort(
- self,
- format!(
+ let requirement = ValidityRequirement::from_intrinsic(intrinsic_name).unwrap();
+
+ let should_panic = !self
+ .tcx
+ .check_validity_requirement((requirement, self.param_env.and(ty)))
+ .map_err(|_| err_inval!(TooGeneric))?;
+
+ if should_panic {
+ let layout = self.layout_of(ty)?;
+
+ let msg = match requirement {
+ // For *all* intrinsics we first check `is_uninhabited` to give a more specific
+ // error message.
+ _ if layout.abi.is_uninhabited() => format!(
"aborted execution: attempted to instantiate uninhabited type `{}`",
ty
),
- )?;
- }
-
- if intrinsic_name == sym::assert_zero_valid {
- let should_panic = !self.tcx.permits_zero_init(layout);
-
- if should_panic {
- M::abort(
- self,
- format!(
- "aborted execution: attempted to zero-initialize type `{}`, which is invalid",
- ty
- ),
- )?;
- }
- }
+ ValidityRequirement::Inhabited => bug!("handled earlier"),
+ ValidityRequirement::Zero => format!(
+ "aborted execution: attempted to zero-initialize type `{}`, which is invalid",
+ ty
+ ),
+ ValidityRequirement::UninitMitigated0x01Fill => format!(
+ "aborted execution: attempted to leave type `{}` uninitialized, which is invalid",
+ ty
+ ),
+ ValidityRequirement::Uninit => bug!("assert_uninit_valid doesn't exist"),
+ };
- if intrinsic_name == sym::assert_mem_uninitialized_valid {
- let should_panic = !self.tcx.permits_uninit_init(layout);
-
- if should_panic {
- M::abort(
- self,
- format!(
- "aborted execution: attempted to leave type `{}` uninitialized, which is invalid",
- ty
- ),
- )?;
- }
+ M::abort(self, msg)?;
}
}
sym::simd_insert => {
@@ -482,7 +458,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
assert_eq!(input_len, dest_len, "Return vector length must match input length");
assert!(
index < dest_len,
- "Index `{}` must be in bounds of vector with length {}`",
+ "Index `{}` must be in bounds of vector with length {}",
index,
dest_len
);
@@ -502,7 +478,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let (input, input_len) = self.operand_to_simd(&args[0])?;
assert!(
index < input_len,
- "index `{}` must be in bounds of vector with length `{}`",
+ "index `{}` must be in bounds of vector with length {}",
index,
input_len
);
@@ -524,12 +500,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
sym::vtable_size => {
let ptr = self.read_pointer(&args[0])?;
let (size, _align) = self.get_vtable_size_and_align(ptr)?;
- self.write_scalar(Scalar::from_machine_usize(size.bytes(), self), dest)?;
+ self.write_scalar(Scalar::from_target_usize(size.bytes(), self), dest)?;
}
sym::vtable_align => {
let ptr = self.read_pointer(&args[0])?;
let (_size, align) = self.get_vtable_size_and_align(ptr)?;
- self.write_scalar(Scalar::from_machine_usize(align.bytes(), self), dest)?;
+ self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?;
}
_ => return Ok(false),
@@ -668,10 +644,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
nonoverlapping: bool,
) -> InterpResult<'tcx> {
- let count = self.read_machine_usize(&count)?;
+ let count = self.read_target_usize(&count)?;
let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
let (size, align) = (layout.size, layout.align.abi);
- // `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max),
+ // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max),
// but no actual allocation can be big enough for the difference to be noticeable.
let size = size.checked_mul(count, self).ok_or_else(|| {
err_ub_format!(
@@ -696,9 +672,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let dst = self.read_pointer(&dst)?;
let byte = self.read_scalar(&byte)?.to_u8()?;
- let count = self.read_machine_usize(&count)?;
+ let count = self.read_target_usize(&count)?;
- // `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max),
+ // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max),
// but no actual allocation can be big enough for the difference to be noticeable.
let len = layout
.size
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
index 77c7b4bac..cf52299b7 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
@@ -78,13 +78,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
col: u32,
) -> MPlaceTy<'tcx, M::Provenance> {
let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail;
+ // This can fail if rustc runs out of memory right here. Trying to emit an error would be
+ // pointless, since that would require allocating more memory than these short strings.
let file = if loc_details.file {
self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
+ .unwrap()
} else {
// FIXME: This creates a new allocation each time. It might be preferable to
// perform this allocation only once, and re-use the `MPlaceTy`.
// See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
- self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not)
+ self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not).unwrap()
};
let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
@@ -92,11 +95,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Allocate memory for `CallerLocation` struct.
let loc_ty = self
.tcx
- .bound_type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None))
- .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter()));
+ .type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None))
+ .subst(*self.tcx, self.tcx.mk_substs(&[self.tcx.lifetimes.re_erased.into()]));
let loc_layout = self.layout_of(loc_ty).unwrap();
- // This can fail if rustc runs out of memory right here. Trying to emit an error would be
- // pointless, since that would require allocating more memory than a Location.
let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
// Initialize fields.