Change:
The following tests do not pass for me, but I think they should, as comparisons with NaN should always simply evaluate to : I get this result on both debug and release builds. I'm on an x86_64 running Linux, rustc 1.27.0-nightly ( 2018-05-15).
Playground link for this test. Affects both debug and release, Nightly and Stable.
: ~I think this is an issue with rather than the floating-point comparisons, but I haven't dug into it yet.~
This seems to be a regression introduced by 1.26.
Reduced, . Edit: Or maybe a bug in Miri (cc
Bisection between ... gives as the regression PR, as expected.
I guess this logic, which I blindly copied, was never correct to begin with: I think this is how old const eval did it, and we didn't want to regress that. cc
Has the comment about existing bad behaviour.
The old logic used unwrap, meaning would just ICE (?). I think we can safely replace them directly as etc. Edit: The unwrap is in
The incorrect behavior mentioned in was this: If we fix the float comparison behavior, this code will no longer compile. But I think this is clearly a bug fix and breaking code like this is .
Fixed in

Discussion:
use rustc::mir; use rustc::ty::{self, Ty}; use syntax::ast::FloatTy; <del> use std::cmp::Ordering; </del> use rustc::ty::layout::LayoutOf; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float;

let l = <$ty>::from_bits(l); let r = <$ty>::from_bits(r); let val = match bin_op { <del> Eq => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) == Ordering::Equal), Ne => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) != Ordering::Equal), Lt => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) == Ordering::Less), Le => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) != Ordering::Greater), Gt => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) == Ordering::Greater), Ge => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) != Ordering::Less), </del> <ins> Eq => PrimVal::from_bool(l == r), Ne => PrimVal::from_bool(l != r), Lt => PrimVal::from_bool(l < r), Le => PrimVal::from_bool(l <= r), Gt => PrimVal::from_bool(l > r), Ge => PrimVal::from_bool(l >= r), </ins> Add => PrimVal::Bytes((l + r).value.to_bits()), Sub => PrimVal::Bytes((l - r).value.to_bits()), Mul => PrimVal::Bytes((l * r).value.to_bits()),

<ins> // Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(test)] extern crate test; use std::f64::{NAN, NEG_INFINITY, INFINITY, MAX}; use std::mem::size_of; use test::black_box; // Ensure the const-eval result and runtime result of float comparison are equivalent. macro_rules! compare { ($op:tt) => { compare!( [NEG_INFINITY, -MAX, -1.0, -0.0, 0.0, 1.0, MAX, INFINITY, NAN], $op ); }; ([$($lhs:expr),+], $op:tt) => { $(compare!( $lhs, $op, [NEG_INFINITY, -MAX, -1.0, -0.0, 0.0, 1.0, MAX, INFINITY, NAN] );)+ }; ($lhs:expr, $op:tt, [$($rhs:expr),+]) => { $({ // Wrap the check in its own function to reduce time needed to borrowck. fn check() { static CONST_EVAL: bool = $lhs $op $rhs; let runtime_eval = black_box($lhs) $op black_box($rhs); assert_eq!(CONST_EVAL, runtime_eval, stringify!($lhs $op $rhs)); assert_eq!( size_of::<[u8; ($lhs $op $rhs) as usize]>(), runtime_eval as usize, stringify!($lhs $op $rhs (forced const eval)) ); } check(); })+ }; } fn main() { assert_eq!(0.0/0.0 < 0.0/0.0, false); assert_eq!(0.0/0.0 > 0.0/0.0, false); assert_eq!(NAN < NAN, false); assert_eq!(NAN > NAN, false); compare!(==); compare!(!=); compare!(<); compare!(<=); compare!(>); compare!(>=); } </ins>