diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 879b8945620..1573d0c4292 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -179,6 +179,12 @@ declare_lint! { "lints that have been renamed or removed" } +declare_lint! { + pub SUPER_OR_SELF_IN_GLOBAL_PATH, + Warn, + "detects super or self keywords at the beginning of global path" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -213,7 +219,8 @@ impl LintPass for HardwiredLints { RAW_POINTER_DERIVE, TRANSMUTE_FROM_FN_ITEM_TYPES, OVERLAPPING_INHERENT_IMPLS, - RENAMED_AND_REMOVED_LINTS + RENAMED_AND_REMOVED_LINTS, + SUPER_OR_SELF_IN_GLOBAL_PATH ) } } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 6e3a961caca..0780e4cd048 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -167,6 +167,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(INVALID_TYPE_PARAM_DEFAULT), reference: "PR 30742 ", }, + FutureIncompatibleInfo { + id: LintId::of(SUPER_OR_SELF_IN_GLOBAL_PATH), + reference: "PR #32403 ", + }, FutureIncompatibleInfo { id: LintId::of(MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT), reference: "RFC 218 Resolver<'b, 'tcx> { // Extract and intern the module part of the path. For // globs and lists, the path is found directly in the AST; // for simple paths we have to munge the path a little. - let module_path = match view_path.node { + let is_global; + let module_path: Vec = match view_path.node { ViewPathSimple(_, ref full_path) => { + is_global = full_path.global; full_path.segments .split_last() .unwrap() @@ -129,6 +132,7 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { ViewPathGlob(ref module_ident_path) | ViewPathList(ref module_ident_path, _) => { + is_global = module_ident_path.global; module_ident_path.segments .iter() .map(|seg| seg.identifier.name) @@ -136,6 +140,18 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { } }; + // Checking for special identifiers in path + // prevent `self` or `super` at beginning of global path + if is_global && (module_path.first() == Some(&SELF_KEYWORD_NAME) || + module_path.first() == Some(&SUPER_KEYWORD_NAME)) { + self.session.add_lint( + lint::builtin::SUPER_OR_SELF_IN_GLOBAL_PATH, + item.id, + item.span, + format!("expected identifier, found keyword `{}`", + module_path.first().unwrap().as_str())); + } + // Build up the import directives. let is_prelude = item.attrs.iter().any(|attr| { attr.name() == special_idents::prelude_import.name.as_str() diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9027a5b1074..75916b87c12 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -6124,7 +6124,7 @@ impl<'a> Parser<'a> { // Allow a leading :: because the paths are absolute either way. // This occurs with "use $crate::..." in macros. - self.eat(&token::ModSep); + let is_global = self.eat(&token::ModSep); if self.check(&token::OpenDelim(token::Brace)) { // use {foo,bar} @@ -6135,7 +6135,7 @@ impl<'a> Parser<'a> { |p| p.parse_path_list_item())?; let path = ast::Path { span: mk_sp(lo, self.span.hi), - global: false, + global: is_global, segments: Vec::new() }; return Ok(P(spanned(lo, self.span.hi, ViewPathList(path, idents)))); @@ -6164,7 +6164,7 @@ impl<'a> Parser<'a> { )?; let path = ast::Path { span: mk_sp(lo, self.span.hi), - global: false, + global: is_global, segments: path.into_iter().map(|identifier| { ast::PathSegment { identifier: identifier, @@ -6180,7 +6180,7 @@ impl<'a> Parser<'a> { self.bump(); let path = ast::Path { span: mk_sp(lo, self.span.hi), - global: false, + global: is_global, segments: path.into_iter().map(|identifier| { ast::PathSegment { identifier: identifier, @@ -6203,7 +6203,7 @@ impl<'a> Parser<'a> { let mut rename_to = path[path.len() - 1]; let path = ast::Path { span: mk_sp(lo, self.last_span.hi), - global: false, + global: is_global, segments: path.into_iter().map(|identifier| { ast::PathSegment { identifier: identifier, diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index a02a10aa003..16417ac0044 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -514,7 +514,7 @@ macro_rules! declare_special_idents_and_keywords {( // If the special idents get renumbered, remember to modify these two as appropriate pub const SELF_KEYWORD_NAME: ast::Name = ast::Name(SELF_KEYWORD_NAME_NUM); const STATIC_KEYWORD_NAME: ast::Name = ast::Name(STATIC_KEYWORD_NAME_NUM); -const SUPER_KEYWORD_NAME: ast::Name = ast::Name(SUPER_KEYWORD_NAME_NUM); +pub const SUPER_KEYWORD_NAME: ast::Name = ast::Name(SUPER_KEYWORD_NAME_NUM); const SELF_TYPE_KEYWORD_NAME: ast::Name = ast::Name(SELF_TYPE_KEYWORD_NAME_NUM); pub const SELF_KEYWORD_NAME_NUM: u32 = 1; diff --git a/src/test/compile-fail/use-super-global-path.rs b/src/test/compile-fail/use-super-global-path.rs new file mode 100644 index 00000000000..d721d428f29 --- /dev/null +++ b/src/test/compile-fail/use-super-global-path.rs @@ -0,0 +1,22 @@ +// 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. + +#![feature(rustc_attrs)] + +mod foo { + pub fn g() { + use ::super::main; //~ WARN expected identifier, found keyword `super` + //~^ WARN this was previously accepted by the compiler but is being phased out + main(); + } +} + +#[rustc_error] +fn main() { foo::g(); } //~ ERROR compilation successful