]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/mir/interpret/value.rs
Scalar: only convert to/from soft-float types, not to/from hard-floats
[rust.git] / src / librustc / mir / interpret / value.rs
index b8d6c1224463128f861704503c083f0756c4de99..1909f3cb998be90584d99480dd7c2e837ed6fd06 100644 (file)
@@ -1,11 +1,12 @@
 use std::fmt;
 use rustc_macros::HashStable;
+use rustc_apfloat::{Float, ieee::{Double, Single}};
 
 use crate::ty::{Ty, InferConst, ParamConst, layout::{HasDataLayout, Size}, subst::SubstsRef};
 use crate::ty::PlaceholderConst;
 use crate::hir::def_id::DefId;
 
-use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};
+use super::{InterpResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};
 
 /// Represents the result of a raw const operation, pre-validation.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash, HashStable)]
@@ -176,7 +177,7 @@ pub fn zst() -> Self {
     }
 
     #[inline]
-    pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
+    pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
         let dl = cx.data_layout();
         match self {
             Scalar::Raw { data, size } => {
@@ -206,7 +207,7 @@ pub fn ptr_wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
     }
 
     #[inline]
-    pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
+    pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
         let dl = cx.data_layout();
         match self {
             Scalar::Raw { data, size } => {
@@ -292,12 +293,12 @@ pub fn from_int(i: impl Into<i128>, size: Size) -> Self {
     }
 
     #[inline]
-    pub fn from_f32(f: f32) -> Self {
+    pub fn from_f32(f: Single) -> Self {
         Scalar::Raw { data: f.to_bits() as u128, size: 4 }
     }
 
     #[inline]
-    pub fn from_f64(f: f64) -> Self {
+    pub fn from_f64(f: Double) -> Self {
         Scalar::Raw { data: f.to_bits() as u128, size: 8 }
     }
 
@@ -322,7 +323,7 @@ pub fn to_bits_or_ptr(
     }
 
     #[inline]
-    pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
+    pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
         match self {
             Scalar::Raw { data, size } => {
                 assert_eq!(target_size.bytes(), size as u64);
@@ -335,7 +336,7 @@ pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
     }
 
     #[inline]
-    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
+    pub fn to_ptr(self) -> InterpResult<'tcx, Pointer<Tag>> {
         match self {
             Scalar::Raw { data: 0, .. } => err!(InvalidNullPointerUsage),
             Scalar::Raw { .. } => err!(ReadBytesAsPointer),
@@ -359,7 +360,7 @@ pub fn is_ptr(self) -> bool {
         }
     }
 
-    pub fn to_bool(self) -> EvalResult<'tcx, bool> {
+    pub fn to_bool(self) -> InterpResult<'tcx, bool> {
         match self {
             Scalar::Raw { data: 0, size: 1 } => Ok(false),
             Scalar::Raw { data: 1, size: 1 } => Ok(true),
@@ -367,7 +368,7 @@ pub fn to_bool(self) -> EvalResult<'tcx, bool> {
         }
     }
 
-    pub fn to_char(self) -> EvalResult<'tcx, char> {
+    pub fn to_char(self) -> InterpResult<'tcx, char> {
         let val = self.to_u32()?;
         match ::std::char::from_u32(val) {
             Some(c) => Ok(c),
@@ -375,51 +376,51 @@ pub fn to_char(self) -> EvalResult<'tcx, char> {
         }
     }
 
-    pub fn to_u8(self) -> EvalResult<'static, u8> {
+    pub fn to_u8(self) -> InterpResult<'static, u8> {
         let sz = Size::from_bits(8);
         let b = self.to_bits(sz)?;
         Ok(b as u8)
     }
 
-    pub fn to_u32(self) -> EvalResult<'static, u32> {
+    pub fn to_u32(self) -> InterpResult<'static, u32> {
         let sz = Size::from_bits(32);
         let b = self.to_bits(sz)?;
         Ok(b as u32)
     }
 
-    pub fn to_u64(self) -> EvalResult<'static, u64> {
+    pub fn to_u64(self) -> InterpResult<'static, u64> {
         let sz = Size::from_bits(64);
         let b = self.to_bits(sz)?;
         Ok(b as u64)
     }
 
-    pub fn to_usize(self, cx: &impl HasDataLayout) -> EvalResult<'static, u64> {
+    pub fn to_usize(self, cx: &impl HasDataLayout) -> InterpResult<'static, u64> {
         let b = self.to_bits(cx.data_layout().pointer_size)?;
         Ok(b as u64)
     }
 
-    pub fn to_i8(self) -> EvalResult<'static, i8> {
+    pub fn to_i8(self) -> InterpResult<'static, i8> {
         let sz = Size::from_bits(8);
         let b = self.to_bits(sz)?;
         let b = sign_extend(b, sz) as i128;
         Ok(b as i8)
     }
 
-    pub fn to_i32(self) -> EvalResult<'static, i32> {
+    pub fn to_i32(self) -> InterpResult<'static, i32> {
         let sz = Size::from_bits(32);
         let b = self.to_bits(sz)?;
         let b = sign_extend(b, sz) as i128;
         Ok(b as i32)
     }
 
