From 5c729c0dca65a014b6dec10cfd5259c6d0687d72 Mon Sep 17 00:00:00 2001 From: Etienne Millon Date: Wed, 24 Jul 2013 18:00:33 +0200 Subject: [PATCH 1/3] Check for comparisons to NaN in patterns For every pattern that refers to a static value, evaluate it and emit a warning if it is a NaN. Fixes #6804 --- src/librustc/middle/check_match.rs | 18 +++++++++++++++++- src/test/compile-fail/issue-6804.rs | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/issue-6804.rs diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 36edb567a50..18bf3859f07 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,22 @@ 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) + match cx.tcx.def_map.find(&pat.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() => { + let msg = "unmatchable NaN in pattern, use is_NaN() in a guard instead"; + cx.tcx.sess.span_warn(pat.span, msg); + } + _ => {} + } + } + _ => {} + } + 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..85e09a777d1 --- /dev/null +++ b/src/test/compile-fail/issue-6804.rs @@ -0,0 +1,16 @@ +// 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 is_NaN() in a guard instead +} + +// At least one error is needed so that compilation fails +#[static_assert] +static b: bool = false; //~ ERROR static assertion failed From fdd71bece23b3d6776ca86336749e50560617a56 Mon Sep 17 00:00:00 2001 From: Etienne Millon Date: Wed, 24 Jul 2013 23:17:10 +0200 Subject: [PATCH 2/3] Generalize NaN pattern detection using walk_pat --- src/librustc/middle/check_match.rs | 23 ++++++++++++++--------- src/test/compile-fail/issue-6804.rs | 5 +++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 18bf3859f07..ea9d84d0aa3 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -104,18 +104,23 @@ pub fn check_arms(cx: &MatchCheckCtxt, arms: &[arm]) { for arm.pats.iter().advance |pat| { // Check that we do not match against a static NaN (#6804) - match cx.tcx.def_map.find(&pat.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() => { - let msg = "unmatchable NaN in pattern, use is_NaN() in a guard instead"; - cx.tcx.sess.span_warn(pat.span, msg); + 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 is_NaN() in a guard instead"); } - _ => {} } let v = ~[*pat]; diff --git a/src/test/compile-fail/issue-6804.rs b/src/test/compile-fail/issue-6804.rs index 85e09a777d1..77cabd1db90 100644 --- a/src/test/compile-fail/issue-6804.rs +++ b/src/test/compile-fail/issue-6804.rs @@ -9,6 +9,11 @@ fn main() { _ => {}, }; //~^^^ WARNING unmatchable NaN in pattern, use is_NaN() in a guard instead + match [x, 1.0] { + [NaN, _] => {}, + _ => {}, + }; + //~^^^ WARNING unmatchable NaN in pattern, use is_NaN() in a guard instead } // At least one error is needed so that compilation fails From f929a49d9c07115124a168bcc9651956683b4c22 Mon Sep 17 00:00:00 2001 From: Etienne Millon Date: Thu, 25 Jul 2013 16:40:59 +0200 Subject: [PATCH 3/3] NaN patterns: indicate that is_NaN is a method --- src/librustc/middle/check_match.rs | 2 +- src/test/compile-fail/issue-6804.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index ea9d84d0aa3..793cd374718 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -119,7 +119,7 @@ pub fn check_arms(cx: &MatchCheckCtxt, arms: &[arm]) { for walk_pat(*pat) |p| { if pat_matches_nan(p) { cx.tcx.sess.span_warn(p.span, "unmatchable NaN in pattern, \ - use is_NaN() in a guard instead"); + use the is_NaN method in a guard instead"); } } diff --git a/src/test/compile-fail/issue-6804.rs b/src/test/compile-fail/issue-6804.rs index 77cabd1db90..0a62e889d09 100644 --- a/src/test/compile-fail/issue-6804.rs +++ b/src/test/compile-fail/issue-6804.rs @@ -8,12 +8,12 @@ fn main() { NaN => {}, _ => {}, }; - //~^^^ WARNING unmatchable NaN in pattern, use is_NaN() in a guard instead + //~^^^ 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 is_NaN() in a guard instead + //~^^^ WARNING unmatchable NaN in pattern, use the is_NaN method in a guard instead } // At least one error is needed so that compilation fails