about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-08-13 16:59:54 +0300
committerAlex Crichton <alex@alexcrichton.com>2017-08-23 07:45:08 -0700
commit5bb0cac84891de785ce803ca2bd36a55cd9775d9 (patch)
tree9a4177820f594f382e1ff2e4352ff1878c3a515f
parentf0cd69592b49821f2f1a1b9f5cf5416ef120b6a9 (diff)
downloadrust-5bb0cac84891de785ce803ca2bd36a55cd9775d9.tar.gz
rust-5bb0cac84891de785ce803ca2bd36a55cd9775d9.zip
ast_validation: forbid "nonstandard" literal patterns
Since #42886, macros can create "nonstandard" PatKind::Lit patterns,
that contain path expressions instead of the usual literal expr. These
can cause trouble, including ICEs.

We *could* map these nonstandard patterns to PatKind::Path patterns
during HIR lowering, but that would be much effort for little gain, and
I think is too risky for beta. So let's just forbid them during AST
validation.

Fixes #43250.
-rw-r--r--src/librustc_passes/ast_validation.rs27
-rw-r--r--src/test/compile-fail/issue-43250.rs23
2 files changed, 44 insertions, 6 deletions
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 72c7b92fe6e..66736507abc 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -94,10 +94,25 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    /// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus)
-    fn check_expr_within_pat(&self, expr: &Expr) {
+    /// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus),
+    /// or path for ranges.
+    ///
+    /// FIXME: do we want to allow expr -> pattern conversion to create path expressions?
+    /// That means making this work:
+    ///
+    /// ```rust,ignore (FIXME)
+    ///     struct S;
+    ///     macro_rules! m {
+    ///         ($a:expr) => {
+    ///             let $a = S;
+    ///         }
+    ///     }
+    ///     m!(S);
+    /// ```
+    fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
         match expr.node {
-            ExprKind::Lit(..) | ExprKind::Path(..) => {}
+            ExprKind::Lit(..) => {}
+            ExprKind::Path(..) if allow_paths => {}
             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 \
@@ -340,11 +355,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     fn visit_pat(&mut self, pat: &'a Pat) {
         match pat.node {
             PatKind::Lit(ref expr) => {
-                self.check_expr_within_pat(expr);
+                self.check_expr_within_pat(expr, false);
             }
             PatKind::Range(ref start, ref end, _) => {
-                self.check_expr_within_pat(start);
-                self.check_expr_within_pat(end);
+                self.check_expr_within_pat(start, true);
+                self.check_expr_within_pat(end, true);
             }
             _ => {}
         }
diff --git a/src/test/compile-fail/issue-43250.rs b/src/test/compile-fail/issue-43250.rs
new file mode 100644
index 00000000000..e1d34f339dc
--- /dev/null
+++ b/src/test/compile-fail/issue-43250.rs
@@ -0,0 +1,23 @@
+// 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.
+
+fn main() {
+    let mut y;
+    const C: u32 = 0;
+    macro_rules! m {
+        ($a:expr) => {
+            let $a = 0;
+        }
+    }
+    m!(y);
+    //~^ ERROR arbitrary expressions aren't allowed in patterns
+    m!(C);
+    //~^ ERROR arbitrary expressions aren't allowed in patterns
+}