-    pub fn to_i64(self) -> EvalResult<'static, i64> {
+    pub fn to_i64(self) -> InterpResult<'static, i64> {
         let sz = Size::from_bits(64);
         let b = self.to_bits(sz)?;
         let b = sign_extend(b, sz) as i128;
         Ok(b as i64)
     }
 
-    pub fn to_isize(self, cx: &impl HasDataLayout) -> EvalResult<'static, i64> {
+    pub fn to_isize(self, cx: &impl HasDataLayout) -> InterpResult<'static, i64> {
         let sz = cx.data_layout().pointer_size;
         let b = self.to_bits(sz)?;
         let b = sign_extend(b, sz) as i128;
@@ -427,13 +428,15 @@ pub fn to_isize(self, cx: &impl HasDataLayout) -> EvalResult<'static, i64> {
     }
 
     #[inline]
-    pub fn to_f32(self) -> EvalResult<'static, f32> {
-        Ok(f32::from_bits(self.to_u32()?))
+    pub fn to_f32(self) -> InterpResult<'static, Single> {
+        // Going through `u32` to check size and truncation.
+        Ok(Single::from_bits(self.to_u32()? as u128))
     }
 
     #[inline]
-    pub fn to_f64(self) -> EvalResult<'static, f64> {
-        Ok(f64::from_bits(self.to_u64()?))
+    pub fn to_f64(self) -> InterpResult<'static, Double> {
+        // Going through `u64` to check size and truncation.
+        Ok(Double::from_bits(self.to_u64()? as u128))
     }
 }
 
@@ -489,7 +492,7 @@ pub fn erase_tag(self) -> ScalarMaybeUndef
     }
 
     #[inline]
-    pub fn not_undef(self) -> EvalResult<'static, Scalar<Tag>> {
+    pub fn not_undef(self) -> InterpResult<'static, Scalar<Tag>> {
         match self {
             ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
             ScalarMaybeUndef::Undef => err!(ReadUndefBytes(Size::from_bytes(0))),
@@ -497,72 +500,72 @@ pub fn not_undef(self) -> EvalResult<'static, Scalar<Tag>> {
     }
 
     #[inline(always)]
-    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
+    pub fn to_ptr(self) -> InterpResult<'tcx, Pointer<Tag>> {
         self.not_undef()?.to_ptr()
     }
 
     #[inline(always)]
-    pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
+    pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
         self.not_undef()?.to_bits(target_size)
     }
 
     #[inline(always)]
-    pub fn to_bool(self) -> EvalResult<'tcx, bool> {
+    pub fn to_bool(self) -> InterpResult<'tcx, bool> {
         self.not_undef()?.to_bool()
     }
 
     #[inline(always)]
-    pub fn to_char(self) -> EvalResult<'tcx, char> {
+    pub fn to_char(self) -> InterpResult<'tcx, char> {
         self.not_undef()?.to_char()
     }
 
     #[inline(always)]
-    pub fn to_f32(self) -> EvalResult<'tcx, f32> {
+    pub fn to_f32(self) -> InterpResult<'tcx, Single> {
         self.not_undef()?.to_f32()
     }
 
     #[inline(always)]
-    pub fn to_f64(self) -> EvalResult<'tcx, f64> {
+    pub fn to_f64(self) -> InterpResult<'tcx, Double> {
         self.not_undef()?.to_f64()
     }
 
     #[inline(always)]
-    pub fn to_u8(self) -> EvalResult<'tcx, u8> {
+    pub fn to_u8(self) -> InterpResult<'tcx, u8> {
         self.not_undef()?.to_u8()
     }
 
     #[inline(always)]
-    pub fn to_u32(self) -> EvalResult<'tcx, u32> {
+    pub fn to_u32(self) -> InterpResult<'tcx, u32> {
         self.not_undef()?.to_u32()
     }
 
     #[inline(always)]
-    pub fn to_u64(self) -> EvalResult<'tcx, u64> {
+    pub fn to_u64(self) -> InterpResult<'tcx, u64> {
         self.not_undef()?.to_u64()
     }
 
     #[inline(always)]
-    pub fn to_usize(self, cx: &impl HasDataLayout) -> EvalResult<'tcx, u64> {
+    pub fn to_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
         self.not_undef()?.to_usize(cx)
     }
 
     #[inline(always)]
-    pub fn to_i8(self) -> EvalResult<'tcx, i8> {
+    pub fn to_i8(self) -> InterpResult<'tcx, i8> {
         self.not_undef()?.to_i8()
     }
 
     #[inline(always)]
-    pub fn to_i32(self) -> EvalResult<'tcx, i32> {
+    pub fn to_i32(self) -> InterpResult<'tcx, i32> {
         self.not_undef()?.to_i32()
     }
 
     #[inline(always)]
-    pub fn to_i64(self) -> EvalResult<'tcx, i64> {
+    pub fn to_i64(self) -> InterpResult<'tcx, i64> {
         self.not_undef()?.to_i64()
     }
 
     #[inline(always)]
-    pub fn to_isize(self, cx: &impl HasDataLayout) -> EvalResult<'tcx, i64> {
+    pub fn to_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> {
         self.not_undef()?.to_isize(cx)
     }
 }