refactor cast_immediate to dispatch on the type first, and on the value second

This commit is contained in:
Ralf Jung 2019-07-24 20:05:53 +02:00
parent ec1e71895a
commit b318bcfa78

View File

@ -14,15 +14,6 @@
use super::{InterpCx, Machine, PlaceTy, OpTy, ImmTy, Immediate, FnVal};
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
match ty.sty {
ty::RawPtr(ty::TypeAndMut { ty, .. }) |
ty::Ref(_, ty, _) => !self.type_is_sized(ty),
ty::Adt(def, _) if def.is_box() => !self.type_is_sized(ty.boxed_ty()),
_ => false,
}
}
pub fn cast(
&mut self,
src: OpTy<'tcx, M::PointerTag>,
@ -99,68 +90,59 @@ fn cast_immediate(
src: ImmTy<'tcx, M::PointerTag>,
dest_layout: TyLayout<'tcx>,
) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
if self.type_is_fat_ptr(src.layout.ty) {
return match (*src, self.type_is_fat_ptr(dest_layout.ty)) {
// pointers to extern types
(Immediate::Scalar(_),_) |
// slices and trait objects to other slices/trait objects
(Immediate::ScalarPair(..), true) => {
// No change to immediate
Ok(*src)
}
// slices and trait objects to thin pointers (dropping the metadata)
(Immediate::ScalarPair(data, _), false) => {
Ok(data.into())
}
};
} else {
match src.layout.variants {
layout::Variants::Single { index } => {
if let Some(discr) =
src.layout.ty.discriminant_for_variant(*self.tcx, index)
{
// Cast from a univariant enum
assert!(src.layout.is_zst());
return Ok(Scalar::from_uint(discr.val, dest_layout.size).into());
}
}
layout::Variants::Multiple { .. } => {},
}
return Ok(self.cast_scalar(src.to_scalar()?, src.layout, dest_layout)?.into());
}
}
fn cast_scalar(
&self,
val: Scalar<M::PointerTag>,
src_layout: TyLayout<'tcx>,
dest_layout: TyLayout<'tcx>,
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
use rustc::ty::TyKind::*;
trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);
trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, dest_layout.ty);
match src_layout.ty.sty {
match src.layout.ty.sty {
// Floating point
Float(FloatTy::F32) => self.cast_from_float(val.to_f32()?, dest_layout.ty),
Float(FloatTy::F64) => self.cast_from_float(val.to_f64()?, dest_layout.ty),
// Integer(-like), including fn ptr casts and casts from enums that
// are represented as integers (this excludes univariant enums, which
// are handled in `cast` directly).
_ => {
Float(FloatTy::F32) =>
return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, dest_layout.ty)?.into()),
Float(FloatTy::F64) =>
return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, dest_layout.ty)?.into()),
// The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
// are represented as integers.
_ =>
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_unsafe_ptr() || src_layout.ty.is_fn_ptr() ||
src_layout.ty.is_region_ptr(),
"Unexpected cast from type {:?}", src_layout.ty
);
match val.to_bits_or_ptr(src_layout.size, self) {
Err(ptr) => self.cast_from_ptr(ptr, src_layout, dest_layout),
Ok(data) => self.cast_from_int(data, src_layout, dest_layout),
src.layout.ty.is_bool() || src.layout.ty.is_char() ||
src.layout.ty.is_enum() || src.layout.ty.is_integral() ||
src.layout.ty.is_unsafe_ptr() || src.layout.ty.is_fn_ptr() ||
src.layout.ty.is_region_ptr(),
"Unexpected cast from type {:?}", src.layout.ty
)
}
// Handle cast the metadata away from a fat pointer.
if dest_layout.size != src.layout.size {
assert_eq!(dest_layout.size, self.memory.pointer_size());
return match *src {
Immediate::ScalarPair(data, _) => Ok(data.into()),
Immediate::Scalar(..) =>
bug!(
"{:?} input to a fat-to-thin cast ({:?} -> {:?})",
*src, src.layout.ty, dest_layout.ty
),
};
}
// Handle cast from a univariant (ZST) enum
match src.layout.variants {
layout::Variants::Single { index } => {
if let Some(discr) =
src.layout.ty.discriminant_for_variant(*self.tcx, index)
{
assert!(src.layout.is_zst());
return Ok(Scalar::from_uint(discr.val, dest_layout.size).into());
}
}
layout::Variants::Multiple { .. } => {},
}
// Handle all the rest.
let val = src.to_scalar()?;
Ok(match val.to_bits_or_ptr(src.layout.size, self) {
Err(ptr) => self.cast_from_ptr(ptr, src.layout, dest_layout)?,
Ok(data) => self.cast_from_int(data, src.layout, dest_layout)?,
}.into())
}
fn cast_from_int(