diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index d7971cd2cf040..41086b5d1c990 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 1f3df1ff6f2d8..c3f89fb8ac06c 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 9fca6d3d20139..ed12d0d9f3c11 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 ", }, + FutureIncompatibleInfo { + id: LintId::of(LIFETIME_UNDERSCORE), + reference: "RFC 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 0000000000000..22f73896f099f --- /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 or the MIT license +// , 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 67a9c2fd17e9f..9e5cc13904097 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 0000000000000..a0fb25ea06eac --- /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 or the MIT license +// , 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 0000000000000..102d3576e5467 --- /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 or the MIT license +// , 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 + } +}