//@ run-pass //@ revisions: opt noopt ctfe //@[opt] compile-flags: -O //@[noopt] compile-flags: -Zmir-opt-level=0 // ignore-tidy-linelength // This tests the float classification functions, for regular runtime code and for const evaluation. #![feature(f16_const)] #![feature(f128_const)] #![feature(const_float_classify)] use std::num::FpCategory::*; #[cfg(not(ctfe))] use std::hint::black_box; #[cfg(ctfe)] #[allow(unused)] const fn black_box(x: T) -> T { x } #[cfg(not(ctfe))] macro_rules! assert_test { ($a:expr, NonDet) => { { // Compute `a`, but do not compare with anything as the result is non-deterministic. let _val = $a; } }; ($a:expr, $b:ident) => { { // Let-bind to avoid promotion. // No black_box here! That can mask x87 failures. let a = $a; let b = $b; assert_eq!(a, b, "{} produces wrong result", stringify!($a)); } }; } #[cfg(ctfe)] macro_rules! assert_test { ($a:expr, NonDet) => { { // Compute `a`, but do not compare with anything as the result is non-deterministic. const _: () = { let _val = $a; }; } }; ($a:expr, $b:ident) => { { const _: () = assert!(matches!($a, $b)); } }; } macro_rules! suite { ( $tyname:ident => $( $tt:tt )* ) => { fn f32() { #[allow(unused)] type $tyname = f32; suite_inner!(f32 => $($tt)*); } fn f64() { #[allow(unused)] type $tyname = f64; suite_inner!(f64 => $($tt)*); } } } macro_rules! suite_inner { ( $ty:ident => [$( $fn:ident ),*]: $(@cfg: $attr:meta)? $val:expr => [$($out:ident),*], $( $tail:tt )* ) => { $(#[cfg($attr)])? { // No black_box here! That can mask x87 failures. $( assert_test!($ty::$fn($val), $out); )* } suite_inner!($ty => [$($fn),*]: $($tail)*) }; ( $ty:ident => [$( $fn:ident ),*]:) => {}; } // The result of the `is_sign` methods are not checked for correctness, since we do not // guarantee anything about the signedness of NaNs. See // https://rust-lang.github.io/rfcs/3514-float-semantics.html. suite! { T => // type alias for the type we are testing [ classify, is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative]: black_box(0.0) / black_box(0.0) => [ Nan, true, false, false, false, NonDet, NonDet], black_box(0.0) / black_box(-0.0) => [ Nan, true, false, false, false, NonDet, NonDet], black_box(0.0) * black_box(T::INFINITY) => [ Nan, true, false, false, false, NonDet, NonDet], black_box(0.0) * black_box(T::NEG_INFINITY) => [ Nan, true, false, false, false, NonDet, NonDet], 1.0 => [ Normal, false, false, true, true, true, false], -1.0 => [ Normal, false, false, true, true, false, true], 0.0 => [ Zero, false, false, true, false, true, false], -0.0 => [ Zero, false, false, true, false, false, true], 1.0 / black_box(0.0) => [ Infinite, false, true, false, false, true, false], -1.0 / black_box(0.0) => [ Infinite, false, true, false, false, false, true], 2.0 * black_box(T::MAX) => [ Infinite, false, true, false, false, true, false], -2.0 * black_box(T::MAX) => [ Infinite, false, true, false, false, false, true], 1.0 / black_box(T::MAX) => [Subnormal, false, false, true, false, true, false], -1.0 / black_box(T::MAX) => [Subnormal, false, false, true, false, false, true], // This specific expression causes trouble on x87 due to // . @cfg: not(all(target_arch = "x86", not(target_feature = "sse2"))) { let x = black_box(T::MAX); x * x } => [ Infinite, false, true, false, false, true, false], } fn main() { f32(); f64(); // FIXME(f16_f128): also test f16 and f128 }