]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #48917 - petrochenkov:import, r=oli-obk
authorbors <bors@rust-lang.org>
Sun, 18 Mar 2018 01:50:52 +0000 (01:50 +0000)
committerbors <bors@rust-lang.org>
Sun, 18 Mar 2018 01:50:52 +0000 (01:50 +0000)
syntax: Make imports in AST closer to the source and cleanup their parsing

This is a continuation of https://github.com/rust-lang/rust/pull/45846 in some sense.

28 files changed:
src/libproc_macro/lib.rs
src/librustc/hir/mod.rs
src/librustc/ich/impls_syntax.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_metadata/decoder.rs
src/librustc_passes/ast_validation.rs
src/librustc_trans/lib.rs
src/librustc_trans_utils/trans_crate.rs
src/librustdoc/html/highlight.rs
src/libsyntax/diagnostics/plugin.rs
src/libsyntax/ext/quote.rs
src/libsyntax/ext/tt/macro_parser.rs
src/libsyntax/feature_gate.rs
src/libsyntax/parse/lexer/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax_ext/env.rs
src/libsyntax_pos/symbol.rs
src/test/parse-fail/issue-32501.rs
src/test/parse-fail/recover-enum2.rs
src/test/parse-fail/underscore-suffix-for-float.rs
src/test/run-make/hotplug_codegen_backend/the_backend.rs
src/test/ui/cross-file-errors/main.stderr
src/test/ui/underscore-ident-matcher.rs [new file with mode: 0644]
src/test/ui/underscore-ident-matcher.stderr [new file with mode: 0644]

