Mark scalar layout unions so that backends that do not support partially initialized scalars can special case them.
This commit is contained in:
parent
2ed6786404
commit
d32ce37a17
37 changed files with 356 additions and 288 deletions
|
@ -188,7 +188,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
let val = self.read_scalar(&args[0])?.check_init()?;
|
||||
let bits = val.to_bits(layout_of.size)?;
|
||||
let kind = match layout_of.abi {
|
||||
Abi::Scalar(scalar) => scalar.value,
|
||||
Abi::Scalar(scalar) => scalar.primitive(),
|
||||
_ => span_bug!(
|
||||
self.cur_span(),
|
||||
"{} called on invalid type {:?}",
|
||||
|
|
|
@ -265,6 +265,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}));
|
||||
};
|
||||
|
||||
// It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point.
|
||||
// However, `MaybeUninit<u64>` is considered a `Scalar` as far as its layout is concerned --
|
||||
// and yet cannot be represented by an interpreter `Scalar`, since we have to handle the
|
||||
// case where some of the bytes are initialized and others are not. So, we only permit
|
||||
// reads from `Scalar`s and `ScalarPair`s that cannot be uninitialized.
|
||||
match mplace.layout.abi {
|
||||
Abi::Scalar(..) => {
|
||||
let scalar = alloc.read_scalar(alloc_range(Size::ZERO, mplace.layout.size))?;
|
||||
|
@ -274,7 +279,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// We checked `ptr_align` above, so all fields will have the alignment they need.
|
||||
// We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
|
||||
// which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
|
||||
let (a, b) = (a.value, b.value);
|
||||
let (a_size, b_size) = (a.size(self), b.size(self));
|
||||
let b_offset = a_size.align_to(b.align(self).abi);
|
||||
assert!(b_offset.bytes() > 0); // we later use the offset to tell apart the fields
|
||||
|
@ -676,7 +680,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// may be a pointer. This is `tag_val.layout`; we just use it for sanity checks.
|
||||
|
||||
// Get layout for tag.
|
||||
let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?;
|
||||
let tag_layout = self.layout_of(tag_scalar_layout.primitive().to_int_ty(*self.tcx))?;
|
||||
|
||||
// Read tag and sanity-check `tag_layout`.
|
||||
let tag_val = self.read_immediate(&self.operand_field(op, tag_field)?)?;
|
||||
|
|
|
@ -772,13 +772,11 @@ where
|
|||
// We checked `ptr_align` above, so all fields will have the alignment they need.
|
||||
// We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
|
||||
// which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
|
||||
let (a, b) = match dest.layout.abi {
|
||||
Abi::ScalarPair(a, b) => (a.value, b.value),
|
||||
_ => span_bug!(
|
||||
let Abi::ScalarPair(a, b) = dest.layout.abi else { span_bug!(
|
||||
self.cur_span(),
|
||||
"write_immediate_to_mplace: invalid ScalarPair layout: {:#?}",
|
||||
dest.layout
|
||||
),
|
||||
)
|
||||
};
|
||||
let (a_size, b_size) = (a.size(&tcx), b.size(&tcx));
|
||||
let b_offset = a_size.align_to(b.align(&tcx).abi);
|
||||
|
@ -1047,7 +1045,7 @@ where
|
|||
// raw discriminants for enums are isize or bigger during
|
||||
// their computation, but the in-memory tag is the smallest possible
|
||||
// representation
|
||||
let size = tag_layout.value.size(self);
|
||||
let size = tag_layout.size(self);
|
||||
let tag_val = size.truncate(discr_val);
|
||||
|
||||
let tag_dest = self.place_field(dest, tag_field)?;
|
||||
|
@ -1071,7 +1069,7 @@ where
|
|||
.expect("overflow computing relative variant idx");
|
||||
// We need to use machine arithmetic when taking into account `niche_start`:
|
||||
// tag_val = variant_index_relative + niche_start_val
|
||||
let tag_layout = self.layout_of(tag_layout.value.to_int_ty(*self.tcx))?;
|
||||
let tag_layout = self.layout_of(tag_layout.primitive().to_int_ty(*self.tcx))?;
|
||||
let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
|
||||
let variant_index_relative_val =
|
||||
ImmTy::from_uint(variant_index_relative, tag_layout);
|
||||
|
|
|
@ -189,12 +189,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// that will take care to make it UB to leave the range, just
|
||||
// like for transmute).
|
||||
(abi::Abi::Scalar(caller), abi::Abi::Scalar(callee)) => {
|
||||
caller.value == callee.value
|
||||
caller.primitive() == callee.primitive()
|
||||
}
|
||||
(
|
||||
abi::Abi::ScalarPair(caller1, caller2),
|
||||
abi::Abi::ScalarPair(callee1, callee2),
|
||||
) => caller1.value == callee1.value && caller2.value == callee2.value,
|
||||
) => {
|
||||
caller1.primitive() == callee1.primitive()
|
||||
&& caller2.primitive() == callee2.primitive()
|
||||
}
|
||||
// Be conservative
|
||||
_ => false,
|
||||
}
|
||||
|
|
|
@ -629,12 +629,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
op: &OpTy<'tcx, M::PointerTag>,
|
||||
scalar_layout: ScalarAbi,
|
||||
) -> InterpResult<'tcx> {
|
||||
if scalar_layout.valid_range.is_full_for(op.layout.size) {
|
||||
if scalar_layout.valid_range(self.ecx).is_full_for(op.layout.size) {
|
||||
// Nothing to check
|
||||
return Ok(());
|
||||
}
|
||||
// At least one value is excluded.
|
||||
let valid_range = scalar_layout.valid_range;
|
||||
let valid_range = scalar_layout.valid_range(self.ecx);
|
||||
let WrappingRange { start, end } = valid_range;
|
||||
let max_value = op.layout.size.unsigned_int_max();
|
||||
assert!(end <= max_value);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue