1
Fork 0

Implement pointer casting.

This commit is contained in:
Charles Lew 2021-07-31 22:46:23 +08:00
parent 7069a8c2b7
commit 63ed625313
11 changed files with 256 additions and 88 deletions

View file

@ -269,12 +269,34 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self);
self.write_immediate(val, dest)
}
(&ty::Dynamic(..), &ty::Dynamic(..)) => {
// For now, upcasts are limited to changes in marker
// traits, and hence never actually require an actual
// change to the vtable.
(&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
let val = self.read_immediate(src)?;
self.write_immediate(*val, dest)
if data_a.principal_def_id() == data_b.principal_def_id() {
return self.write_immediate(*val, dest);
}
// trait upcasting coercion
let principal_a = data_a.principal().expect(
"unsize_into_ptr: missing principal trait for trait upcasting coercion",
);
let principal_b = data_b.principal().expect(
"unsize_into_ptr: missing principal trait for trait upcasting coercion",
);
let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
principal_a.with_self_ty(*self.tcx, src_pointee_ty),
principal_b.with_self_ty(*self.tcx, src_pointee_ty),
));
if let Some(entry_idx) = vptr_entry_idx {
let entry_idx = u64::try_from(entry_idx).unwrap();
let (old_data, old_vptr) = val.to_scalar_pair()?;
let old_vptr = self.scalar_to_ptr(old_vptr);
let new_vptr = self
.read_new_vtable_after_trait_upcasting_from_vtable(old_vptr, entry_idx)?;
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
} else {
self.write_immediate(*val, dest)
}
}
(_, &ty::Dynamic(ref data, _)) => {
// Initial cast from sized to dyn trait

View file

@ -79,6 +79,16 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> {
pub fn to_scalar(self) -> InterpResult<'tcx, Scalar<Tag>> {
self.to_scalar_or_uninit().check_init()
}
#[inline]
pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> {
match self {
Immediate::ScalarPair(val1, val2) => Ok((val1.check_init()?, val2.check_init()?)),
Immediate::Scalar(..) => {
bug!("Got a scalar where a wide pointer was expected")
}
}
}
}
// ScalarPair needs a type to interpret, so we often have an immediate and a type together

View file

@ -121,4 +121,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
Ok((Size::from_bytes(size), align))
}
pub fn read_new_vtable_after_trait_upcasting_from_vtable(
&self,
vtable: Pointer<Option<M::PointerTag>>,
idx: u64,
) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
let pointer_size = self.pointer_size();
let vtable = self
.memory
.get(
vtable,
pointer_size * idx.checked_add(1).unwrap(),
self.tcx.data_layout.pointer_align.abi,
)?
.expect("cannot be a ZST");
let new_vtable = self
.scalar_to_ptr(vtable.read_ptr_sized(pointer_size * idx)?.check_init()?)
.into_pointer_or_addr()
.expect("should be a pointer");
Ok(new_vtable)
}
}