Merge pull request #1096 from cramertj/1086-negative-zero

Fix #1086-Added sign check on Constant f64 PartialEq implementation
This commit is contained in:
Oliver Schneider 2016-07-14 13:13:11 +02:00 committed by GitHub
commit 99b1ebbb33
3 changed files with 56 additions and 2 deletions

View file

@ -92,7 +92,10 @@ impl PartialEq for Constant {
// we want `Fw32 == FwAny` and `FwAny == Fw64`, by transitivity we must have
// `Fw32 == Fw64` so dont compare them
match (ls.parse::<f64>(), rs.parse::<f64>()) {
(Ok(l), Ok(r)) => l.eq(&r),
// mem::transmute is required to catch non-matching 0.0, -0.0, and NaNs
(Ok(l), Ok(r)) => unsafe {
mem::transmute::<f64, u64>(l) == mem::transmute::<f64, u64>(r)
},
_ => false,
}
}
@ -159,7 +162,11 @@ impl PartialOrd for Constant {
(&Constant::Int(l), &Constant::Int(r)) => Some(l.cmp(&r)),
(&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => {
match (ls.parse::<f64>(), rs.parse::<f64>()) {
(Ok(ref l), Ok(ref r)) => l.partial_cmp(r),
(Ok(ref l), Ok(ref r)) => match (l.partial_cmp(r), l.is_sign_positive() == r.is_sign_positive()) {
// Check for comparison of -0.0 and 0.0
(Some(Ordering::Equal), false) => None,
(x, _) => x
},
_ => None,
}
}

View file

@ -9,6 +9,7 @@
#![allow(cyclomatic_complexity)]
#![allow(blacklisted_name)]
#![allow(collapsible_if)]
#![allow(zero_divided_by_zero, eq_op)]
fn bar<T>(_: T) {}
fn foo() -> bool { unimplemented!() }
@ -229,6 +230,46 @@ fn if_same_then_else() -> Result<&'static str, ()> {
_ => 0,
};
let _ = if true {
//~^NOTE same as this
0.0
} else { //~ERROR this `if` has identical blocks
0.0
};
let _ = if true {
//~^NOTE same as this
-0.0
} else { //~ERROR this `if` has identical blocks
-0.0
};
let _ = if true {
0.0
} else {
-0.0
};
// Different NaNs
let _ = if true {
0.0 / 0.0
} else {
std::f32::NAN
};
// Same NaNs
let _ = if true {
//~^NOTE same as this
std::f32::NAN
} else { //~ERROR this `if` has identical blocks
std::f32::NAN
};
let _ = match Some(()) {
Some(()) => 0.0,
None => -0.0
};
match (Some(42), Some("")) {
(Some(a), None) => bar(a),
(None, Some(a)) => bar(a), // bindings have different types

View file

@ -82,6 +82,12 @@ fn test_ops() {
let half_any = Constant::Float("0.5".into(), FloatWidth::Any);
let half32 = Constant::Float("0.5".into(), FloatWidth::F32);
let half64 = Constant::Float("0.5".into(), FloatWidth::F64);
let pos_zero = Constant::Float("0.0".into(), FloatWidth::F64);
let neg_zero = Constant::Float("-0.0".into(), FloatWidth::F64);
assert_eq!(pos_zero, pos_zero);
assert_eq!(neg_zero, neg_zero);
assert_eq!(None, pos_zero.partial_cmp(&neg_zero));
assert_eq!(half_any, half32);
assert_eq!(half_any, half64);