summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/tests/ui/float_cmp.rs
blob: 5057c643732913386c8f51caf4d74e1ca4907d80 (plain)
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
130
131
132
133
134
135
136
137
138
139
140
#![warn(clippy::float_cmp)]
#![allow(
    unused,
    clippy::no_effect,
    clippy::op_ref,
    clippy::unnecessary_operation,
    clippy::cast_lossless
)]
//@no-rustfix
use std::ops::Add;

const ZERO: f32 = 0.0;
const ONE: f32 = ZERO + 1.0;

fn twice<T>(x: T) -> T
where
    T: Add<T, Output = T> + Copy,
{
    x + x
}

fn eq_fl(x: f32, y: f32) -> bool {
    if x.is_nan() { y.is_nan() } else { x == y } // no error, inside "eq" fn
}

fn fl_eq(x: f32, y: f32) -> bool {
    if x.is_nan() { y.is_nan() } else { x == y } // no error, inside "eq" fn
}

struct X {
    val: f32,
}

impl PartialEq for X {
    fn eq(&self, o: &X) -> bool {
        if self.val.is_nan() {
            o.val.is_nan()
        } else {
            self.val == o.val // no error, inside "eq" fn
        }
    }
}

impl PartialEq<f32> for X {
    fn eq(&self, o: &f32) -> bool {
        if self.val.is_nan() {
            o.is_nan()
        } else {
            self.val == *o // no error, inside "eq" fn
        }
    }
}

fn main() {
    ZERO == 0f32; //no error, comparison with zero is ok
    1.0f32 != f32::INFINITY; // also comparison with infinity
    1.0f32 != f32::NEG_INFINITY; // and negative infinity
    ZERO == 0.0; //no error, comparison with zero is ok
    ZERO + ZERO != 1.0; //no error, comparison with zero is ok

    let x = X { val: 1.0 };
    x == 1.0; // no error, custom type that implement PartialOrder for float is not checked

    ONE == 1f32;
    ONE == 1.0 + 0.0;
    ONE + ONE == ZERO + ONE + ONE;
    ONE != 2.0;
    ONE != 0.0; // no error, comparison with zero is ok
    twice(ONE) != ONE;
    ONE as f64 != 2.0;
    //~^ ERROR: strict comparison of `f32` or `f64`
    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
    ONE as f64 != 0.0; // no error, comparison with zero is ok

    let x: f64 = 1.0;

    x == 1.0;
    //~^ ERROR: strict comparison of `f32` or `f64`
    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
    x != 0f64; // no error, comparison with zero is ok

    twice(x) != twice(ONE as f64);
    //~^ ERROR: strict comparison of `f32` or `f64`
    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`

    x < 0.0; // no errors, lower or greater comparisons need no fuzzyness
    x > 0.0;
    x <= 0.0;
    x >= 0.0;

    let xs: [f32; 1] = [0.0];
    let a: *const f32 = xs.as_ptr();
    let b: *const f32 = xs.as_ptr();

    assert_eq!(a, b); // no errors

    const ZERO_ARRAY: [f32; 2] = [0.0, 0.0];
    const NON_ZERO_ARRAY: [f32; 2] = [0.0, 0.1];

    let i = 0;
    let j = 1;

    ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; // ok, because lhs is zero regardless of i
    NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
    //~^ ERROR: strict comparison of `f32` or `f64`
    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`

    let a1: [f32; 1] = [0.0];
    let a2: [f32; 1] = [1.1];

    a1 == a2;
    //~^ ERROR: strict comparison of `f32` or `f64` arrays
    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
    a1[0] == a2[0];
    //~^ ERROR: strict comparison of `f32` or `f64`
    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`

    // no errors - comparing signums is ok
    let x32 = 3.21f32;
    1.23f32.signum() == x32.signum();
    1.23f32.signum() == -(x32.signum());
    1.23f32.signum() == 3.21f32.signum();

    1.23f32.signum() != x32.signum();
    1.23f32.signum() != -(x32.signum());
    1.23f32.signum() != 3.21f32.signum();

    let x64 = 3.21f64;
    1.23f64.signum() == x64.signum();
    1.23f64.signum() == -(x64.signum());
    1.23f64.signum() == 3.21f64.signum();

    1.23f64.signum() != x64.signum();
    1.23f64.signum() != -(x64.signum());
    1.23f64.signum() != 3.21f64.signum();

    // the comparison should also look through references
    &0.0 == &ZERO;
    &&&&0.0 == &&&&ZERO;
}