Auto merge of #42902 - petrochenkov:keydcrate, r=jseyfried

Make `$crate` a keyword

Fixes https://github.com/rust-lang/rust/issues/42898

r? @jseyfried or @nrc
This commit is contained in:
bors 2017-06-29 23:48:17 +00:00
commit 5eef7c7966
16 changed files with 184 additions and 121 deletions

View File

@ -1527,7 +1527,8 @@ impl<'a> State<'a> {
if i > 0 { if i > 0 {
word(&mut self.s, "::")? 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_name(segment.name)?;
self.print_path_parameters(&segment.parameters, colons_before_params)?; self.print_path_parameters(&segment.parameters, colons_before_params)?;
} }
@ -1554,7 +1555,8 @@ impl<'a> State<'a> {
if i > 0 { if i > 0 {
word(&mut self.s, "::")? 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_name(segment.name)?;
self.print_path_parameters(&segment.parameters, colons_before_params)?; self.print_path_parameters(&segment.parameters, colons_before_params)?;
} }

View File

@ -149,14 +149,15 @@ impl<'a> Resolver<'a> {
resolve_error(self, resolve_error(self,
view_path.span, view_path.span,
ResolutionError::SelfImportsOnlyAllowedWithin); 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_root = self.resolve_crate_root(source.ctxt);
let crate_name = match crate_root.kind { let crate_name = match crate_root.kind {
ModuleKind::Def(_, name) => name, ModuleKind::Def(_, name) => name,
ModuleKind::Block(..) => unreachable!(), ModuleKind::Block(..) => unreachable!(),
}; };
source.name = crate_name; source.name = crate_name;
if binding.name == "$crate" { if binding.name == keywords::DollarCrate.name() {
binding.name = crate_name; binding.name = crate_name;
} }

View File

@ -2665,7 +2665,8 @@ impl<'a> Resolver<'a> {
}; };
if path.len() > 1 && !global_by_default && result.base_def() != Def::Err && 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 = { let unqualified_result = {
match self.resolve_path(&[*path.last().unwrap()], Some(ns), false, span) { match self.resolve_path(&[*path.last().unwrap()], Some(ns), false, span) {
PathResult::NonModule(path_res) => path_res.base_def(), 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() { if i == 0 && ns == TypeNS && ident.name == keywords::CrateRoot.name() {
module = Some(self.resolve_crate_root(ident.ctxt.modern())); module = Some(self.resolve_crate_root(ident.ctxt.modern()));
continue 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)); module = Some(self.resolve_crate_root(ident.ctxt));
continue continue
} }

View File

@ -128,7 +128,7 @@ impl<'a> base::Resolver for Resolver<'a> {
impl<'a, 'b> Folder for EliminateCrateVar<'a, 'b> { impl<'a, 'b> Folder for EliminateCrateVar<'a, 'b> {
fn fold_path(&mut self, mut path: ast::Path) -> ast::Path { fn fold_path(&mut self, mut path: ast::Path) -> ast::Path {
let ident = path.segments[0].identifier; let ident = path.segments[0].identifier;
if ident.name == "$crate" { if ident.name == keywords::DollarCrate.name() {
path.segments[0].identifier.name = keywords::CrateRoot.name(); path.segments[0].identifier.name = keywords::CrateRoot.name();
let module = self.0.resolve_crate_root(ident.ctxt); let module = self.0.resolve_crate_root(ident.ctxt);
if !module.is_local() { if !module.is_local() {

View File

@ -300,7 +300,7 @@ impl<'a> Classifier<'a> {
"Some" | "None" | "Ok" | "Err" => Class::PreludeVal, "Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
"$crate" => Class::KeyWord, "$crate" => Class::KeyWord,
_ if tas.tok.is_any_keyword() => Class::KeyWord, _ if tas.tok.is_reserved_ident() => Class::KeyWord,
_ => { _ => {
if self.in_macro_nonterminal { if self.in_macro_nonterminal {

View File

@ -97,9 +97,8 @@ impl Path {
} }
pub fn default_to_global(mut self) -> Path { pub fn default_to_global(mut self) -> Path {
let name = self.segments[0].identifier.name; if !self.is_global() &&
if !self.is_global() && name != "$crate" && !::parse::token::Ident(self.segments[0].identifier).is_path_segment_keyword() {
name != keywords::SelfValue.name() && name != keywords::Super.name() {
self.segments.insert(0, PathSegment::crate_root()); self.segments.insert(0, PathSegment::crate_root());
} }
self self

View File

@ -12,7 +12,7 @@ use ast;
use ext::tt::macro_parser; use ext::tt::macro_parser;
use parse::{ParseSess, token}; use parse::{ParseSess, token};
use print::pprust; use print::pprust;
use symbol::{keywords, Symbol}; use symbol::keywords;
use syntax_pos::{DUMMY_SP, Span, BytePos}; use syntax_pos::{DUMMY_SP, Span, BytePos};
use tokenstream; use tokenstream;
@ -196,7 +196,7 @@ fn parse_tree<I>(tree: tokenstream::TokenTree,
Some(tokenstream::TokenTree::Token(ident_span, token::Ident(ident))) => { Some(tokenstream::TokenTree::Token(ident_span, token::Ident(ident))) => {
let span = Span { lo: span.lo, ..ident_span }; let span = Span { lo: span.lo, ..ident_span };
if ident.name == keywords::Crate.name() { 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)) TokenTree::Token(span, token::Ident(ident))
} else { } else {
TokenTree::Token(span, token::SubstNt(ident)) TokenTree::Token(span, token::SubstNt(ident))

View File

@ -1283,7 +1283,7 @@ impl<'a> StringReader<'a> {
}); });
let keyword_checking_token = &token::Ident(keyword_checking_ident); let keyword_checking_token = &token::Ident(keyword_checking_ident);
let last_bpos = self.pos; 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) { !keyword_checking_token.is_keyword(keywords::Static) {
self.err_span_(start, last_bpos, "lifetimes cannot use keyword names"); self.err_span_(start, last_bpos, "lifetimes cannot use keyword names");
} }

View File

@ -511,14 +511,13 @@ impl<'a> Parser<'a> {
} }
pub fn this_token_descr(&self) -> String { pub fn this_token_descr(&self) -> String {
let s = self.this_token_to_string(); let prefix = match &self.token {
if self.token.is_strict_keyword() { t if t.is_special_ident() => "reserved identifier ",
format!("keyword `{}`", s) t if t.is_used_keyword() => "keyword ",
} else if self.token.is_reserved_keyword() { t if t.is_unused_keyword() => "reserved keyword ",
format!("reserved keyword `{}`", s) _ => "",
} else { };
format!("`{}`", s) format!("{}`{}`", prefix, self.this_token_to_string())
}
} }
pub fn unexpected_last<T>(&self, t: &token::Token) -> PResult<'a, T> { pub fn unexpected_last<T>(&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> { pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> {
self.check_strict_keywords();
self.check_reserved_keywords();
match self.token { match self.token {
token::Ident(i) => { token::Ident(i) => {
if self.token.is_reserved_ident() {
self.span_err(self.span, &format!("expected identifier, found {}",
self.this_token_descr()));
}
self.bump(); self.bump();
Ok(i) 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 { fn check_ident(&mut self) -> bool {
if self.token.is_ident() { if self.token.is_ident() {
true true
@ -2301,7 +2283,7 @@ impl<'a> Parser<'a> {
ex = ExprKind::Break(lt, e); ex = ExprKind::Break(lt, e);
hi = self.prev_span; hi = self.prev_span;
} else if self.token.is_keyword(keywords::Let) { } 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 // 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`)"); let mut db = self.fatal("expected expression, found statement (`let`)");
db.note("variable declaration using `let` is a statement"); db.note("variable declaration using `let` is a statement");
@ -3540,7 +3522,7 @@ impl<'a> Parser<'a> {
// Parse box pat // Parse box pat
let subpat = self.parse_pat()?; let subpat = self.parse_pat()?;
pat = PatKind::Box(subpat); 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() { self.parse_as_ident() {
// Parse ident @ pat // Parse ident @ pat
// This can give false positives and parse nullary enums, // This can give false positives and parse nullary enums,
@ -3815,7 +3797,7 @@ impl<'a> Parser<'a> {
fn is_union_item(&self) -> bool { fn is_union_item(&self) -> bool {
self.token.is_keyword(keywords::Union) && 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 { fn is_defaultness(&self) -> bool {

View File

@ -87,7 +87,7 @@ impl Lit {
fn ident_can_begin_expr(ident: ast::Ident) -> bool { fn ident_can_begin_expr(ident: ast::Ident) -> bool {
let ident_token: Token = Ident(ident); let ident_token: Token = Ident(ident);
!ident_token.is_any_keyword() || !ident_token.is_reserved_ident() ||
ident_token.is_path_segment_keyword() || ident_token.is_path_segment_keyword() ||
[ [
keywords::Do.name(), 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 { fn ident_can_begin_type(ident: ast::Ident) -> bool {
let ident_token: Token = Ident(ident); let ident_token: Token = Ident(ident);
!ident_token.is_any_keyword() || !ident_token.is_reserved_ident() ||
ident_token.is_path_segment_keyword() || ident_token.is_path_segment_keyword() ||
[ [
keywords::For.name(), keywords::For.name(),
@ -315,7 +315,7 @@ impl Token {
pub fn is_path_start(&self) -> bool { pub fn is_path_start(&self) -> bool {
self == &ModSep || self.is_qpath_start() || self.is_path() || 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`. /// Returns `true` if the token is a given keyword, `kw`.
@ -327,18 +327,23 @@ impl Token {
match self.ident() { match self.ident() {
Some(id) => id.name == keywords::Super.name() || Some(id) => id.name == keywords::Super.name() ||
id.name == keywords::SelfValue.name() || id.name == keywords::SelfValue.name() ||
id.name == keywords::SelfType.name(), id.name == keywords::SelfType.name() ||
id.name == keywords::DollarCrate.name(),
None => false, None => false,
} }
} }
/// Returns `true` if the token is either a strict or reserved keyword. // Returns true for reserved identifiers used internally for elided lifetimes,
pub fn is_any_keyword(&self) -> bool { // unnamed method parameters, crate root module, error recovery etc.
self.is_strict_keyword() || self.is_reserved_keyword() 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. /// Returns `true` if the token is a keyword used in the language.
pub fn is_strict_keyword(&self) -> bool { pub fn is_used_keyword(&self) -> bool {
match self.ident() { match self.ident() {
Some(id) => id.name >= keywords::As.name() && id.name <= keywords::While.name(), Some(id) => id.name >= keywords::As.name() && id.name <= keywords::While.name(),
_ => false, _ => false,
@ -346,12 +351,17 @@ impl Token {
} }
/// Returns `true` if the token is a keyword reserved for possible future use. /// 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() { match self.ident() {
Some(id) => id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name(), Some(id) => id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name(),
_ => false, _ => 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)] #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)]

View File

@ -761,7 +761,7 @@ pub trait PrintState<'a> {
word(self.writer(), "::")? word(self.writer(), "::")?
} }
if segment.identifier.name != keywords::CrateRoot.name() && 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())?; word(self.writer(), &segment.identifier.name.as_str())?;
} }
} }
@ -2375,7 +2375,7 @@ impl<'a> State<'a> {
-> io::Result<()> -> io::Result<()>
{ {
if segment.identifier.name != keywords::CrateRoot.name() && if segment.identifier.name != keywords::CrateRoot.name() &&
segment.identifier.name != "$crate" { segment.identifier.name != keywords::DollarCrate.name() {
self.print_ident(segment.identifier)?; self.print_ident(segment.identifier)?;
if let Some(ref parameters) = segment.parameters { if let Some(ref parameters) = segment.parameters {
self.print_path_parameters(parameters, colons_before_params)?; self.print_path_parameters(parameters, colons_before_params)?;

View File

@ -237,76 +237,76 @@ macro_rules! declare_keywords {(
// NB: leaving holes in the ident table is bad! a different ident will get // 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 // 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". // 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. // this should be rarely necessary though if the keywords are kept in alphabetic order.
declare_keywords! { declare_keywords! {
// Invalid identifier // Special reserved identifiers used internally for elided lifetimes,
// unnamed method parameters, crate root module, error recovery etc.
(0, Invalid, "") (0, Invalid, "")
(1, CrateRoot, "{{root}}")
(2, DollarCrate, "$crate")
// Strict keywords used in the language. // Keywords used in the language.
(1, As, "as") (3, As, "as")
(2, Box, "box") (4, Box, "box")
(3, Break, "break") (5, Break, "break")
(4, Const, "const") (6, Const, "const")
(5, Continue, "continue") (7, Continue, "continue")
(6, Crate, "crate") (8, Crate, "crate")
(7, Else, "else") (9, Else, "else")
(8, Enum, "enum") (10, Enum, "enum")
(9, Extern, "extern") (11, Extern, "extern")
(10, False, "false") (12, False, "false")
(11, Fn, "fn") (13, Fn, "fn")
(12, For, "for") (14, For, "for")
(13, If, "if") (15, If, "if")
(14, Impl, "impl") (16, Impl, "impl")
(15, In, "in") (17, In, "in")
(16, Let, "let") (18, Let, "let")
(17, Loop, "loop") (19, Loop, "loop")
(18, Match, "match") (20, Match, "match")
(19, Mod, "mod") (21, Mod, "mod")
(20, Move, "move") (22, Move, "move")
(21, Mut, "mut") (23, Mut, "mut")
(22, Pub, "pub") (24, Pub, "pub")
(23, Ref, "ref") (25, Ref, "ref")
(24, Return, "return") (26, Return, "return")
(25, SelfValue, "self") (27, SelfValue, "self")
(26, SelfType, "Self") (28, SelfType, "Self")
(27, Static, "static") (29, Static, "static")
(28, Struct, "struct") (30, Struct, "struct")
(29, Super, "super") (31, Super, "super")
(30, Trait, "trait") (32, Trait, "trait")
(31, True, "true") (33, True, "true")
(32, Type, "type") (34, Type, "type")
(33, Unsafe, "unsafe") (35, Unsafe, "unsafe")
(34, Use, "use") (36, Use, "use")
(35, Where, "where") (37, Where, "where")
(36, While, "while") (38, While, "while")
// Keywords reserved for future use. // Keywords reserved for future use.
(37, Abstract, "abstract") (39, Abstract, "abstract")
(38, Alignof, "alignof") (40, Alignof, "alignof")
(39, Become, "become") (41, Become, "become")
(40, Do, "do") (42, Do, "do")
(41, Final, "final") (43, Final, "final")
(42, Macro, "macro") (44, Macro, "macro")
(43, Offsetof, "offsetof") (45, Offsetof, "offsetof")
(44, Override, "override") (46, Override, "override")
(45, Priv, "priv") (47, Priv, "priv")
(46, Proc, "proc") (48, Proc, "proc")
(47, Pure, "pure") (49, Pure, "pure")
(48, Sizeof, "sizeof") (50, Sizeof, "sizeof")
(49, Typeof, "typeof") (51, Typeof, "typeof")
(50, Unsized, "unsized") (52, Unsized, "unsized")
(51, Virtual, "virtual") (53, Virtual, "virtual")
(52, Yield, "yield") (54, Yield, "yield")
// Weak keywords, have special meaning only in specific contexts. // Weak keywords, have special meaning only in specific contexts.
(53, Default, "default") (55, Default, "default")
(54, StaticLifetime, "'static") (56, StaticLifetime, "'static")
(55, Union, "union") (57, Union, "union")
(56, Catch, "catch") (58, Catch, "catch")
// A virtual keyword that resolves to the crate root when used in a lexical scope.
(57, CrateRoot, "{{root}}")
} }
// If an interner exists in TLS, return it. Otherwise, prepare a fresh one. // If an interner exists in TLS, return it. Otherwise, prepare a fresh one.

View File

@ -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.
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() {}

View File

@ -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 <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.
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() {}

View File

@ -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 <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.
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() {}

View File

@ -10,7 +10,7 @@
// compile-flags: -Z parse-only // 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() { pub fn main() {