about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <arielb1@mail.tau.ac.il>2017-06-29 08:40:05 +0000
committerGitHub <noreply@github.com>2017-06-29 08:40:05 +0000
commiteffd1e040ea34c02892209caf0b46d535d4940e8 (patch)
tree4740f7cf4f21f712cb902e27360a64615556b968 /src
parent4bae0d8b7fef1a5eb1027dcdc6a7b322b0dbc29c (diff)
parent0dfd9c30f2c61458343e0816c66f448019e826d1 (diff)
downloadrust-effd1e040ea34c02892209caf0b46d535d4940e8.tar.gz
rust-effd1e040ea34c02892209caf0b46d535d4940e8.zip
Rollup merge of #42886 - durka:pplmm-mwe, r=petrochenkov
syntax: allow negative integer literal expression to be interpolated as pattern

Fixes #42820.

r? @jseyfried
Diffstat (limited to 'src')
-rw-r--r--src/librustc_lint/builtin.rs10
-rw-r--r--src/librustc_passes/ast_validation.rs26
-rw-r--r--src/libsyntax/parse/parser.rs4
-rw-r--r--src/test/compile-fail/patkind-litrange-no-expr.rs36
-rw-r--r--src/test/run-pass/macro-pat-neg-lit.rs35
5 files changed, 103 insertions, 8 deletions
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index ad154f9b815..2b331509025 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -684,13 +684,9 @@ fn fl_lit_check_expr(cx: &EarlyContext, expr: &ast::Expr) {
         // 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),
+        // Other kinds of exprs can't occur in patterns so we don't have to check them
+        // (ast_validation will emit an error if they occur)
+        _ => (),
     }
 }
 
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 7c443a4ac75..6ad03186dc7 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -93,6 +93,17 @@ impl<'a> AstValidator<'a> {
             }
         }
     }
+
+    /// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus)
+    fn check_expr_within_pat(&self, expr: &Expr) {
+        match expr.node {
+            ExprKind::Lit(..) | ExprKind::Path(..) => {}
+            ExprKind::Unary(UnOp::Neg, ref inner)
+                if match inner.node { ExprKind::Lit(_) => true, _ => false } => {}
+            _ => self.err_handler().span_err(expr.span, "arbitrary expressions aren't allowed \
+                                                         in patterns")
+        }
+    }
 }
 
 impl<'a> Visitor<'a> for AstValidator<'a> {
@@ -308,6 +319,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         }
         visit::walk_generics(self, g)
     }
+
+    fn visit_pat(&mut self, pat: &'a Pat) {
+        match pat.node {
+            PatKind::Lit(ref expr) => {
+                self.check_expr_within_pat(expr);
+            }
+            PatKind::Range(ref start, ref end, _) => {
+                self.check_expr_within_pat(start);
+                self.check_expr_within_pat(end);
+            }
+            _ => {}
+        }
+
+        visit::walk_pat(self, pat)
+    }
 }
 
 pub fn check_crate(session: &Session, krate: &Crate) {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 851a638e148..5b0031b2f17 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1659,8 +1659,10 @@ impl<'a> Parser<'a> {
         Ok(codemap::Spanned { node: lit, span: lo.to(self.prev_span) })
     }
 
-    /// matches '-' lit | lit
+    /// matches '-' lit | lit (cf. ast_validation::AstValidator::check_expr_within_pat)
     pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
+        maybe_whole_expr!(self);
+
         let minus_lo = self.span;
         let minus_present = self.eat(&token::BinOp(token::Minus));
         let lo = self.span;
diff --git a/src/test/compile-fail/patkind-litrange-no-expr.rs b/src/test/compile-fail/patkind-litrange-no-expr.rs
new file mode 100644
index 00000000000..afb2cbb7db3
--- /dev/null
+++ b/src/test/compile-fail/patkind-litrange-no-expr.rs
@@ -0,0 +1,36 @@
+// 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.
+
+macro_rules! enum_number {
+    ($name:ident { $($variant:ident = $value:expr, )* }) => {
+        enum $name {
+            $($variant = $value,)*
+        }
+
+        fn foo(value: i32) -> Option<$name> {
+            match value {
+                $( $value => Some($name::$variant), )* // PatKind::Lit
+                $( $value ... 42 => Some($name::$variant), )* // PatKind::Range
+                _ => None
+            }
+        }
+    }
+}
+
+enum_number!(Change {
+    Pos = 1,
+    Neg = -1,
+    Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns
+                   //~^ ERROR arbitrary expressions aren't allowed in patterns
+                   //~^^ ERROR only char and numeric types are allowed in range patterns
+});
+
+fn main() {}
+
diff --git a/src/test/run-pass/macro-pat-neg-lit.rs b/src/test/run-pass/macro-pat-neg-lit.rs
new file mode 100644
index 00000000000..43ac697edce
--- /dev/null
+++ b/src/test/run-pass/macro-pat-neg-lit.rs
@@ -0,0 +1,35 @@
+// 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.
+
+macro_rules! enum_number {
+    ($name:ident { $($variant:ident = $value:expr, )* }) => {
+        enum $name {
+            $($variant = $value,)*
+        }
+
+        fn foo(value: i32) -> Option<$name> {
+            match value {
+                $( $value => Some($name::$variant), )*
+                _ => None
+            }
+        }
+    }
+}
+
+enum_number!(Change {
+    Down = -1,
+    None = 0,
+    Up = 1,
+});
+
+fn main() {
+    if let Some(Change::Down) = foo(-1) {} else { panic!() }
+}
+