From b318bcfa784cead43a8b5aa553dcc4999e46b32e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 20:05:53 +0200 Subject: [PATCH] refactor cast_immediate to dispatch on the type first, and on the value second --- src/librustc_mir/interpret/cast.rs | 110 ++++++++++++----------------- 1 file changed, 46 insertions(+), 64 deletions(-) diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 7e752e2edc4..4758e7ff170 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -14,15 +14,6 @@ use rustc::mir::CastKind; 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 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { src: ImmTy<'tcx, M::PointerTag>, dest_layout: TyLayout<'tcx>, ) -> InterpResult<'tcx, Immediate> { - 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, - src_layout: TyLayout<'tcx>, - dest_layout: TyLayout<'tcx>, - ) -> InterpResult<'tcx, Scalar> { 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(