about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-05-22 17:51:22 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-05-28 20:27:57 +0300
commit2abdf963441dad5e5ec516af8ee2f9b459f9e47d (patch)
tree903a774d07993a87ffbe0c7f3f0ec77e1cec4d16
parentf1776fe244d8603006536dceb7a21967e1c21f9c (diff)
downloadrust-2abdf963441dad5e5ec516af8ee2f9b459f9e47d.tar.gz
rust-2abdf963441dad5e5ec516af8ee2f9b459f9e47d.zip
Add an AST sanity checking pass and use it to catch some illegal lifetime/label names
-rw-r--r--src/librustc/lint/builtin.rs9
-rw-r--r--src/librustc_driver/driver.rs6
-rw-r--r--src/librustc_lint/lib.rs4
-rw-r--r--src/librustc_passes/ast_sanity.rs79
-rw-r--r--src/librustc_passes/lib.rs1
-rw-r--r--src/test/compile-fail/label-static.rs15
-rw-r--r--src/test/compile-fail/lifetime-underscore.rs27
7 files changed, 139 insertions, 2 deletions
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index d7971cd2cf0..41086b5d1c9 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -204,6 +204,12 @@ declare_lint! {
     "object-unsafe non-principal fragments in object types were erroneously allowed"
 }
 
+declare_lint! {
+    pub LIFETIME_UNDERSCORE,
+    Warn,
+    "lifetimes or labels named `'_` were erroneously allowed"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// which are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -242,7 +248,8 @@ impl LintPass for HardwiredLints {
             SUPER_OR_SELF_IN_GLOBAL_PATH,
             UNSIZED_IN_TUPLE,
             OBJECT_UNSAFE_FRAGMENT,
-            HR_LIFETIME_IN_ASSOC_TYPE
+            HR_LIFETIME_IN_ASSOC_TYPE,
+            LIFETIME_UNDERSCORE
         )
     }
 }
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 48b86d862f5..570135e0713 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -38,7 +38,7 @@ use rustc_privacy;
 use rustc_plugin::registry::Registry;
 use rustc_plugin as plugin;
 use rustc::hir::lowering::lower_crate;
-use rustc_passes::{no_asm, loops, consts, rvalues, static_recursion};
+use rustc_passes::{ast_sanity, no_asm, loops, consts, rvalues, static_recursion};
 use rustc_const_eval::check_match;
 use super::Compilation;
 
@@ -166,6 +166,10 @@ pub fn compile_input(sess: &Session,
              "early lint checks",
              || lint::check_ast_crate(sess, &expanded_crate));
 
+        time(sess.time_passes(),
+             "AST sanity checking",
+             || ast_sanity::check_crate(sess, &expanded_crate));
+
         let (analysis, resolutions, mut hir_forest) = {
             lower_and_resolve(sess, &id, &mut defs, &expanded_crate,
                               &sess.dep_graph, control.make_glob_map)
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 9fca6d3d201..ed12d0d9f3c 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -202,6 +202,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             id: LintId::of(HR_LIFETIME_IN_ASSOC_TYPE),
             reference: "issue #33685 <https://github.com/rust-lang/rust/issues/33685>",
         },
+        FutureIncompatibleInfo {
+            id: LintId::of(LIFETIME_UNDERSCORE),
+            reference: "RFC 1177 <https://github.com/rust-lang/rfcs/pull/1177>",
+        },
         ]);
 
     // We have one lint pass defined specially
