diff --git a/compiler-builtins/src/float/add.rs b/compiler-builtins/src/float/add.rs index 43e3ae931..0cc362f70 100644 --- a/compiler-builtins/src/float/add.rs +++ b/compiler-builtins/src/float/add.rs @@ -168,7 +168,7 @@ where } // Low three bits are round, guard, and sticky. - let a_significand_i32: i32 = a_significand.cast(); + let a_significand_i32: i32 = a_significand.cast_lossy(); let round_guard_sticky: i32 = a_significand_i32 & 0x7; // Shift the significand into place, and mask off the implicit bit. diff --git a/compiler-builtins/src/float/conv.rs b/compiler-builtins/src/float/conv.rs index 9d732f2cd..75ea7ce02 100644 --- a/compiler-builtins/src/float/conv.rs +++ b/compiler-builtins/src/float/conv.rs @@ -74,7 +74,7 @@ mod int_to_float { F::Int: CastFrom, Conv: Fn(I::Unsigned) -> F::Int, { - let sign_bit = F::Int::cast_from(i >> (I::BITS - 1)) << (F::BITS - 1); + let sign_bit = F::Int::cast_from_lossy(i >> (I::BITS - 1)) << (F::BITS - 1); F::from_bits(conv(i.unsigned_abs()) | sign_bit) } @@ -166,7 +166,7 @@ mod int_to_float { // Within the upper `F::BITS`, everything except for the signifcand // gets truncated - let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIG_BITS - 1)).cast(); + let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIG_BITS - 1)).cast_lossy(); // The entire rest of `i_m` gets truncated. Zero the upper `F::BITS` then just // check if it is nonzero. @@ -371,7 +371,7 @@ where let m_base = if I::Unsigned::BITS >= F::Int::BITS { I::Unsigned::cast_from(fbits) << (I::BITS - F::SIG_BITS - 1) } else { - I::Unsigned::cast_from(fbits >> (F::SIG_BITS - I::BITS + 1)) + I::Unsigned::cast_from_lossy(fbits >> (F::SIG_BITS - I::BITS + 1)) }; // Set the implicit 1-bit. diff --git a/compiler-builtins/src/float/div.rs b/compiler-builtins/src/float/div.rs index 3e4f0e20d..fc1fc0851 100644 --- a/compiler-builtins/src/float/div.rs +++ b/compiler-builtins/src/float/div.rs @@ -482,7 +482,7 @@ where let ret = quotient.wrapping_shr(u32::cast_from(res_exponent.wrapping_neg()) + 1); residual_lo = a_significand - .wrapping_shl(significand_bits.wrapping_add(CastInto::::cast(res_exponent))) + .wrapping_shl(significand_bits.wrapping_add(CastInto::::cast_lossy(res_exponent))) .wrapping_sub(ret.wrapping_mul(b_significand) << 1); ret }; diff --git a/compiler-builtins/src/float/mul.rs b/compiler-builtins/src/float/mul.rs index c811f1406..dbed3095c 100644 --- a/compiler-builtins/src/float/mul.rs +++ b/compiler-builtins/src/float/mul.rs @@ -143,7 +143,7 @@ where // a zero of the appropriate sign. Mathematically there is no need to // handle this case separately, but we make it a special case to // simplify the shift logic. - let shift: u32 = one.wrapping_sub(product_exponent.cast()).cast(); + let shift: u32 = one.wrapping_sub(product_exponent.cast_lossy()).cast(); if shift >= bits { return F::from_bits(product_sign); } diff --git a/compiler-builtins/src/float/trunc.rs b/compiler-builtins/src/float/trunc.rs index ca8a0f368..93db5d8bb 100644 --- a/compiler-builtins/src/float/trunc.rs +++ b/compiler-builtins/src/float/trunc.rs @@ -50,7 +50,7 @@ where // The exponent of a is within the range of normal numbers in the // destination format. We can convert by simply right-shifting with // rounding and adjusting the exponent. - abs_result = (a_abs >> sig_bits_delta).cast(); + abs_result = (a_abs >> sig_bits_delta).cast_lossy(); // Cast before shifting to prevent overflow. let bias_diff: R::Int = src_exp_bias.wrapping_sub(dst_exp_bias).cast(); let tmp = bias_diff << R::SIG_BITS; diff --git a/compiler-builtins/src/int/trailing_zeros.rs b/compiler-builtins/src/int/trailing_zeros.rs index 8f63c22c8..1b0ae5b73 100644 --- a/compiler-builtins/src/int/trailing_zeros.rs +++ b/compiler-builtins/src/int/trailing_zeros.rs @@ -20,18 +20,18 @@ mod implementation { const { assert!(I::BITS <= 64) }; if I::BITS >= 64 { - r += ((u32::cast_from(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + r += ((u32::cast_from_lossy(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 x >>= r; // remove 32 zero bits } if I::BITS >= 32 { - t = ((u16::cast_from(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 + t = ((u16::cast_from_lossy(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 r += t; x >>= t; // x = [0 - 0xFFFF] + higher garbage bits } const { assert!(I::BITS >= 16) }; - t = ((u8::cast_from(x) == 0) as u32) << 3; + t = ((u8::cast_from_lossy(x) == 0) as u32) << 3; x >>= t; // x = [0 - 0xFF] + higher garbage bits r += t; diff --git a/compiler-builtins/src/int/traits.rs b/compiler-builtins/src/int/traits.rs index b474df366..25b9718ad 100644 --- a/compiler-builtins/src/int/traits.rs +++ b/compiler-builtins/src/int/traits.rs @@ -1,4 +1,4 @@ -pub use crate::support::{Int, MinInt}; +pub use crate::support::{CastFrom, CastInto, Int, MinInt}; /// Trait for integers twice the bit width of another integer. This is implemented for all /// primitives except for `u8`, because there is not a smaller primitive. @@ -97,44 +97,3 @@ impl_h_int!( i32 u32 i64, i64 u64 i128 ); - -/// Trait to express (possibly lossy) casting of integers -pub trait CastInto: Copy { - fn cast(self) -> T; -} - -pub trait CastFrom: Copy { - fn cast_from(value: T) -> Self; -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - self as $into - } - } - )*}; -} - -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); diff --git a/libm/src/math/support/int_traits.rs b/libm/src/math/support/int_traits.rs index fa9e06066..716af748a 100644 --- a/libm/src/math/support/int_traits.rs +++ b/libm/src/math/support/int_traits.rs @@ -374,14 +374,19 @@ impl_h_int!( /// Trait to express (possibly lossy) casting of integers pub trait CastInto: Copy { /// By default, casts should be exact. + #[track_caller] fn cast(self) -> T; /// Call for casts that are expected to truncate. + /// + /// In practice, this is exactly the same as `cast`; the main difference is to document intent + /// in code. `cast` may panic in debug mode. fn cast_lossy(self) -> T; } pub trait CastFrom: Copy { /// By default, casts should be exact. + #[track_caller] fn cast_from(value: T) -> Self; /// Call for casts that are expected to truncate.