index 1163c1a98d5acd3ae1ad68796f6ed1cfac850331..b239f8018bebb9207b22527fcb834efddf33c9e0 100644 (file)
@@ -680,7 +680,6 @@ fn joint(first: char, rest: Token, is_joint: bool, span: &mut syntax_pos::Span,
             Pound => op!('#'),
             Dollar => op!('$'),
             Question => op!('?'),
-            Underscore => op!('_'),
 
             Ident(ident) | Lifetime(ident) => TokenNode::Term(Term(ident.name)),
             Literal(..) | DocComment(..) => TokenNode::Literal(self::Literal(token)),
@@ -743,7 +742,6 @@ fn to_internal(self) -> tokenstream::TokenStream {
             '#' => Pound,
             '$' => Dollar,
             '?' => Question,
-            '_' => Underscore,
             _ => panic!("unsupported character {}", op),
         };
 
index 46c79d03149ef632eb977c792f6bfbe82582008a..5ae84f5685eafca61a09c0716dd2de7ff76d7a56 100644 (file)
@@ -214,7 +214,7 @@ pub fn name(&self) -> Name {
         use self::LifetimeName::*;
         match *self {
             Implicit => keywords::Invalid.name(),
-            Underscore => Symbol::intern("'_"),
+            Underscore => keywords::UnderscoreLifetime.name(),
             Static => keywords::StaticLifetime.name(),
             Name(name) => name,
         }
index 289bc753d7fecb7d938d50003509f5c3e9c9b570..513b6c835f982337cb3b9f72b85e9a473446eab2 100644 (file)
@@ -287,7 +287,6 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>(
         token::Token::Pound |
         token::Token::Dollar |
         token::Token::Question |
-        token::Token::Underscore |
         token::Token::Whitespace |
         token::Token::Comment |
         token::Token::Eof => {}
index ee372c0bc5d1636a4ac733fd67386398cbfd1c18..a0546b369a8ebba094105cdc45f61cbe485ee9b7 100644 (file)
@@ -14,7 +14,7 @@
 use locator::{self, CratePaths};
 use native_libs::relevant_lib;
 use schema::CrateRoot;
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{Lrc, RwLock, Lock};
 
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX};
 use rustc::hir::svh::Svh;
@@ -30,7 +30,6 @@
 use rustc::util::nodemap::FxHashSet;
 use rustc::hir::map::Definitions;
 
-use std::cell::{RefCell, Cell};
 use std::ops::Deref;
 use std::path::PathBuf;
 use std::{cmp, fs};
@@ -63,7 +62,7 @@ fn dump_crates(cstore: &CStore) {
         info!("  name: {}", data.name());
         info!("  cnum: {}", data.cnum);
         info!("  hash: {}", data.hash());
-        info!("  reqd: {:?}", data.dep_kind.get());
+        info!("  reqd: {:?}", *data.dep_kind.lock());
         let CrateSource { dylib, rlib, rmeta } = data.source.clone();
         dylib.map(|dl| info!("  dylib: {}", dl.0.display()));
         rlib.map(|rl|  info!("   rlib: {}", rl.0.display()));
@@ -233,7 +232,7 @@ fn register_crate(&mut self,
 
         let mut cmeta = cstore::CrateMetadata {
             name,
-            extern_crate: Cell::new(None),
+            extern_crate: Lock::new(None),
             def_path_table: Lrc::new(def_path_table),
             trait_impls,
             proc_macros: crate_root.macro_derive_registrar.map(|_| {
@@ -241,11 +240,11 @@ fn register_crate(&mut self,
             }),
             root: crate_root,
             blob: metadata,
-            cnum_map: RefCell::new(cnum_map),
+            cnum_map: Lock::new(cnum_map),
             cnum,
-            codemap_import_info: RefCell::new(vec![]),
-            attribute_cache: RefCell::new([Vec::new(), Vec::new()]),
-            dep_kind: Cell::new(dep_kind),
+            codemap_import_info: RwLock::new(vec![]),
+            attribute_cache: Lock::new([Vec::new(), Vec::new()]),
+            dep_kind: Lock::new(dep_kind),
             source: cstore::CrateSource {
                 dylib,
                 rlib,
@@ -335,7 +334,9 @@ fn resolve_crate(&mut self,
                 if data.root.macro_derive_registrar.is_some() {
                     dep_kind = DepKind::UnexportedMacrosOnly;
                 }
-                data.dep_kind.set(cmp::max(data.dep_kind.get(), dep_kind));
+                data.dep_kind.with_lock(|data_dep_kind| {
+                    *data_dep_kind = cmp::max(*data_dep_kind, dep_kind);
+                });
                 (cnum, data)
             }
             LoadResult::Loaded(library) => {
@@ -379,14 +380,14 @@ fn update_extern_crate(&mut self,
         if !visited.insert((cnum, extern_crate.direct)) { return }
 
         let cmeta = self.cstore.get_crate_data(cnum);
-        let old_extern_crate = cmeta.extern_crate.get();
+        let mut old_extern_crate = cmeta.extern_crate.borrow_mut();
 
         // Prefer:
         // - something over nothing (tuple.0);
         // - direct extern crate to indirect (tuple.1);
         // - shorter paths to longer (tuple.2).
         let new_rank = (true, extern_crate.direct, !extern_crate.path_len);
-        let old_rank = match old_extern_crate {
+        let old_rank = match *old_extern_crate {
             None => (false, false, !0),
             Some(ref c) => (true, c.direct, !c.path_len),
         };
@@ -395,7 +396,9 @@ fn update_extern_crate(&mut self,
             return; // no change needed
         }
 
-        cmeta.extern_crate.set(Some(extern_crate));
+        *old_extern_crate = Some(extern_crate);
+        drop(old_extern_crate);
+
         // Propagate the extern crate info to dependencies.
         extern_crate.direct = false;
         for &dep_cnum in cmeta.cnum_map.borrow().iter() {
@@ -646,7 +649,7 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
                 // #![panic_runtime] crate.
                 self.inject_dependency_if(cnum, "a panic runtime",
                                           &|data| data.needs_panic_runtime(sess));
-                runtime_found = runtime_found || data.dep_kind.get() == DepKind::Explicit;
+                runtime_found = runtime_found || *data.dep_kind.lock() == DepKind::Explicit;
             }
         });
 
index 202efb9276a81e0f8071e1b9915cee8fcc30080c..bd5ad93946e3cf9a10f9531fb423af50942cbc4a 100644 (file)
@@ -22,8 +22,7 @@
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc::util::nodemap::{FxHashMap, FxHashSet, NodeMap};
 
-use std::cell::{RefCell, Cell};
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{Lrc, RwLock, Lock};
 use syntax::{ast, attr};
 use syntax::ext::base::SyntaxExtension;
 use syntax::symbol::Symbol;
@@ -62,13 +61,13 @@ pub struct CrateMetadata {
     /// Information about the extern crate that caused this crate to
     /// be loaded. If this is `None`, then the crate was injected
     /// (e.g., by the allocator)
-    pub extern_crate: Cell<Option<ExternCrate>>,
+    pub extern_crate: Lock<Option<ExternCrate>>,
 
     pub blob: MetadataBlob,
-    pub cnum_map: RefCell<CrateNumMap>,
+    pub cnum_map: Lock<CrateNumMap>,
     pub cnum: CrateNum,
-    pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
-    pub attribute_cache: RefCell<[Vec<Option<Lrc<[ast::Attribute]>>>; 2]>,
+    pub codemap_import_info: RwLock<Vec<ImportedFileMap>>,
+    pub attribute_cache: Lock<[Vec<Option<Lrc<[ast::Attribute]>>>; 2]>,
 
     pub root: schema::CrateRoot,
 
@@ -81,7 +80,7 @@ pub struct CrateMetadata {
 
     pub trait_impls: FxHashMap<(u32, DefIndex), schema::LazySeq<DefIndex>>,
 
-    pub dep_kind: Cell<DepKind>,
+    pub dep_kind: Lock<DepKind>,
     pub source: CrateSource,
 
     pub proc_macros: Option<Vec<(ast::Name, Lrc<SyntaxExtension>)>>,
@@ -90,21 +89,23 @@ pub struct CrateMetadata {
 }
 
 pub struct CStore {
-    metas: RefCell<IndexVec<CrateNum, Option<Lrc<CrateMetadata>>>>,
+    metas: RwLock<IndexVec<CrateNum, Option<Lrc<CrateMetadata>>>>,
     /// Map from NodeId's of local extern crate statements to crate numbers
-    extern_mod_crate_map: RefCell<NodeMap<CrateNum>>,
-    pub metadata_loader: Box<MetadataLoader>,
+    extern_mod_crate_map: Lock<NodeMap<CrateNum>>,
+    pub metadata_loader: Box<MetadataLoader + Sync>,
 }
 
 impl CStore {
-    pub fn new(metadata_loader: Box<MetadataLoader>) -> CStore {
+    pub fn new(metadata_loader: Box<MetadataLoader + Sync>) -> CStore {
         CStore {
-            metas: RefCell::new(IndexVec::new()),
-            extern_mod_crate_map: RefCell::new(FxHashMap()),
+            metas: RwLock::new(IndexVec::new()),
+            extern_mod_crate_map: Lock::new(FxHashMap()),
             metadata_loader,
         }
     }
 
+    /// You cannot use this function to allocate a CrateNum in a thread-safe manner.
+    /// It is currently only used in CrateLoader which is single-threaded code.
     pub fn next_crate_num(&self) -> CrateNum {
         CrateNum::new(self.metas.borrow().len() + 1)
     }
index 30ff03a26538b2fa13a5d01170729c10875e5542..2de27f3a1c3eac510b32a74ba637cfaf92528185 100644 (file)
@@ -175,7 +175,10 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
     is_sanitizer_runtime => { cdata.is_sanitizer_runtime(tcx.sess) }
     is_profiler_runtime => { cdata.is_profiler_runtime(tcx.sess) }
     panic_strategy => { cdata.panic_strategy() }
-    extern_crate => { Lrc::new(cdata.extern_crate.get()) }
+    extern_crate => {
+        let r = Lrc::new(*cdata.extern_crate.lock());
+        r
+    }
     is_no_builtins => { cdata.is_no_builtins(tcx.sess) }
     impl_defaultness => { cdata.get_impl_defaultness(def_id.index) }
     reachable_non_generics => {
@@ -225,7 +228,10 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
         cdata.is_dllimport_foreign_item(def_id.index)
     }
     visibility => { cdata.get_visibility(def_id.index) }
-    dep_kind => { cdata.dep_kind.get() }
+    dep_kind => {
+        let r = *cdata.dep_kind.lock();
+        r
+    }
     crate_name => { cdata.name }
     item_children => {
         let mut result = vec![];
@@ -241,10 +247,11 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
     }
 
     missing_extern_crate_item => {
-        match cdata.extern_crate.get() {
+        let r = match *cdata.extern_crate.borrow() {
             Some(extern_crate) if !extern_crate.direct => true,
             _ => false,
-        }
+        };
+        r
     }
 
     used_crate_source => { Lrc::new(cdata.source.clone()) }
@@ -419,13 +426,16 @@ fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem
 
     fn dep_kind_untracked(&self, cnum: CrateNum) -> DepKind
     {
-        self.get_crate_data(cnum).dep_kind.get()
+        let data = self.get_crate_data(cnum);
+        let r = *data.dep_kind.lock();
+        r
     }
 
     fn export_macros_untracked(&self, cnum: CrateNum) {
         let data = self.get_crate_data(cnum);
-        if data.dep_kind.get() == DepKind::UnexportedMacrosOnly {
-            data.dep_kind.set(DepKind::MacrosOnly)
+        let mut dep_kind = data.dep_kind.lock();
+        if *dep_kind == DepKind::UnexportedMacrosOnly {
+            *dep_kind = DepKind::MacrosOnly;
         }
     }
 
index f44703b9335e20e360c71e02414e0ddbc976e61a..d83d6f26393d1ef2efde82e2dc1d68adf60c1c9a 100644 (file)
@@ -13,7 +13,7 @@
 use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary};
 use schema::*;
 
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{Lrc, ReadGuard};
 use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
 use rustc::hir;
 use rustc::middle::cstore::{LinkagePreference, ExternConstBody,
@@ -31,7 +31,6 @@
 use rustc::mir::Mir;
 use rustc::util::nodemap::FxHashMap;
 
-use std::cell::Ref;
 use std::collections::BTreeMap;
 use std::io;
 use std::mem;
@@ -714,7 +713,7 @@ pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Sessio
         };
 
         // Iterate over all children.
-        let macros_only = self.dep_kind.get().macros_only();
+        let macros_only = self.dep_kind.lock().macros_only();
         for child_index in item.children.decode((self, sess)) {
             if macros_only {
                 continue
@@ -950,6 +949,8 @@ pub fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Lrc<[ast::Att
         if vec_.len() < node_index + 1 {
             vec_.resize(node_index + 1, None);
         }
+        // This can overwrite the result produced by another thread, but the value
+        // written should be the same
         vec_[node_index] = Some(result.clone());
         result
     }
@@ -1156,7 +1157,7 @@ pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
     /// for items inlined from other crates.
     pub fn imported_filemaps(&'a self,
                              local_codemap: &codemap::CodeMap)
-                             -> Ref<'a, Vec<cstore::ImportedFileMap>> {
+                             -> ReadGuard<'a, Vec<cstore::ImportedFileMap>> {
         {
             let filemaps = self.codemap_import_info.borrow();
             if !filemaps.is_empty() {
@@ -1164,6 +1165,14 @@ pub fn imported_filemaps(&'a self,
             }
         }
 
+        // Lock the codemap_import_info to ensure this only happens once
+        let mut codemap_import_info = self.codemap_import_info.borrow_mut();
+
+        if !codemap_import_info.is_empty() {
+            drop(codemap_import_info);
+            return self.codemap_import_info.borrow();
+        }
+
         let external_codemap = self.root.codemap.decode(self);
 
         let imported_filemaps = external_codemap.map(|filemap_to_import| {
@@ -1222,8 +1231,10 @@ pub fn imported_filemaps(&'a self,
             }
         }).collect();
 
+        *codemap_import_info = imported_filemaps;
+        drop(codemap_import_info);
+
         // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref.
-        *self.codemap_import_info.borrow_mut() = imported_filemaps;
         self.codemap_import_info.borrow()
     }
 }
index 55d00f92e4dac0b1d235fa3bb9f72b6996e5a927..4215bf306a4fd9306ea3f0e89bbcc45054d1e6ad 100644 (file)
@@ -37,7 +37,9 @@ fn err_handler(&self) -> &errors::Handler {
     }
 
     fn check_lifetime(&self, lifetime: &Lifetime) {
-        let valid_names = [keywords::StaticLifetime.name(), keywords::Invalid.name()];
+        let valid_names = [keywords::UnderscoreLifetime.name(),
+                           keywords::StaticLifetime.name(),
+                           keywords::Invalid.name()];
         if !valid_names.contains(&lifetime.ident.name) &&
             token::Ident(lifetime.ident.without_first_quote()).is_reserved_ident() {
             self.err_handler().span_err(lifetime.span, "lifetimes cannot use keyword names");
@@ -45,7 +47,7 @@ fn check_lifetime(&self, lifetime: &Lifetime) {
     }
 
     fn check_label(&self, label: Ident, span: Span) {
-        if token::Ident(label.without_first_quote()).is_reserved_ident() || label.name == "'_" {
+        if token::Ident(label.without_first_quote()).is_reserved_ident() {
             self.err_handler().span_err(span, &format!("invalid label name `{}`", label.name));
         }
     }
index 0a98f74212d69e59281e35762a081a58f9372db8..3645e7288420873bdd48ca27db0f4ed69a46cf09 100644 (file)
@@ -201,7 +201,7 @@ fn target_features(&self, sess: &Session) -> Vec<Symbol> {
         target_features(sess)
     }
 
-    fn metadata_loader(&self) -> Box<MetadataLoader> {
+    fn metadata_loader(&self) -> Box<MetadataLoader + Sync> {
         box metadata::LlvmMetadataLoader
     }
 
index 0d4811c4b025dfd05c14eeaf3a9b5ac93f6ed70f..5cf9819288b5ef7628c1a8b670c05f979aa37b10 100644 (file)
@@ -58,7 +58,7 @@ fn print_passes(&self) {}
     fn print_version(&self) {}
     fn diagnostics(&self) -> &[(&'static str, &'static str)] { &[] }
 
-    fn metadata_loader(&self) -> Box<MetadataLoader>;
+    fn metadata_loader(&self) -> Box<MetadataLoader + Sync>;
     fn provide(&self, _providers: &mut Providers);
     fn provide_extern(&self, _providers: &mut Providers);
     fn trans_crate<'a, 'tcx>(
@@ -84,7 +84,7 @@ fn join_trans_and_link(
 pub struct DummyTransCrate;
 
 impl TransCrate for DummyTransCrate {
-    fn metadata_loader(&self) -> Box<MetadataLoader> {
+    fn metadata_loader(&self) -> Box<MetadataLoader + Sync> {
         box DummyMetadataLoader(())
     }
 
@@ -195,7 +195,7 @@ fn init(&self, sess: &Session) {
         }
     }
 
-    fn metadata_loader(&self) -> Box<MetadataLoader> {
+    fn metadata_loader(&self) -> Box<MetadataLoader + Sync> {
         box NoLlvmMetadataLoader
     }
 
index ef01c3e6bdb0c224b69168552082b069a3e00f36..659ec8a993dc8e3f60e5b3ea6db95f11e38b5c87 100644 (file)
@@ -352,7 +352,7 @@ fn write_token<W: Writer>(&mut self,
 
             token::Lifetime(..) => Class::Lifetime,
 
-            token::Underscore | token::Eof | token::Interpolated(..) |
+            token::Eof | token::Interpolated(..) |
             token::Tilde | token::At | token::DotEq => Class::None,
         };
 
index 97cb6b492d73a7b5557e5c37e6412cbd8c950b9d..2c91844da96d70ecec36f6b9aa113ec102ad37a5 100644 (file)
@@ -19,7 +19,7 @@
 use ext::build::AstBuilder;
 use parse::token;
 use ptr::P;
-use symbol::Symbol;
+use symbol::{keywords, Symbol};
 use tokenstream::{TokenTree};
 use util::small_vector::SmallVector;
 
@@ -192,7 +192,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt,
             (descriptions.len(), ecx.expr_vec(span, descriptions))
         });
 
-    let static_ = ecx.lifetime(span, Ident::from_str("'static"));
+    let static_ = ecx.lifetime(span, keywords::StaticLifetime.ident());
     let ty_str = ecx.ty_rptr(
         span,
         ecx.ty_ident(span, ecx.ident_of("str")),
index b322fd9df3ec03f7e4e04b2f6c2c1b57df5b2c0d..6844532e7b375ece36530f74a3d9c56dfb85e9ef 100644 (file)
@@ -709,7 +709,6 @@ macro_rules! mk_lit {
         token::Pound        => "Pound",
         token::Dollar       => "Dollar",
         token::Question     => "Question",
-        token::Underscore   => "Underscore",
         token::Eof          => "Eof",
 
         token::Whitespace | token::Comment | token::Shebang(_) => {
index 0621f728e2a9d0fa6a33988977c9e618c9a63959..667653b5f7f26686f62a9f245ee65a053b86bd52 100644 (file)
@@ -86,7 +86,7 @@
 
 use ast::Ident;
 use syntax_pos::{self, BytePos, Span};
-use codemap::Spanned;
+use codemap::respan;
 use errors::FatalError;
 use ext::tt::quoted::{self, TokenTree};
 use parse::{Directory, ParseSess};
@@ -709,6 +709,15 @@ pub fn parse(
     }
 }
 
+/// The token is an identifier, but not `_`.
+/// We prohibit passing `_` to macros expecting `ident` for now.
+fn get_macro_ident(token: &Token) -> Option<Ident> {
+    match *token {
+        token::Ident(ident) if ident.name != keywords::Underscore.name() => Some(ident),
+        _ => None,
+    }
+}
+
 /// Checks whether a non-terminal may begin with a particular token.
 ///
 /// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with that
@@ -725,7 +734,7 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
     match name {
         "expr" => token.can_begin_expr(),
         "ty" => token.can_begin_type(),
-        "ident" => token.is_ident(),
+        "ident" => get_macro_ident(token).is_some(),
         "vis" => match *token {
             // The follow-set of :vis + "priv" keyword + interpolated
             Token::Comma | Token::Ident(_) | Token::Interpolated(_) => true,
@@ -765,8 +774,7 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
             Token::DotDotDot |                  // range pattern (future compat)
             Token::ModSep |                     // path
             Token::Lt |                         // path (UFCS constant)
-            Token::BinOp(token::Shl) |          // path (double UFCS)
-            Token::Underscore => true,          // placeholder
+            Token::BinOp(token::Shl) => true,   // path (double UFCS)
             Token::Interpolated(ref nt) => may_be_ident(&nt.0),
             _ => false,
         },
@@ -815,21 +823,14 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
         "expr" => token::NtExpr(panictry!(p.parse_expr())),
         "ty" => token::NtTy(panictry!(p.parse_ty())),
         // this could be handled like a token, since it is one
-        "ident" => match p.token {
-            token::Ident(sn) => {
-                p.bump();
-                token::NtIdent(Spanned::<Ident> {
-                    node: sn,
-                    span: p.prev_span,
-                })
-            }
-            _ => {
-                let token_str = pprust::token_to_string(&p.token);
-                p.fatal(&format!("expected ident, found {}", &token_str[..]))
-                    .emit();
-                FatalError.raise()
-            }
-        },
+        "ident" => if let Some(ident) = get_macro_ident(&p.token) {
+            p.bump();
+            token::NtIdent(respan(p.prev_span, ident))
+        } else {
+            let token_str = pprust::token_to_string(&p.token);
+            p.fatal(&format!("expected ident, found {}", &token_str)).emit();
+            FatalError.raise()
+        }
         "path" => token::NtPath(panictry!(p.parse_path_common(PathStyle::Type, false))),
         "meta" => token::NtMeta(panictry!(p.parse_meta_item())),
         "vis" => token::NtVis(panictry!(p.parse_visibility(true))),
index 0aef5045341835c01e36db6296a4313bd3c94c42..a5af8564057f61cfbb1b71a077e649f593c6f3d4 100644 (file)
@@ -1790,7 +1790,7 @@ fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
     }
 
     fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {
-        if lt.ident.name == "'_" {
+        if lt.ident.name == keywords::UnderscoreLifetime.name() {
             gate_feature_post!(&self, underscore_lifetimes, lt.span,
                                "underscore lifetimes are unstable");
         }
index 5b8887f3536e800d95a8eb653413719e029b011c..0e20eb49d395ed213211ff0a02ce52be7ee3e748 100644 (file)
@@ -34,7 +34,7 @@ pub struct TokenAndSpan {
 
 impl Default for TokenAndSpan {
     fn default() -> Self {
-        TokenAndSpan { tok: token::Underscore, sp: syntax_pos::DUMMY_SP }
+        TokenAndSpan { tok: token::Whitespace, sp: syntax_pos::DUMMY_SP }
     }
 }
 
@@ -126,7 +126,7 @@ fn is_eof(&self) -> bool {
     pub fn try_next_token(&mut self) -> Result<TokenAndSpan, ()> {
         assert!(self.fatal_errs.is_empty());
         let ret_val = TokenAndSpan {
-            tok: replace(&mut self.peek_tok, token::Underscore),
+            tok: replace(&mut self.peek_tok, token::Whitespace),
             sp: self.peek_span,
         };
         self.advance_token()?;
@@ -1133,14 +1133,8 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                 self.bump();
             }
 
-            return Ok(self.with_str_from(start, |string| {
-                if string == "_" {
-                    token::Underscore
-                } else {
-                    // FIXME: perform NFKC normalization here. (Issue #2253)
-                    token::Ident(self.mk_ident(string))
-                }
-            }));
+            // FIXME: perform NFKC normalization here. (Issue #2253)
+            return Ok(self.with_str_from(start, |string| token::Ident(self.mk_ident(string))));
         }
 
         if is_dec_digit(c) {
index f1967ebf590d60f19f8f1f4e800ece76ce3a46f7..cb5010a638df4f67b899c06b824009c326d60415 100644 (file)
@@ -549,7 +549,7 @@ pub fn new(sess: &'a ParseSess,
                -> Self {
         let mut parser = Parser {
             sess,
-            token: token::Underscore,
+            token: token::Whitespace,
             span: syntax_pos::DUMMY_SP,
             prev_span: syntax_pos::DUMMY_SP,
             meta_var_span: None,
@@ -800,11 +800,7 @@ fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> {
                 Err(if self.prev_token_kind == PrevTokenKind::DocComment {
                         self.span_fatal_err(self.prev_span, Error::UselessDocComment)
                     } else {
-                        let mut err = self.expected_ident_found();
-                        if self.token == token::Underscore {
-                            err.note("`_` is a wildcard pattern, not an identifier");
-                        }
-                        err
+                        self.expected_ident_found()
                     })
             }
         }
@@ -1602,7 +1598,7 @@ fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool)
             let e = self.parse_expr()?;
             self.expect(&token::CloseDelim(token::Paren))?;
             TyKind::Typeof(e)
-        } else if self.eat(&token::Underscore) {
+        } else if self.eat_keyword(keywords::Underscore) {
             // A type to be inferred `_`
             TyKind::Infer
         } else if self.token_is_bare_fn_keyword() {
@@ -1796,7 +1792,7 @@ fn is_named_argument(&mut self) -> bool {
             _ => 0,
         };
 
-        self.look_ahead(offset, |t| t.is_ident() || t == &token::Underscore) &&
+        self.look_ahead(offset, |t| t.is_ident()) &&
         self.look_ahead(offset + 1, |t| t == &token::Colon)
     }
 
@@ -2782,7 +2778,7 @@ pub fn parse_token_tree(&mut self) -> TokenTree {
             },
             token::CloseDelim(_) | token::Eof => unreachable!(),
             _ => {
-                let (token, span) = (mem::replace(&mut self.token, token::Underscore), self.span);
+                let (token, span) = (mem::replace(&mut self.token, token::Whitespace), self.span);
                 self.bump();
                 TokenTree::Token(span, token)
             }
@@ -3815,11 +3811,6 @@ fn parse_pat_with_range_pat(&mut self, allow_range_pat: bool) -> PResult<'a, P<P
         let lo = self.span;
         let pat;
         match self.token {
-            token::Underscore => {
-                // Parse _
-                self.bump();
-                pat = PatKind::Wild;
-            }
             token::BinOp(token::And) | token::AndAnd => {
                 // Parse &pat / &mut pat
                 self.expect_and()?;
@@ -3849,8 +3840,11 @@ fn parse_pat_with_range_pat(&mut self, allow_range_pat: bool) -> PResult<'a, P<P
                 self.expect(&token::CloseDelim(token::Bracket))?;
                 pat = PatKind::Slice(before, slice, after);
             }
-            // At this point, token != _, &, &&, (, [
-            _ => if self.eat_keyword(keywords::Mut) {
+            // At this point, token != &, &&, (, [
+            _ => if self.eat_keyword(keywords::Underscore) {
+                // Parse _
+                pat = PatKind::Wild;
+            } else if self.eat_keyword(keywords::Mut) {
                 // Parse mut ident @ pat / mut ref ident @ pat
                 let mutref_span = self.prev_span.to(self.span);
                 let binding_mode = if self.eat_keyword(keywords::Ref) {
@@ -7021,10 +7015,12 @@ fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> {
 
     fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
         if self.eat_keyword(keywords::As) {
-            if self.eat(&token::Underscore) {
-                Ok(Some(Ident::with_empty_ctxt(Symbol::gensym("_"))))
-            } else {
-                self.parse_ident().map(Some)
+            match self.token {
+                token::Ident(ident) if ident.name == keywords::Underscore.name() => {
+                    self.bump(); // `_`
+                    Ok(Some(Ident { name: ident.name.gensymed(), ..ident }))
+                }
+                _ => self.parse_ident().map(Some),
             }
         } else {
             Ok(None)
index 3c602f1d1a800c07b476ebb4c43d67c6577cccbf..4ada9e20f2cc0db63af93a20cf04bdf6be3e9856 100644 (file)
@@ -122,6 +122,7 @@ fn ident_can_begin_type(ident: ast::Ident) -> bool {
     !ident_token.is_reserved_ident() ||
     ident_token.is_path_segment_keyword() ||
     [
+        keywords::Underscore.name(),
         keywords::For.name(),
         keywords::Impl.name(),
         keywords::Fn.name(),
@@ -175,7 +176,6 @@ pub enum Token {
 
     /* Name components */
     Ident(ast::Ident),
-    Underscore,
     Lifetime(ast::Ident),
 
     // The `LazyTokenStream` is a pure function of the `Nonterminal`,
@@ -242,7 +242,6 @@ pub fn can_begin_type(&self) -> bool {
             Ident(ident)                => ident_can_begin_type(ident), // type name or keyword
             OpenDelim(Paren)            | // tuple
             OpenDelim(Bracket)          | // array
-            Underscore                  | // placeholder
             Not                         | // never
             BinOp(Star)                 | // raw pointer
             BinOp(And)                  | // reference
@@ -372,7 +371,7 @@ pub fn is_path_segment_keyword(&self) -> bool {
     // 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(),
+            Some(id) => id.name <= keywords::Underscore.name(),
             _ => false,
         }
     }
@@ -442,7 +441,7 @@ pub fn glue(self, joint: Token) -> Option<Token> {
 
             Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotEq |
             DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar |
-            Question | OpenDelim(..) | CloseDelim(..) | Underscore => return None,
+            Question | OpenDelim(..) | CloseDelim(..) => return None,
 
             Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) |
             Whitespace | Comment | Shebang(..) | Eof => return None,
@@ -574,7 +573,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 pub fn is_op(tok: &Token) -> bool {
     match *tok {
         OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) |
-        Ident(..) | Underscore | Lifetime(..) | Interpolated(..) |
+        Ident(..) | Lifetime(..) | Interpolated(..) |
         Whitespace | Comment | Shebang(..) | Eof => false,
         _ => true,
     }
index e6ed6d7b84ab3315c1d2e15b2825b63a7a7c38c9..7adb2848f8d94fae5f43842e0b3693f293bb56db 100644 (file)
@@ -252,7 +252,6 @@ pub fn token_to_string(tok: &Token) -> String {
         /* Name components */
         token::Ident(s)             => s.to_string(),
         token::Lifetime(s)          => s.to_string(),
-        token::Underscore           => "_".to_string(),
 
         /* Other */
         token::DocComment(s)        => s.to_string(),
index fcad065be52bcaf1868a5594dc95e1ea5d89fea5..ba6d25f7a60a4bf8647d0f22608cec67ba868b3d 100644 (file)
@@ -17,7 +17,7 @@
 use syntax::ext::base::*;
 use syntax::ext::base;
 use syntax::ext::build::AstBuilder;
-use syntax::symbol::Symbol;
+use syntax::symbol::{keywords, Symbol};
 use syntax_pos::Span;
 use syntax::tokenstream;
 
@@ -35,14 +35,14 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt,
     let sp = sp.with_ctxt(sp.ctxt().apply_mark(cx.current_expansion.mark));
     let e = match env::var(&*var.as_str()) {
         Err(..) => {
+            let lt = cx.lifetime(sp, keywords::StaticLifetime.ident());
             cx.expr_path(cx.path_all(sp,
                                      true,
                                      cx.std_path(&["option", "Option", "None"]),
                                      Vec::new(),
                                      vec![cx.ty_rptr(sp,
                                                      cx.ty_ident(sp, Ident::from_str("str")),
-                                                     Some(cx.lifetime(sp,
-                                                                      Ident::from_str("'static"))),
+                                                     Some(lt),
                                                      ast::Mutability::Immutable)],
                                      Vec::new()))
         }
index e95079f7c88dd412db2455fa1a0bbe4b81bdd398..0cba094da641d234b6d7bbcd8c61614714a2a02e 100644 (file)
@@ -261,73 +261,77 @@ pub fn fresh() -> Self {
 declare_keywords! {
     // 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")
+    (0,  Invalid,            "")
+    (1,  CrateRoot,          "{{root}}")
+    (2,  DollarCrate,        "$crate")
+    (3,  Underscore,         "_")
 
     // 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")
+    (4,  As,                 "as")
+    (5,  Box,                "box")
+    (6,  Break,              "break")
+    (7,  Const,              "const")
+    (8,  Continue,           "continue")
+    (9,  Crate,              "crate")
+    (10, Else,               "else")
+    (11, Enum,               "enum")
+    (12, Extern,             "extern")
+    (13, False,              "false")
+    (14, Fn,                 "fn")
+    (15, For,                "for")
+    (16, If,                 "if")
+    (17, Impl,               "impl")
+    (18, In,                 "in")
+    (19, Let,                "let")
+    (20, Loop,               "loop")
+    (21, Match,              "match")
+    (22, Mod,                "mod")
+    (23, Move,               "move")
+    (24, Mut,                "mut")
+    (25, Pub,                "pub")
+    (26, Ref,                "ref")
+    (27, Return,             "return")
+    (28, SelfValue,          "self")
+    (29, SelfType,           "Self")
+    (30, Static,             "static")
+    (31, Struct,             "struct")
+    (32, Super,              "super")
+    (33, Trait,              "trait")
+    (34, True,               "true")
+    (35, Type,               "type")
+    (36, Unsafe,             "unsafe")
+    (37, Use,                "use")
+    (38, Where,              "where")
+    (39, While,              "while")
 
     // Keywords reserved for future use.
-    (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")
+    (40, Abstract,           "abstract")
+    (41, Alignof,            "alignof")
+    (42, Become,             "become")
+    (43, Do,                 "do")
+    (44, Final,              "final")
+    (45, Macro,              "macro")
+    (46, Offsetof,           "offsetof")
+    (47, Override,           "override")
+    (48, Priv,               "priv")
+    (49, Proc,               "proc")
+    (50, Pure,               "pure")
+    (51, Sizeof,             "sizeof")
+    (52, Typeof,             "typeof")
+    (53, Unsized,            "unsized")
+    (54, Virtual,            "virtual")
+    (55, Yield,              "yield")
+
+    // Special lifetime names
+    (56, UnderscoreLifetime, "'_")
+    (57, StaticLifetime,     "'static")
 
     // Weak keywords, have special meaning only in specific contexts.
-    (55, Auto,           "auto")
-    (56, Catch,          "catch")
-    (57, Default,        "default")
-    (58, Dyn,            "dyn")
-    (59, StaticLifetime, "'static")
-    (60, Union,          "union")
+    (58, Auto,               "auto")
+    (59, Catch,              "catch")
+    (60, Default,            "default")
+    (61, Dyn,                "dyn")
+    (62, Union,              "union")
 }
 
 // If an interner exists, return it. Otherwise, prepare a fresh one.
index f29c1fa27940071dff6f6e2677ddbf0ce1ad5ae4..21db2f5051703dffd4c3582b3d874150bdc8da93 100644 (file)
@@ -16,7 +16,5 @@ fn main() {
     let _ = 0;
     let mut b = 0;
     let mut _b = 0;
-    let mut _ = 0; //~ ERROR expected identifier, found `_`
-    //~^ NOTE `_` is a wildcard pattern, not an identifier
-    //~| NOTE expected identifier
+    let mut _ = 0; //~ ERROR expected identifier, found reserved identifier `_`
 }
index 49380a03e156a27598ea472f49c64a4f897fe67a..6fd32f842f1353131e9b1e4913ffa9549d0512a1 100644 (file)
@@ -39,5 +39,5 @@ enum Test4 {
         }
     }
     // still recover later
-    let bad_syntax = _; //~ ERROR: found `_`
+    let bad_syntax = _; //~ ERROR: expected expression, found reserved identifier `_`
 }
index df7d9aa374dce948bd094241a51566c7693a9fd2..8327217e6f286bb3cf4c98b33669c05a8d5f50c1 100644 (file)
@@ -9,5 +9,6 @@
 // except according to those terms.
 
 fn main() {
-    let a = 42._; //~ ERROR unexpected token: `_`
+    let a = 42._; //~ ERROR expected identifier, found reserved identifier `_`
+                  //~^ ERROR `{integer}` is a primitive type and therefore doesn't have fields
 }
index 9e87268e6999da1ec81d5193fa093d19ab68776e..e266b0f5e834744e25371dd838a50844ccfd6147 100644 (file)
@@ -28,7 +28,7 @@
 struct TheBackend(Box<TransCrate>);
 
 impl TransCrate for TheBackend {
-    fn metadata_loader(&self) -> Box<MetadataLoader> {
+    fn metadata_loader(&self) -> Box<MetadataLoader + Sync> {
         self.0.metadata_loader()
     }
 
index a9db5214e6a2eabdc1c8a326373890bb6ef662f1..41a2172d2958024535d5e9e542e01f8e6305087b 100644 (file)
@@ -1,4 +1,4 @@
-error: expected expression, found `_`
+error: expected expression, found reserved identifier `_`
   --> $DIR/underscore.rs:18:9
    |
 LL |         _
diff --git a/src/test/ui/underscore-ident-matcher.rs b/src/test/ui/underscore-ident-matcher.rs
new file mode 100644 (file)
index 0000000..eee9929
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2018 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! identity {
+    ($i: ident) => (
+        $i
+    )
+}
+
+fn main() {
+    let identity!(_) = 10; //~ ERROR no rules expected the token `_`
+}
diff --git a/src/test/ui/underscore-ident-matcher.stderr b/src/test/ui/underscore-ident-matcher.stderr
new file mode 100644 (file)
index 0000000..7f2b6ac
--- /dev/null
@@ -0,0 +1,8 @@
+error: no rules expected the token `_`
+  --> $DIR/underscore-ident-matcher.rs:18:19
+   |
+LL |     let identity!(_) = 10; //~ ERROR no rules expected the token `_`
+   |                   ^
+
+error: aborting due to previous error
+