]> git.lizzy.rs Git - rust.git/commitdiff
make floating point casts nicer with generics
authorRalf Jung <post@ralfj.de>
Sun, 9 Jun 2019 10:31:19 +0000 (12:31 +0200)
committerRalf Jung <post@ralfj.de>
Sun, 9 Jun 2019 10:51:07 +0000 (12:51 +0200)
src/librustc/ty/sty.rs
src/librustc_mir/interpret/cast.rs
src/librustc_mir/interpret/operator.rs

index ddc4bd3f9f6c3c057cd918147a6eef1937be875e..5cc46b21fca1f1bf27de4e57f469d89b0ee6709b 100644 (file)
@@ -2035,6 +2035,14 @@ pub fn is_fn(&self) -> bool {
         }
     }
 
+    #[inline]
+    pub fn is_fn_ptr(&self) -> bool {
+        match self.sty {
+            FnPtr(_) => true,
+            _ => false,
+        }
+    }
+
     pub fn is_impl_trait(&self) -> bool {
         match self.sty {
             Opaque(..) => true,
index 4395f0c947b152820b235ad828458ddb20a6df26..7a0c98bc44c3751b1ef0bd2cee5a2efc71a3dac7 100644 (file)
@@ -5,11 +5,11 @@
 use syntax::symbol::sym;
 
 use rustc_apfloat::ieee::{Single, Double};
+use rustc_apfloat::{Float, FloatConvert};
 use rustc::mir::interpret::{
     Scalar, InterpResult, Pointer, PointerArithmetic, InterpError,
 };
 use rustc::mir::CastKind;
-use rustc_apfloat::Float;
 
 use super::{InterpretCx, Machine, PlaceTy, OpTy, Immediate};
 
@@ -126,7 +126,7 @@ pub fn cast(
         Ok(())
     }
 
-    pub(super) fn cast_scalar(
+    fn cast_scalar(
         &self,
         val: Scalar<M::PointerTag>,
         src_layout: TyLayout<'tcx>,
@@ -135,12 +135,21 @@ pub(super) fn cast_scalar(
         use rustc::ty::TyKind::*;
         trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);
 
-        match val.to_bits_or_ptr(src_layout.size, self) {
-            Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
-            Ok(data) => {
-                match src_layout.ty.sty {
-                    Float(fty) => self.cast_from_float(data, fty, dest_layout.ty),
-                    _ => self.cast_from_int(data, src_layout, dest_layout),
+        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
+            _ => {
+                assert!(
+                    src_layout.ty.is_bool() || src_layout.ty.is_char() ||
+                    src_layout.ty.is_integral()   || src_layout.ty.is_region_ptr() ||
+                    src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_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, dest_layout.ty),
+                    Ok(data) => self.cast_from_int(data, src_layout, dest_layout),
                 }
             }
         }
@@ -148,10 +157,11 @@ pub(super) fn cast_scalar(
 
     fn cast_from_int(
         &self,
-        v: u128,
+        v: u128, // raw bits
         src_layout: TyLayout<'tcx>,
         dest_layout: TyLayout<'tcx>,
     ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
+        // Let's make sure v is sign-extended *if* it has a signed type.
         let signed = src_layout.abi.is_signed();
         let v = if signed {
             self.sign_extend(v, src_layout)
@@ -190,46 +200,36 @@ fn cast_from_int(
         }
     }
 
-    fn cast_from_float(
+    fn cast_from_float<F>(
         &self,
-        bits: u128,
-        fty: FloatTy,
+        f: F,
         dest_ty: Ty<'tcx>
-    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Scalar<M::PointerTag>>
+    where F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>
+    {
         use rustc::ty::TyKind::*;
-        use rustc_apfloat::FloatConvert;
         match dest_ty.sty {
             // float -> uint
             Uint(t) => {
                 let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
-                let v = match fty {
-                    FloatTy::F32 => Single::from_bits(bits).to_u128(width).value,
-                    FloatTy::F64 => Double::from_bits(bits).to_u128(width).value,
-                };
+                let v = f.to_u128(width).value;
                 // This should already fit the bit width
                 Ok(Scalar::from_uint(v, Size::from_bits(width as u64)))
             },
             // float -> int
             Int(t) => {
                 let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
-                let v = match fty {
-                    FloatTy::F32 => Single::from_bits(bits).to_i128(width).value,
-                    FloatTy::F64 => Double::from_bits(bits).to_i128(width).value,
-                };
+                let v = f.to_i128(width).value;
                 Ok(Scalar::from_int(v, Size::from_bits(width as u64)))
             },
-            // f64 -> f32
-            Float(FloatTy::F32) if fty == FloatTy::F64 =>
-                Ok(Scalar::from_f32(Double::from_bits(bits).convert(&mut false).value)),
-            // f32 -> f64
-            Float(FloatTy::F64) if fty == FloatTy::F32 =>
-                Ok(Scalar::from_f64(Single::from_bits(bits).convert(&mut false).value)),
-            // identity cast
-            Float(FloatTy::F64) if fty == FloatTy::F64 =>
-                Ok(Scalar::from_uint(bits, Size::from_bits(64))),
-            Float(FloatTy::F32) if fty == FloatTy::F32 =>
-                Ok(Scalar::from_uint(bits, Size::from_bits(32))),
-            _ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
+            // float -> f32
+            Float(FloatTy::F32) =>
+                Ok(Scalar::from_f32(f.convert(&mut false).value)),
+            // float -> f64
+            Float(FloatTy::F64) =>
+                Ok(Scalar::from_f64(f.convert(&mut false).value)),
+            // That's it.
+            _ => bug!("invalid float to {:?} cast", dest_ty),
         }
     }
 
index eb45bb0e2771b76f6ba05ff87009b6df1e547096..db7da9359de7b7762bfc153120bdce4bd56dc699 100644 (file)
@@ -292,10 +292,14 @@ pub fn binary_op(
             }
             _ => {
                 // Must be integer(-like) types.  Don't forget about == on fn pointers.
-                assert!(left.layout.ty.is_integral() || left.layout.ty.is_unsafe_ptr() ||
-                    left.layout.ty.is_fn());
-                assert!(right.layout.ty.is_integral() || right.layout.ty.is_unsafe_ptr() ||
-                    right.layout.ty.is_fn());
+                assert!(
+                    left.layout.ty.is_integral()   ||
+                    left.layout.ty.is_unsafe_ptr() || left.layout.ty.is_fn_ptr(),
+                    "Unexpected LHS type {:?} for BinOp {:?}", left.layout.ty, bin_op);
+                assert!(
+                    right.layout.ty.is_integral()   ||
+                    right.layout.ty.is_unsafe_ptr() || right.layout.ty.is_fn_ptr(),
+                    "Unexpected RHS type {:?} for BinOp {:?}", right.layout.ty, bin_op);
 
                 // Handle operations that support pointer values
                 if left.to_scalar_ptr()?.is_ptr() ||