File: classify-runtime-const.rs

package info (click to toggle)
rustc 1.85.0%2Bdfsg3-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental, trixie
  • size: 893,396 kB
  • sloc: xml: 158,127; python: 35,830; javascript: 19,497; cpp: 19,002; sh: 17,245; ansic: 13,127; asm: 4,376; makefile: 1,051; perl: 29; lisp: 29; ruby: 19; sql: 11
file content (129 lines) | stat: -rw-r--r-- 4,802 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//@ 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)]
#![feature(f128)]

use std::num::FpCategory::*;

#[cfg(not(ctfe))]
use std::hint::black_box;
#[cfg(ctfe)]
#[allow(unused)]
const fn black_box<T>(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
    // <https://github.com/rust-lang/rust/issues/114479>.
    @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
}