diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index a78d5ce1c16..c6f4cd585d7 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1527,7 +1527,8 @@ impl<'a> State<'a> { if i > 0 { word(&mut self.s, "::")? } - if segment.name != keywords::CrateRoot.name() && segment.name != "$crate" { + if segment.name != keywords::CrateRoot.name() && + segment.name != keywords::DollarCrate.name() { self.print_name(segment.name)?; self.print_path_parameters(&segment.parameters, colons_before_params)?; } @@ -1554,7 +1555,8 @@ impl<'a> State<'a> { if i > 0 { word(&mut self.s, "::")? } - if segment.name != keywords::CrateRoot.name() && segment.name != "$crate" { + if segment.name != keywords::CrateRoot.name() && + segment.name != keywords::DollarCrate.name() { self.print_name(segment.name)?; self.print_path_parameters(&segment.parameters, colons_before_params)?; } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index b97c08b5bde..4b6b754dca6 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -149,14 +149,15 @@ impl<'a> Resolver<'a> { resolve_error(self, view_path.span, ResolutionError::SelfImportsOnlyAllowedWithin); - } else if source_name == "$crate" && full_path.segments.len() == 1 { + } else if source_name == keywords::DollarCrate.name() && + full_path.segments.len() == 1 { let crate_root = self.resolve_crate_root(source.ctxt); let crate_name = match crate_root.kind { ModuleKind::Def(_, name) => name, ModuleKind::Block(..) => unreachable!(), }; source.name = crate_name; - if binding.name == "$crate" { + if binding.name == keywords::DollarCrate.name() { binding.name = crate_name; } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8c11aa7def8..4bfe4d25ded 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2665,7 +2665,8 @@ impl<'a> Resolver<'a> { }; if path.len() > 1 && !global_by_default && result.base_def() != Def::Err && - path[0].name != keywords::CrateRoot.name() && path[0].name != "$crate" { + path[0].name != keywords::CrateRoot.name() && + path[0].name != keywords::DollarCrate.name() { let unqualified_result = { match self.resolve_path(&[*path.last().unwrap()], Some(ns), false, span) { PathResult::NonModule(path_res) => path_res.base_def(), @@ -2718,7 +2719,7 @@ impl<'a> Resolver<'a> { if i == 0 && ns == TypeNS && ident.name == keywords::CrateRoot.name() { module = Some(self.resolve_crate_root(ident.ctxt.modern())); continue - } else if i == 0 && ns == TypeNS && ident.name == "$crate" { + } else if i == 0 && ns == TypeNS && ident.name == keywords::DollarCrate.name() { module = Some(self.resolve_crate_root(ident.ctxt)); continue } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 60c07eda4d5..0fbc596f2e1 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -128,7 +128,7 @@ impl<'a> base::Resolver for Resolver<'a> { impl<'a, 'b> Folder for EliminateCrateVar<'a, 'b> { fn fold_path(&mut self, mut path: ast::Path) -> ast::Path { let ident = path.segments[0].identifier; - if ident.name == "$crate" { + if ident.name == keywords::DollarCrate.name() { path.segments[0].identifier.name = keywords::CrateRoot.name(); let module = self.0.resolve_crate_root(ident.ctxt); if !module.is_local() { diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index a40d1e6bdc9..de8749c43d9 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -300,7 +300,7 @@ impl<'a> Classifier<'a> { "Some" | "None" | "Ok" | "Err" => Class::PreludeVal, "$crate" => Class::KeyWord, - _ if tas.tok.is_any_keyword() => Class::KeyWord, + _ if tas.tok.is_reserved_ident() => Class::KeyWord, _ => { if self.in_macro_nonterminal { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 8bd58ec7a52..ecab801d408 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -97,9 +97,8 @@ impl Path { } pub fn default_to_global(mut self) -> Path { - let name = self.segments[0].identifier.name; - if !self.is_global() && name != "$crate" && - name != keywords::SelfValue.name() && name != keywords::Super.name() { + if !self.is_global() && + !::parse::token::Ident(self.segments[0].identifier).is_path_segment_keyword() { self.segments.insert(0, PathSegment::crate_root()); } self diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index fa65e9501c2..c094a23cefc 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -12,7 +12,7 @@ use ast; use ext::tt::macro_parser; use parse::{ParseSess, token}; use print::pprust; -use symbol::{keywords, Symbol}; +use symbol::keywords; use syntax_pos::{DUMMY_SP, Span, BytePos}; use tokenstream; @@ -196,7 +196,7 @@ fn parse_tree(tree: tokenstream::TokenTree, Some(tokenstream::TokenTree::Token(ident_span, token::Ident(ident))) => { let span = Span { lo: span.lo, ..ident_span }; if ident.name == keywords::Crate.name() { - let ident = ast::Ident { name: Symbol::intern("$crate"), ..ident }; + let ident = ast::Ident { name: keywords::DollarCrate.name(), ..ident }; TokenTree::Token(span, token::Ident(ident)) } else { TokenTree::Token(span, token::SubstNt(ident)) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index e2656bea483..a35b278a4b0 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1283,7 +1283,7 @@ impl<'a> StringReader<'a> { }); let keyword_checking_token = &token::Ident(keyword_checking_ident); let last_bpos = self.pos; - if keyword_checking_token.is_any_keyword() && + if keyword_checking_token.is_reserved_ident() && !keyword_checking_token.is_keyword(keywords::Static) { self.err_span_(start, last_bpos, "lifetimes cannot use keyword names"); } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5b0031b2f17..64506c4af46 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -511,14 +511,13 @@ impl<'a> Parser<'a> { } pub fn this_token_descr(&self) -> String { - let s = self.this_token_to_string(); - if self.token.is_strict_keyword() { - format!("keyword `{}`", s) - } else if self.token.is_reserved_keyword() { - format!("reserved keyword `{}`", s) - } else { - format!("`{}`", s) - } + let prefix = match &self.token { + t if t.is_special_ident() => "reserved identifier ", + t if t.is_used_keyword() => "keyword ", + t if t.is_unused_keyword() => "reserved keyword ", + _ => "", + }; + format!("{}`{}`", prefix, self.this_token_to_string()) } pub fn unexpected_last(&self, t: &token::Token) -> PResult<'a, T> { @@ -637,10 +636,12 @@ impl<'a> Parser<'a> { } pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { - self.check_strict_keywords(); - self.check_reserved_keywords(); match self.token { token::Ident(i) => { + if self.token.is_reserved_ident() { + self.span_err(self.span, &format!("expected identifier, found {}", + self.this_token_descr())); + } self.bump(); Ok(i) } @@ -713,25 +714,6 @@ impl<'a> Parser<'a> { } } - /// Signal an error if the given string is a strict keyword - pub fn check_strict_keywords(&mut self) { - if self.token.is_strict_keyword() { - let token_str = self.this_token_to_string(); - let span = self.span; - self.span_err(span, - &format!("expected identifier, found keyword `{}`", - token_str)); - } - } - - /// Signal an error if the current token is a reserved keyword - pub fn check_reserved_keywords(&mut self) { - if self.token.is_reserved_keyword() { - let token_str = self.this_token_to_string(); - self.fatal(&format!("`{}` is a reserved keyword", token_str)).emit() - } - } - fn check_ident(&mut self) -> bool { if self.token.is_ident() { true @@ -2301,7 +2283,7 @@ impl<'a> Parser<'a> { ex = ExprKind::Break(lt, e); hi = self.prev_span; } else if self.token.is_keyword(keywords::Let) { - // Catch this syntax error here, instead of in `check_strict_keywords`, so + // Catch this syntax error here, instead of in `parse_ident`, so // that we can explicitly mention that let is not to be used as an expression let mut db = self.fatal("expected expression, found statement (`let`)"); db.note("variable declaration using `let` is a statement"); @@ -3540,7 +3522,7 @@ impl<'a> Parser<'a> { // Parse box pat let subpat = self.parse_pat()?; pat = PatKind::Box(subpat); - } else if self.token.is_ident() && !self.token.is_any_keyword() && + } else if self.token.is_ident() && !self.token.is_reserved_ident() && self.parse_as_ident() { // Parse ident @ pat // This can give false positives and parse nullary enums, @@ -3815,7 +3797,7 @@ impl<'a> Parser<'a> { fn is_union_item(&self) -> bool { self.token.is_keyword(keywords::Union) && - self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) + self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) } fn is_defaultness(&self) -> bool { diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 77db604c56e..75969cf2eb8 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -87,7 +87,7 @@ impl Lit { fn ident_can_begin_expr(ident: ast::Ident) -> bool { let ident_token: Token = Ident(ident); - !ident_token.is_any_keyword() || + !ident_token.is_reserved_ident() || ident_token.is_path_segment_keyword() || [ keywords::Do.name(), @@ -110,7 +110,7 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { fn ident_can_begin_type(ident: ast::Ident) -> bool { let ident_token: Token = Ident(ident); - !ident_token.is_any_keyword() || + !ident_token.is_reserved_ident() || ident_token.is_path_segment_keyword() || [ keywords::For.name(), @@ -315,7 +315,7 @@ impl Token { pub fn is_path_start(&self) -> bool { self == &ModSep || self.is_qpath_start() || self.is_path() || - self.is_path_segment_keyword() || self.is_ident() && !self.is_any_keyword() + self.is_path_segment_keyword() || self.is_ident() && !self.is_reserved_ident() } /// Returns `true` if the token is a given keyword, `kw`. @@ -327,18 +327,23 @@ impl Token { match self.ident() { Some(id) => id.name == keywords::Super.name() || id.name == keywords::SelfValue.name() || - id.name == keywords::SelfType.name(), + id.name == keywords::SelfType.name() || + id.name == keywords::DollarCrate.name(), None => false, } } - /// Returns `true` if the token is either a strict or reserved keyword. - pub fn is_any_keyword(&self) -> bool { - self.is_strict_keyword() || self.is_reserved_keyword() + // Returns true for reserved identifiers used internally for elided lifetimes, + // unnamed method parameters, crate root module, error recovery etc. + pub fn is_special_ident(&self) -> bool { + match self.ident() { + Some(id) => id.name <= keywords::DollarCrate.name(), + _ => false, + } } - /// Returns `true` if the token is a strict keyword. - pub fn is_strict_keyword(&self) -> bool { + /// Returns `true` if the token is a keyword used in the language. + pub fn is_used_keyword(&self) -> bool { match self.ident() { Some(id) => id.name >= keywords::As.name() && id.name <= keywords::While.name(), _ => false, @@ -346,12 +351,17 @@ impl Token { } /// Returns `true` if the token is a keyword reserved for possible future use. - pub fn is_reserved_keyword(&self) -> bool { + pub fn is_unused_keyword(&self) -> bool { match self.ident() { Some(id) => id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name(), _ => false, } } + + /// Returns `true` if the token is either a special identifier or a keyword. + pub fn is_reserved_ident(&self) -> bool { + self.is_special_ident() || self.is_used_keyword() || self.is_unused_keyword() + } } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)] diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 34cda433d52..6c00e0b9efd 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -761,7 +761,7 @@ pub trait PrintState<'a> { word(self.writer(), "::")? } if segment.identifier.name != keywords::CrateRoot.name() && - segment.identifier.name != "$crate" { + segment.identifier.name != keywords::DollarCrate.name() { word(self.writer(), &segment.identifier.name.as_str())?; } } @@ -2375,7 +2375,7 @@ impl<'a> State<'a> { -> io::Result<()> { if segment.identifier.name != keywords::CrateRoot.name() && - segment.identifier.name != "$crate" { + segment.identifier.name != keywords::DollarCrate.name() { self.print_ident(segment.identifier)?; if let Some(ref parameters) = segment.parameters { self.print_path_parameters(parameters, colons_before_params)?; diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 6b5caff27e8..debac70545a 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -237,76 +237,76 @@ macro_rules! declare_keywords {( // NB: leaving holes in the ident table is bad! a different ident will get // interned with the id from the hole, but it will be between the min and max // of the reserved words, and thus tagged as "reserved". -// After modifying this list adjust `is_strict_keyword`/`is_reserved_keyword`, +// After modifying this list adjust `is_special_ident`, `is_used_keyword`/`is_unused_keyword`, // this should be rarely necessary though if the keywords are kept in alphabetic order. declare_keywords! { - // Invalid identifier + // Special reserved identifiers used internally for elided lifetimes, + // unnamed method parameters, crate root module, error recovery etc. (0, Invalid, "") + (1, CrateRoot, "{{root}}") + (2, DollarCrate, "$crate") - // Strict keywords used in the language. - (1, As, "as") - (2, Box, "box") - (3, Break, "break") - (4, Const, "const") - (5, Continue, "continue") - (6, Crate, "crate") - (7, Else, "else") - (8, Enum, "enum") - (9, Extern, "extern") - (10, False, "false") - (11, Fn, "fn") - (12, For, "for") - (13, If, "if") - (14, Impl, "impl") - (15, In, "in") - (16, Let, "let") - (17, Loop, "loop") - (18, Match, "match") - (19, Mod, "mod") - (20, Move, "move") - (21, Mut, "mut") - (22, Pub, "pub") - (23, Ref, "ref") - (24, Return, "return") - (25, SelfValue, "self") - (26, SelfType, "Self") - (27, Static, "static") - (28, Struct, "struct") - (29, Super, "super") - (30, Trait, "trait") - (31, True, "true") - (32, Type, "type") - (33, Unsafe, "unsafe") - (34, Use, "use") - (35, Where, "where") - (36, While, "while") + // Keywords used in the language. + (3, As, "as") + (4, Box, "box") + (5, Break, "break") + (6, Const, "const") + (7, Continue, "continue") + (8, Crate, "crate") + (9, Else, "else") + (10, Enum, "enum") + (11, Extern, "extern") + (12, False, "false") + (13, Fn, "fn") + (14, For, "for") + (15, If, "if") + (16, Impl, "impl") + (17, In, "in") + (18, Let, "let") + (19, Loop, "loop") + (20, Match, "match") + (21, Mod, "mod") + (22, Move, "move") + (23, Mut, "mut") + (24, Pub, "pub") + (25, Ref, "ref") + (26, Return, "return") + (27, SelfValue, "self") + (28, SelfType, "Self") + (29, Static, "static") + (30, Struct, "struct") + (31, Super, "super") + (32, Trait, "trait") + (33, True, "true") + (34, Type, "type") + (35, Unsafe, "unsafe") + (36, Use, "use") + (37, Where, "where") + (38, While, "while") // Keywords reserved for future use. - (37, Abstract, "abstract") - (38, Alignof, "alignof") - (39, Become, "become") - (40, Do, "do") - (41, Final, "final") - (42, Macro, "macro") - (43, Offsetof, "offsetof") - (44, Override, "override") - (45, Priv, "priv") - (46, Proc, "proc") - (47, Pure, "pure") - (48, Sizeof, "sizeof") - (49, Typeof, "typeof") - (50, Unsized, "unsized") - (51, Virtual, "virtual") - (52, Yield, "yield") + (39, Abstract, "abstract") + (40, Alignof, "alignof") + (41, Become, "become") + (42, Do, "do") + (43, Final, "final") + (44, Macro, "macro") + (45, Offsetof, "offsetof") + (46, Override, "override") + (47, Priv, "priv") + (48, Proc, "proc") + (49, Pure, "pure") + (50, Sizeof, "sizeof") + (51, Typeof, "typeof") + (52, Unsized, "unsized") + (53, Virtual, "virtual") + (54, Yield, "yield") // Weak keywords, have special meaning only in specific contexts. - (53, Default, "default") - (54, StaticLifetime, "'static") - (55, Union, "union") - (56, Catch, "catch") - - // A virtual keyword that resolves to the crate root when used in a lexical scope. - (57, CrateRoot, "{{root}}") + (55, Default, "default") + (56, StaticLifetime, "'static") + (57, Union, "union") + (58, Catch, "catch") } // If an interner exists in TLS, return it. Otherwise, prepare a fresh one. diff --git a/src/test/compile-fail/dollar-crate-is-keyword-2.rs b/src/test/compile-fail/dollar-crate-is-keyword-2.rs new file mode 100644 index 00000000000..e221fc6e9e0 --- /dev/null +++ b/src/test/compile-fail/dollar-crate-is-keyword-2.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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod a {} + +macro_rules! m { + () => { + use a::$crate; //~ ERROR unresolved import `a::$crate` + use a::$crate::b; //~ ERROR unresolved import `a::$crate::b` + type A = a::$crate; //~ ERROR cannot find type `$crate` in module `a` + } +} + +m!(); + +fn main() {} diff --git a/src/test/compile-fail/dollar-crate-is-keyword.rs b/src/test/compile-fail/dollar-crate-is-keyword.rs new file mode 100644 index 00000000000..70597a230a8 --- /dev/null +++ b/src/test/compile-fail/dollar-crate-is-keyword.rs @@ -0,0 +1,24 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! m { + () => { + struct $crate {} //~ ERROR expected identifier, found reserved identifier `$crate` + + use $crate; // OK + //~^ WARN `$crate` may not be imported + use $crate as $crate; //~ ERROR expected identifier, found reserved identifier `$crate` + //~^ WARN `$crate` may not be imported + } +} + +m!(); + +fn main() {} diff --git a/src/test/compile-fail/use-self-type.rs b/src/test/compile-fail/use-self-type.rs new file mode 100644 index 00000000000..6b5286bf0a7 --- /dev/null +++ b/src/test/compile-fail/use-self-type.rs @@ -0,0 +1,21 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S; + +impl S { + fn f() {} + fn g() { + use Self::f; //~ ERROR unresolved import + pub(in Self::f) struct Z; //~ ERROR Use of undeclared type or module `Self` + } +} + +fn main() {} diff --git a/src/test/parse-fail/macro-keyword.rs b/src/test/parse-fail/macro-keyword.rs index 6a7ccff1554..c7dcaf4137e 100644 --- a/src/test/parse-fail/macro-keyword.rs +++ b/src/test/parse-fail/macro-keyword.rs @@ -10,7 +10,7 @@ // compile-flags: -Z parse-only -fn macro() { //~ ERROR `macro` is a reserved keyword +fn macro() { //~ ERROR expected identifier, found reserved keyword `macro` } pub fn main() {