Skip to content

Commit

Permalink
Rollup merge of #70487 - Mark-Simulacrum:float-unchecked-casts, r=Sim…
Browse files Browse the repository at this point in the history
…onSapin

Stabilize float::to_int_unchecked

This renames and stabilizes unsafe floating point to integer casts, which are intended to be the substitute for the currently unsound `as` behavior, once that changes to safe-but-slower saturating casts. As such, I believe this also likely unblocks #10184 (our oldest I-unsound issue!), as once this rolls out to stable it would be far easier IMO to change the behavior of `as` to be safe by default.

This does not stabilize the trait or the associated method, as they are deemed internal implementation details (and consumers should not, generally, want to expose them, as in practice all callers likely know statically/without generics what the return type is).

Closes #67058
  • Loading branch information
Centril committed Apr 2, 2020
2 parents 537ccdf + 5614721 commit 1eabbd0
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 22 deletions.
15 changes: 11 additions & 4 deletions src/libcore/convert/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ mod private {
/// Typically doesn’t need to be used directly.
#[unstable(feature = "convert_float_to_int", issue = "67057")]
pub trait FloatToInt<Int>: private::Sealed + Sized {
#[unstable(feature = "float_approx_unchecked_to", issue = "67058")]
#[unstable(feature = "convert_float_to_int", issue = "67057")]
#[doc(hidden)]
unsafe fn approx_unchecked(self) -> Int;
unsafe fn to_int_unchecked(self) -> Int;
}

macro_rules! impl_float_to_int {
Expand All @@ -27,8 +27,15 @@ macro_rules! impl_float_to_int {
impl FloatToInt<$Int> for $Float {
#[doc(hidden)]
#[inline]
unsafe fn approx_unchecked(self) -> $Int {
crate::intrinsics::float_to_int_approx_unchecked(self)
unsafe fn to_int_unchecked(self) -> $Int {
#[cfg(bootstrap)]
{
crate::intrinsics::float_to_int_approx_unchecked(self)
}
#[cfg(not(bootstrap))]
{
crate::intrinsics::float_to_int_unchecked(self)
}
}
}
)+
Expand Down
8 changes: 8 additions & 0 deletions src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1582,8 +1582,16 @@ extern "rust-intrinsic" {
/// Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range
/// (<https://github.com/rust-lang/rust/issues/10184>)
/// This is under stabilization at <https://github.com/rust-lang/rust/issues/67058>
#[cfg(bootstrap)]
pub fn float_to_int_approx_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;

/// Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range
/// (<https://github.com/rust-lang/rust/issues/10184>)
///
/// Stabilized as `f32::to_int_unchecked` and `f64::to_int_unchecked`.
#[cfg(not(bootstrap))]
pub fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;

/// Returns the number of bits set in an integer type `T`
///
/// The stabilized versions of this intrinsic are available on the integer
Expand Down
12 changes: 5 additions & 7 deletions src/libcore/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,14 +464,12 @@ impl f32 {
/// assuming that the value is finite and fits in that type.
///
/// ```
/// #![feature(float_approx_unchecked_to)]
///
/// let value = 4.6_f32;
/// let rounded = unsafe { value.approx_unchecked_to::<u16>() };
/// let rounded = unsafe { value.to_int_unchecked::<u16>() };
/// assert_eq!(rounded, 4);
///
/// let value = -128.9_f32;
/// let rounded = unsafe { value.approx_unchecked_to::<i8>() };
/// let rounded = unsafe { value.to_int_unchecked::<i8>() };
/// assert_eq!(rounded, std::i8::MIN);
/// ```
///
Expand All @@ -482,13 +480,13 @@ impl f32 {
/// * Not be `NaN`
/// * Not be infinite
/// * Be representable in the return type `Int`, after truncating off its fractional part
#[unstable(feature = "float_approx_unchecked_to", issue = "67058")]
#[stable(feature = "float_approx_unchecked_to", since = "1.44.0")]
#[inline]
pub unsafe fn approx_unchecked_to<Int>(self) -> Int
pub unsafe fn to_int_unchecked<Int>(self) -> Int
where
Self: FloatToInt<Int>,
{
FloatToInt::<Int>::approx_unchecked(self)
FloatToInt::<Int>::to_int_unchecked(self)
}

/// Raw transmutation to `u32`.
Expand Down
12 changes: 5 additions & 7 deletions src/libcore/num/f64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,14 +478,12 @@ impl f64 {
/// assuming that the value is finite and fits in that type.
///
/// ```
/// #![feature(float_approx_unchecked_to)]
///
/// let value = 4.6_f32;
/// let rounded = unsafe { value.approx_unchecked_to::<u16>() };
/// let rounded = unsafe { value.to_int_unchecked::<u16>() };
/// assert_eq!(rounded, 4);
///
/// let value = -128.9_f32;
/// let rounded = unsafe { value.approx_unchecked_to::<i8>() };
/// let rounded = unsafe { value.to_int_unchecked::<i8>() };
/// assert_eq!(rounded, std::i8::MIN);
/// ```
///
Expand All @@ -496,13 +494,13 @@ impl f64 {
/// * Not be `NaN`
/// * Not be infinite
/// * Be representable in the return type `Int`, after truncating off its fractional part
#[unstable(feature = "float_approx_unchecked_to", issue = "67058")]
#[stable(feature = "float_approx_unchecked_to", since = "1.44.0")]
#[inline]
pub unsafe fn approx_unchecked_to<Int>(self) -> Int
pub unsafe fn to_int_unchecked<Int>(self) -> Int
where
Self: FloatToInt<Int>,
{
FloatToInt::<Int>::approx_unchecked(self)
FloatToInt::<Int>::to_int_unchecked(self)
}

/// Raw transmutation to `u64`.
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_codegen_llvm/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,13 +543,13 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
}
}

"float_to_int_approx_unchecked" => {
"float_to_int_unchecked" => {
if float_type_width(arg_tys[0]).is_none() {
span_invalid_monomorphization_error(
tcx.sess,
span,
&format!(
"invalid monomorphization of `float_to_int_approx_unchecked` \
"invalid monomorphization of `float_to_int_unchecked` \
intrinsic: expected basic float type, \
found `{}`",
arg_tys[0]
Expand All @@ -570,7 +570,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
tcx.sess,
span,
&format!(
"invalid monomorphization of `float_to_int_approx_unchecked` \
"invalid monomorphization of `float_to_int_unchecked` \
intrinsic: expected basic integer type, \
found `{}`",
ret_ty
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
"fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
(1, vec![param(0), param(0)], param(0))
}
"float_to_int_approx_unchecked" => (2, vec![param(0)], param(1)),
"float_to_int_unchecked" => (2, vec![param(0)], param(1)),

"assume" => (0, vec![tcx.types.bool], tcx.mk_unit()),
"likely" => (0, vec![tcx.types.bool], tcx.types.bool),
Expand Down

0 comments on commit 1eabbd0

Please sign in to comment.