use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
-use rustc_target::abi::{Integer, Variants};
+use rustc_target::abi::Integer;
use rustc_type_ir::sty::TyKind::*;
use super::{
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
pub fn cast(
&mut self,
- src: &OpTy<'tcx, M::PointerTag>,
+ src: &OpTy<'tcx, M::Provenance>,
cast_kind: CastKind,
cast_ty: Ty<'tcx>,
- dest: &PlaceTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx> {
use rustc_middle::mir::CastKind::*;
// FIXME: In which cases should we trigger UB when the source is uninit?
def_id,
substs,
ty::ClosureKind::FnOnce,
- );
+ )
+ .ok_or_else(|| err_inval!(TooGeneric))?;
let fn_ptr = self.create_fn_alloc_ptr(FnVal::Instance(instance));
self.write_pointer(fn_ptr, dest)?;
}
pub fn misc_cast(
&mut self,
- src: &ImmTy<'tcx, M::PointerTag>,
+ src: &ImmTy<'tcx, M::Provenance>,
cast_ty: Ty<'tcx>,
- ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+ ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
use rustc_type_ir::sty::TyKind::*;
trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty);
Float(FloatTy::F64) => {
return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, cast_ty).into());
}
- // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
- // are represented as integers.
+ // The rest is integer/pointer-"like", including fn ptr casts
_ => assert!(
src.layout.ty.is_bool()
|| src.layout.ty.is_char()
- || src.layout.ty.is_enum()
|| src.layout.ty.is_integral()
|| src.layout.ty.is_any_ptr(),
"Unexpected cast from type {:?}",
// # First handle non-scalar source values.
- // Handle cast from a ZST enum (0 or 1 variants).
- match src.layout.variants {
- Variants::Single { index } => {
- if src.layout.abi.is_uninhabited() {
- // This is dead code, because an uninhabited enum is UB to
- // instantiate.
- throw_ub!(Unreachable);
- }
- if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) {
- assert!(src.layout.is_zst());
- let discr_layout = self.layout_of(discr.ty)?;
-
- let scalar = Scalar::from_uint(discr.val, discr_layout.layout.size());
- return Ok(self.cast_from_int_like(scalar, discr_layout, cast_ty)?.into());
- }
- }
- Variants::Multiple { .. } => {}
- }
-
// Handle casting any ptr to raw ptr (might be a fat ptr).
if src.layout.ty.is_any_ptr() && cast_ty.is_unsafe_ptr() {
let dest_layout = self.layout_of(cast_ty)?;
assert_eq!(dest_layout.size, self.pointer_size());
assert!(src.layout.ty.is_unsafe_ptr());
return match **src {
- Immediate::ScalarPair(data, _) => Ok(data.into()),
+ Immediate::ScalarPair(data, _) => Ok(data.check_init()?.into()),
Immediate::Scalar(..) => span_bug!(
self.cur_span(),
"{:?} input to a fat-to-thin cast ({:?} -> {:?})",
src.layout.ty,
cast_ty
),
+ Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
};
}
}
pub fn pointer_expose_address_cast(
&mut self,
- src: &ImmTy<'tcx, M::PointerTag>,
+ src: &ImmTy<'tcx, M::Provenance>,
cast_ty: Ty<'tcx>,
- ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+ ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_));
assert!(cast_ty.is_integral());
let scalar = src.to_scalar()?;
- let ptr = self.scalar_to_ptr(scalar)?;
+ let ptr = scalar.to_pointer(self)?;
match ptr.into_pointer_or_addr() {
Ok(ptr) => M::expose_ptr(self, ptr)?,
- Err(_) => {} // do nothing, exposing an invalid pointer has no meaning
+ Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP.
};
Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
}
pub fn pointer_from_exposed_address_cast(
&mut self,
- src: &ImmTy<'tcx, M::PointerTag>,
+ src: &ImmTy<'tcx, M::Provenance>,
cast_ty: Ty<'tcx>,
- ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+ ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
assert!(src.layout.ty.is_integral());
assert_matches!(cast_ty.kind(), ty::RawPtr(_));
pub fn cast_from_int_like(
&self,
- scalar: Scalar<M::PointerTag>, // input value (there is no ScalarTy so we separate data+layout)
+ scalar: Scalar<M::Provenance>, // input value (there is no ScalarTy so we separate data+layout)
src_layout: TyAndLayout<'tcx>,
cast_ty: Ty<'tcx>,
- ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
+ ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
// Let's make sure v is sign-extended *if* it has a signed type.
let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`.
})
}
- fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::PointerTag>
+ fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance>
where
- F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>,
+ F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>,
{
use rustc_type_ir::sty::TyKind::*;
match *dest_ty.kind() {
fn unsize_into_ptr(
&mut self,
- src: &OpTy<'tcx, M::PointerTag>,
- dest: &PlaceTy<'tcx, M::PointerTag>,
+ src: &OpTy<'tcx, M::Provenance>,
+ dest: &PlaceTy<'tcx, M::Provenance>,
// The pointee types
source_ty: Ty<'tcx>,
cast_ty: Ty<'tcx>,
self.write_immediate(val, dest)
}
(&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
- let val = self.read_immediate(src)?;
- if data_a.principal_def_id() == data_b.principal_def_id() {
- return self.write_immediate(*val, dest);
- }
- // trait upcasting coercion
- let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
- src_pointee_ty,
- dest_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)
+ let (old_data, old_vptr) = self.read_immediate(src)?.to_scalar_pair()?;
+ let old_vptr = old_vptr.to_pointer(self)?;
+ let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?;
+ if old_trait != data_a.principal() {
+ throw_ub_format!("upcast on a pointer whose vtable does not match its type");
}
+ let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?;
+ self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
}
(_, &ty::Dynamic(ref data, _)) => {
// Initial cast from sized to dyn trait
- let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
+ let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?;
let ptr = self.read_immediate(src)?.to_scalar()?;
let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx);
self.write_immediate(val, dest)
fn unsize_into(
&mut self,
- src: &OpTy<'tcx, M::PointerTag>,
+ src: &OpTy<'tcx, M::Provenance>,
cast_ty: TyAndLayout<'tcx>,
- dest: &PlaceTy<'tcx, M::PointerTag>,
+ dest: &PlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx> {
trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty);
match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
}
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
assert_eq!(def_a, def_b);
- if def_a.is_box() || def_b.is_box() {
- if !def_a.is_box() || !def_b.is_box() {
- span_bug!(
- self.cur_span(),
- "invalid unsizing between {:?} -> {:?}",
- src.layout.ty,
- cast_ty.ty
- );
- }
- return self.unsize_into_ptr(
- src,
- dest,
- src.layout.ty.boxed_ty(),
- cast_ty.ty.boxed_ty(),
- );
- }
// unsizing of generic struct with pointer fields
// Example: `Arc<T>` -> `Arc<Trait>`
let src_field = self.operand_field(src, i)?;
let dst_field = self.place_field(dest, i)?;
if src_field.layout.ty == cast_ty_field.ty {
- self.copy_op(&src_field, &dst_field)?;
+ self.copy_op(&src_field, &dst_field, /*allow_transmute*/ false)?;
} else {
self.unsize_into(&src_field, cast_ty_field, &dst_field)?;
}