about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_lint/builtin.rs76
-rw-r--r--src/librustc_lint/lib.rs5
-rw-r--r--src/test/compile-fail/issue-41255.rs51
3 files changed, 132 insertions, 0 deletions
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index c9ec152841b..715a769158b 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -693,6 +693,82 @@ impl EarlyLintPass for DeprecatedAttr {
 }
 
 declare_lint! {
+    pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+    Warn,
+    "floating-point literals cannot be used in patterns"
+}
+
+/// Checks for floating point literals in patterns.
+#[derive(Clone)]
+pub struct IllegalFloatLiteralPattern;
+
+impl LintPass for IllegalFloatLiteralPattern {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN)
+    }
+}
+
+fn fl_lit_check_expr(cx: &EarlyContext, expr: &ast::Expr) {
+    use self::ast::{ExprKind, LitKind};
+    match expr.node {
+        ExprKind::Lit(ref l) => {
+            match l.node {
+                LitKind::FloatUnsuffixed(..) |
+                LitKind::Float(..) => {
+                    cx.span_lint(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+                                 l.span,
+                                 "floating-point literals cannot be used in patterns");
+                    error!("span mc spanspam");
+                    },
+                _ => (),
+            }
+        }
+        // These may occur in patterns
+        // and can maybe contain float literals
+        ExprKind::Unary(_, ref f) => fl_lit_check_expr(cx, f),
+        // These may occur in patterns
+        // and can't contain float literals
+        ExprKind::Path(..) => (),
+        // If something unhandled is encountered, we need to expand the
+        // search or ignore more ExprKinds.
+        _ => span_bug!(expr.span, "Unhandled expression {:?} in float lit pattern lint",
+                       expr.node),
+    }
+}
+
+impl EarlyLintPass for IllegalFloatLiteralPattern {
+    fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat) {
+        use self::ast::PatKind;
+        pat.walk(&mut |p| {
+            match p.node {
+                // Wildcard patterns and paths are uninteresting for the lint
+                PatKind::Wild |
+                PatKind::Path(..) => (),
+
+                // The walk logic recurses inside these
+                PatKind::Ident(..) |
+                PatKind::Struct(..) |
+                PatKind::Tuple(..) |
+                PatKind::TupleStruct(..) |
+                PatKind::Ref(..) |
+                PatKind::Box(..) |
+                PatKind::Slice(..) => (),
+
+                // Extract the expressions and check them
+                PatKind::Lit(ref e) => fl_lit_check_expr(cx, e),
+                PatKind::Range(ref st, ref en, _) => {
+                    fl_lit_check_expr(cx, st);
+                    fl_lit_check_expr(cx, en);
+                },
+
+                PatKind::Mac(_) => bug!("lint must run post-expansion"),
+            }
+            true
+        });
+    }
+}
+
+declare_lint! {
     pub UNCONDITIONAL_RECURSION,
     Warn,
     "functions that cannot return without calling themselves"
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index c1c14cb1fd2..53ea3a8333f 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -113,6 +113,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                        UnusedParens,
                        UnusedImportBraces,
                        AnonymousParameters,
+                       IllegalFloatLiteralPattern,
                        );
 
     add_early_builtin_with_new!(sess,
@@ -202,6 +203,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             reference: "issue #36890 <https://github.com/rust-lang/rust/issues/36890>",
         },
         FutureIncompatibleInfo {
+            id: LintId::of(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN),
+            reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
+        },
+        FutureIncompatibleInfo {
             id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN),
             reference: "issue #36891 <https://github.com/rust-lang/rust/issues/36891>",
         },
diff --git a/src/test/compile-fail/issue-41255.rs b/src/test/compile-fail/issue-41255.rs
new file mode 100644
index 00000000000..191b867e7a8
--- /dev/null
+++ b/src/test/compile-fail/issue-41255.rs
@@ -0,0 +1,51 @@
+// Copyright 2017 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.
+
+// Matching against float literals should result in a linter error
+
+#![feature(slice_patterns)]
+#![feature(exclusive_range_pattern)]
+#![allow(unused)]
+#![forbid(illegal_floating_point_literal_pattern)]
+
+fn main() {
+    let x = 42.0;
+    match x {
+        5.0 => {}, //~ ERROR floating-point literals cannot be used
+                   //~| WARNING hard error
+        5.0f32 => {}, //~ ERROR floating-point literals cannot be used
+                      //~| WARNING hard error
+        -5.0 => {}, //~ ERROR floating-point literals cannot be used
+                    //~| WARNING hard error
+        1.0 .. 33.0 => {}, //~ ERROR floating-point literals cannot be used
+                           //~| WARNING hard error
+                           //~| ERROR floating-point literals cannot be used
+                           //~| WARNING hard error
+        39.0 ... 70.0 => {}, //~ ERROR floating-point literals cannot be used
+                             //~| WARNING hard error
+                             //~| ERROR floating-point literals cannot be used
+                             //~| WARNING hard error
+        _ => {},
+    };
+    let y = 5.0;
+    // Same for tuples
+    match (x, 5) {
+        (3.14, 1) => {}, //~ ERROR floating-point literals cannot be used
+                         //~| WARNING hard error
+        _ => {},
+    }
+    // Or structs
+    struct Foo { x: f32 };
+    match (Foo { x }) {
+        Foo { x: 2.0 } => {}, //~ ERROR floating-point literals cannot be used
+                              //~| WARNING hard error
+        _ => {},
+    }
+}