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:
bors 2016-11-10 02:05:45 -08:00 committed by GitHub
commit ab03f85522
24 changed files with 477 additions and 419 deletions

View file

@ -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",
}
}

View file

@ -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));

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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

View file

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

View file

@ -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]

View file

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

View file

@ -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, _)| {

View file

@ -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>

View file

@ -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,

View file

@ -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(&macro_def.body)
};
Entry {
kind: EntryKind::MacroDef(self.lazy(&macro_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);

View file

@ -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

View file

@ -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>>),

View file

@ -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(&macro_rules.body, mark);
let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, &macro_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");
}
}
}

View file

@ -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

View file

@ -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>) {

View file

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

View file

@ -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: {:?}",

View file

@ -565,6 +565,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
Def::PrimTy(..) |
Def::SelfTy(..) |
Def::Label(..) |
Def::Macro(..) |
Def::Err => None,
}
}

View file

@ -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());

View file

@ -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);

View file

@ -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
}

View file

@ -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
}