Skip to content

Commit 0ec9459

Browse files
committed
Auto merge of #72449 - ecstatic-morse:const-float-bitcast, r=RalfJung
Const floating point bitcasts and classification Makes the `f32` and `f64` methods described in #72447 and #72505 unstably const. r? @RalfJung
2 parents d02a209 + 130766c commit 0ec9459

File tree

5 files changed

+238
-34
lines changed

5 files changed

+238
-34
lines changed

library/core/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@
7373
#![feature(const_discriminant)]
7474
#![feature(const_checked_int_methods)]
7575
#![feature(const_euclidean_int_methods)]
76+
#![feature(const_float_classify)]
77+
#![feature(const_float_bits_conv)]
7678
#![feature(const_overflowing_int_methods)]
7779
#![feature(const_int_unchecked_arith)]
7880
#![feature(const_int_pow)]

library/core/src/num/f32.rs

+33-17
Original file line numberDiff line numberDiff line change
@@ -381,16 +381,18 @@ impl f32 {
381381
/// assert!(!f.is_nan());
382382
/// ```
383383
#[stable(feature = "rust1", since = "1.0.0")]
384+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
384385
#[inline]
385-
pub fn is_nan(self) -> bool {
386+
pub const fn is_nan(self) -> bool {
386387
self != self
387388
}
388389

389390
// FIXME(#50145): `abs` is publicly unavailable in libcore due to
390391
// concerns about portability, so this implementation is for
391392
// private use internally.
392393
#[inline]
393-
fn abs_private(self) -> f32 {
394+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
395+
const fn abs_private(self) -> f32 {
394396
f32::from_bits(self.to_bits() & 0x7fff_ffff)
395397
}
396398

@@ -410,8 +412,9 @@ impl f32 {
410412
/// assert!(neg_inf.is_infinite());
411413
/// ```
412414
#[stable(feature = "rust1", since = "1.0.0")]
415+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
413416
#[inline]
414-
pub fn is_infinite(self) -> bool {
417+
pub const fn is_infinite(self) -> bool {
415418
self.abs_private() == Self::INFINITY
416419
}
417420

@@ -430,8 +433,9 @@ impl f32 {
430433
/// assert!(!neg_inf.is_finite());
431434
/// ```
432435
#[stable(feature = "rust1", since = "1.0.0")]
436+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
433437
#[inline]
434-
pub fn is_finite(self) -> bool {
438+
pub const fn is_finite(self) -> bool {
435439
// There's no need to handle NaN separately: if self is NaN,
436440
// the comparison is not true, exactly as desired.
437441
self.abs_private() < Self::INFINITY
@@ -457,9 +461,10 @@ impl f32 {
457461
/// ```
458462
/// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
459463
#[stable(feature = "rust1", since = "1.0.0")]
464+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
460465
#[inline]
461-
pub fn is_normal(self) -> bool {
462-
self.classify() == FpCategory::Normal
466+
pub const fn is_normal(self) -> bool {
467+
matches!(self.classify(), FpCategory::Normal)
463468
}
464469

465470
/// Returns the floating point category of the number. If only one property
@@ -476,7 +481,8 @@ impl f32 {
476481
/// assert_eq!(inf.classify(), FpCategory::Infinite);
477482
/// ```
478483
#[stable(feature = "rust1", since = "1.0.0")]
479-
pub fn classify(self) -> FpCategory {
484+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
485+
pub const fn classify(self) -> FpCategory {
480486
const EXP_MASK: u32 = 0x7f800000;
481487
const MAN_MASK: u32 = 0x007fffff;
482488

@@ -501,8 +507,9 @@ impl f32 {
501507
/// assert!(!g.is_sign_positive());
502508
/// ```
503509
#[stable(feature = "rust1", since = "1.0.0")]
510+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
504511
#[inline]
505-
pub fn is_sign_positive(self) -> bool {
512+
pub const fn is_sign_positive(self) -> bool {
506513
!self.is_sign_negative()
507514
}
508515

@@ -517,8 +524,9 @@ impl f32 {
517524
/// assert!(g.is_sign_negative());
518525
/// ```
519526
#[stable(feature = "rust1", since = "1.0.0")]
527+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
520528
#[inline]
521-
pub fn is_sign_negative(self) -> bool {
529+
pub const fn is_sign_negative(self) -> bool {
522530
// IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
523531
// applies to zeros and NaNs as well.
524532
self.to_bits() & 0x8000_0000 != 0
@@ -652,8 +660,9 @@ impl f32 {
652660
///
653661
/// ```
654662
#[stable(feature = "float_bits_conv", since = "1.20.0")]
663+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
655664
#[inline]
656-
pub fn to_bits(self) -> u32 {
665+
pub const fn to_bits(self) -> u32 {
657666
// SAFETY: `u32` is a plain old datatype so we can always transmute to it
658667
unsafe { mem::transmute(self) }
659668
}
@@ -695,8 +704,9 @@ impl f32 {
695704
/// assert_eq!(v, 12.5);
696705
/// ```
697706
#[stable(feature = "float_bits_conv", since = "1.20.0")]
707+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
698708
#[inline]
699-
pub fn from_bits(v: u32) -> Self {
709+
pub const fn from_bits(v: u32) -> Self {
700710
// SAFETY: `u32` is a plain old datatype so we can always transmute from it
701711
// It turns out the safety issues with sNaN were overblown! Hooray!
702712
unsafe { mem::transmute(v) }
@@ -712,8 +722,9 @@ impl f32 {
712722
/// assert_eq!(bytes, [0x41, 0x48, 0x00, 0x00]);
713723
/// ```
714724
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
725+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
715726
#[inline]
716-
pub fn to_be_bytes(self) -> [u8; 4] {
727+
pub const fn to_be_bytes(self) -> [u8; 4] {
717728
self.to_bits().to_be_bytes()
718729
}
719730

@@ -727,8 +738,9 @@ impl f32 {
727738
/// assert_eq!(bytes, [0x00, 0x00, 0x48, 0x41]);
728739
/// ```
729740
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
741+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
730742
#[inline]
731-
pub fn to_le_bytes(self) -> [u8; 4] {
743+
pub const fn to_le_bytes(self) -> [u8; 4] {
732744
self.to_bits().to_le_bytes()
733745
}
734746

@@ -755,8 +767,9 @@ impl f32 {
755767
/// );
756768
/// ```
757769
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
770+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
758771
#[inline]
759-
pub fn to_ne_bytes(self) -> [u8; 4] {
772+
pub const fn to_ne_bytes(self) -> [u8; 4] {
760773
self.to_bits().to_ne_bytes()
761774
}
762775

@@ -769,8 +782,9 @@ impl f32 {
769782
/// assert_eq!(value, 12.5);
770783
/// ```
771784
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
785+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
772786
#[inline]
773-
pub fn from_be_bytes(bytes: [u8; 4]) -> Self {
787+
pub const fn from_be_bytes(bytes: [u8; 4]) -> Self {
774788
Self::from_bits(u32::from_be_bytes(bytes))
775789
}
776790

@@ -783,8 +797,9 @@ impl f32 {
783797
/// assert_eq!(value, 12.5);
784798
/// ```
785799
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
800+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
786801
#[inline]
787-
pub fn from_le_bytes(bytes: [u8; 4]) -> Self {
802+
pub const fn from_le_bytes(bytes: [u8; 4]) -> Self {
788803
Self::from_bits(u32::from_le_bytes(bytes))
789804
}
790805

@@ -808,8 +823,9 @@ impl f32 {
808823
/// assert_eq!(value, 12.5);
809824
/// ```
810825
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
826+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
811827
#[inline]
812-
pub fn from_ne_bytes(bytes: [u8; 4]) -> Self {
828+
pub const fn from_ne_bytes(bytes: [u8; 4]) -> Self {
813829
Self::from_bits(u32::from_ne_bytes(bytes))
814830
}
815831

library/core/src/num/f64.rs

+33-17
Original file line numberDiff line numberDiff line change
@@ -380,16 +380,18 @@ impl f64 {
380380
/// assert!(!f.is_nan());
381381
/// ```
382382
#[stable(feature = "rust1", since = "1.0.0")]
383+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
383384
#[inline]
384-
pub fn is_nan(self) -> bool {
385+
pub const fn is_nan(self) -> bool {
385386
self != self
386387
}
387388

388389
// FIXME(#50145): `abs` is publicly unavailable in libcore due to
389390
// concerns about portability, so this implementation is for
390391
// private use internally.
391392
#[inline]
392-
fn abs_private(self) -> f64 {
393+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
394+
const fn abs_private(self) -> f64 {
393395
f64::from_bits(self.to_bits() & 0x7fff_ffff_ffff_ffff)
394396
}
395397

@@ -409,8 +411,9 @@ impl f64 {
409411
/// assert!(neg_inf.is_infinite());
410412
/// ```
411413
#[stable(feature = "rust1", since = "1.0.0")]
414+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
412415
#[inline]
413-
pub fn is_infinite(self) -> bool {
416+
pub const fn is_infinite(self) -> bool {
414417
self.abs_private() == Self::INFINITY
415418
}
416419

@@ -429,8 +432,9 @@ impl f64 {
429432
/// assert!(!neg_inf.is_finite());
430433
/// ```
431434
#[stable(feature = "rust1", since = "1.0.0")]
435+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
432436
#[inline]
433-
pub fn is_finite(self) -> bool {
437+
pub const fn is_finite(self) -> bool {
434438
// There's no need to handle NaN separately: if self is NaN,
435439
// the comparison is not true, exactly as desired.
436440
self.abs_private() < Self::INFINITY
@@ -456,9 +460,10 @@ impl f64 {
456460
/// ```
457461
/// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
458462
#[stable(feature = "rust1", since = "1.0.0")]
463+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
459464
#[inline]
460-
pub fn is_normal(self) -> bool {
461-
self.classify() == FpCategory::Normal
465+
pub const fn is_normal(self) -> bool {
466+
matches!(self.classify(), FpCategory::Normal)
462467
}
463468

464469
/// Returns the floating point category of the number. If only one property
@@ -475,7 +480,8 @@ impl f64 {
475480
/// assert_eq!(inf.classify(), FpCategory::Infinite);
476481
/// ```
477482
#[stable(feature = "rust1", since = "1.0.0")]
478-
pub fn classify(self) -> FpCategory {
483+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
484+
pub const fn classify(self) -> FpCategory {
479485
const EXP_MASK: u64 = 0x7ff0000000000000;
480486
const MAN_MASK: u64 = 0x000fffffffffffff;
481487

@@ -500,8 +506,9 @@ impl f64 {
500506
/// assert!(!g.is_sign_positive());
501507
/// ```
502508
#[stable(feature = "rust1", since = "1.0.0")]
509+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
503510
#[inline]
504-
pub fn is_sign_positive(self) -> bool {
511+
pub const fn is_sign_positive(self) -> bool {
505512
!self.is_sign_negative()
506513
}
507514

@@ -524,8 +531,9 @@ impl f64 {
524531
/// assert!(g.is_sign_negative());
525532
/// ```
526533
#[stable(feature = "rust1", since = "1.0.0")]
534+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
527535
#[inline]
528-
pub fn is_sign_negative(self) -> bool {
536+
pub const fn is_sign_negative(self) -> bool {
529537
self.to_bits() & 0x8000_0000_0000_0000 != 0
530538
}
531539

@@ -666,8 +674,9 @@ impl f64 {
666674
///
667675
/// ```
668676
#[stable(feature = "float_bits_conv", since = "1.20.0")]
677+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
669678
#[inline]
670-
pub fn to_bits(self) -> u64 {
679+
pub const fn to_bits(self) -> u64 {
671680
// SAFETY: `u64` is a plain old datatype so we can always transmute to it
672681
unsafe { mem::transmute(self) }
673682
}
@@ -709,8 +718,9 @@ impl f64 {
709718
/// assert_eq!(v, 12.5);
710719
/// ```
711720
#[stable(feature = "float_bits_conv", since = "1.20.0")]
721+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
712722
#[inline]
713-
pub fn from_bits(v: u64) -> Self {
723+
pub const fn from_bits(v: u64) -> Self {
714724
// SAFETY: `u64` is a plain old datatype so we can always transmute from it
715725
// It turns out the safety issues with sNaN were overblown! Hooray!
716726
unsafe { mem::transmute(v) }
@@ -726,8 +736,9 @@ impl f64 {
726736
/// assert_eq!(bytes, [0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
727737
/// ```
728738
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
739+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
729740
#[inline]
730-
pub fn to_be_bytes(self) -> [u8; 8] {
741+
pub const fn to_be_bytes(self) -> [u8; 8] {
731742
self.to_bits().to_be_bytes()
732743
}
733744

@@ -741,8 +752,9 @@ impl f64 {
741752
/// assert_eq!(bytes, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40]);
742753
/// ```
743754
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
755+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
744756
#[inline]
745-
pub fn to_le_bytes(self) -> [u8; 8] {
757+
pub const fn to_le_bytes(self) -> [u8; 8] {
746758
self.to_bits().to_le_bytes()
747759
}
748760

@@ -769,8 +781,9 @@ impl f64 {
769781
/// );
770782
/// ```
771783
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
784+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
772785
#[inline]
773-
pub fn to_ne_bytes(self) -> [u8; 8] {
786+
pub const fn to_ne_bytes(self) -> [u8; 8] {
774787
self.to_bits().to_ne_bytes()
775788
}
776789

@@ -783,8 +796,9 @@ impl f64 {
783796
/// assert_eq!(value, 12.5);
784797
/// ```
785798
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
799+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
786800
#[inline]
787-
pub fn from_be_bytes(bytes: [u8; 8]) -> Self {
801+
pub const fn from_be_bytes(bytes: [u8; 8]) -> Self {
788802
Self::from_bits(u64::from_be_bytes(bytes))
789803
}
790804

@@ -797,8 +811,9 @@ impl f64 {
797811
/// assert_eq!(value, 12.5);
798812
/// ```
799813
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
814+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
800815
#[inline]
801-
pub fn from_le_bytes(bytes: [u8; 8]) -> Self {
816+
pub const fn from_le_bytes(bytes: [u8; 8]) -> Self {
802817
Self::from_bits(u64::from_le_bytes(bytes))
803818
}
804819

@@ -822,8 +837,9 @@ impl f64 {
822837
/// assert_eq!(value, 12.5);
823838
/// ```
824839
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
840+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
825841
#[inline]
826-
pub fn from_ne_bytes(bytes: [u8; 8]) -> Self {
842+
pub const fn from_ne_bytes(bytes: [u8; 8]) -> Self {
827843
Self::from_bits(u64::from_ne_bytes(bytes))
828844
}
829845

0 commit comments

Comments
 (0)