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 @@ pub fn print_path(&mut self,
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 @@ pub fn print_qpath(&mut self,
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)?;
}

View File

@ -149,14 +149,15 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
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;
}

View File

@ -2665,7 +2665,8 @@ fn resolve_qpath(&mut self,
};
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 @@ fn resolve_path(&mut self,
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
}

View File

@ -128,7 +128,7 @@ fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> {
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() {

View File

@ -300,7 +300,7 @@ fn write_token<W: Writer>(&mut self,
"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 {

View File

@ -97,9 +97,8 @@ pub fn from_ident(s: Span, identifier: Ident) -> 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

View File

@ -12,7 +12,7 @@
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<I>(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))

View File

@ -1283,7 +1283,7 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
});
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");
}

View File

@ -511,14 +511,13 @@ pub fn this_token_to_string(&self) -> String {
}
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<T>(&self, t: &token::Token) -> PResult<'a, T> {
@ -637,10 +636,12 @@ fn interpolated_or_expr_span(&self,
}
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 @@ pub fn expect_keyword(&mut self, kw: keywords::Keyword) -> PResult<'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 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
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 @@ pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
// 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 @@ fn is_catch_expr(&mut self) -> bool {
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 {

View File

@ -87,7 +87,7 @@ pub fn short_name(&self) -> &'static str {
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 @@ pub fn is_qpath_start(&self) -> bool {
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 @@ pub fn is_path_segment_keyword(&self) -> bool {
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 @@ pub fn is_strict_keyword(&self) -> bool {
}
/// 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)]

View File

@ -761,7 +761,7 @@ fn print_attribute_inline(&mut self, attr: &ast::Attribute,
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 @@ fn print_path_segment(&mut self,
-> 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)?;

View File

@ -237,76 +237,76 @@ fn fresh() -> Self {
// 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.

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
fn macro() { //~ ERROR `macro` is a reserved keyword
fn macro() { //~ ERROR expected identifier, found reserved keyword `macro`
}
pub fn main() {