diff --git a/src/librustc_passes/ast_sanity.rs b/src/librustc_passes/ast_sanity.rs
new file mode 100644
index 00000000000..22f73896f09
--- /dev/null
+++ b/src/librustc_passes/ast_sanity.rs
@@ -0,0 +1,79 @@
+// Copyright 2016 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.
+
+// Sanity check AST before lowering it to HIR
+//
+// This pass is supposed to catch things that fit into AST data structures,
+// but not permitted by the language. It runs after expansion when AST is frozen,
+// so it can check for erroneous constructions produced by syntax extensions.
+// This pass is supposed to perform only simple checks not requiring name resolution
+// or type checking or some other kind of complex analysis.
+
+use rustc::lint;
+use rustc::session::Session;
+use syntax::ast::*;
+use syntax::codemap::Span;
+use syntax::errors;
+use syntax::parse::token::keywords;
+use syntax::visit::{self, Visitor};
+
+struct SanityChecker<'a> {
+    session: &'a Session,
+}
+
+impl<'a> SanityChecker<'a> {
+    fn err_handler(&self) -> &errors::Handler {
+        &self.session.parse_sess.span_diagnostic
+    }
+
+    fn check_label(&self, label: Ident, span: Span, id: NodeId) {
+        if label.name == keywords::StaticLifetime.name() {
+            self.err_handler().span_err(span, &format!("invalid label name `{}`", label.name));
+        }
+        if label.name.as_str() == "'_" {
+            self.session.add_lint(
+                lint::builtin::LIFETIME_UNDERSCORE, id, span,
+                format!("invalid label name `{}`", label.name)
+            );
+        }
+    }
+}
+
+impl<'a, 'v> Visitor<'v> for SanityChecker<'a> {
+    fn visit_lifetime(&mut self, lt: &Lifetime) {
+        if lt.name.as_str() == "'_" {
+            self.session.add_lint(
+                lint::builtin::LIFETIME_UNDERSCORE, lt.id, lt.span,
+                format!("invalid lifetime name `{}`", lt.name)
+            );
+        }
+
+        visit::walk_lifetime(self, lt)
+    }
+
+    fn visit_expr(&mut self, expr: &Expr) {
+        match expr.node {
+            ExprKind::While(_, _, Some(ident)) | ExprKind::Loop(_, Some(ident)) |
+            ExprKind::WhileLet(_, _, _, Some(ident)) | ExprKind::ForLoop(_, _, _, Some(ident)) => {
+                self.check_label(ident, expr.span, expr.id);
+            }
+            ExprKind::Break(Some(ident)) | ExprKind::Again(Some(ident)) => {
+                self.check_label(ident.node, ident.span, expr.id);
+            }
+            _ => {}
+        }
+
+        visit::walk_expr(self, expr)
+    }
+}
+
+pub fn check_crate(session: &Session, krate: &Crate) {
+    visit::walk_crate(&mut SanityChecker { session: session }, krate)
+}
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index 67a9c2fd17e..9e5cc139040 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -37,6 +37,7 @@ extern crate rustc_const_math;
 
 pub mod diagnostics;
 
+pub mod ast_sanity;
 pub mod consts;
 pub mod loops;
 pub mod no_asm;
diff --git a/src/test/compile-fail/label-static.rs b/src/test/compile-fail/label-static.rs
new file mode 100644
index 00000000000..a0fb25ea06e
--- /dev/null
+++ b/src/test/compile-fail/label-static.rs
@@ -0,0 +1,15 @@
+// Copyright 2016 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() {
+    'static: loop { //~ ERROR invalid label name `'static`
+        break 'static //~ ERROR invalid label name `'static`
+    }
+}
diff --git a/src/test/compile-fail/lifetime-underscore.rs b/src/test/compile-fail/lifetime-underscore.rs
new file mode 100644
index 00000000000..102d3576e54
--- /dev/null
+++ b/src/test/compile-fail/lifetime-underscore.rs
@@ -0,0 +1,27 @@
+// Copyright 2016 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.
+
+#![deny(lifetime_underscore)]
+
+fn _f<'_>() //~ ERROR invalid lifetime name `'_`
+//~^ WARN this was previously accepted
+    -> &'_ u8 //~ ERROR invalid lifetime name `'_`
+    //~^ WARN this was previously accepted
+{
+    panic!();
+}
+
+fn main() {
+    '_: loop { //~ ERROR invalid label name `'_`
+    //~^ WARN this was previously accepted
+        break '_ //~ ERROR invalid label name `'_`
+        //~^ WARN this was previously accepted
+    }
+}