Auto merge of #37463 - jseyfried:refactor_macro_reexports, r=nrc
macros: improve reexports This PR - avoids building multiple module graphs for a crate that is referenced by multiple `extern crate` items, - registers `#[no_link] extern crate`s to avoid loading the same crate metadata twice, - stability checks `#[no_link] extern crate`s, - [breaking-chage]: `#[no_link] #[macro_use] extern crate syntax;` is allowed on stable today - fixes `$crate` in `#[macro_reexport]`ed macros, - [breaking-change] for `#[feature(macro_reexport)]` (technically) - allows selective macro importing (i.e. `#[macro_use(foo, bar)]`) from custom derive crates, and - refactors the crate metadata to support re-exported macros in arbitrary modules (not yet needed). r? @nrc
This commit is contained in:
commit
ab03f85522
24 changed files with 477 additions and 419 deletions
|
|
@ -52,6 +52,9 @@ pub enum Def {
|
|||
ast::NodeId), // expr node that creates the closure
|
||||
Label(ast::NodeId),
|
||||
|
||||
// Macro namespace
|
||||
Macro(DefId),
|
||||
|
||||
// Both namespaces
|
||||
Err,
|
||||
}
|
||||
|
|
@ -133,7 +136,7 @@ impl Def {
|
|||
Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) |
|
||||
Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
|
||||
Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
|
||||
Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) => {
|
||||
Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id) => {
|
||||
id
|
||||
}
|
||||
|
||||
|
|
@ -173,6 +176,7 @@ impl Def {
|
|||
Def::Upvar(..) => "closure capture",
|
||||
Def::Label(..) => "label",
|
||||
Def::SelfTy(..) => "self type",
|
||||
Def::Macro(..) => "macro",
|
||||
Def::Err => "unresolved item",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ impl Idx for CrateNum {
|
|||
/// LOCAL_CRATE in their DefId.
|
||||
pub const LOCAL_CRATE: CrateNum = CrateNum(0);
|
||||
|
||||
/// Virtual crate for builtin macros
|
||||
// FIXME(jseyfried): this is also used for custom derives until proc-macro crates get `CrateNum`s.
|
||||
pub const BUILTIN_MACROS_CRATE: CrateNum = CrateNum(!0);
|
||||
|
||||
impl CrateNum {
|
||||
pub fn new(x: usize) -> CrateNum {
|
||||
assert!(x < (u32::MAX as usize));
|
||||
|
|
|
|||
|
|
@ -226,4 +226,8 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
|
|||
fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
|
||||
self.insert(lifetime.id, NodeLifetime(lifetime));
|
||||
}
|
||||
|
||||
fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) {
|
||||
self.insert_entry(macro_def.id, NotPresent);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,18 @@ pub struct LinkMeta {
|
|||
pub struct CrateSource {
|
||||
pub dylib: Option<(PathBuf, PathKind)>,
|
||||
pub rlib: Option<(PathBuf, PathKind)>,
|
||||
pub cnum: CrateNum,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
|
||||
pub enum DepKind {
|
||||
/// A dependency that is only used for its macros.
|
||||
MacrosOnly,
|
||||
/// A dependency that is always injected into the dependency list and so
|
||||
/// doesn't need to be linked to an rlib, e.g. the injected allocator.
|
||||
Implicit,
|
||||
/// A dependency that is required by an rlib version of this crate.
|
||||
/// Ordinary `extern crate`s result in `Explicit` dependencies.
|
||||
Explicit,
|
||||
}
|
||||
|
||||
#[derive(Copy, Debug, PartialEq, Clone, RustcEncodable, RustcDecodable)]
|
||||
|
|
@ -170,10 +181,10 @@ pub trait CrateStore<'tcx> {
|
|||
// crate metadata
|
||||
fn dylib_dependency_formats(&self, cnum: CrateNum)
|
||||
-> Vec<(CrateNum, LinkagePreference)>;
|
||||
fn dep_kind(&self, cnum: CrateNum) -> DepKind;
|
||||
fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>;
|
||||
fn missing_lang_items(&self, cnum: CrateNum) -> Vec<lang_items::LangItem>;
|
||||
fn is_staged_api(&self, cnum: CrateNum) -> bool;
|
||||
fn is_explicitly_linked(&self, cnum: CrateNum) -> bool;
|
||||
fn is_allocator(&self, cnum: CrateNum) -> bool;
|
||||
fn is_panic_runtime(&self, cnum: CrateNum) -> bool;
|
||||
fn is_compiler_builtins(&self, cnum: CrateNum) -> bool;
|
||||
|
|
@ -200,6 +211,7 @@ pub trait CrateStore<'tcx> {
|
|||
fn relative_def_path(&self, def: DefId) -> Option<hir_map::DefPath>;
|
||||
fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>;
|
||||
fn item_children(&self, did: DefId) -> Vec<def::Export>;
|
||||
fn load_macro(&self, did: DefId, sess: &Session) -> ast::MacroDef;
|
||||
|
||||
// misc. metadata
|
||||
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
|
||||
|
|
@ -342,7 +354,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
|
|||
fn missing_lang_items(&self, cnum: CrateNum) -> Vec<lang_items::LangItem>
|
||||
{ bug!("missing_lang_items") }
|
||||
fn is_staged_api(&self, cnum: CrateNum) -> bool { bug!("is_staged_api") }
|
||||
fn is_explicitly_linked(&self, cnum: CrateNum) -> bool { bug!("is_explicitly_linked") }
|
||||
fn dep_kind(&self, cnum: CrateNum) -> DepKind { bug!("is_explicitly_linked") }
|
||||
fn is_allocator(&self, cnum: CrateNum) -> bool { bug!("is_allocator") }
|
||||
fn is_panic_runtime(&self, cnum: CrateNum) -> bool { bug!("is_panic_runtime") }
|
||||
fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { bug!("is_compiler_builtins") }
|
||||
|
|
@ -371,6 +383,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
|
|||
}
|
||||
fn struct_field_names(&self, def: DefId) -> Vec<ast::Name> { bug!("struct_field_names") }
|
||||
fn item_children(&self, did: DefId) -> Vec<def::Export> { bug!("item_children") }
|
||||
fn load_macro(&self, did: DefId, sess: &Session) -> ast::MacroDef { bug!("load_macro") }
|
||||
|
||||
// misc. metadata
|
||||
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
|
||||
|
|
@ -410,22 +423,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
|
|||
fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") }
|
||||
}
|
||||
|
||||
pub enum LoadedMacros {
|
||||
MacroRules(Vec<ast::MacroDef>),
|
||||
ProcMacros(Vec<(ast::Name, SyntaxExtension)>),
|
||||
}
|
||||
|
||||
impl LoadedMacros {
|
||||
pub fn is_proc_macros(&self) -> bool {
|
||||
match *self {
|
||||
LoadedMacros::ProcMacros(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CrateLoader {
|
||||
fn process_item(&mut self, item: &ast::Item, defs: &Definitions, load_macros: bool)
|
||||
-> Option<LoadedMacros>;
|
||||
-> Vec<(ast::Name, SyntaxExtension)>;
|
||||
fn postprocess(&mut self, krate: &ast::Crate);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ use hir::def_id::CrateNum;
|
|||
|
||||
use session;
|
||||
use session::config;
|
||||
use middle::cstore::DepKind;
|
||||
use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic};
|
||||
use util::nodemap::FxHashMap;
|
||||
use rustc_back::PanicStrategy;
|
||||
|
|
@ -123,6 +124,7 @@ fn calculate_type(sess: &session::Session,
|
|||
return v;
|
||||
}
|
||||
for cnum in sess.cstore.crates() {
|
||||
if sess.cstore.dep_kind(cnum) == DepKind::MacrosOnly { continue }
|
||||
let src = sess.cstore.used_crate_source(cnum);
|
||||
if src.rlib.is_some() { continue }
|
||||
sess.err(&format!("dependency `{}` not found in rlib format",
|
||||
|
|
@ -155,6 +157,7 @@ fn calculate_type(sess: &session::Session,
|
|||
// dependencies, ensuring there are no conflicts. The only valid case for a
|
||||
// dependency to be relied upon twice is for both cases to rely on a dylib.
|
||||
for cnum in sess.cstore.crates() {
|
||||
if sess.cstore.dep_kind(cnum) == DepKind::MacrosOnly { continue }
|
||||
let name = sess.cstore.crate_name(cnum);
|
||||
let src = sess.cstore.used_crate_source(cnum);
|
||||
if src.dylib.is_some() {
|
||||
|
|
@ -188,7 +191,7 @@ fn calculate_type(sess: &session::Session,
|
|||
let src = sess.cstore.used_crate_source(cnum);
|
||||
if src.dylib.is_none() &&
|
||||
!formats.contains_key(&cnum) &&
|
||||
sess.cstore.is_explicitly_linked(cnum) {
|
||||
sess.cstore.dep_kind(cnum) == DepKind::Explicit {
|
||||
assert!(src.rlib.is_some());
|
||||
info!("adding staticlib: {}", sess.cstore.crate_name(cnum));
|
||||
add_library(sess, cnum, RequireStatic, &mut formats);
|
||||
|
|
@ -272,7 +275,7 @@ fn attempt_static(sess: &session::Session) -> Option<DependencyList> {
|
|||
// everything in explicitly so long as it's actually required.
|
||||
let last_crate = sess.cstore.crates().len();
|
||||
let mut ret = (1..last_crate+1).map(|cnum| {
|
||||
if sess.cstore.is_explicitly_linked(CrateNum::new(cnum)) {
|
||||
if sess.cstore.dep_kind(CrateNum::new(cnum)) == DepKind::Explicit {
|
||||
Linkage::Static
|
||||
} else {
|
||||
Linkage::NotLinked
|
||||
|
|
|
|||
|
|
@ -834,7 +834,8 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
|
|||
Def::Const(..) |
|
||||
Def::AssociatedConst(..) |
|
||||
Def::Local(..) |
|
||||
Def::Upvar(..) => {
|
||||
Def::Upvar(..) |
|
||||
Def::Macro(..) => {
|
||||
DefHash::SawDefId.hash(self.st);
|
||||
self.hash_def_id(def.def_id());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#![feature(staged_api)]
|
||||
#![feature(linked_from)]
|
||||
#![feature(concat_idents)]
|
||||
#![cfg_attr(not(stage0), feature(rustc_private))]
|
||||
|
||||
extern crate libc;
|
||||
#[macro_use]
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use schema::CrateRoot;
|
|||
|
||||
use rustc::hir::def_id::{CrateNum, DefIndex};
|
||||
use rustc::hir::svh::Svh;
|
||||
use rustc::middle::cstore::LoadedMacros;
|
||||
use rustc::middle::cstore::DepKind;
|
||||
use rustc::session::{config, Session};
|
||||
use rustc_back::PanicStrategy;
|
||||
use rustc::session::search_paths::PathKind;
|
||||
|
|
@ -29,15 +29,15 @@ use std::cell::{RefCell, Cell};
|
|||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::fs;
|
||||
use std::{cmp, fs};
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::abi::Abi;
|
||||
use syntax::parse;
|
||||
use syntax::attr;
|
||||
use syntax::ext::base::SyntaxExtension;
|
||||
use syntax::feature_gate::{self, emit_feature_err};
|
||||
use syntax::parse::token::{InternedString, intern};
|
||||
use syntax_pos::{self, Span, mk_sp};
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use log;
|
||||
|
||||
pub struct Library {
|
||||
|
|
@ -56,29 +56,23 @@ pub struct CrateLoader<'a> {
|
|||
|
||||
fn dump_crates(cstore: &CStore) {
|
||||
info!("resolved crates:");
|
||||
cstore.iter_crate_data_origins(|_, data, opt_source| {
|
||||
cstore.iter_crate_data(|_, data| {
|
||||
info!(" name: {}", data.name());
|
||||
info!(" cnum: {}", data.cnum);
|
||||
info!(" hash: {}", data.hash());
|
||||
info!(" reqd: {}", data.explicitly_linked.get());
|
||||
opt_source.map(|cs| {
|
||||
let CrateSource { dylib, rlib, cnum: _ } = cs;
|
||||
dylib.map(|dl| info!(" dylib: {}", dl.0.display()));
|
||||
rlib.map(|rl| info!(" rlib: {}", rl.0.display()));
|
||||
});
|
||||
info!(" reqd: {:?}", data.dep_kind.get());
|
||||
let CrateSource { dylib, rlib } = data.source.clone();
|
||||
dylib.map(|dl| info!(" dylib: {}", dl.0.display()));
|
||||
rlib.map(|rl| info!(" rlib: {}", rl.0.display()));
|
||||
})
|
||||
}
|
||||
|
||||
fn should_link(i: &ast::Item) -> bool {
|
||||
!attr::contains_name(&i.attrs, "no_link")
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ExternCrateInfo {
|
||||
ident: String,
|
||||
name: String,
|
||||
id: ast::NodeId,
|
||||
should_link: bool,
|
||||
dep_kind: DepKind,
|
||||
}
|
||||
|
||||
fn register_native_lib(sess: &Session,
|
||||
|
|
@ -170,7 +164,11 @@ impl<'a> CrateLoader<'a> {
|
|||
ident: i.ident.to_string(),
|
||||
name: name,
|
||||
id: i.id,
|
||||
should_link: should_link(i),
|
||||
dep_kind: if attr::contains_name(&i.attrs, "no_link") {
|
||||
DepKind::MacrosOnly
|
||||
} else {
|
||||
DepKind::Explicit
|
||||
},
|
||||
})
|
||||
}
|
||||
_ => None
|
||||
|
|
@ -260,9 +258,8 @@ impl<'a> CrateLoader<'a> {
|
|||
name: &str,
|
||||
span: Span,
|
||||
lib: Library,
|
||||
explicitly_linked: bool)
|
||||
-> (CrateNum, Rc<cstore::CrateMetadata>,
|
||||
cstore::CrateSource) {
|
||||
dep_kind: DepKind)
|
||||
-> (CrateNum, Rc<cstore::CrateMetadata>) {
|
||||
info!("register crate `extern crate {} as {}`", name, ident);
|
||||
let crate_root = lib.metadata.get_root();
|
||||
self.verify_no_symbol_conflicts(span, &crate_root);
|
||||
|
|
@ -286,7 +283,7 @@ impl<'a> CrateLoader<'a> {
|
|||
|
||||
let Library { dylib, rlib, metadata } = lib;
|
||||
|
||||
let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span);
|
||||
let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
|
||||
|
||||
if crate_root.macro_derive_registrar.is_some() {
|
||||
self.sess.span_err(span, "crates of the `proc-macro` crate type \
|
||||
|
|
@ -302,18 +299,15 @@ impl<'a> CrateLoader<'a> {
|
|||
cnum_map: RefCell::new(cnum_map),
|
||||
cnum: cnum,
|
||||
codemap_import_info: RefCell::new(vec![]),
|
||||
explicitly_linked: Cell::new(explicitly_linked),
|
||||
dep_kind: Cell::new(dep_kind),
|
||||
source: cstore::CrateSource {
|
||||
dylib: dylib,
|
||||
rlib: rlib,
|
||||
},
|
||||
});
|
||||
|
||||
let source = cstore::CrateSource {
|
||||
dylib: dylib,
|
||||
rlib: rlib,
|
||||
cnum: cnum,
|
||||
};
|
||||
|
||||
self.cstore.set_crate_data(cnum, cmeta.clone());
|
||||
self.cstore.add_used_crate_source(source.clone());
|
||||
(cnum, cmeta, source)
|
||||
(cnum, cmeta)
|
||||
}
|
||||
|
||||
fn resolve_crate(&mut self,
|
||||
|
|
@ -323,8 +317,8 @@ impl<'a> CrateLoader<'a> {
|
|||
hash: Option<&Svh>,
|
||||
span: Span,
|
||||
kind: PathKind,
|
||||
explicitly_linked: bool)
|
||||
-> (CrateNum, Rc<cstore::CrateMetadata>, cstore::CrateSource) {
|
||||
dep_kind: DepKind)
|
||||
-> (CrateNum, Rc<cstore::CrateMetadata>) {
|
||||
info!("resolving crate `extern crate {} as {}`", name, ident);
|
||||
let result = match self.existing_match(name, hash, kind) {
|
||||
Some(cnum) => LoadResult::Previous(cnum),
|
||||
|
|
@ -356,14 +350,11 @@ impl<'a> CrateLoader<'a> {
|
|||
match result {
|
||||
LoadResult::Previous(cnum) => {
|
||||
let data = self.cstore.get_crate_data(cnum);
|
||||
if explicitly_linked && !data.explicitly_linked.get() {
|
||||
data.explicitly_linked.set(explicitly_linked);
|
||||
}
|
||||
(cnum, data, self.cstore.used_crate_source(cnum))
|
||||
data.dep_kind.set(cmp::max(data.dep_kind.get(), dep_kind));
|
||||
(cnum, data)
|
||||
}
|
||||
LoadResult::Loaded(library) => {
|
||||
self.register_crate(root, ident, name, span, library,
|
||||
explicitly_linked)
|
||||
self.register_crate(root, ident, name, span, library, dep_kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -436,7 +427,8 @@ impl<'a> CrateLoader<'a> {
|
|||
crate_root: &CrateRoot,
|
||||
metadata: &MetadataBlob,
|
||||
krate: CrateNum,
|
||||
span: Span)
|
||||
span: Span,
|
||||
dep_kind: DepKind)
|
||||
-> cstore::CrateNumMap {
|
||||
debug!("resolving deps of external crate");
|
||||
// The map from crate numbers in the crate we're resolving to local crate
|
||||
|
|
@ -444,13 +436,14 @@ impl<'a> CrateLoader<'a> {
|
|||
let deps = crate_root.crate_deps.decode(metadata);
|
||||
let map: FxHashMap<_, _> = deps.enumerate().map(|(crate_num, dep)| {
|
||||
debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
|
||||
let (local_cnum, ..) = self.resolve_crate(root,
|
||||
&dep.name.as_str(),
|
||||
&dep.name.as_str(),
|
||||
Some(&dep.hash),
|
||||
span,
|
||||
PathKind::Dependency,
|
||||
dep.explicitly_linked);
|
||||
let dep_name = &dep.name.as_str();
|
||||
let dep_kind = match dep_kind {
|
||||
DepKind::MacrosOnly => DepKind::MacrosOnly,
|
||||
_ => dep.kind,
|
||||
};
|
||||
let (local_cnum, ..) = self.resolve_crate(
|
||||
root, dep_name, dep_name, Some(&dep.hash), span, PathKind::Dependency, dep_kind,
|
||||
);
|
||||
(CrateNum::new(crate_num + 1), local_cnum)
|
||||
}).collect();
|
||||
|
||||
|
|
@ -464,8 +457,8 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
|
||||
fn read_extension_crate(&mut self, span: Span, info: &ExternCrateInfo) -> ExtensionCrate {
|
||||
info!("read extension crate {} `extern crate {} as {}` linked={}",
|
||||
info.id, info.name, info.ident, info.should_link);
|
||||
info!("read extension crate {} `extern crate {} as {}` dep_kind={:?}",
|
||||
info.id, info.name, info.ident, info.dep_kind);
|
||||
let target_triple = &self.sess.opts.target_triple[..];
|
||||
let is_cross = target_triple != config::host_triple();
|
||||
let mut target_only = false;
|
||||
|
|
@ -508,9 +501,8 @@ impl<'a> CrateLoader<'a> {
|
|||
|
||||
let (dylib, metadata) = match library {
|
||||
LoadResult::Previous(cnum) => {
|
||||
let dylib = self.cstore.opt_used_crate_source(cnum).unwrap().dylib;
|
||||
let data = self.cstore.get_crate_data(cnum);
|
||||
(dylib, PMDSource::Registered(data))
|
||||
(data.source.dylib.clone(), PMDSource::Registered(data))
|
||||
}
|
||||
LoadResult::Loaded(library) => {
|
||||
let dylib = library.dylib.clone();
|
||||
|
|
@ -526,68 +518,6 @@ impl<'a> CrateLoader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn read_macros(&mut self, item: &ast::Item, ekrate: &ExtensionCrate) -> LoadedMacros {
|
||||
let root = ekrate.metadata.get_root();
|
||||
let source_name = format!("<{} macros>", item.ident);
|
||||
let mut macro_rules = Vec::new();
|
||||
|
||||
for def in root.macro_defs.decode(&*ekrate.metadata) {
|
||||
// NB: Don't use parse::parse_tts_from_source_str because it parses with
|
||||
// quote_depth > 0.
|
||||
let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess,
|
||||
source_name.clone(),
|
||||
def.body);
|
||||
let lo = p.span.lo;
|
||||
let body = match p.parse_all_token_trees() {
|
||||
Ok(body) => body,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
self.sess.abort_if_errors();
|
||||
unreachable!();
|
||||
}
|
||||
};
|
||||
let local_span = mk_sp(lo, p.prev_span.hi);
|
||||
|
||||
// Mark the attrs as used
|
||||
for attr in &def.attrs {
|
||||
attr::mark_used(attr);
|
||||
}
|
||||
|
||||
macro_rules.push(ast::MacroDef {
|
||||
ident: ast::Ident::with_empty_ctxt(def.name),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: local_span,
|
||||
imported_from: Some(item.ident),
|
||||
allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"),
|
||||
attrs: def.attrs,
|
||||
body: body,
|
||||
});
|
||||
self.sess.imported_macro_spans.borrow_mut()
|
||||
.insert(local_span, (def.name.as_str().to_string(), def.span));
|
||||
}
|
||||
|
||||
if let Some(id) = root.macro_derive_registrar {
|
||||
let dylib = match ekrate.dylib.clone() {
|
||||
Some(dylib) => dylib,
|
||||
None => span_bug!(item.span, "proc-macro crate not dylib"),
|
||||
};
|
||||
if ekrate.target_only {
|
||||
let message = format!("proc-macro crate is not available for \
|
||||
triple `{}` (only found {})",
|
||||
config::host_triple(),
|
||||
self.sess.opts.target_triple);
|
||||
self.sess.span_fatal(item.span, &message);
|
||||
}
|
||||
|
||||
// custom derive crates currently should not have any macro_rules!
|
||||
// exported macros, enforced elsewhere
|
||||
assert_eq!(macro_rules.len(), 0);
|
||||
LoadedMacros::ProcMacros(self.load_derive_macros(item, id, root.hash, dylib))
|
||||
} else {
|
||||
LoadedMacros::MacroRules(macro_rules)
|
||||
}
|
||||
}
|
||||
|
||||
/// Load custom derive macros.
|
||||
///
|
||||
/// Note that this is intentionally similar to how we load plugins today,
|
||||
|
|
@ -595,14 +525,34 @@ impl<'a> CrateLoader<'a> {
|
|||
/// implemented as dynamic libraries, but we have a possible future where
|
||||
/// custom derive (and other macro-1.1 style features) are implemented via
|
||||
/// executables and custom IPC.
|
||||
fn load_derive_macros(&mut self, item: &ast::Item, index: DefIndex, svh: Svh, path: PathBuf)
|
||||
-> Vec<(ast::Name, SyntaxExtension)> {
|
||||
fn load_derive_macros(&mut self, item: &ast::Item, ekrate: &ExtensionCrate)
|
||||
-> Option<Vec<(ast::Name, SyntaxExtension)>> {
|
||||
use std::{env, mem};
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro::__internal::Registry;
|
||||
use rustc_back::dynamic_lib::DynamicLibrary;
|
||||
use syntax_ext::deriving::custom::CustomDerive;
|
||||
|
||||
let root = ekrate.metadata.get_root();
|
||||
let index = match root.macro_derive_registrar {
|
||||
Some(index) => index,
|
||||
None => return None,
|
||||
};
|
||||
if !self.sess.features.borrow().proc_macro {
|
||||
let issue = feature_gate::GateIssue::Language;
|
||||
let msg = "loading custom derive macro crates is experimentally supported";
|
||||
emit_feature_err(&self.sess.parse_sess, "proc_macro", item.span, issue, msg);
|
||||
}
|
||||
|
||||
if ekrate.target_only {
|
||||
let msg = format!("proc-macro crate is not available for triple `{}` (only found {})",
|
||||
config::host_triple(), self.sess.opts.target_triple);
|
||||
self.sess.span_fatal(item.span, &msg);
|
||||
}
|
||||
let path = match ekrate.dylib.clone() {
|
||||
Some(dylib) => dylib,
|
||||
None => span_bug!(item.span, "proc-macro crate not dylib"),
|
||||
};
|
||||
// Make sure the path contains a / or the linker will search for it.
|
||||
let path = env::current_dir().unwrap().join(path);
|
||||
let lib = match DynamicLibrary::open(Some(&path)) {
|
||||
|
|
@ -610,7 +560,7 @@ impl<'a> CrateLoader<'a> {
|
|||
Err(err) => self.sess.span_fatal(item.span, &err),
|
||||
};
|
||||
|
||||
let sym = self.sess.generate_derive_registrar_symbol(&svh, index);
|
||||
let sym = self.sess.generate_derive_registrar_symbol(&root.hash, index);
|
||||
let registrar = unsafe {
|
||||
let sym = match lib.symbol(&sym) {
|
||||
Ok(f) => f,
|
||||
|
|
@ -640,7 +590,7 @@ impl<'a> CrateLoader<'a> {
|
|||
// Intentionally leak the dynamic library. We can't ever unload it
|
||||
// since the library can make things that will live arbitrarily long.
|
||||
mem::forget(lib);
|
||||
my_registrar.0
|
||||
Some(my_registrar.0)
|
||||
}
|
||||
|
||||
/// Look for a plugin registrar. Returns library path, crate
|
||||
|
|
@ -651,7 +601,7 @@ impl<'a> CrateLoader<'a> {
|
|||
name: name.to_string(),
|
||||
ident: name.to_string(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
should_link: false,
|
||||
dep_kind: DepKind::MacrosOnly,
|
||||
});
|
||||
|
||||
if ekrate.target_only {
|
||||
|
|
@ -725,7 +675,7 @@ impl<'a> CrateLoader<'a> {
|
|||
// #![panic_runtime] crate.
|
||||
self.inject_dependency_if(cnum, "a panic runtime",
|
||||
&|data| data.needs_panic_runtime());
|
||||
runtime_found = runtime_found || data.explicitly_linked.get();
|
||||
runtime_found = runtime_found || data.dep_kind.get() == DepKind::Explicit;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -754,9 +704,9 @@ impl<'a> CrateLoader<'a> {
|
|||
};
|
||||
info!("panic runtime not found -- loading {}", name);
|
||||
|
||||
let (cnum, data, _) = self.resolve_crate(&None, name, name, None,
|
||||
syntax_pos::DUMMY_SP,
|
||||
PathKind::Crate, false);
|
||||
let dep_kind = DepKind::Implicit;
|
||||
let (cnum, data) =
|
||||
self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, dep_kind);
|
||||
|
||||
// Sanity check the loaded crate to ensure it is indeed a panic runtime
|
||||
// and the panic strategy is indeed what we thought it was.
|
||||
|
|
@ -790,7 +740,7 @@ impl<'a> CrateLoader<'a> {
|
|||
self.inject_dependency_if(cnum, "an allocator",
|
||||
&|data| data.needs_allocator());
|
||||
found_required_allocator = found_required_allocator ||
|
||||
data.explicitly_linked.get();
|
||||
data.dep_kind.get() == DepKind::Explicit;
|
||||
}
|
||||
});
|
||||
if !needs_allocator || found_required_allocator { return }
|
||||
|
|
@ -836,9 +786,9 @@ impl<'a> CrateLoader<'a> {
|
|||
} else {
|
||||
&self.sess.target.target.options.exe_allocation_crate
|
||||
};
|
||||
let (cnum, data, _) = self.resolve_crate(&None, name, name, None,
|
||||
syntax_pos::DUMMY_SP,
|
||||
PathKind::Crate, false);
|
||||
let dep_kind = DepKind::Implicit;
|
||||
let (cnum, data) =
|
||||
self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, dep_kind);
|
||||
|
||||
// Sanity check the crate we loaded to ensure that it is indeed an
|
||||
// allocator.
|
||||
|
|
@ -979,45 +929,36 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
|
|||
}
|
||||
|
||||
fn process_item(&mut self, item: &ast::Item, definitions: &Definitions, load_macros: bool)
|
||||
-> Option<LoadedMacros> {
|
||||
-> Vec<(ast::Name, SyntaxExtension)> {
|
||||
match item.node {
|
||||
ast::ItemKind::ExternCrate(_) => {}
|
||||
ast::ItemKind::ForeignMod(ref fm) => {
|
||||
self.process_foreign_mod(item, fm);
|
||||
return None;
|
||||
return Vec::new();
|
||||
}
|
||||
_ => return None,
|
||||
_ => return Vec::new(),
|
||||
}
|
||||
|
||||
let info = self.extract_crate_info(item).unwrap();
|
||||
let loaded_macros = if load_macros {
|
||||
if load_macros {
|
||||
let ekrate = self.read_extension_crate(item.span, &info);
|
||||
let loaded_macros = self.read_macros(item, &ekrate);
|
||||
|
||||
// If this is a proc-macro crate or `#[no_link]` crate, it is only used at compile time,
|
||||
// so we return here to avoid registering the crate.
|
||||
if loaded_macros.is_proc_macros() || !info.should_link {
|
||||
return Some(loaded_macros);
|
||||
// If this is a proc-macro crate, return here to avoid registering.
|
||||
if let Some(custom_derives) = self.load_derive_macros(item, &ekrate) {
|
||||
return custom_derives;
|
||||
}
|
||||
|
||||
// Register crate now to avoid double-reading metadata
|
||||
if let PMDSource::Owned(lib) = ekrate.metadata {
|
||||
if ekrate.target_only || config::host_triple() == self.sess.opts.target_triple {
|
||||
let ExternCrateInfo { ref ident, ref name, .. } = info;
|
||||
self.register_crate(&None, ident, name, item.span, lib, true);
|
||||
let ExternCrateInfo { ref ident, ref name, dep_kind, .. } = info;
|
||||
self.register_crate(&None, ident, name, item.span, lib, dep_kind);
|
||||
}
|
||||
}
|
||||
|
||||
Some(loaded_macros)
|
||||
} else {
|
||||
if !info.should_link {
|
||||
return None;
|
||||
}
|
||||
None
|
||||
};
|
||||
}
|
||||
|
||||
let (cnum, ..) = self.resolve_crate(
|
||||
&None, &info.ident, &info.name, None, item.span, PathKind::Crate, true,
|
||||
&None, &info.ident, &info.name, None, item.span, PathKind::Crate, info.dep_kind,
|
||||
);
|
||||
|
||||
let def_id = definitions.opt_local_def_id(item.id).unwrap();
|
||||
|
|
@ -1028,6 +969,6 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
|
|||
self.update_extern_crate(cnum, extern_crate, &mut FxHashSet());
|
||||
self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
|
||||
|
||||
loaded_macros
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use rustc::dep_graph::DepGraph;
|
|||
use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, DefId};
|
||||
use rustc::hir::map::DefKey;
|
||||
use rustc::hir::svh::Svh;
|
||||
use rustc::middle::cstore::ExternCrate;
|
||||
use rustc::middle::cstore::{DepKind, ExternCrate};
|
||||
use rustc_back::PanicStrategy;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use rustc::util::nodemap::{FxHashMap, NodeMap, NodeSet, DefIdMap};
|
||||
|
|
@ -78,11 +78,8 @@ pub struct CrateMetadata {
|
|||
/// compilation support.
|
||||
pub key_map: FxHashMap<DefKey, DefIndex>,
|
||||
|
||||
/// Flag if this crate is required by an rlib version of this crate, or in
|
||||
/// other words whether it was explicitly linked to. An example of a crate
|
||||
/// where this is false is when an allocator crate is injected into the
|
||||
/// dependency list, and therefore isn't actually needed to link an rlib.
|
||||
pub explicitly_linked: Cell<bool>,
|
||||
pub dep_kind: Cell<DepKind>,
|
||||
pub source: CrateSource,
|
||||
}
|
||||
|
||||
pub struct CachedInlinedItem {
|
||||
|
|
@ -97,7 +94,6 @@ pub struct CStore {
|
|||
metas: RefCell<FxHashMap<CrateNum, Rc<CrateMetadata>>>,
|
||||
/// Map from NodeId's of local extern crate statements to crate numbers
|
||||
extern_mod_crate_map: RefCell<NodeMap<CrateNum>>,
|
||||
used_crate_sources: RefCell<Vec<CrateSource>>,
|
||||
used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>,
|
||||
used_link_args: RefCell<Vec<String>>,
|
||||
statically_included_foreign_items: RefCell<NodeSet>,
|
||||
|
|
@ -112,7 +108,6 @@ impl CStore {
|
|||
dep_graph: dep_graph.clone(),
|
||||
metas: RefCell::new(FxHashMap()),
|
||||
extern_mod_crate_map: RefCell::new(FxHashMap()),
|
||||
used_crate_sources: RefCell::new(Vec::new()),
|
||||
used_libraries: RefCell::new(Vec::new()),
|
||||
used_link_args: RefCell::new(Vec::new()),
|
||||
statically_included_foreign_items: RefCell::new(NodeSet()),
|
||||
|
|
@ -146,38 +141,9 @@ impl CStore {
|
|||
}
|
||||
}
|
||||
|
||||
/// Like `iter_crate_data`, but passes source paths (if available) as well.
|
||||
pub fn iter_crate_data_origins<I>(&self, mut i: I)
|
||||
where I: FnMut(CrateNum, &CrateMetadata, Option<CrateSource>)
|
||||
{
|
||||
for (&k, v) in self.metas.borrow().iter() {
|
||||
let origin = self.opt_used_crate_source(k);
|
||||
origin.as_ref().map(|cs| {
|
||||
assert!(k == cs.cnum);
|
||||
});
|
||||
i(k, &v, origin);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_used_crate_source(&self, src: CrateSource) {
|
||||
let mut used_crate_sources = self.used_crate_sources.borrow_mut();
|
||||
if !used_crate_sources.contains(&src) {
|
||||
used_crate_sources.push(src);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn opt_used_crate_source(&self, cnum: CrateNum) -> Option<CrateSource> {
|
||||
self.used_crate_sources
|
||||
.borrow_mut()
|
||||
.iter()
|
||||
.find(|source| source.cnum == cnum)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub fn reset(&self) {
|
||||
self.metas.borrow_mut().clear();
|
||||
self.extern_mod_crate_map.borrow_mut().clear();
|
||||
self.used_crate_sources.borrow_mut().clear();
|
||||
self.used_libraries.borrow_mut().clear();
|
||||
self.used_link_args.borrow_mut().clear();
|
||||
self.statically_included_foreign_items.borrow_mut().clear();
|
||||
|
|
@ -223,15 +189,16 @@ impl CStore {
|
|||
}
|
||||
info!("topological ordering: {:?}", ordering);
|
||||
ordering.reverse();
|
||||
let mut libs = self.used_crate_sources
|
||||
let mut libs = self.metas
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|src| {
|
||||
(src.cnum,
|
||||
match prefer {
|
||||
LinkagePreference::RequireDynamic => src.dylib.clone().map(|p| p.0),
|
||||
LinkagePreference::RequireStatic => src.rlib.clone().map(|p| p.0),
|
||||
})
|
||||
.filter_map(|(&cnum, data)| {
|
||||
if data.dep_kind.get() == DepKind::MacrosOnly { return None; }
|
||||
let path = match prefer {
|
||||
LinkagePreference::RequireDynamic => data.source.dylib.clone().map(|p| p.0),
|
||||
LinkagePreference::RequireStatic => data.source.rlib.clone().map(|p| p.0),
|
||||
};
|
||||
Some((cnum, path))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
libs.sort_by(|&(a, _), &(b, _)| {
|
||||
|
|
|
|||
|
|
@ -13,10 +13,11 @@ use encoder;
|
|||
use locator;
|
||||
use schema;
|
||||
|
||||
use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, ExternCrate};
|
||||
use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, ExternCrate};
|
||||
use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference};
|
||||
use rustc::hir::def::{self, Def};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::session::Session;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
|
||||
|
||||
|
|
@ -30,7 +31,8 @@ use rustc_back::PanicStrategy;
|
|||
use std::path::PathBuf;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::parse::token;
|
||||
use syntax::parse::{token, new_parser_from_source_str};
|
||||
use syntax_pos::mk_sp;
|
||||
use rustc::hir::svh::Svh;
|
||||
use rustc_back::target::Target;
|
||||
use rustc::hir;
|
||||
|
|
@ -221,6 +223,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
|
|||
self.get_crate_data(cnum).get_dylib_dependency_formats()
|
||||
}
|
||||
|
||||
fn dep_kind(&self, cnum: CrateNum) -> DepKind
|
||||
{
|
||||
self.get_crate_data(cnum).dep_kind.get()
|
||||
}
|
||||
|
||||
fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>
|
||||
{
|
||||
self.get_crate_data(cnum).get_lang_items()
|
||||
|
|
@ -237,11 +244,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
|
|||
self.get_crate_data(cnum).is_staged_api()
|
||||
}
|
||||
|
||||
fn is_explicitly_linked(&self, cnum: CrateNum) -> bool
|
||||
{
|
||||
self.get_crate_data(cnum).explicitly_linked.get()
|
||||
}
|
||||
|
||||
fn is_allocator(&self, cnum: CrateNum) -> bool
|
||||
{
|
||||
self.get_crate_data(cnum).is_allocator()
|
||||
|
|
@ -351,6 +353,43 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
|
|||
result
|
||||
}
|
||||
|
||||
fn load_macro(&self, id: DefId, sess: &Session) -> ast::MacroDef {
|
||||
let (name, def) = self.get_crate_data(id.krate).get_macro(id.index);
|
||||
let source_name = format!("<{} macros>", name);
|
||||
|
||||
// NB: Don't use parse_tts_from_source_str because it parses with quote_depth > 0.
|
||||
let mut parser = new_parser_from_source_str(&sess.parse_sess, source_name, def.body);
|
||||
|
||||
let lo = parser.span.lo;
|
||||
let body = match parser.parse_all_token_trees() {
|
||||
Ok(body) => body,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
sess.abort_if_errors();
|
||||
unreachable!();
|
||||
}
|
||||
};
|
||||
let local_span = mk_sp(lo, parser.prev_span.hi);
|
||||
|
||||
// Mark the attrs as used
|
||||
for attr in &def.attrs {
|
||||
attr::mark_used(attr);
|
||||
}
|
||||
|
||||
sess.imported_macro_spans.borrow_mut()
|
||||
.insert(local_span, (def.name.as_str().to_string(), def.span));
|
||||
|
||||
ast::MacroDef {
|
||||
ident: ast::Ident::with_empty_ctxt(def.name),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: local_span,
|
||||
imported_from: None, // FIXME
|
||||
allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"),
|
||||
attrs: def.attrs,
|
||||
body: body,
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_get_item_ast<'a>(&'tcx self,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId)
|
||||
|
|
@ -507,7 +546,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
|
|||
|
||||
fn used_crate_source(&self, cnum: CrateNum) -> CrateSource
|
||||
{
|
||||
self.opt_used_crate_source(cnum).unwrap()
|
||||
self.get_crate_data(cnum).source.clone()
|
||||
}
|
||||
|
||||
fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use rustc::util::nodemap::FxHashMap;
|
|||
use rustc::hir;
|
||||
use rustc::hir::intravisit::IdRange;
|
||||
|
||||
use rustc::middle::cstore::{InlinedItem, LinkagePreference};
|
||||
use rustc::middle::cstore::{DepKind, InlinedItem, LinkagePreference};
|
||||
use rustc::hir::def::{self, Def, CtorKind};
|
||||
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
|
||||
use rustc::middle::lang_items;
|
||||
|
|
@ -468,6 +468,7 @@ impl<'tcx> EntryKind<'tcx> {
|
|||
EntryKind::Variant(_) => Def::Variant(did),
|
||||
EntryKind::Trait(_) => Def::Trait(did),
|
||||
EntryKind::Enum => Def::Enum(did),
|
||||
EntryKind::MacroDef(_) => Def::Macro(did),
|
||||
|
||||
EntryKind::ForeignMod |
|
||||
EntryKind::Impl(_) |
|
||||
|
|
@ -690,6 +691,8 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F)
|
||||
where F: FnMut(def::Export)
|
||||
{
|
||||
let macros_only = self.dep_kind.get() == DepKind::MacrosOnly;
|
||||
|
||||
// Find the item.
|
||||
let item = match self.maybe_entry(id) {
|
||||
None => return,
|
||||
|
|
@ -698,9 +701,19 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
|
||||
// Iterate over all children.
|
||||
for child_index in item.children.decode(self) {
|
||||
if macros_only {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get the item.
|
||||
if let Some(child) = self.maybe_entry(child_index) {
|
||||
let child = child.decode(self);
|
||||
match child.kind {
|
||||
EntryKind::MacroDef(..) => {}
|
||||
_ if macros_only => continue,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Hand off the item to the callback.
|
||||
match child.kind {
|
||||
// FIXME(eddyb) Don't encode these in children.
|
||||
|
|
@ -759,6 +772,11 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
|
||||
if let EntryKind::Mod(data) = item.kind {
|
||||
for exp in data.decode(self).reexports.decode(self) {
|
||||
match exp.def {
|
||||
Def::Macro(..) => {}
|
||||
_ if macros_only => continue,
|
||||
_ => {}
|
||||
}
|
||||
callback(exp);
|
||||
}
|
||||
}
|
||||
|
|
@ -987,6 +1005,14 @@ impl<'a, 'tcx> CrateMetadata {
|
|||
self.root.reachable_ids.decode(self).map(|index| self.local_def_id(index)).collect()
|
||||
}
|
||||
|
||||
pub fn get_macro(&self, id: DefIndex) -> (ast::Name, MacroDef) {
|
||||
let entry = self.entry(id);
|
||||
match entry.kind {
|
||||
EntryKind::MacroDef(macro_def) => (self.item_name(&entry), macro_def.decode(self)),
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_const_fn(&self, id: DefIndex) -> bool {
|
||||
let constness = match self.entry(id).kind {
|
||||
EntryKind::Method(data) => data.decode(self).fn_data.constness,
|
||||
|
|
|
|||
|
|
@ -830,6 +830,34 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize the text of exported macros
|
||||
fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef) -> Entry<'tcx> {
|
||||
let def_id = self.tcx.map.local_def_id(macro_def.id);
|
||||
let macro_def = MacroDef {
|
||||
name: macro_def.name,
|
||||
attrs: macro_def.attrs.to_vec(),
|
||||
span: macro_def.span,
|
||||
body: ::syntax::print::pprust::tts_to_string(¯o_def.body)
|
||||
};
|
||||
Entry {
|
||||
kind: EntryKind::MacroDef(self.lazy(¯o_def)),
|
||||
visibility: ty::Visibility::Public,
|
||||
def_key: self.encode_def_key(def_id),
|
||||
|
||||
attributes: LazySeq::empty(),
|
||||
children: LazySeq::empty(),
|
||||
stability: None,
|
||||
deprecation: None,
|
||||
ty: None,
|
||||
inherent_impls: LazySeq::empty(),
|
||||
variances: LazySeq::empty(),
|
||||
generics: None,
|
||||
predicates: None,
|
||||
ast: None,
|
||||
mir: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
|
||||
|
|
@ -964,6 +992,10 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
|
|||
intravisit::walk_ty(self, ty);
|
||||
self.index.encode_info_for_ty(ty);
|
||||
}
|
||||
fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef) {
|
||||
let def_id = self.index.tcx.map.local_def_id(macro_def.id);
|
||||
self.index.record(def_id, EncodeContext::encode_info_for_macro_def, macro_def);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
|
||||
|
|
@ -1043,6 +1075,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public)));
|
||||
let mut visitor = EncodeVisitor { index: index };
|
||||
krate.visit_all_items(&mut visitor);
|
||||
for macro_def in &krate.exported_macros {
|
||||
visitor.visit_macro_def(macro_def);
|
||||
}
|
||||
visitor.index.into_items()
|
||||
}
|
||||
|
||||
|
|
@ -1080,7 +1115,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
CrateDep {
|
||||
name: syntax::parse::token::intern(dep.name()),
|
||||
hash: dep.hash(),
|
||||
explicitly_linked: dep.explicitly_linked.get(),
|
||||
kind: dep.dep_kind.get(),
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
|
@ -1122,19 +1157,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
})
|
||||
.map(|filemap| &**filemap))
|
||||
}
|
||||
|
||||
/// Serialize the text of the exported macros
|
||||
fn encode_macro_defs(&mut self) -> LazySeq<MacroDef> {
|
||||
let tcx = self.tcx;
|
||||
self.lazy_seq(tcx.map.krate().exported_macros.iter().map(|def| {
|
||||
MacroDef {
|
||||
name: def.name,
|
||||
attrs: def.attrs.to_vec(),
|
||||
span: def.span,
|
||||
body: ::syntax::print::pprust::tts_to_string(&def.body),
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
struct ImplVisitor<'a, 'tcx: 'a> {
|
||||
|
|
@ -1228,11 +1250,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
let codemap = self.encode_codemap();
|
||||
let codemap_bytes = self.position() - i;
|
||||
|
||||
// Encode macro definitions
|
||||
i = self.position();
|
||||
let macro_defs = self.encode_macro_defs();
|
||||
let macro_defs_bytes = self.position() - i;
|
||||
|
||||
// Encode the def IDs of impls, for coherence checking.
|
||||
i = self.position();
|
||||
let impls = self.encode_impls();
|
||||
|
|
@ -1279,7 +1296,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
lang_items_missing: lang_items_missing,
|
||||
native_libraries: native_libraries,
|
||||
codemap: codemap,
|
||||
macro_defs: macro_defs,
|
||||
impls: impls,
|
||||
reachable_ids: reachable_ids,
|
||||
index: index,
|
||||
|
|
@ -1300,7 +1316,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
println!(" lang item bytes: {}", lang_item_bytes);
|
||||
println!(" native bytes: {}", native_lib_bytes);
|
||||
println!(" codemap bytes: {}", codemap_bytes);
|
||||
println!(" macro def bytes: {}", macro_defs_bytes);
|
||||
println!(" impl bytes: {}", impl_bytes);
|
||||
println!(" reachable bytes: {}", reachable_bytes);
|
||||
println!(" item bytes: {}", item_bytes);
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ read_hir!(hir::Item);
|
|||
read_hir!(hir::ImplItem);
|
||||
read_hir!(hir::TraitItem);
|
||||
read_hir!(hir::ForeignItem);
|
||||
read_hir!(hir::MacroDef);
|
||||
|
||||
/// Leaks access to a value of type T without any tracking. This is
|
||||
/// suitable for ambiguous types like `usize`, which *could* represent
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use index;
|
|||
use rustc::hir;
|
||||
use rustc::hir::def::{self, CtorKind};
|
||||
use rustc::hir::def_id::{DefIndex, DefId};
|
||||
use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind};
|
||||
use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibraryKind};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, Ty};
|
||||
|
|
@ -177,7 +177,6 @@ pub struct CrateRoot {
|
|||
pub lang_items_missing: LazySeq<lang_items::LangItem>,
|
||||
pub native_libraries: LazySeq<(NativeLibraryKind, String)>,
|
||||
pub codemap: LazySeq<syntax_pos::FileMap>,
|
||||
pub macro_defs: LazySeq<MacroDef>,
|
||||
pub impls: LazySeq<TraitImpls>,
|
||||
pub reachable_ids: LazySeq<DefIndex>,
|
||||
pub index: LazySeq<index::Index>,
|
||||
|
|
@ -187,7 +186,7 @@ pub struct CrateRoot {
|
|||
pub struct CrateDep {
|
||||
pub name: ast::Name,
|
||||
pub hash: hir::svh::Svh,
|
||||
pub explicitly_linked: bool,
|
||||
pub kind: DepKind,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
|
|
@ -241,6 +240,7 @@ pub enum EntryKind<'tcx> {
|
|||
Fn(Lazy<FnData>),
|
||||
ForeignFn(Lazy<FnData>),
|
||||
Mod(Lazy<ModData>),
|
||||
MacroDef(Lazy<MacroDef>),
|
||||
Closure(Lazy<ClosureData<'tcx>>),
|
||||
Trait(Lazy<TraitData<'tcx>>),
|
||||
Impl(Lazy<ImplData<'tcx>>),
|
||||
|
|
|
|||
|
|
@ -14,18 +14,17 @@
|
|||
//! any imports resolved.
|
||||
|
||||
use macros::{InvocationData, LegacyScope};
|
||||
use resolve_imports::ImportDirective;
|
||||
use resolve_imports::ImportDirectiveSubclass::{self, GlobImport};
|
||||
use {Module, ModuleS, ModuleKind};
|
||||
use Namespace::{self, TypeNS, ValueNS};
|
||||
use {NameBinding, NameBindingKind, ToNameBinding};
|
||||
use Resolver;
|
||||
use {Resolver, Module, ModuleS, ModuleKind, NameBinding, NameBindingKind, ToNameBinding};
|
||||
use Namespace::{self, TypeNS, ValueNS, MacroNS};
|
||||
use ResolveResult::Success;
|
||||
use {resolve_error, resolve_struct_error, ResolutionError};
|
||||
|
||||
use rustc::middle::cstore::LoadedMacros;
|
||||
use rustc::middle::cstore::DepKind;
|
||||
use rustc::hir::def::*;
|
||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
|
||||
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, DefIndex, BUILTIN_MACROS_CRATE};
|
||||
use rustc::ty;
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
|
|
@ -37,10 +36,9 @@ use syntax::parse::token;
|
|||
use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind};
|
||||
use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind};
|
||||
use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
|
||||
use syntax::ext::base::{SyntaxExtension, Resolver as SyntaxResolver};
|
||||
use syntax::ext::base::SyntaxExtension;
|
||||
use syntax::ext::expand::mark_tts;
|
||||
use syntax::ext::hygiene::Mark;
|
||||
use syntax::feature_gate::{self, emit_feature_err};
|
||||
use syntax::ext::tt::macro_rules;
|
||||
use syntax::parse::token::keywords;
|
||||
use syntax::visit::{self, Visitor};
|
||||
|
|
@ -221,47 +219,53 @@ impl<'b> Resolver<'b> {
|
|||
legacy_imports.import_all.is_some() || !legacy_imports.imports.is_empty() ||
|
||||
!legacy_imports.reexports.is_empty()
|
||||
} {
|
||||
if self.current_module.parent.is_some() {
|
||||
span_err!(self.session, item.span, E0468,
|
||||
"an `extern crate` loading macros must be at the crate root");
|
||||
}
|
||||
span_err!(self.session, item.span, E0468,
|
||||
"an `extern crate` loading macros must be at the crate root");
|
||||
}
|
||||
|
||||
let loaded_macros = if legacy_imports != LegacyMacroImports::default() {
|
||||
self.crate_loader.process_item(item, &self.definitions, true)
|
||||
} else {
|
||||
self.crate_loader.process_item(item, &self.definitions, false)
|
||||
};
|
||||
let load_macros = legacy_imports != LegacyMacroImports::default();
|
||||
let proc_macros =
|
||||
self.crate_loader.process_item(item, &self.definitions, load_macros);
|
||||
|
||||
// n.b. we don't need to look at the path option here, because cstore already did
|
||||
let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id);
|
||||
let module = if let Some(crate_id) = crate_id {
|
||||
let def_id = DefId {
|
||||
krate: crate_id,
|
||||
index: CRATE_DEF_INDEX,
|
||||
};
|
||||
let module = self.arenas.alloc_module(ModuleS {
|
||||
extern_crate_id: Some(item.id),
|
||||
populated: Cell::new(false),
|
||||
..ModuleS::new(Some(parent), ModuleKind::Def(Def::Mod(def_id), name))
|
||||
let module = self.get_extern_crate_root(crate_id);
|
||||
let binding = (module, sp, ty::Visibility::Public).to_name_binding();
|
||||
let binding = self.arenas.alloc_name_binding(binding);
|
||||
let directive = self.arenas.alloc_import_directive(ImportDirective {
|
||||
id: item.id,
|
||||
parent: parent,
|
||||
imported_module: Cell::new(Some(module)),
|
||||
subclass: ImportDirectiveSubclass::ExternCrate,
|
||||
span: item.span,
|
||||
module_path: Vec::new(),
|
||||
vis: Cell::new(vis),
|
||||
});
|
||||
self.define(parent, name, TypeNS, (module, sp, vis));
|
||||
let imported_binding = self.import(binding, directive);
|
||||
self.define(parent, name, TypeNS, imported_binding);
|
||||
self.populate_module_if_necessary(module);
|
||||
module
|
||||
} else {
|
||||
// Define an empty module
|
||||
let def = Def::Mod(self.definitions.local_def_id(item.id));
|
||||
let module = ModuleS::new(Some(parent), ModuleKind::Def(def, name));
|
||||
let module = self.arenas.alloc_module(module);
|
||||
// Define a module and populate it with proc macros.
|
||||
let module_kind =
|
||||
ModuleKind::Def(Def::Mod(self.definitions.local_def_id(item.id)), name);
|
||||
let module = self.arenas.alloc_module(ModuleS::new(None, module_kind));
|
||||
self.define(parent, name, TypeNS, (module, sp, vis));
|
||||
for (name, ext) in proc_macros {
|
||||
let def_id = DefId {
|
||||
krate: BUILTIN_MACROS_CRATE,
|
||||
index: DefIndex::new(self.macro_map.len()),
|
||||
};
|
||||
self.macro_map.insert(def_id, Rc::new(ext));
|
||||
let vis = ty::Visibility::Public;
|
||||
self.define(module, name, MacroNS, (Def::Macro(def_id), DUMMY_SP, vis));
|
||||
}
|
||||
module
|
||||
};
|
||||
|
||||
if let Some(loaded_macros) = loaded_macros {
|
||||
self.import_extern_crate_macros(
|
||||
item, module, loaded_macros, legacy_imports, expansion == Mark::root(),
|
||||
);
|
||||
}
|
||||
let allow_shadowing = expansion == Mark::root();
|
||||
self.process_legacy_macro_imports(module, legacy_imports, allow_shadowing);
|
||||
}
|
||||
|
||||
ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
|
||||
|
|
@ -484,6 +488,9 @@ impl<'b> Resolver<'b> {
|
|||
let field_names = self.session.cstore.struct_field_names(def_id);
|
||||
self.insert_field_names(def_id, field_names);
|
||||
}
|
||||
Def::Macro(..) => {
|
||||
self.define(parent, name, MacroNS, (def, DUMMY_SP, vis));
|
||||
}
|
||||
Def::Local(..) |
|
||||
Def::PrimTy(..) |
|
||||
Def::TyParam(..) |
|
||||
|
|
@ -496,6 +503,43 @@ impl<'b> Resolver<'b> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_extern_crate_root(&mut self, cnum: CrateNum) -> Module<'b> {
|
||||
let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
|
||||
let macros_only = self.session.cstore.dep_kind(cnum) == DepKind::MacrosOnly;
|
||||
let arenas = self.arenas;
|
||||
*self.extern_crate_roots.entry((cnum, macros_only)).or_insert_with(|| {
|
||||
arenas.alloc_module(ModuleS {
|
||||
populated: Cell::new(false),
|
||||
..ModuleS::new(None, ModuleKind::Def(Def::Mod(def_id), keywords::Invalid.name()))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_macro(&mut self, def: Def) -> Rc<SyntaxExtension> {
|
||||
let def_id = match def {
|
||||
Def::Macro(def_id) => def_id,
|
||||
_ => panic!("Expected Def::Macro(..)"),
|
||||
};
|
||||
if let Some(ext) = self.macro_map.get(&def_id) {
|
||||
return ext.clone();
|
||||
}
|
||||
|
||||
let mut macro_rules = self.session.cstore.load_macro(def_id, &self.session);
|
||||
let mark = Mark::fresh();
|
||||
let invocation = self.arenas.alloc_invocation_data(InvocationData {
|
||||
module: Cell::new(self.get_extern_crate_root(def_id.krate)),
|
||||
def_index: CRATE_DEF_INDEX,
|
||||
const_integer: false,
|
||||
legacy_scope: Cell::new(LegacyScope::Empty),
|
||||
expansion: Cell::new(LegacyScope::Empty),
|
||||
});
|
||||
self.invocations.insert(mark, invocation);
|
||||
macro_rules.body = mark_tts(¯o_rules.body, mark);
|
||||
let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_rules));
|
||||
self.macro_map.insert(def_id, ext.clone());
|
||||
ext
|
||||
}
|
||||
|
||||
/// Ensures that the reduced graph rooted at the given external module
|
||||
/// is built, building it if it is not.
|
||||
pub fn populate_module_if_necessary(&mut self, module: Module<'b>) {
|
||||
|
|
@ -506,90 +550,46 @@ impl<'b> Resolver<'b> {
|
|||
module.populated.set(true)
|
||||
}
|
||||
|
||||
fn import_extern_crate_macros(&mut self,
|
||||
extern_crate: &Item,
|
||||
module: Module<'b>,
|
||||
loaded_macros: LoadedMacros,
|
||||
legacy_imports: LegacyMacroImports,
|
||||
allow_shadowing: bool) {
|
||||
let import_macro = |this: &mut Self, name, ext: Rc<_>, span| {
|
||||
this.used_crates.insert(module.def_id().unwrap().krate);
|
||||
if let SyntaxExtension::NormalTT(..) = *ext {
|
||||
this.macro_names.insert(name);
|
||||
}
|
||||
if this.builtin_macros.insert(name, ext).is_some() && !allow_shadowing {
|
||||
let msg = format!("`{}` is already in scope", name);
|
||||
let note =
|
||||
"macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
|
||||
this.session.struct_span_err(span, &msg).note(note).emit();
|
||||
}
|
||||
};
|
||||
fn legacy_import_macro(&mut self, name: Name, def: Def, span: Span, allow_shadowing: bool) {
|
||||
self.used_crates.insert(def.def_id().krate);
|
||||
self.macro_names.insert(name);
|
||||
if self.builtin_macros.insert(name, def.def_id()).is_some() && !allow_shadowing {
|
||||
let msg = format!("`{}` is already in scope", name);
|
||||
let note =
|
||||
"macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
|
||||
self.session.struct_span_err(span, &msg).note(note).emit();
|
||||
}
|
||||
}
|
||||
|
||||
match loaded_macros {
|
||||
LoadedMacros::MacroRules(macros) => {
|
||||
let mark = Mark::fresh();
|
||||
if !macros.is_empty() {
|
||||
let invocation = self.arenas.alloc_invocation_data(InvocationData {
|
||||
module: Cell::new(module),
|
||||
def_index: CRATE_DEF_INDEX,
|
||||
const_integer: false,
|
||||
legacy_scope: Cell::new(LegacyScope::Empty),
|
||||
expansion: Cell::new(LegacyScope::Empty),
|
||||
});
|
||||
self.invocations.insert(mark, invocation);
|
||||
}
|
||||
|
||||
let mut macros: FxHashMap<_, _> = macros.into_iter().map(|mut def| {
|
||||
def.body = mark_tts(&def.body, mark);
|
||||
let ext = macro_rules::compile(&self.session.parse_sess, &def);
|
||||
(def.ident.name, (def, Rc::new(ext)))
|
||||
}).collect();
|
||||
|
||||
if let Some(span) = legacy_imports.import_all {
|
||||
for (&name, &(_, ref ext)) in macros.iter() {
|
||||
import_macro(self, name, ext.clone(), span);
|
||||
}
|
||||
fn process_legacy_macro_imports(&mut self,
|
||||
module: Module<'b>,
|
||||
legacy_imports: LegacyMacroImports,
|
||||
allow_shadowing: bool) {
|
||||
if let Some(span) = legacy_imports.import_all {
|
||||
module.for_each_child(|name, ns, binding| if ns == MacroNS {
|
||||
self.legacy_import_macro(name, binding.def(), span, allow_shadowing);
|
||||
});
|
||||
} else {
|
||||
for (name, span) in legacy_imports.imports {
|
||||
let result = self.resolve_name_in_module(module, name, MacroNS, false, None);
|
||||
if let Success(binding) = result {
|
||||
self.legacy_import_macro(name, binding.def(), span, allow_shadowing);
|
||||
} else {
|
||||
for (name, span) in legacy_imports.imports {
|
||||
if let Some(&(_, ref ext)) = macros.get(&name) {
|
||||
import_macro(self, name, ext.clone(), span);
|
||||
} else {
|
||||
span_err!(self.session, span, E0469, "imported macro not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
for (name, span) in legacy_imports.reexports {
|
||||
if let Some((mut def, _)) = macros.remove(&name) {
|
||||
def.id = self.next_node_id();
|
||||
self.exported_macros.push(def);
|
||||
} else {
|
||||
span_err!(self.session, span, E0470, "reexported macro not found");
|
||||
}
|
||||
span_err!(self.session, span, E0469, "imported macro not found");
|
||||
}
|
||||
}
|
||||
|
||||
LoadedMacros::ProcMacros(macros) => {
|
||||
if !self.session.features.borrow().proc_macro {
|
||||
let sess = &self.session.parse_sess;
|
||||
let issue = feature_gate::GateIssue::Language;
|
||||
let msg =
|
||||
"loading custom derive macro crates is experimentally supported";
|
||||
emit_feature_err(sess, "proc_macro", extern_crate.span, issue, msg);
|
||||
}
|
||||
if !legacy_imports.imports.is_empty() {
|
||||
let msg = "`proc-macro` crates cannot be selectively imported from, \
|
||||
must use `#[macro_use]`";
|
||||
self.session.span_err(extern_crate.span, msg);
|
||||
}
|
||||
if !legacy_imports.reexports.is_empty() {
|
||||
let msg = "`proc-macro` crates cannot be reexported from";
|
||||
self.session.span_err(extern_crate.span, msg);
|
||||
}
|
||||
if let Some(span) = legacy_imports.import_all {
|
||||
for (name, ext) in macros {
|
||||
import_macro(self, name, Rc::new(ext), span);
|
||||
}
|
||||
}
|
||||
for (name, span) in legacy_imports.reexports {
|
||||
self.used_crates.insert(module.def_id().unwrap().krate);
|
||||
let result = self.resolve_name_in_module(module, name, MacroNS, false, None);
|
||||
if let Success(binding) = result {
|
||||
let def = binding.def();
|
||||
if let Def::Macro(DefId { krate: BUILTIN_MACROS_CRATE, .. }) = def {
|
||||
self.session.span_err(span, "`proc-macro` crates cannot be reexported from");
|
||||
}
|
||||
self.macro_exports.push(Export { name: name, def: def });
|
||||
} else {
|
||||
span_err!(self.session, span, E0470, "reexported macro not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ use std::fmt;
|
|||
use std::mem::replace;
|
||||
use std::rc::Rc;
|
||||
|
||||
use resolve_imports::{ImportDirective, NameResolution};
|
||||
use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution};
|
||||
use macros::{InvocationData, LegacyBinding, LegacyScope};
|
||||
|
||||
// NB: This module needs to be declared first so diagnostics are
|
||||
|
|
@ -533,6 +533,7 @@ impl PatternSource {
|
|||
pub enum Namespace {
|
||||
TypeNS,
|
||||
ValueNS,
|
||||
MacroNS,
|
||||
}
|
||||
|
||||
impl<'a> Visitor for Resolver<'a> {
|
||||
|
|
@ -796,10 +797,6 @@ pub struct ModuleS<'a> {
|
|||
// The node id of the closest normal module (`mod`) ancestor (including this module).
|
||||
normal_ancestor_id: Option<NodeId>,
|
||||
|
||||
// If the module is an extern crate, `def` is root of the external crate and `extern_crate_id`
|
||||
// is the NodeId of the local `extern crate` item (otherwise, `extern_crate_id` is None).
|
||||
extern_crate_id: Option<NodeId>,
|
||||
|
||||
resolutions: RefCell<FxHashMap<(Name, Namespace), &'a RefCell<NameResolution<'a>>>>,
|
||||
|
||||
no_implicit_prelude: bool,
|
||||
|
|
@ -824,7 +821,6 @@ impl<'a> ModuleS<'a> {
|
|||
parent: parent,
|
||||
kind: kind,
|
||||
normal_ancestor_id: None,
|
||||
extern_crate_id: None,
|
||||
resolutions: RefCell::new(FxHashMap()),
|
||||
no_implicit_prelude: false,
|
||||
glob_importers: RefCell::new(Vec::new()),
|
||||
|
|
@ -953,7 +949,14 @@ impl<'a> NameBinding<'a> {
|
|||
}
|
||||
|
||||
fn is_extern_crate(&self) -> bool {
|
||||
self.module().ok().and_then(|module| module.extern_crate_id).is_some()
|
||||
match self.kind {
|
||||
NameBindingKind::Import {
|
||||
directive: &ImportDirective {
|
||||
subclass: ImportDirectiveSubclass::ExternCrate, ..
|
||||
}, ..
|
||||
} => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_import(&self) -> bool {
|
||||
|
|
@ -1081,6 +1084,7 @@ pub struct Resolver<'a> {
|
|||
// There will be an anonymous module created around `g` with the ID of the
|
||||
// entry block for `f`.
|
||||
module_map: NodeMap<Module<'a>>,
|
||||
extern_crate_roots: FxHashMap<(CrateNum, bool /* MacrosOnly? */), Module<'a>>,
|
||||
|
||||
// Whether or not to print error messages. Can be set to true
|
||||
// when getting additional info for error message suggestions,
|
||||
|
|
@ -1107,8 +1111,10 @@ pub struct Resolver<'a> {
|
|||
pub exported_macros: Vec<ast::MacroDef>,
|
||||
crate_loader: &'a mut CrateLoader,
|
||||
macro_names: FxHashSet<Name>,
|
||||
builtin_macros: FxHashMap<Name, Rc<SyntaxExtension>>,
|
||||
builtin_macros: FxHashMap<Name, DefId>,
|
||||
lexical_macro_resolutions: Vec<(Name, LegacyScope<'a>)>,
|
||||
macro_map: FxHashMap<DefId, Rc<SyntaxExtension>>,
|
||||
macro_exports: Vec<Export>,
|
||||
|
||||
// Maps the `Mark` of an expansion to its containing module or block.
|
||||
invocations: FxHashMap<Mark, &'a InvocationData<'a>>,
|
||||
|
|
@ -1274,6 +1280,7 @@ impl<'a> Resolver<'a> {
|
|||
export_map: NodeMap(),
|
||||
trait_map: NodeMap(),
|
||||
module_map: module_map,
|
||||
extern_crate_roots: FxHashMap(),
|
||||
|
||||
emit_errors: true,
|
||||
make_glob_map: make_glob_map == MakeGlobMap::Yes,
|
||||
|
|
@ -1300,6 +1307,8 @@ impl<'a> Resolver<'a> {
|
|||
macro_names: FxHashSet(),
|
||||
builtin_macros: FxHashMap(),
|
||||
lexical_macro_resolutions: Vec::new(),
|
||||
macro_map: FxHashMap(),
|
||||
macro_exports: Vec::new(),
|
||||
invocations: invocations,
|
||||
}
|
||||
}
|
||||
|
|
@ -1318,13 +1327,6 @@ impl<'a> Resolver<'a> {
|
|||
|
||||
/// Entry point to crate resolution.
|
||||
pub fn resolve_crate(&mut self, krate: &Crate) {
|
||||
// Collect `DefId`s for exported macro defs.
|
||||
for def in &krate.exported_macros {
|
||||
DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| {
|
||||
collector.visit_macro_def(def)
|
||||
})
|
||||
}
|
||||
|
||||
self.current_module = self.graph_root;
|
||||
visit::walk_crate(self, krate);
|
||||
|
||||
|
|
@ -1342,7 +1344,11 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
|
||||
fn get_ribs<'b>(&'b mut self, ns: Namespace) -> &'b mut Vec<Rib<'a>> {
|
||||
match ns { ValueNS => &mut self.value_ribs, TypeNS => &mut self.type_ribs }
|
||||
match ns {
|
||||
ValueNS => &mut self.value_ribs,
|
||||
TypeNS => &mut self.type_ribs,
|
||||
MacroNS => panic!("The macro namespace has no ribs"),
|
||||
}
|
||||
}
|
||||
|
||||
fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
|
||||
|
|
@ -3233,7 +3239,7 @@ impl<'a> Resolver<'a> {
|
|||
in_module.for_each_child(|name, ns, name_binding| {
|
||||
|
||||
// avoid imports entirely
|
||||
if name_binding.is_import() { return; }
|
||||
if name_binding.is_import() && !name_binding.is_extern_crate() { return; }
|
||||
|
||||
// collect results based on the filter function
|
||||
if name == lookup_name && ns == namespace {
|
||||
|
|
@ -3269,21 +3275,11 @@ impl<'a> Resolver<'a> {
|
|||
// collect submodules to explore
|
||||
if let Ok(module) = name_binding.module() {
|
||||
// form the path
|
||||
let path_segments = match module.kind {
|
||||
_ if module.parent.is_none() => path_segments.clone(),
|
||||
ModuleKind::Def(_, name) => {
|
||||
let mut paths = path_segments.clone();
|
||||
let ident = Ident::with_empty_ctxt(name);
|
||||
let params = PathParameters::none();
|
||||
let segm = PathSegment {
|
||||
identifier: ident,
|
||||
parameters: params,
|
||||
};
|
||||
paths.push(segm);
|
||||
paths
|
||||
}
|
||||
_ => bug!(),
|
||||
};
|
||||
let mut path_segments = path_segments.clone();
|
||||
path_segments.push(PathSegment {
|
||||
identifier: Ident::with_empty_ctxt(name),
|
||||
parameters: PathParameters::none(),
|
||||
});
|
||||
|
||||
if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
|
||||
// add the module to the lookup
|
||||
|
|
@ -3369,7 +3365,10 @@ impl<'a> Resolver<'a> {
|
|||
if !reported_spans.insert(span) { continue }
|
||||
if binding.is_extern_crate() {
|
||||
// Warn when using an inaccessible extern crate.
|
||||
let node_id = binding.module().unwrap().extern_crate_id.unwrap();
|
||||
let node_id = match binding.kind {
|
||||
NameBindingKind::Import { directive, .. } => directive.id,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let msg = format!("extern crate `{}` is private", name);
|
||||
self.session.add_lint(lint::builtin::INACCESSIBLE_EXTERN_CRATE, node_id, span, msg);
|
||||
} else {
|
||||
|
|
@ -3415,7 +3414,7 @@ impl<'a> Resolver<'a> {
|
|||
_ => "enum",
|
||||
};
|
||||
|
||||
let (participle, noun) = match old_binding.is_import() || old_binding.is_extern_crate() {
|
||||
let (participle, noun) = match old_binding.is_import() {
|
||||
true => ("imported", "import"),
|
||||
false => ("defined", "definition"),
|
||||
};
|
||||
|
|
@ -3424,7 +3423,8 @@ impl<'a> Resolver<'a> {
|
|||
let msg = {
|
||||
let kind = match (ns, old_binding.module()) {
|
||||
(ValueNS, _) => "a value",
|
||||
(TypeNS, Ok(module)) if module.extern_crate_id.is_some() => "an extern crate",
|
||||
(MacroNS, _) => "a macro",
|
||||
(TypeNS, _) if old_binding.is_extern_crate() => "an extern crate",
|
||||
(TypeNS, Ok(module)) if module.is_normal() => "a module",
|
||||
(TypeNS, Ok(module)) if module.is_trait() => "a trait",
|
||||
(TypeNS, _) => "a type",
|
||||
|
|
@ -3439,7 +3439,7 @@ impl<'a> Resolver<'a> {
|
|||
e.span_label(span, &format!("`{}` was already imported", name));
|
||||
e
|
||||
},
|
||||
(true, _) | (_, true) if binding.is_import() || old_binding.is_import() => {
|
||||
(true, _) | (_, true) if binding.is_import() && old_binding.is_import() => {
|
||||
let mut e = struct_span_err!(self.session, span, E0254, "{}", msg);
|
||||
e.span_label(span, &"already imported");
|
||||
e
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
|
||||
use {Module, Resolver};
|
||||
use build_reduced_graph::BuildReducedGraphVisitor;
|
||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex};
|
||||
use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex};
|
||||
use rustc::hir::def::{Def, Export};
|
||||
use rustc::hir::map::{self, DefCollector};
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
|
|
@ -23,6 +24,7 @@ use syntax::ext::hygiene::Mark;
|
|||
use syntax::ext::tt::macro_rules;
|
||||
use syntax::parse::token::intern;
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
use syntax::visit::Visitor;
|
||||
use syntax_pos::Span;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -128,6 +130,13 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||
|
||||
if export {
|
||||
def.id = self.next_node_id();
|
||||
DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| {
|
||||
collector.visit_macro_def(&def)
|
||||
});
|
||||
self.macro_exports.push(Export {
|
||||
name: def.ident.name,
|
||||
def: Def::Macro(self.definitions.local_def_id(def.id)),
|
||||
});
|
||||
self.exported_macros.push(def);
|
||||
}
|
||||
}
|
||||
|
|
@ -136,7 +145,12 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||
if let NormalTT(..) = *ext {
|
||||
self.macro_names.insert(ident.name);
|
||||
}
|
||||
self.builtin_macros.insert(ident.name, ext);
|
||||
let def_id = DefId {
|
||||
krate: BUILTIN_MACROS_CRATE,
|
||||
index: DefIndex::new(self.macro_map.len()),
|
||||
};
|
||||
self.macro_map.insert(def_id, ext);
|
||||
self.builtin_macros.insert(ident.name, def_id);
|
||||
}
|
||||
|
||||
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
|
||||
|
|
@ -147,7 +161,7 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||
for i in 0..attrs.len() {
|
||||
let name = intern(&attrs[i].name());
|
||||
match self.builtin_macros.get(&name) {
|
||||
Some(ext) => match **ext {
|
||||
Some(&def_id) => match *self.get_macro(Def::Macro(def_id)) {
|
||||
MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
|
||||
return Some(attrs.remove(i))
|
||||
}
|
||||
|
|
@ -226,7 +240,7 @@ impl<'a> Resolver<'a> {
|
|||
if let Some(scope) = possible_time_travel {
|
||||
self.lexical_macro_resolutions.push((name, scope));
|
||||
}
|
||||
self.builtin_macros.get(&name).cloned()
|
||||
self.builtin_macros.get(&name).cloned().map(|def_id| self.get_macro(Def::Macro(def_id)))
|
||||
}
|
||||
|
||||
fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
|
|||
use syntax_pos::Span;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::mem;
|
||||
|
||||
impl<'a> Resolver<'a> {
|
||||
pub fn resolve_imports(&mut self) {
|
||||
|
|
@ -51,6 +52,7 @@ pub enum ImportDirectiveSubclass<'a> {
|
|||
max_vis: Cell<ty::Visibility>, // The visibility of the greatest reexport.
|
||||
// n.b. `max_vis` is only used in `finalize_import` to check for reexport errors.
|
||||
},
|
||||
ExternCrate,
|
||||
}
|
||||
|
||||
impl<'a> ImportDirectiveSubclass<'a> {
|
||||
|
|
@ -68,12 +70,12 @@ impl<'a> ImportDirectiveSubclass<'a> {
|
|||
#[derive(Debug,Clone)]
|
||||
pub struct ImportDirective<'a> {
|
||||
pub id: NodeId,
|
||||
parent: Module<'a>,
|
||||
module_path: Vec<Ident>,
|
||||
imported_module: Cell<Option<Module<'a>>>, // the resolution of `module_path`
|
||||
subclass: ImportDirectiveSubclass<'a>,
|
||||
span: Span,
|
||||
vis: Cell<ty::Visibility>,
|
||||
pub parent: Module<'a>,
|
||||
pub module_path: Vec<Ident>,
|
||||
pub imported_module: Cell<Option<Module<'a>>>, // the resolution of `module_path`
|
||||
pub subclass: ImportDirectiveSubclass<'a>,
|
||||
pub span: Span,
|
||||
pub vis: Cell<ty::Visibility>,
|
||||
}
|
||||
|
||||
impl<'a> ImportDirective<'a> {
|
||||
|
|
@ -169,7 +171,8 @@ impl<'a> Resolver<'a> {
|
|||
let new_import_semantics = self.new_import_semantics;
|
||||
let is_disallowed_private_import = |binding: &NameBinding| {
|
||||
!new_import_semantics && !allow_private_imports && // disallowed
|
||||
binding.vis != ty::Visibility::Public && binding.is_import() // non-`pub` import
|
||||
binding.vis != ty::Visibility::Public && binding.is_import() && // non-`pub` import
|
||||
!binding.is_extern_crate() // not an `extern crate`
|
||||
};
|
||||
|
||||
if let Some(span) = record_used {
|
||||
|
|
@ -237,7 +240,7 @@ impl<'a> Resolver<'a> {
|
|||
};
|
||||
let name = match directive.subclass {
|
||||
SingleImport { source, .. } => source,
|
||||
GlobImport { .. } => unreachable!(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
match self.resolve_name_in_module(module, name, ns, true, None) {
|
||||
Failed(_) => {}
|
||||
|
|
@ -280,13 +283,14 @@ impl<'a> Resolver<'a> {
|
|||
// which are not relevant to import resolution.
|
||||
GlobImport { is_prelude: true, .. } => {}
|
||||
GlobImport { .. } => self.current_module.globs.borrow_mut().push(directive),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// Given a binding and an import directive that resolves to it,
|
||||
// return the corresponding binding defined by the import directive.
|
||||
fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
|
||||
-> NameBinding<'a> {
|
||||
pub fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
|
||||
-> NameBinding<'a> {
|
||||
let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) ||
|
||||
!directive.is_glob() && binding.is_extern_crate() { // c.f. `PRIVATE_IN_PUBLIC`
|
||||
directive.vis.get()
|
||||
|
|
@ -529,6 +533,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
|||
self.resolve_glob_import(directive);
|
||||
return Success(());
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let mut indeterminate = false;
|
||||
|
|
@ -616,6 +621,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
|||
}
|
||||
return Success(());
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] {
|
||||
|
|
@ -767,6 +773,10 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
|||
*module.globs.borrow_mut() = Vec::new();
|
||||
|
||||
let mut reexports = Vec::new();
|
||||
if module as *const _ == self.graph_root as *const _ {
|
||||
reexports = mem::replace(&mut self.macro_exports, Vec::new());
|
||||
}
|
||||
|
||||
for (&(name, ns), resolution) in module.resolutions.borrow().iter() {
|
||||
let resolution = resolution.borrow();
|
||||
let binding = match resolution.binding {
|
||||
|
|
@ -831,5 +841,6 @@ fn import_directive_subclass_to_string(subclass: &ImportDirectiveSubclass) -> St
|
|||
match *subclass {
|
||||
SingleImport { source, .. } => source.to_string(),
|
||||
GlobImport { .. } => "*".to_string(),
|
||||
ExternCrate => "<extern crate>".to_string(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -341,6 +341,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
|
|||
Def::AssociatedTy(..) |
|
||||
Def::AssociatedConst(..) |
|
||||
Def::PrimTy(_) |
|
||||
Def::Macro(_) |
|
||||
Def::Err => {
|
||||
span_bug!(span,
|
||||
"process_def_kind for unexpected item: {:?}",
|
||||
|
|
|
|||
|
|
@ -565,6 +565,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
Def::PrimTy(..) |
|
||||
Def::SelfTy(..) |
|
||||
Def::Label(..) |
|
||||
Def::Macro(..) |
|
||||
Def::Err => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use rustc_driver::{driver, target_features, abort_on_err};
|
|||
use rustc::dep_graph::DepGraph;
|
||||
use rustc::session::{self, config};
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::hir::def::{Def, ExportMap};
|
||||
use rustc::middle::privacy::AccessLevels;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::hir::map as hir_map;
|
||||
|
|
@ -74,6 +74,7 @@ pub struct DocContext<'a, 'tcx: 'a> {
|
|||
pub ty_substs: RefCell<FxHashMap<Def, clean::Type>>,
|
||||
/// Table node id of lifetime parameter definition -> substituted lifetime
|
||||
pub lt_substs: RefCell<FxHashMap<ast::NodeId, clean::Lifetime>>,
|
||||
pub export_map: ExportMap,
|
||||
}
|
||||
|
||||
impl<'b, 'tcx> DocContext<'b, 'tcx> {
|
||||
|
|
@ -196,7 +197,7 @@ pub fn run_core(search_paths: SearchPaths,
|
|||
sess.fatal("Compilation failed, aborting rustdoc");
|
||||
}
|
||||
|
||||
let ty::CrateAnalysis { access_levels, .. } = analysis;
|
||||
let ty::CrateAnalysis { access_levels, export_map, .. } = analysis;
|
||||
|
||||
// Convert from a NodeId set to a DefId set since we don't always have easy access
|
||||
// to the map from defid -> nodeid
|
||||
|
|
@ -218,6 +219,7 @@ pub fn run_core(search_paths: SearchPaths,
|
|||
renderinfo: Default::default(),
|
||||
ty_substs: Default::default(),
|
||||
lt_substs: Default::default(),
|
||||
export_map: export_map,
|
||||
};
|
||||
debug!("crate: {:?}", ctxt.map.krate());
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ pub fn run(input: &str,
|
|||
config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
|
||||
|
||||
let krate = panictry!(driver::phase_1_parse_input(&sess, &input));
|
||||
let driver::ExpansionResult { defs, mut hir_forest, .. } = {
|
||||
let driver::ExpansionResult { defs, mut hir_forest, analysis, .. } = {
|
||||
phase_2_configure_and_expand(
|
||||
&sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(())
|
||||
).expect("phase_2_configure_and_expand aborted in rustdoc!")
|
||||
|
|
@ -110,6 +110,7 @@ pub fn run(input: &str,
|
|||
renderinfo: Default::default(),
|
||||
ty_substs: Default::default(),
|
||||
lt_substs: Default::default(),
|
||||
export_map: analysis.export_map,
|
||||
};
|
||||
|
||||
let mut v = RustdocVisitor::new(&ctx);
|
||||
|
|
|
|||
|
|
@ -85,8 +85,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
&krate.module,
|
||||
None);
|
||||
// attach the crate's exported macros to the top-level module:
|
||||
self.module.macros = krate.exported_macros.iter()
|
||||
.map(|def| self.visit_macro(def)).collect();
|
||||
let macro_exports: Vec<_> =
|
||||
krate.exported_macros.iter().map(|def| self.visit_macro(def)).collect();
|
||||
self.module.macros.extend(macro_exports);
|
||||
self.module.is_crate = true;
|
||||
}
|
||||
|
||||
|
|
@ -191,6 +192,28 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
let item = self.cx.map.expect_item(i.id);
|
||||
self.visit_item(item, None, &mut om);
|
||||
}
|
||||
if let Some(exports) = self.cx.export_map.get(&id) {
|
||||
for export in exports {
|
||||
if let Def::Macro(def_id) = export.def {
|
||||
if def_id.krate == LOCAL_CRATE {
|
||||
continue // These are `krate.exported_macros`, handled in `self.visit()`.
|
||||
}
|
||||
let def = self.cx.sess().cstore.load_macro(def_id, self.cx.sess());
|
||||
// FIXME(jseyfried) merge with `self.visit_macro()`
|
||||
let matchers = def.body.chunks(4).map(|arm| arm[0].get_span()).collect();
|
||||
om.macros.push(Macro {
|
||||
id: def.id,
|
||||
attrs: def.attrs.clone().into(),
|
||||
name: def.ident.name,
|
||||
whence: def.span,
|
||||
matchers: matchers,
|
||||
stab: self.stability(def.id),
|
||||
depr: self.deprecation(def.id),
|
||||
imported_from: def.imported_from.map(|ident| ident.name),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
om
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:empty-struct.rs
|
||||
|
||||
#[no_link]
|
||||
extern crate libc;
|
||||
extern crate empty_struct;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
libc::abs(0); //~ ERROR unresolved name
|
||||
}
|
||||
empty_struct::XEmpty1; //~ ERROR unresolved name
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue