about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-07-25 10:55:47 -0700
committerbors <bors@rust-lang.org>2013-07-25 10:55:47 -0700
commitb1f5b1ba5fd12a058d153e9da8f11cd1bc597bf0 (patch)
treed50a42ff7c3d172e21157325a1cbae7d33361f40
parentbaa649ede6df96f645a9e28acfdc0b66b63e48b5 (diff)
parentf929a49d9c07115124a168bcc9651956683b4c22 (diff)
downloadrust-b1f5b1ba5fd12a058d153e9da8f11cd1bc597bf0.tar.gz
rust-b1f5b1ba5fd12a058d153e9da8f11cd1bc597bf0.zip
auto merge of #8029 : emillon/rust/issue-6804, r=cmr
Hi,

As noted in #6804, a pattern that contains `NaN` will never match because `NaN != NaN`. This adds a warning for such a case. The first commit handles the basic case and the second one generalizes it to more complex patterns using `walk_pat`.
-rw-r--r--src/librustc/middle/check_match.rs23
-rw-r--r--src/test/compile-fail/issue-6804.rs21
2 files changed, 43 insertions, 1 deletions
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 36edb567a50..793cd374718 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -10,7 +10,7 @@
 
 
 use middle::const_eval::{compare_const_vals, lookup_const_by_id};
-use middle::const_eval::{eval_const_expr, const_val, const_bool};
+use middle::const_eval::{eval_const_expr, const_val, const_bool, const_float};
 use middle::pat_util::*;
 use middle::ty::*;
 use middle::ty;
@@ -102,6 +102,27 @@ pub fn check_arms(cx: &MatchCheckCtxt, arms: &[arm]) {
     let mut seen = ~[];
     for arms.iter().advance |arm| {
         for arm.pats.iter().advance |pat| {
+
+            // Check that we do not match against a static NaN (#6804)
+            let pat_matches_nan: &fn(@pat) -> bool = |p| {
+                match cx.tcx.def_map.find(&p.id) {
+                    Some(&def_static(did, false)) => {
+                        let const_expr = lookup_const_by_id(cx.tcx, did).get();
+                        match eval_const_expr(cx.tcx, const_expr) {
+                            const_float(f) if f.is_NaN() => true,
+                            _ => false
+                        }
+                    }
+                    _ => false
+                }
+            };
+            for walk_pat(*pat) |p| {
+                if pat_matches_nan(p) {
+                    cx.tcx.sess.span_warn(p.span, "unmatchable NaN in pattern, \
+                                                   use the is_NaN method in a guard instead");
+                }
+            }
+
             let v = ~[*pat];
             match is_useful(cx, &seen, v) {
               not_useful => {
diff --git a/src/test/compile-fail/issue-6804.rs b/src/test/compile-fail/issue-6804.rs
new file mode 100644
index 00000000000..0a62e889d09
--- /dev/null
+++ b/src/test/compile-fail/issue-6804.rs
@@ -0,0 +1,21 @@
+// Matching against NaN should result in a warning
+
+use std::float::NaN;
+
+fn main() {
+    let x = NaN;
+    match x {
+        NaN => {},
+        _ => {},
+    };
+    //~^^^ WARNING unmatchable NaN in pattern, use the is_NaN method in a guard instead
+    match [x, 1.0] {
+        [NaN, _] => {},
+        _ => {},
+    };
+    //~^^^ WARNING unmatchable NaN in pattern, use the is_NaN method in a guard instead
+}
+
+// At least one error is needed so that compilation fails
+#[static_assert]
+static b: bool = false; //~ ERROR static assertion failed