Skip to content

Commit 802a9ac

Browse files
authored
Rollup merge of rust-lang#72449 - ecstatic-morse:const-float-bitcast, r=RalfJung,oli-obk
Const floating point bitcasts and classification Makes the `f32` and `f64` methods described in rust-lang#72447 and rust-lang#72505 unstably const. r? @RalfJung
2 parents e91bf6c + 9dadeb3 commit 802a9ac

File tree

4 files changed

+158
-36
lines changed

4 files changed

+158
-36
lines changed

src/libcore/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@
8484
#![feature(constctlz)]
8585
#![feature(const_panic)]
8686
#![feature(const_fn_union)]
87+
#![feature(const_float_bits_conv)]
88+
#![feature(const_float_classify)]
8789
#![feature(const_generics)]
8890
#![feature(const_ptr_offset)]
8991
#![feature(const_ptr_offset_from)]

src/libcore/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.
393+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
392394
#[inline]
393-
fn abs_private(self) -> f32 {
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
@@ -650,8 +658,9 @@ impl f32 {
650658
///
651659
/// ```
652660
#[stable(feature = "float_bits_conv", since = "1.20.0")]
661+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
653662
#[inline]
654-
pub fn to_bits(self) -> u32 {
663+
pub const fn to_bits(self) -> u32 {
655664
// SAFETY: `u32` is a plain old datatype so we can always transmute to it
656665
unsafe { mem::transmute(self) }
657666
}
@@ -693,8 +702,9 @@ impl f32 {
693702
/// assert_eq!(v, 12.5);
694703
/// ```
695704
#[stable(feature = "float_bits_conv", since = "1.20.0")]
705+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
696706
#[inline]
697-
pub fn from_bits(v: u32) -> Self {
707+
pub const fn from_bits(v: u32) -> Self {
698708
// SAFETY: `u32` is a plain old datatype so we can always transmute from it
699709
// It turns out the safety issues with sNaN were overblown! Hooray!
700710
unsafe { mem::transmute(v) }
@@ -710,8 +720,9 @@ impl f32 {
710720
/// assert_eq!(bytes, [0x41, 0x48, 0x00, 0x00]);
711721
/// ```
712722
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
723+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
713724
#[inline]
714-
pub fn to_be_bytes(self) -> [u8; 4] {
725+
pub const fn to_be_bytes(self) -> [u8; 4] {
715726
self.to_bits().to_be_bytes()
716727
}
717728

@@ -725,8 +736,9 @@ impl f32 {
725736
/// assert_eq!(bytes, [0x00, 0x00, 0x48, 0x41]);
726737
/// ```
727738
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
739+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
728740
#[inline]
729-
pub fn to_le_bytes(self) -> [u8; 4] {
741+
pub const fn to_le_bytes(self) -> [u8; 4] {
730742
self.to_bits().to_le_bytes()
731743
}
732744

@@ -753,8 +765,9 @@ impl f32 {
753765
/// );
754766
/// ```
755767
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
768+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
756769
#[inline]
757-
pub fn to_ne_bytes(self) -> [u8; 4] {
770+
pub const fn to_ne_bytes(self) -> [u8; 4] {
758771
self.to_bits().to_ne_bytes()
759772
}
760773

@@ -767,8 +780,9 @@ impl f32 {
767780
/// assert_eq!(value, 12.5);
768781
/// ```
769782
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
783+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
770784
#[inline]
771-
pub fn from_be_bytes(bytes: [u8; 4]) -> Self {
785+
pub const fn from_be_bytes(bytes: [u8; 4]) -> Self {
772786
Self::from_bits(u32::from_be_bytes(bytes))
773787
}
774788

@@ -781,8 +795,9 @@ impl f32 {
781795
/// assert_eq!(value, 12.5);
782796
/// ```
783797
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
798+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
784799
#[inline]
785-
pub fn from_le_bytes(bytes: [u8; 4]) -> Self {
800+
pub const fn from_le_bytes(bytes: [u8; 4]) -> Self {
786801
Self::from_bits(u32::from_le_bytes(bytes))
787802
}
788803

@@ -806,8 +821,9 @@ impl f32 {
806821
/// assert_eq!(value, 12.5);
807822
/// ```
808823
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
824+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
809825
#[inline]
810-
pub fn from_ne_bytes(bytes: [u8; 4]) -> Self {
826+
pub const fn from_ne_bytes(bytes: [u8; 4]) -> Self {
811827
Self::from_bits(u32::from_ne_bytes(bytes))
812828
}
813829

src/libcore/num/f64.rs

+37-19
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,16 +506,18 @@ 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

508515
#[stable(feature = "rust1", since = "1.0.0")]
516+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
509517
#[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")]
510518
#[inline]
511519
#[doc(hidden)]
512-
pub fn is_positive(self) -> bool {
520+
pub const fn is_positive(self) -> bool {
513521
self.is_sign_positive()
514522
}
515523

@@ -524,16 +532,18 @@ impl f64 {
524532
/// assert!(g.is_sign_negative());
525533
/// ```
526534
#[stable(feature = "rust1", since = "1.0.0")]
535+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
527536
#[inline]
528-
pub fn is_sign_negative(self) -> bool {
537+
pub const fn is_sign_negative(self) -> bool {
529538
self.to_bits() & 0x8000_0000_0000_0000 != 0
530539
}
531540

532541
#[stable(feature = "rust1", since = "1.0.0")]
542+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
533543
#[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")]
534544
#[inline]
535545
#[doc(hidden)]
536-
pub fn is_negative(self) -> bool {
546+
pub const fn is_negative(self) -> bool {
537547
self.is_sign_negative()
538548
}
539549

@@ -664,8 +674,9 @@ impl f64 {
664674
///
665675
/// ```
666676
#[stable(feature = "float_bits_conv", since = "1.20.0")]
677+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
667678
#[inline]
668-
pub fn to_bits(self) -> u64 {
679+
pub const fn to_bits(self) -> u64 {
669680
// SAFETY: `u64` is a plain old datatype so we can always transmute to it
670681
unsafe { mem::transmute(self) }
671682
}
@@ -707,8 +718,9 @@ impl f64 {
707718
/// assert_eq!(v, 12.5);
708719
/// ```
709720
#[stable(feature = "float_bits_conv", since = "1.20.0")]
721+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
710722
#[inline]
711-
pub fn from_bits(v: u64) -> Self {
723+
pub const fn from_bits(v: u64) -> Self {
712724
// SAFETY: `u64` is a plain old datatype so we can always transmute from it
713725
// It turns out the safety issues with sNaN were overblown! Hooray!
714726
unsafe { mem::transmute(v) }
@@ -724,8 +736,9 @@ impl f64 {
724736
/// assert_eq!(bytes, [0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
725737
/// ```
726738
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
739+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
727740
#[inline]
728-
pub fn to_be_bytes(self) -> [u8; 8] {
741+
pub const fn to_be_bytes(self) -> [u8; 8] {
729742
self.to_bits().to_be_bytes()
730743
}
731744

@@ -739,8 +752,9 @@ impl f64 {
739752
/// assert_eq!(bytes, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40]);
740753
/// ```
741754
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
755+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
742756
#[inline]
743-
pub fn to_le_bytes(self) -> [u8; 8] {
757+
pub const fn to_le_bytes(self) -> [u8; 8] {
744758
self.to_bits().to_le_bytes()
745759
}
746760

@@ -767,8 +781,9 @@ impl f64 {
767781
/// );
768782
/// ```
769783
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
784+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
770785
#[inline]
771-
pub fn to_ne_bytes(self) -> [u8; 8] {
786+
pub const fn to_ne_bytes(self) -> [u8; 8] {
772787
self.to_bits().to_ne_bytes()
773788
}
774789

@@ -781,8 +796,9 @@ impl f64 {
781796
/// assert_eq!(value, 12.5);
782797
/// ```
783798
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
799+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
784800
#[inline]
785-
pub fn from_be_bytes(bytes: [u8; 8]) -> Self {
801+
pub const fn from_be_bytes(bytes: [u8; 8]) -> Self {
786802
Self::from_bits(u64::from_be_bytes(bytes))
787803
}
788804

@@ -795,8 +811,9 @@ impl f64 {
795811
/// assert_eq!(value, 12.5);
796812
/// ```
797813
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
814+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
798815
#[inline]
799-
pub fn from_le_bytes(bytes: [u8; 8]) -> Self {
816+
pub const fn from_le_bytes(bytes: [u8; 8]) -> Self {
800817
Self::from_bits(u64::from_le_bytes(bytes))
801818
}
802819

@@ -820,8 +837,9 @@ impl f64 {
820837
/// assert_eq!(value, 12.5);
821838
/// ```
822839
#[stable(feature = "float_to_from_bytes", since = "1.40.0")]
840+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
823841
#[inline]
824-
pub fn from_ne_bytes(bytes: [u8; 8]) -> Self {
842+
pub const fn from_ne_bytes(bytes: [u8; 8]) -> Self {
825843
Self::from_bits(u64::from_ne_bytes(bytes))
826844
}
827845

0 commit comments

Comments
 (0)