about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2019-07-24 20:05:53 +0200
committerRalf Jung <post@ralfj.de>2019-08-02 22:33:36 +0200
commitb318bcfa784cead43a8b5aa553dcc4999e46b32e (patch)
tree48dbd3479414518b8471c1b68ac43b70996dfaae
parentec1e71895aa450606d99d7705dac20d689a330d1 (diff)
downloadrust-b318bcfa784cead43a8b5aa553dcc4999e46b32e.tar.gz
rust-b318bcfa784cead43a8b5aa553dcc4999e46b32e.zip
refactor cast_immediate to dispatch on the type first, and on the value second
-rw-r--r--src/librustc_mir/interpret/cast.rs110
1 files 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<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(