Auto merge of #37292 - jseyfried:import_macros_in_resolve, r=nrc
Process `#[macro_use]` imports in `resolve` and clean up macro loading Groundwork macro modularization (cc #35896). r? @nrc
This commit is contained in:
commit
affc3b7552
|
@ -716,8 +716,6 @@ impl<'a> LoweringContext<'a> {
|
||||||
id: m.id,
|
id: m.id,
|
||||||
span: m.span,
|
span: m.span,
|
||||||
imported_from: m.imported_from.map(|x| x.name),
|
imported_from: m.imported_from.map(|x| x.name),
|
||||||
export: m.export,
|
|
||||||
use_locally: m.use_locally,
|
|
||||||
allow_internal_unstable: m.allow_internal_unstable,
|
allow_internal_unstable: m.allow_internal_unstable,
|
||||||
body: m.body.clone().into(),
|
body: m.body.clone().into(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -458,8 +458,6 @@ pub struct MacroDef {
|
||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub imported_from: Option<Name>,
|
pub imported_from: Option<Name>,
|
||||||
pub export: bool,
|
|
||||||
pub use_locally: bool,
|
|
||||||
pub allow_internal_unstable: bool,
|
pub allow_internal_unstable: bool,
|
||||||
pub body: HirVec<TokenTree>,
|
pub body: HirVec<TokenTree>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ use util::nodemap::{NodeSet, DefIdMap};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::ext::base::MultiItemModifier;
|
use syntax::ext::base::SyntaxExtension;
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
use syntax::parse::token::InternedString;
|
use syntax::parse::token::InternedString;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
@ -417,18 +417,22 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
|
||||||
fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") }
|
fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LoadedMacro {
|
pub enum LoadedMacros {
|
||||||
pub import_site: Span,
|
MacroRules(Vec<ast::MacroDef>),
|
||||||
pub kind: LoadedMacroKind,
|
ProcMacros(Vec<(ast::Name, SyntaxExtension)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum LoadedMacroKind {
|
impl LoadedMacros {
|
||||||
Def(ast::MacroDef),
|
pub fn is_proc_macros(&self) -> bool {
|
||||||
CustomDerive(String, Box<MultiItemModifier>),
|
match *self {
|
||||||
|
LoadedMacros::ProcMacros(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CrateLoader {
|
pub trait CrateLoader {
|
||||||
fn load_macros(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro>;
|
fn process_item(&mut self, item: &ast::Item, defs: &Definitions, load_macros: bool)
|
||||||
fn process_item(&mut self, item: &ast::Item, defs: &Definitions);
|
-> Option<LoadedMacros>;
|
||||||
fn postprocess(&mut self, krate: &ast::Crate);
|
fn postprocess(&mut self, krate: &ast::Crate);
|
||||||
}
|
}
|
||||||
|
|
|
@ -675,13 +675,11 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
|
||||||
|
|
||||||
fn visit_macro_def(&mut self, macro_def: &'tcx MacroDef) {
|
fn visit_macro_def(&mut self, macro_def: &'tcx MacroDef) {
|
||||||
debug!("visit_macro_def: st={:?}", self.st);
|
debug!("visit_macro_def: st={:?}", self.st);
|
||||||
if macro_def.export {
|
SawMacroDef.hash(self.st);
|
||||||
SawMacroDef.hash(self.st);
|
hash_attrs!(self, ¯o_def.attrs);
|
||||||
hash_attrs!(self, ¯o_def.attrs);
|
visit::walk_macro_def(self, macro_def)
|
||||||
visit::walk_macro_def(self, macro_def)
|
// FIXME(mw): We should hash the body of the macro too but we don't
|
||||||
// FIXME(mw): We should hash the body of the macro too but we don't
|
// have a stable way of doing so yet.
|
||||||
// have a stable way of doing so yet.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,19 +12,18 @@
|
||||||
|
|
||||||
use cstore::{self, CStore, CrateSource, MetadataBlob};
|
use cstore::{self, CStore, CrateSource, MetadataBlob};
|
||||||
use locator::{self, CratePaths};
|
use locator::{self, CratePaths};
|
||||||
use macro_import;
|
|
||||||
use schema::CrateRoot;
|
use schema::CrateRoot;
|
||||||
|
|
||||||
use rustc::hir::def_id::{CrateNum, DefIndex};
|
use rustc::hir::def_id::{CrateNum, DefIndex};
|
||||||
use rustc::hir::svh::Svh;
|
use rustc::hir::svh::Svh;
|
||||||
use rustc::middle::cstore::LoadedMacro;
|
use rustc::middle::cstore::LoadedMacros;
|
||||||
use rustc::session::{config, Session};
|
use rustc::session::{config, Session};
|
||||||
use rustc_back::PanicStrategy;
|
use rustc_back::PanicStrategy;
|
||||||
use rustc::session::search_paths::PathKind;
|
use rustc::session::search_paths::PathKind;
|
||||||
use rustc::middle;
|
use rustc::middle;
|
||||||
use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
|
use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
|
||||||
use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
|
use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
|
||||||
use rustc::hir::map as hir_map;
|
use rustc::hir::map::Definitions;
|
||||||
|
|
||||||
use std::cell::{RefCell, Cell};
|
use std::cell::{RefCell, Cell};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -36,7 +35,8 @@ use syntax::ast;
|
||||||
use syntax::abi::Abi;
|
use syntax::abi::Abi;
|
||||||
use syntax::parse;
|
use syntax::parse;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::parse::token::InternedString;
|
use syntax::ext::base::SyntaxExtension;
|
||||||
|
use syntax::parse::token::{InternedString, intern};
|
||||||
use syntax_pos::{self, Span, mk_sp};
|
use syntax_pos::{self, Span, mk_sp};
|
||||||
use log;
|
use log;
|
||||||
|
|
||||||
|
@ -120,11 +120,6 @@ struct ExtensionCrate {
|
||||||
metadata: PMDSource,
|
metadata: PMDSource,
|
||||||
dylib: Option<PathBuf>,
|
dylib: Option<PathBuf>,
|
||||||
target_only: bool,
|
target_only: bool,
|
||||||
|
|
||||||
ident: String,
|
|
||||||
name: String,
|
|
||||||
span: Span,
|
|
||||||
should_link: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PMDSource {
|
enum PMDSource {
|
||||||
|
@ -148,17 +143,6 @@ enum LoadResult {
|
||||||
Loaded(Library),
|
Loaded(Library),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Macros {
|
|
||||||
pub macro_rules: Vec<ast::MacroDef>,
|
|
||||||
|
|
||||||
/// An array of pairs where the first element is the name of the custom
|
|
||||||
/// derive (e.g. the trait being derived) and the second element is the
|
|
||||||
/// index of the definition.
|
|
||||||
pub custom_derive_registrar: Option<DefIndex>,
|
|
||||||
pub svh: Svh,
|
|
||||||
pub dylib: Option<PathBuf>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CrateLoader<'a> {
|
impl<'a> CrateLoader<'a> {
|
||||||
pub fn new(sess: &'a Session,
|
pub fn new(sess: &'a Session,
|
||||||
cstore: &'a CStore,
|
cstore: &'a CStore,
|
||||||
|
@ -490,7 +474,6 @@ impl<'a> CrateLoader<'a> {
|
||||||
info.id, info.name, info.ident, info.should_link);
|
info.id, info.name, info.ident, info.should_link);
|
||||||
let target_triple = &self.sess.opts.target_triple[..];
|
let target_triple = &self.sess.opts.target_triple[..];
|
||||||
let is_cross = target_triple != config::host_triple();
|
let is_cross = target_triple != config::host_triple();
|
||||||
let mut should_link = info.should_link && !is_cross;
|
|
||||||
let mut target_only = false;
|
let mut target_only = false;
|
||||||
let ident = info.ident.clone();
|
let ident = info.ident.clone();
|
||||||
let name = info.name.clone();
|
let name = info.name.clone();
|
||||||
|
@ -517,7 +500,6 @@ impl<'a> CrateLoader<'a> {
|
||||||
// Try loading from target crates. This will abort later if we
|
// Try loading from target crates. This will abort later if we
|
||||||
// try to load a plugin registrar function,
|
// try to load a plugin registrar function,
|
||||||
target_only = true;
|
target_only = true;
|
||||||
should_link = info.should_link;
|
|
||||||
|
|
||||||
locate_ctxt.target = &self.sess.target.target;
|
locate_ctxt.target = &self.sess.target.target;
|
||||||
locate_ctxt.triple = target_triple;
|
locate_ctxt.triple = target_triple;
|
||||||
|
@ -547,25 +529,14 @@ impl<'a> CrateLoader<'a> {
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
dylib: dylib.map(|p| p.0),
|
dylib: dylib.map(|p| p.0),
|
||||||
target_only: target_only,
|
target_only: target_only,
|
||||||
name: info.name.to_string(),
|
|
||||||
ident: info.ident.to_string(),
|
|
||||||
span: span,
|
|
||||||
should_link: should_link,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_macros(&mut self, item: &ast::Item) -> Macros {
|
fn read_macros(&mut self, item: &ast::Item, ekrate: &ExtensionCrate) -> LoadedMacros {
|
||||||
let ci = self.extract_crate_info(item).unwrap();
|
|
||||||
let ekrate = self.read_extension_crate(item.span, &ci);
|
|
||||||
|
|
||||||
let root = ekrate.metadata.get_root();
|
let root = ekrate.metadata.get_root();
|
||||||
let source_name = format!("<{} macros>", item.ident);
|
let source_name = format!("<{} macros>", item.ident);
|
||||||
let mut ret = Macros {
|
let mut macro_rules = Vec::new();
|
||||||
macro_rules: Vec::new(),
|
|
||||||
custom_derive_registrar: None,
|
|
||||||
svh: root.hash,
|
|
||||||
dylib: None,
|
|
||||||
};
|
|
||||||
for def in root.macro_defs.decode(&*ekrate.metadata) {
|
for def in root.macro_defs.decode(&*ekrate.metadata) {
|
||||||
// NB: Don't use parse::parse_tts_from_source_str because it parses with
|
// NB: Don't use parse::parse_tts_from_source_str because it parses with
|
||||||
// quote_depth > 0.
|
// quote_depth > 0.
|
||||||
|
@ -589,54 +560,90 @@ impl<'a> CrateLoader<'a> {
|
||||||
attr::mark_used(attr);
|
attr::mark_used(attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.macro_rules.push(ast::MacroDef {
|
macro_rules.push(ast::MacroDef {
|
||||||
ident: ast::Ident::with_empty_ctxt(def.name),
|
ident: ast::Ident::with_empty_ctxt(def.name),
|
||||||
attrs: def.attrs,
|
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
span: local_span,
|
span: local_span,
|
||||||
imported_from: Some(item.ident),
|
imported_from: Some(item.ident),
|
||||||
// overridden in plugin/load.rs
|
allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"),
|
||||||
export: false,
|
attrs: def.attrs,
|
||||||
use_locally: false,
|
|
||||||
allow_internal_unstable: false,
|
|
||||||
|
|
||||||
body: body,
|
body: body,
|
||||||
});
|
});
|
||||||
self.sess.imported_macro_spans.borrow_mut()
|
self.sess.imported_macro_spans.borrow_mut()
|
||||||
.insert(local_span, (def.name.as_str().to_string(), def.span));
|
.insert(local_span, (def.name.as_str().to_string(), def.span));
|
||||||
}
|
}
|
||||||
|
|
||||||
match root.macro_derive_registrar {
|
if let Some(id) = root.macro_derive_registrar {
|
||||||
Some(id) => ret.custom_derive_registrar = Some(id),
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
// If this crate is not a proc-macro crate then we might be able to
|
// custom derive crates currently should not have any macro_rules!
|
||||||
// register it with the local crate store to prevent loading the
|
// exported macros, enforced elsewhere
|
||||||
// metadata twice.
|
assert_eq!(macro_rules.len(), 0);
|
||||||
//
|
LoadedMacros::ProcMacros(self.load_derive_macros(item, id, root.hash, dylib))
|
||||||
// If it's a proc-macro crate, though, then we definitely don't
|
} else {
|
||||||
// want to register it with the local crate store as we're just
|
LoadedMacros::MacroRules(macro_rules)
|
||||||
// going to use it as we would a plugin.
|
}
|
||||||
None => {
|
}
|
||||||
ekrate.register(self);
|
|
||||||
return ret
|
/// Load custom derive macros.
|
||||||
|
///
|
||||||
|
/// Note that this is intentionally similar to how we load plugins today,
|
||||||
|
/// but also intentionally separate. Plugins are likely always going to be
|
||||||
|
/// 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)> {
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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)) {
|
||||||
|
Ok(lib) => lib,
|
||||||
|
Err(err) => self.sess.span_fatal(item.span, &err),
|
||||||
|
};
|
||||||
|
|
||||||
|
let sym = self.sess.generate_derive_registrar_symbol(&svh, index);
|
||||||
|
let registrar = unsafe {
|
||||||
|
let sym = match lib.symbol(&sym) {
|
||||||
|
Ok(f) => f,
|
||||||
|
Err(err) => self.sess.span_fatal(item.span, &err),
|
||||||
|
};
|
||||||
|
mem::transmute::<*mut u8, fn(&mut Registry)>(sym)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MyRegistrar(Vec<(ast::Name, SyntaxExtension)>);
|
||||||
|
|
||||||
|
impl Registry for MyRegistrar {
|
||||||
|
fn register_custom_derive(&mut self,
|
||||||
|
trait_name: &str,
|
||||||
|
expand: fn(TokenStream) -> TokenStream) {
|
||||||
|
let derive = SyntaxExtension::CustomDerive(Box::new(CustomDerive::new(expand)));
|
||||||
|
self.0.push((intern(trait_name), derive));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.cstore.add_used_for_derive_macros(item);
|
let mut my_registrar = MyRegistrar(Vec::new());
|
||||||
ret.dylib = ekrate.dylib.clone();
|
registrar(&mut my_registrar);
|
||||||
if ret.dylib.is_none() {
|
|
||||||
span_bug!(item.span, "proc-macro crate not dylib");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ekrate.target_only {
|
// Intentionally leak the dynamic library. We can't ever unload it
|
||||||
let message = format!("proc-macro crate is not available for \
|
// since the library can make things that will live arbitrarily long.
|
||||||
triple `{}` (only found {})",
|
mem::forget(lib);
|
||||||
config::host_triple(),
|
my_registrar.0
|
||||||
self.sess.opts.target_triple);
|
|
||||||
self.sess.span_fatal(item.span, &message);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Look for a plugin registrar. Returns library path, crate
|
/// Look for a plugin registrar. Returns library path, crate
|
||||||
|
@ -889,22 +896,6 @@ impl<'a> CrateLoader<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtensionCrate {
|
|
||||||
fn register(self, loader: &mut CrateLoader) {
|
|
||||||
if !self.should_link {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let library = match self.metadata {
|
|
||||||
PMDSource::Owned(lib) => lib,
|
|
||||||
PMDSource::Registered(_) => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Register crate now to avoid double-reading metadata
|
|
||||||
loader.register_crate(&None, &self.ident, &self.name, self.span, library, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CrateLoader<'a> {
|
impl<'a> CrateLoader<'a> {
|
||||||
pub fn preprocess(&mut self, krate: &ast::Crate) {
|
pub fn preprocess(&mut self, krate: &ast::Crate) {
|
||||||
for attr in krate.attrs.iter().filter(|m| m.name() == "link_args") {
|
for attr in krate.attrs.iter().filter(|m| m.name() == "link_args") {
|
||||||
|
@ -990,47 +981,56 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
|
||||||
self.register_statically_included_foreign_items();
|
self.register_statically_included_foreign_items();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_item(&mut self, item: &ast::Item, definitions: &hir_map::Definitions) {
|
fn process_item(&mut self, item: &ast::Item, definitions: &Definitions, load_macros: bool)
|
||||||
|
-> Option<LoadedMacros> {
|
||||||
match item.node {
|
match item.node {
|
||||||
ast::ItemKind::ExternCrate(_) => {}
|
ast::ItemKind::ExternCrate(_) => {}
|
||||||
ast::ItemKind::ForeignMod(ref fm) => return self.process_foreign_mod(item, fm),
|
ast::ItemKind::ForeignMod(ref fm) => {
|
||||||
_ => return,
|
self.process_foreign_mod(item, fm);
|
||||||
}
|
return None;
|
||||||
|
|
||||||
// If this `extern crate` item has `#[macro_use]` then we can safely skip it.
|
|
||||||
// These annotations were processed during macro expansion and are already loaded
|
|
||||||
// (if necessary) into our crate store.
|
|
||||||
//
|
|
||||||
// Note that it's important we *don't* fall through below as some `#[macro_use]`
|
|
||||||
// crates are explicitly not linked (e.g. macro crates) so we want to ensure
|
|
||||||
// we avoid `resolve_crate` with those.
|
|
||||||
if attr::contains_name(&item.attrs, "macro_use") {
|
|
||||||
if self.cstore.was_used_for_derive_macros(item) {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
_ => return None,
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(info) = self.extract_crate_info(item) {
|
let info = self.extract_crate_info(item).unwrap();
|
||||||
|
let loaded_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(loaded_macros)
|
||||||
|
} else {
|
||||||
if !info.should_link {
|
if !info.should_link {
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let (cnum, ..) = self.resolve_crate(
|
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, true,
|
||||||
);
|
);
|
||||||
|
|
||||||
let def_id = definitions.opt_local_def_id(item.id).unwrap();
|
let def_id = definitions.opt_local_def_id(item.id).unwrap();
|
||||||
let len = definitions.def_path(def_id.index).data.len();
|
let len = definitions.def_path(def_id.index).data.len();
|
||||||
|
|
||||||
let extern_crate =
|
let extern_crate =
|
||||||
ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len };
|
ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len };
|
||||||
self.update_extern_crate(cnum, extern_crate, &mut FnvHashSet());
|
self.update_extern_crate(cnum, extern_crate, &mut FnvHashSet());
|
||||||
|
self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
|
||||||
|
|
||||||
self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
|
loaded_macros
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_macros(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro> {
|
|
||||||
macro_import::load_macros(self, extern_crate, allows_macros)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,14 +21,13 @@ use rustc::hir::svh::Svh;
|
||||||
use rustc::middle::cstore::ExternCrate;
|
use rustc::middle::cstore::ExternCrate;
|
||||||
use rustc_back::PanicStrategy;
|
use rustc_back::PanicStrategy;
|
||||||
use rustc_data_structures::indexed_vec::IndexVec;
|
use rustc_data_structures::indexed_vec::IndexVec;
|
||||||
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap, FnvHashSet};
|
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
|
||||||
|
|
||||||
use std::cell::{RefCell, Cell};
|
use std::cell::{RefCell, Cell};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use flate::Bytes;
|
use flate::Bytes;
|
||||||
use syntax::ast::{self, Ident};
|
use syntax::{ast, attr};
|
||||||
use syntax::attr;
|
|
||||||
use syntax_pos;
|
use syntax_pos;
|
||||||
|
|
||||||
pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference};
|
pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference};
|
||||||
|
@ -105,7 +104,6 @@ pub struct CStore {
|
||||||
pub inlined_item_cache: RefCell<DefIdMap<Option<CachedInlinedItem>>>,
|
pub inlined_item_cache: RefCell<DefIdMap<Option<CachedInlinedItem>>>,
|
||||||
pub defid_for_inlined_node: RefCell<NodeMap<DefId>>,
|
pub defid_for_inlined_node: RefCell<NodeMap<DefId>>,
|
||||||
pub visible_parent_map: RefCell<DefIdMap<DefId>>,
|
pub visible_parent_map: RefCell<DefIdMap<DefId>>,
|
||||||
pub used_for_derive_macro: RefCell<FnvHashSet<Ident>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CStore {
|
impl CStore {
|
||||||
|
@ -121,7 +119,6 @@ impl CStore {
|
||||||
visible_parent_map: RefCell::new(FnvHashMap()),
|
visible_parent_map: RefCell::new(FnvHashMap()),
|
||||||
inlined_item_cache: RefCell::new(FnvHashMap()),
|
inlined_item_cache: RefCell::new(FnvHashMap()),
|
||||||
defid_for_inlined_node: RefCell::new(FnvHashMap()),
|
defid_for_inlined_node: RefCell::new(FnvHashMap()),
|
||||||
used_for_derive_macro: RefCell::new(FnvHashSet()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,14 +276,6 @@ impl CStore {
|
||||||
pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
|
pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
|
||||||
self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
|
self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn was_used_for_derive_macros(&self, i: &ast::Item) -> bool {
|
|
||||||
self.used_for_derive_macro.borrow().contains(&i.ident)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_used_for_derive_macros(&self, i: &ast::Item) {
|
|
||||||
self.used_for_derive_macro.borrow_mut().insert(i.ident);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CrateMetadata {
|
impl CrateMetadata {
|
||||||
|
|
|
@ -91,185 +91,6 @@ You need to link your code to the relevant crate in order to be able to use it
|
||||||
well, and you link to them the same way.
|
well, and you link to them the same way.
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
E0466: r##"
|
|
||||||
Macro import declarations were malformed.
|
|
||||||
|
|
||||||
Erroneous code examples:
|
|
||||||
|
|
||||||
```compile_fail,E0466
|
|
||||||
#[macro_use(a_macro(another_macro))] // error: invalid import declaration
|
|
||||||
extern crate core as some_crate;
|
|
||||||
|
|
||||||
#[macro_use(i_want = "some_macros")] // error: invalid import declaration
|
|
||||||
extern crate core as another_crate;
|
|
||||||
```
|
|
||||||
|
|
||||||
This is a syntax error at the level of attribute declarations. The proper
|
|
||||||
syntax for macro imports is the following:
|
|
||||||
|
|
||||||
```ignore
|
|
||||||
// In some_crate:
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! get_tacos {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! get_pimientos {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
// In your crate:
|
|
||||||
#[macro_use(get_tacos, get_pimientos)] // It imports `get_tacos` and
|
|
||||||
extern crate some_crate; // `get_pimientos` macros from some_crate
|
|
||||||
```
|
|
||||||
|
|
||||||
If you would like to import all exported macros, write `macro_use` with no
|
|
||||||
arguments.
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0467: r##"
|
|
||||||
Macro reexport declarations were empty or malformed.
|
|
||||||
|
|
||||||
Erroneous code examples:
|
|
||||||
|
|
||||||
```compile_fail,E0467
|
|
||||||
#[macro_reexport] // error: no macros listed for export
|
|
||||||
extern crate core as macros_for_good;
|
|
||||||
|
|
||||||
#[macro_reexport(fun_macro = "foo")] // error: not a macro identifier
|
|
||||||
extern crate core as other_macros_for_good;
|
|
||||||
```
|
|
||||||
|
|
||||||
This is a syntax error at the level of attribute declarations.
|
|
||||||
|
|
||||||
Currently, `macro_reexport` requires at least one macro name to be listed.
|
|
||||||
Unlike `macro_use`, listing no names does not reexport all macros from the
|
|
||||||
given crate.
|
|
||||||
|
|
||||||
Decide which macros you would like to export and list them properly.
|
|
||||||
|
|
||||||
These are proper reexport declarations:
|
|
||||||
|
|
||||||
```ignore
|
|
||||||
#[macro_reexport(some_macro, another_macro)]
|
|
||||||
extern crate macros_for_good;
|
|
||||||
```
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0468: r##"
|
|
||||||
A non-root module attempts to import macros from another crate.
|
|
||||||
|
|
||||||
Example of erroneous code:
|
|
||||||
|
|
||||||
```compile_fail,E0468
|
|
||||||
mod foo {
|
|
||||||
#[macro_use(helpful_macro)] // error: must be at crate root to import
|
|
||||||
extern crate core; // macros from another crate
|
|
||||||
helpful_macro!(...);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Only `extern crate` imports at the crate root level are allowed to import
|
|
||||||
macros.
|
|
||||||
|
|
||||||
Either move the macro import to crate root or do without the foreign macros.
|
|
||||||
This will work:
|
|
||||||
|
|
||||||
```ignore
|
|
||||||
#[macro_use(helpful_macro)]
|
|
||||||
extern crate some_crate;
|
|
||||||
|
|
||||||
mod foo {
|
|
||||||
helpful_macro!(...)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0469: r##"
|
|
||||||
A macro listed for import was not found.
|
|
||||||
|
|
||||||
Erroneous code example:
|
|
||||||
|
|
||||||
```compile_fail,E0469
|
|
||||||
#[macro_use(drink, be_merry)] // error: imported macro not found
|
|
||||||
extern crate collections;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Either the listed macro is not contained in the imported crate, or it is not
|
|
||||||
exported from the given crate.
|
|
||||||
|
|
||||||
This could be caused by a typo. Did you misspell the macro's name?
|
|
||||||
|
|
||||||
Double-check the names of the macros listed for import, and that the crate
|
|
||||||
in question exports them.
|
|
||||||
|
|
||||||
A working version would be:
|
|
||||||
|
|
||||||
```ignore
|
|
||||||
// In some_crate crate:
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! eat {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! drink {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
// In your crate:
|
|
||||||
#[macro_use(eat, drink)]
|
|
||||||
extern crate some_crate; //ok!
|
|
||||||
```
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0470: r##"
|
|
||||||
A macro listed for reexport was not found.
|
|
||||||
|
|
||||||
Erroneous code example:
|
|
||||||
|
|
||||||
```compile_fail,E0470
|
|
||||||
#[macro_reexport(drink, be_merry)]
|
|
||||||
extern crate collections;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Either the listed macro is not contained in the imported crate, or it is not
|
|
||||||
exported from the given crate.
|
|
||||||
|
|
||||||
This could be caused by a typo. Did you misspell the macro's name?
|
|
||||||
|
|
||||||
Double-check the names of the macros listed for reexport, and that the crate
|
|
||||||
in question exports them.
|
|
||||||
|
|
||||||
A working version:
|
|
||||||
|
|
||||||
```ignore
|
|
||||||
// In some_crate crate:
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! eat {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! drink {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
// In your_crate:
|
|
||||||
#[macro_reexport(eat, drink)]
|
|
||||||
extern crate some_crate;
|
|
||||||
```
|
|
||||||
"##,
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
register_diagnostics! {
|
register_diagnostics! {
|
||||||
|
|
|
@ -59,6 +59,5 @@ mod schema;
|
||||||
pub mod creader;
|
pub mod creader;
|
||||||
pub mod cstore;
|
pub mod cstore;
|
||||||
pub mod locator;
|
pub mod locator;
|
||||||
pub mod macro_import;
|
|
||||||
|
|
||||||
__build_diagnostic_array! { librustc_metadata, DIAGNOSTICS }
|
__build_diagnostic_array! { librustc_metadata, DIAGNOSTICS }
|
||||||
|
|
|
@ -1,235 +0,0 @@
|
||||||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Used by `rustc` when loading a crate with exported macros.
|
|
||||||
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::env;
|
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
use creader::{CrateLoader, Macros};
|
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
|
||||||
use proc_macro::__internal::Registry;
|
|
||||||
use rustc::hir::def_id::DefIndex;
|
|
||||||
use rustc::middle::cstore::{LoadedMacro, LoadedMacroKind};
|
|
||||||
use rustc::session::Session;
|
|
||||||
use rustc::util::nodemap::FnvHashMap;
|
|
||||||
use rustc_back::dynamic_lib::DynamicLibrary;
|
|
||||||
use syntax::ast;
|
|
||||||
use syntax::attr;
|
|
||||||
use syntax::parse::token;
|
|
||||||
use syntax_ext::deriving::custom::CustomDerive;
|
|
||||||
use syntax_pos::{Span, DUMMY_SP};
|
|
||||||
|
|
||||||
pub fn call_bad_macro_reexport(a: &Session, b: Span) {
|
|
||||||
span_err!(a, b, E0467, "bad macro reexport");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type MacroSelection = FnvHashMap<token::InternedString, Span>;
|
|
||||||
|
|
||||||
enum ImportSelection {
|
|
||||||
All(Span),
|
|
||||||
Some(MacroSelection),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_macros(loader: &mut CrateLoader, extern_crate: &ast::Item, allows_macros: bool)
|
|
||||||
-> Vec<LoadedMacro> {
|
|
||||||
loader.load_crate(extern_crate, allows_macros)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CrateLoader<'a> {
|
|
||||||
fn load_crate(&mut self,
|
|
||||||
extern_crate: &ast::Item,
|
|
||||||
allows_macros: bool) -> Vec<LoadedMacro> {
|
|
||||||
// Parse the attributes relating to macros.
|
|
||||||
let mut import = ImportSelection::Some(FnvHashMap());
|
|
||||||
let mut reexport = FnvHashMap();
|
|
||||||
let mut no_link = false;
|
|
||||||
|
|
||||||
for attr in &extern_crate.attrs {
|
|
||||||
let mut used = true;
|
|
||||||
match &attr.name()[..] {
|
|
||||||
"macro_use" => {
|
|
||||||
let names = attr.meta_item_list();
|
|
||||||
if names.is_none() {
|
|
||||||
import = ImportSelection::All(attr.span);
|
|
||||||
} else if let ImportSelection::Some(ref mut sel) = import {
|
|
||||||
for attr in names.unwrap() {
|
|
||||||
if let Some(word) = attr.word() {
|
|
||||||
sel.insert(word.name().clone(), attr.span());
|
|
||||||
} else {
|
|
||||||
span_err!(self.sess, attr.span(), E0466, "bad macro import");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"macro_reexport" => {
|
|
||||||
let names = match attr.meta_item_list() {
|
|
||||||
Some(names) => names,
|
|
||||||
None => {
|
|
||||||
call_bad_macro_reexport(self.sess, attr.span);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for attr in names {
|
|
||||||
if let Some(word) = attr.word() {
|
|
||||||
reexport.insert(word.name().clone(), attr.span());
|
|
||||||
} else {
|
|
||||||
call_bad_macro_reexport(self.sess, attr.span());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"no_link" => no_link = true,
|
|
||||||
_ => used = false,
|
|
||||||
}
|
|
||||||
if used {
|
|
||||||
attr::mark_used(attr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.load_macros(extern_crate, allows_macros, import, reexport, no_link)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_macros<'b>(&mut self,
|
|
||||||
vi: &ast::Item,
|
|
||||||
allows_macros: bool,
|
|
||||||
import: ImportSelection,
|
|
||||||
reexport: MacroSelection,
|
|
||||||
no_link: bool)
|
|
||||||
-> Vec<LoadedMacro> {
|
|
||||||
if let ImportSelection::Some(ref sel) = import {
|
|
||||||
if sel.is_empty() && reexport.is_empty() {
|
|
||||||
// Make sure we can read macros from `#[no_link]` crates.
|
|
||||||
if no_link {
|
|
||||||
self.read_macros(vi);
|
|
||||||
}
|
|
||||||
return Vec::new();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !allows_macros {
|
|
||||||
span_err!(self.sess, vi.span, E0468,
|
|
||||||
"an `extern crate` loading macros must be at the crate root");
|
|
||||||
return Vec::new();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut macros = self.read_macros(vi);
|
|
||||||
let mut ret = Vec::new();
|
|
||||||
let mut seen = HashSet::new();
|
|
||||||
|
|
||||||
for mut def in macros.macro_rules.drain(..) {
|
|
||||||
let name = def.ident.name.as_str();
|
|
||||||
|
|
||||||
let import_site = match import {
|
|
||||||
ImportSelection::All(span) => Some(span),
|
|
||||||
ImportSelection::Some(ref sel) => sel.get(&name).cloned()
|
|
||||||
};
|
|
||||||
def.use_locally = import_site.is_some();
|
|
||||||
def.export = reexport.contains_key(&name);
|
|
||||||
def.allow_internal_unstable = attr::contains_name(&def.attrs,
|
|
||||||
"allow_internal_unstable");
|
|
||||||
debug!("load_macros: loaded: {:?}", def);
|
|
||||||
ret.push(LoadedMacro {
|
|
||||||
kind: LoadedMacroKind::Def(def),
|
|
||||||
import_site: import_site.unwrap_or(DUMMY_SP),
|
|
||||||
});
|
|
||||||
seen.insert(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(index) = macros.custom_derive_registrar {
|
|
||||||
// custom derive crates currently should not have any macro_rules!
|
|
||||||
// exported macros, enforced elsewhere
|
|
||||||
assert_eq!(ret.len(), 0);
|
|
||||||
|
|
||||||
if let ImportSelection::Some(..) = import {
|
|
||||||
self.sess.span_err(vi.span, "`proc-macro` crates cannot be \
|
|
||||||
selectively imported from, must \
|
|
||||||
use `#[macro_use]`");
|
|
||||||
}
|
|
||||||
|
|
||||||
if reexport.len() > 0 {
|
|
||||||
self.sess.span_err(vi.span, "`proc-macro` crates cannot be \
|
|
||||||
reexported from");
|
|
||||||
}
|
|
||||||
|
|
||||||
self.load_derive_macros(vi.span, ¯os, index, &mut ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let ImportSelection::Some(sel) = import {
|
|
||||||
for (name, span) in sel {
|
|
||||||
if !seen.contains(&name) {
|
|
||||||
span_err!(self.sess, span, E0469,
|
|
||||||
"imported macro not found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (name, span) in &reexport {
|
|
||||||
if !seen.contains(&name) {
|
|
||||||
span_err!(self.sess, *span, E0470,
|
|
||||||
"reexported macro not found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load the custom derive macros into the list of macros we're loading.
|
|
||||||
///
|
|
||||||
/// Note that this is intentionally similar to how we load plugins today,
|
|
||||||
/// but also intentionally separate. Plugins are likely always going to be
|
|
||||||
/// 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,
|
|
||||||
span: Span,
|
|
||||||
macros: &Macros,
|
|
||||||
index: DefIndex,
|
|
||||||
ret: &mut Vec<LoadedMacro>) {
|
|
||||||
// Make sure the path contains a / or the linker will search for it.
|
|
||||||
let path = macros.dylib.as_ref().unwrap();
|
|
||||||
let path = env::current_dir().unwrap().join(path);
|
|
||||||
let lib = match DynamicLibrary::open(Some(&path)) {
|
|
||||||
Ok(lib) => lib,
|
|
||||||
Err(err) => self.sess.span_fatal(span, &err),
|
|
||||||
};
|
|
||||||
|
|
||||||
let sym = self.sess.generate_derive_registrar_symbol(¯os.svh, index);
|
|
||||||
let registrar = unsafe {
|
|
||||||
let sym = match lib.symbol(&sym) {
|
|
||||||
Ok(f) => f,
|
|
||||||
Err(err) => self.sess.span_fatal(span, &err),
|
|
||||||
};
|
|
||||||
mem::transmute::<*mut u8, fn(&mut Registry)>(sym)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MyRegistrar<'a>(&'a mut Vec<LoadedMacro>, Span);
|
|
||||||
|
|
||||||
impl<'a> Registry for MyRegistrar<'a> {
|
|
||||||
fn register_custom_derive(&mut self,
|
|
||||||
trait_name: &str,
|
|
||||||
expand: fn(TokenStream) -> TokenStream) {
|
|
||||||
let derive = Box::new(CustomDerive::new(expand));
|
|
||||||
self.0.push(LoadedMacro {
|
|
||||||
kind: LoadedMacroKind::CustomDerive(trait_name.to_string(), derive),
|
|
||||||
import_site: self.1,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
registrar(&mut MyRegistrar(ret, span));
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,10 +21,11 @@ use {NameBinding, NameBindingKind, ToNameBinding};
|
||||||
use Resolver;
|
use Resolver;
|
||||||
use {resolve_error, resolve_struct_error, ResolutionError};
|
use {resolve_error, resolve_struct_error, ResolutionError};
|
||||||
|
|
||||||
use rustc::middle::cstore::LoadedMacroKind;
|
use rustc::middle::cstore::LoadedMacros;
|
||||||
use rustc::hir::def::*;
|
use rustc::hir::def::*;
|
||||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
|
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
|
use rustc::util::nodemap::FnvHashMap;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -58,6 +59,14 @@ impl<'a> ToNameBinding<'a> for (Def, Span, ty::Visibility) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, PartialEq, Eq)]
|
||||||
|
struct LegacyMacroImports {
|
||||||
|
import_all: Option<Span>,
|
||||||
|
imports: Vec<(Name, Span)>,
|
||||||
|
reexports: Vec<(Name, Span)>,
|
||||||
|
no_link: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'b> Resolver<'b> {
|
impl<'b> Resolver<'b> {
|
||||||
/// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
|
/// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
|
||||||
/// otherwise, reports an error.
|
/// otherwise, reports an error.
|
||||||
|
@ -193,57 +202,27 @@ impl<'b> Resolver<'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemKind::ExternCrate(_) => {
|
ItemKind::ExternCrate(_) => {
|
||||||
// We need to error on `#[macro_use] extern crate` when it isn't at the
|
let legacy_imports = self.legacy_macro_imports(&item.attrs);
|
||||||
// crate root, because `$crate` won't work properly.
|
// `#[macro_use]` and `#[macro_reexport]` are only allowed at the crate root.
|
||||||
let is_crate_root = self.current_module.parent.is_none();
|
if self.current_module.parent.is_some() && {
|
||||||
let import_macro = |this: &mut Self, name, ext, span| {
|
legacy_imports.import_all.is_some() || !legacy_imports.imports.is_empty() ||
|
||||||
let shadowing = this.builtin_macros.insert(name, Rc::new(ext)).is_some();
|
!legacy_imports.reexports.is_empty()
|
||||||
if shadowing && expansion != Mark::root() {
|
} {
|
||||||
let msg = format!("`{}` is already in scope", name);
|
if self.current_module.parent.is_some() {
|
||||||
this.session.struct_span_err(span, &msg)
|
span_err!(self.session, item.span, E0468,
|
||||||
.note("macro-expanded `#[macro_use]`s may not shadow \
|
"an `extern crate` loading macros must be at the crate root");
|
||||||
existing macros (see RFC 1560)")
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 mut custom_derive_crate = false;
|
|
||||||
// The mark of the expansion that generates the loaded macros.
|
|
||||||
let mut opt_mark = None;
|
|
||||||
for loaded_macro in self.crate_loader.load_macros(item, is_crate_root) {
|
|
||||||
let mark = opt_mark.unwrap_or_else(Mark::fresh);
|
|
||||||
opt_mark = Some(mark);
|
|
||||||
match loaded_macro.kind {
|
|
||||||
LoadedMacroKind::Def(mut def) => {
|
|
||||||
if def.use_locally {
|
|
||||||
self.macro_names.insert(def.ident.name);
|
|
||||||
def.body = mark_tts(&def.body, mark);
|
|
||||||
let ext = macro_rules::compile(&self.session.parse_sess, &def);
|
|
||||||
import_macro(self, def.ident.name, ext, loaded_macro.import_site);
|
|
||||||
}
|
|
||||||
if def.export {
|
|
||||||
def.id = self.next_node_id();
|
|
||||||
self.exported_macros.push(def);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LoadedMacroKind::CustomDerive(name, ext) => {
|
|
||||||
custom_derive_crate = true;
|
|
||||||
let ext = SyntaxExtension::CustomDerive(ext);
|
|
||||||
import_macro(self, token::intern(&name), ext, loaded_macro.import_site);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if custom_derive_crate && !self.session.features.borrow().proc_macro {
|
|
||||||
let issue = feature_gate::GateIssue::Language;
|
|
||||||
let msg = "loading custom derive macro crates is experimentally supported";
|
|
||||||
emit_feature_err(&self.session.parse_sess, "proc_macro", item.span, issue, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.crate_loader.process_item(item, &self.definitions);
|
|
||||||
|
|
||||||
// n.b. we don't need to look at the path option here, because cstore already did
|
// n.b. we don't need to look at the path option here, because cstore already did
|
||||||
if let Some(crate_id) = self.session.cstore.extern_mod_stmt_cnum(item.id) {
|
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 {
|
let def_id = DefId {
|
||||||
krate: crate_id,
|
krate: crate_id,
|
||||||
index: CRATE_DEF_INDEX,
|
index: CRATE_DEF_INDEX,
|
||||||
|
@ -254,25 +233,21 @@ impl<'b> Resolver<'b> {
|
||||||
..ModuleS::new(Some(parent), ModuleKind::Def(Def::Mod(def_id), name))
|
..ModuleS::new(Some(parent), ModuleKind::Def(Def::Mod(def_id), name))
|
||||||
});
|
});
|
||||||
self.define(parent, name, TypeNS, (module, sp, vis));
|
self.define(parent, name, TypeNS, (module, sp, vis));
|
||||||
|
|
||||||
if let Some(mark) = opt_mark {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.populate_module_if_necessary(module);
|
self.populate_module_if_necessary(module);
|
||||||
|
module
|
||||||
} else {
|
} else {
|
||||||
// Define an empty module
|
// Define an empty module
|
||||||
let def = Def::Mod(self.definitions.local_def_id(item.id));
|
let def = Def::Mod(self.definitions.local_def_id(item.id));
|
||||||
let module = ModuleS::new(Some(parent), ModuleKind::Def(def, name));
|
let module = ModuleS::new(Some(parent), ModuleKind::Def(def, name));
|
||||||
let module = self.arenas.alloc_module(module);
|
let module = self.arenas.alloc_module(module);
|
||||||
self.define(parent, name, TypeNS, (module, sp, vis));
|
self.define(parent, name, TypeNS, (module, sp, vis));
|
||||||
|
module
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(loaded_macros) = loaded_macros {
|
||||||
|
self.import_extern_crate_macros(
|
||||||
|
item, module, loaded_macros, legacy_imports, expansion == Mark::root(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +269,9 @@ impl<'b> Resolver<'b> {
|
||||||
self.current_module = module;
|
self.current_module = module;
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemKind::ForeignMod(..) => self.crate_loader.process_item(item, &self.definitions),
|
ItemKind::ForeignMod(..) => {
|
||||||
|
self.crate_loader.process_item(item, &self.definitions, false);
|
||||||
|
}
|
||||||
|
|
||||||
// These items live in the value namespace.
|
// These items live in the value namespace.
|
||||||
ItemKind::Static(_, m, _) => {
|
ItemKind::Static(_, m, _) => {
|
||||||
|
@ -516,6 +493,93 @@ impl<'b> Resolver<'b> {
|
||||||
module.populated.set(true)
|
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| {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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: FnvHashMap<_, _> = 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);
|
||||||
|
}
|
||||||
|
} 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// does this attribute list contain "macro_use"?
|
// does this attribute list contain "macro_use"?
|
||||||
fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
|
fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
|
||||||
for attr in attrs {
|
for attr in attrs {
|
||||||
|
@ -539,6 +603,42 @@ impl<'b> Resolver<'b> {
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn legacy_macro_imports(&mut self, attrs: &[ast::Attribute]) -> LegacyMacroImports {
|
||||||
|
let mut imports = LegacyMacroImports::default();
|
||||||
|
for attr in attrs {
|
||||||
|
if attr.check_name("macro_use") {
|
||||||
|
match attr.meta_item_list() {
|
||||||
|
Some(names) => for attr in names {
|
||||||
|
if let Some(word) = attr.word() {
|
||||||
|
imports.imports.push((token::intern(&word.name()), attr.span()));
|
||||||
|
} else {
|
||||||
|
span_err!(self.session, attr.span(), E0466, "bad macro import");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => imports.import_all = Some(attr.span),
|
||||||
|
}
|
||||||
|
} else if attr.check_name("macro_reexport") {
|
||||||
|
let bad_macro_reexport = |this: &mut Self, span| {
|
||||||
|
span_err!(this.session, span, E0467, "bad macro reexport");
|
||||||
|
};
|
||||||
|
if let Some(names) = attr.meta_item_list() {
|
||||||
|
for attr in names {
|
||||||
|
if let Some(word) = attr.word() {
|
||||||
|
imports.reexports.push((token::intern(&word.name()), attr.span()));
|
||||||
|
} else {
|
||||||
|
bad_macro_reexport(self, attr.span());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bad_macro_reexport(self, attr.span());
|
||||||
|
}
|
||||||
|
} else if attr.check_name("no_link") {
|
||||||
|
imports.no_link = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imports
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
|
pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
|
||||||
|
|
|
@ -1272,6 +1272,185 @@ impl Foo for i32 {}
|
||||||
```
|
```
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
|
E0466: r##"
|
||||||
|
Macro import declarations were malformed.
|
||||||
|
|
||||||
|
Erroneous code examples:
|
||||||
|
|
||||||
|
```compile_fail,E0466
|
||||||
|
#[macro_use(a_macro(another_macro))] // error: invalid import declaration
|
||||||
|
extern crate core as some_crate;
|
||||||
|
|
||||||
|
#[macro_use(i_want = "some_macros")] // error: invalid import declaration
|
||||||
|
extern crate core as another_crate;
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a syntax error at the level of attribute declarations. The proper
|
||||||
|
syntax for macro imports is the following:
|
||||||
|
|
||||||
|
```ignore
|
||||||
|
// In some_crate:
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! get_tacos {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! get_pimientos {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
// In your crate:
|
||||||
|
#[macro_use(get_tacos, get_pimientos)] // It imports `get_tacos` and
|
||||||
|
extern crate some_crate; // `get_pimientos` macros from some_crate
|
||||||
|
```
|
||||||
|
|
||||||
|
If you would like to import all exported macros, write `macro_use` with no
|
||||||
|
arguments.
|
||||||
|
"##,
|
||||||
|
|
||||||
|
E0467: r##"
|
||||||
|
Macro reexport declarations were empty or malformed.
|
||||||
|
|
||||||
|
Erroneous code examples:
|
||||||
|
|
||||||
|
```compile_fail,E0467
|
||||||
|
#[macro_reexport] // error: no macros listed for export
|
||||||
|
extern crate core as macros_for_good;
|
||||||
|
|
||||||
|
#[macro_reexport(fun_macro = "foo")] // error: not a macro identifier
|
||||||
|
extern crate core as other_macros_for_good;
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a syntax error at the level of attribute declarations.
|
||||||
|
|
||||||
|
Currently, `macro_reexport` requires at least one macro name to be listed.
|
||||||
|
Unlike `macro_use`, listing no names does not reexport all macros from the
|
||||||
|
given crate.
|
||||||
|
|
||||||
|
Decide which macros you would like to export and list them properly.
|
||||||
|
|
||||||
|
These are proper reexport declarations:
|
||||||
|
|
||||||
|
```ignore
|
||||||
|
#[macro_reexport(some_macro, another_macro)]
|
||||||
|
extern crate macros_for_good;
|
||||||
|
```
|
||||||
|
"##,
|
||||||
|
|
||||||
|
E0468: r##"
|
||||||
|
A non-root module attempts to import macros from another crate.
|
||||||
|
|
||||||
|
Example of erroneous code:
|
||||||
|
|
||||||
|
```compile_fail,E0468
|
||||||
|
mod foo {
|
||||||
|
#[macro_use(helpful_macro)] // error: must be at crate root to import
|
||||||
|
extern crate core; // macros from another crate
|
||||||
|
helpful_macro!(...);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Only `extern crate` imports at the crate root level are allowed to import
|
||||||
|
macros.
|
||||||
|
|
||||||
|
Either move the macro import to crate root or do without the foreign macros.
|
||||||
|
This will work:
|
||||||
|
|
||||||
|
```ignore
|
||||||
|
#[macro_use(helpful_macro)]
|
||||||
|
extern crate some_crate;
|
||||||
|
|
||||||
|
mod foo {
|
||||||
|
helpful_macro!(...)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"##,
|
||||||
|
|
||||||
|
E0469: r##"
|
||||||
|
A macro listed for import was not found.
|
||||||
|
|
||||||
|
Erroneous code example:
|
||||||
|
|
||||||
|
```compile_fail,E0469
|
||||||
|
#[macro_use(drink, be_merry)] // error: imported macro not found
|
||||||
|
extern crate collections;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Either the listed macro is not contained in the imported crate, or it is not
|
||||||
|
exported from the given crate.
|
||||||
|
|
||||||
|
This could be caused by a typo. Did you misspell the macro's name?
|
||||||
|
|
||||||
|
Double-check the names of the macros listed for import, and that the crate
|
||||||
|
in question exports them.
|
||||||
|
|
||||||
|
A working version would be:
|
||||||
|
|
||||||
|
```ignore
|
||||||
|
// In some_crate crate:
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! eat {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! drink {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
// In your crate:
|
||||||
|
#[macro_use(eat, drink)]
|
||||||
|
extern crate some_crate; //ok!
|
||||||
|
```
|
||||||
|
"##,
|
||||||
|
|
||||||
|
E0470: r##"
|
||||||
|
A macro listed for reexport was not found.
|
||||||
|
|
||||||
|
Erroneous code example:
|
||||||
|
|
||||||
|
```compile_fail,E0470
|
||||||
|
#[macro_reexport(drink, be_merry)]
|
||||||
|
extern crate collections;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Either the listed macro is not contained in the imported crate, or it is not
|
||||||
|
exported from the given crate.
|
||||||
|
|
||||||
|
This could be caused by a typo. Did you misspell the macro's name?
|
||||||
|
|
||||||
|
Double-check the names of the macros listed for reexport, and that the crate
|
||||||
|
in question exports them.
|
||||||
|
|
||||||
|
A working version:
|
||||||
|
|
||||||
|
```ignore
|
||||||
|
// In some_crate crate:
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! eat {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! drink {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
// In your_crate:
|
||||||
|
#[macro_reexport(eat, drink)]
|
||||||
|
extern crate some_crate;
|
||||||
|
```
|
||||||
|
"##,
|
||||||
|
|
||||||
E0530: r##"
|
E0530: r##"
|
||||||
A binding shadowed something it shouldn't.
|
A binding shadowed something it shouldn't.
|
||||||
|
|
||||||
|
|
|
@ -114,22 +114,22 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||||
invocation.expansion.set(visitor.legacy_scope);
|
invocation.expansion.set(visitor.legacy_scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
|
fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef, export: bool) {
|
||||||
if &def.ident.name.as_str() == "macro_rules" {
|
if &def.ident.name.as_str() == "macro_rules" {
|
||||||
self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`");
|
self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`");
|
||||||
}
|
}
|
||||||
if def.use_locally {
|
|
||||||
let invocation = self.invocations[&scope];
|
let invocation = self.invocations[&scope];
|
||||||
let binding = self.arenas.alloc_legacy_binding(LegacyBinding {
|
let binding = self.arenas.alloc_legacy_binding(LegacyBinding {
|
||||||
parent: invocation.legacy_scope.get(),
|
parent: invocation.legacy_scope.get(),
|
||||||
name: def.ident.name,
|
name: def.ident.name,
|
||||||
ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
|
ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
|
||||||
span: def.span,
|
span: def.span,
|
||||||
});
|
});
|
||||||
invocation.legacy_scope.set(LegacyScope::Binding(binding));
|
invocation.legacy_scope.set(LegacyScope::Binding(binding));
|
||||||
self.macro_names.insert(def.ident.name);
|
self.macro_names.insert(def.ident.name);
|
||||||
}
|
|
||||||
if def.export {
|
if export {
|
||||||
def.id = self.next_node_id();
|
def.id = self.next_node_id();
|
||||||
self.exported_macros.push(def);
|
self.exported_macros.push(def);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2012,8 +2012,6 @@ pub struct MacroDef {
|
||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub imported_from: Option<Ident>,
|
pub imported_from: Option<Ident>,
|
||||||
pub export: bool,
|
|
||||||
pub use_locally: bool,
|
|
||||||
pub allow_internal_unstable: bool,
|
pub allow_internal_unstable: bool,
|
||||||
pub body: Vec<TokenTree>,
|
pub body: Vec<TokenTree>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -519,7 +519,7 @@ pub trait Resolver {
|
||||||
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
|
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
|
||||||
|
|
||||||
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
|
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
|
||||||
fn add_macro(&mut self, scope: Mark, def: ast::MacroDef);
|
fn add_macro(&mut self, scope: Mark, def: ast::MacroDef, export: bool);
|
||||||
fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>);
|
fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>);
|
||||||
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
|
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
|
||||||
|
|
||||||
|
@ -541,7 +541,7 @@ impl Resolver for DummyResolver {
|
||||||
fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
|
fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
|
||||||
|
|
||||||
fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
|
fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
|
||||||
fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef) {}
|
fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef, _export: bool) {}
|
||||||
fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
|
fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
|
||||||
fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
|
fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
|
||||||
|
|
||||||
|
|
|
@ -157,14 +157,13 @@ impl IdentMacroExpander for MacroRulesExpander {
|
||||||
tts: Vec<tokenstream::TokenTree>,
|
tts: Vec<tokenstream::TokenTree>,
|
||||||
attrs: Vec<ast::Attribute>)
|
attrs: Vec<ast::Attribute>)
|
||||||
-> Box<MacResult> {
|
-> Box<MacResult> {
|
||||||
|
let export = attr::contains_name(&attrs, "macro_export");
|
||||||
let def = ast::MacroDef {
|
let def = ast::MacroDef {
|
||||||
ident: ident,
|
ident: ident,
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
span: span,
|
span: span,
|
||||||
imported_from: None,
|
imported_from: None,
|
||||||
use_locally: true,
|
|
||||||
body: tts,
|
body: tts,
|
||||||
export: attr::contains_name(&attrs, "macro_export"),
|
|
||||||
allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
|
allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
|
||||||
attrs: attrs,
|
attrs: attrs,
|
||||||
};
|
};
|
||||||
|
@ -176,7 +175,7 @@ impl IdentMacroExpander for MacroRulesExpander {
|
||||||
MacEager::items(placeholders::macro_scope_placeholder().make_items())
|
MacEager::items(placeholders::macro_scope_placeholder().make_items())
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.resolver.add_macro(cx.current_expansion.mark, def);
|
cx.resolver.add_macro(cx.current_expansion.mark, def, export);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue