Load macros from #[macro_use]
extern crates in resolve
.
This commit is contained in:
parent
1599461256
commit
b4906a93a0
@ -36,9 +36,10 @@ use session::config::PanicStrategy;
|
||||
use session::search_paths::PathKind;
|
||||
use util::nodemap::{NodeSet, DefIdMap};
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::ext::base::LoadedMacro;
|
||||
use syntax::ext::base::MultiItemModifier;
|
||||
use syntax::ptr::P;
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax_pos::Span;
|
||||
@ -422,6 +423,11 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
|
||||
fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") }
|
||||
}
|
||||
|
||||
pub enum LoadedMacro {
|
||||
Def(ast::MacroDef),
|
||||
CustomDerive(String, Rc<MultiItemModifier>),
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -43,6 +43,7 @@ use super::Compilation;
|
||||
use serialize::json;
|
||||
|
||||
use std::env;
|
||||
use std::mem;
|
||||
use std::ffi::{OsString, OsStr};
|
||||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
@ -686,6 +687,8 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
|
||||
ret
|
||||
});
|
||||
|
||||
krate.exported_macros = mem::replace(&mut resolver.exported_macros, Vec::new());
|
||||
|
||||
krate = time(time_passes, "maybe building test harness", || {
|
||||
syntax::test::modify_for_testing(&sess.parse_sess,
|
||||
&mut resolver,
|
||||
|
@ -17,6 +17,7 @@ use schema::CrateRoot;
|
||||
|
||||
use rustc::hir::def_id::{CrateNum, DefIndex};
|
||||
use rustc::hir::svh::Svh;
|
||||
use rustc::middle::cstore::LoadedMacro;
|
||||
use rustc::session::{config, Session};
|
||||
use rustc::session::config::PanicStrategy;
|
||||
use rustc::session::search_paths::PathKind;
|
||||
@ -32,7 +33,6 @@ use std::rc::Rc;
|
||||
use std::fs;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::ext::base::LoadedMacro;
|
||||
use syntax::abi::Abi;
|
||||
use syntax::parse;
|
||||
use syntax::attr;
|
||||
|
@ -11,12 +11,14 @@
|
||||
//! Used by `rustc` when loading a crate with exported macros.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::rc::Rc;
|
||||
use std::env;
|
||||
use std::mem;
|
||||
|
||||
use creader::{CrateLoader, Macros};
|
||||
|
||||
use rustc::hir::def_id::DefIndex;
|
||||
use rustc::middle::cstore::LoadedMacro;
|
||||
use rustc::session::Session;
|
||||
use rustc::util::nodemap::FnvHashMap;
|
||||
use rustc_back::dynamic_lib::DynamicLibrary;
|
||||
@ -24,7 +26,6 @@ use rustc_macro::TokenStream;
|
||||
use rustc_macro::__internal::Registry;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::ext::base::LoadedMacro;
|
||||
use syntax::parse::token;
|
||||
use syntax_ext::deriving::custom::CustomDerive;
|
||||
use syntax_pos::Span;
|
||||
@ -204,9 +205,8 @@ impl<'a> CrateLoader<'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::CustomDerive(trait_name.to_string(),
|
||||
derive));
|
||||
let derive = Rc::new(CustomDerive::new(expand));
|
||||
self.0.push(LoadedMacro::CustomDerive(trait_name.to_string(), derive));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ use rustc::ty;
|
||||
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
|
||||
use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet};
|
||||
|
||||
use syntax::ext::base::MultiItemModifier;
|
||||
use syntax::ext::hygiene::Mark;
|
||||
use syntax::ast::{self, FloatTy};
|
||||
use syntax::ast::{CRATE_NODE_ID, Name, NodeId, IntTy, UintTy};
|
||||
@ -71,6 +72,7 @@ use syntax_pos::{Span, DUMMY_SP};
|
||||
use errors::DiagnosticBuilder;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use std::fmt;
|
||||
use std::mem::replace;
|
||||
|
||||
@ -1066,6 +1068,8 @@ pub struct Resolver<'a> {
|
||||
dummy_binding: &'a NameBinding<'a>,
|
||||
new_import_semantics: bool, // true if `#![feature(item_like_imports)]`
|
||||
|
||||
pub exported_macros: Vec<ast::MacroDef>,
|
||||
pub derive_modes: FnvHashMap<Name, Rc<MultiItemModifier>>,
|
||||
crate_loader: &'a mut CrateLoader,
|
||||
macro_names: FnvHashSet<Name>,
|
||||
|
||||
@ -1240,6 +1244,8 @@ impl<'a> Resolver<'a> {
|
||||
}),
|
||||
new_import_semantics: session.features.borrow().item_like_imports,
|
||||
|
||||
exported_macros: Vec::new(),
|
||||
derive_modes: FnvHashMap(),
|
||||
crate_loader: crate_loader,
|
||||
macro_names: FnvHashSet(),
|
||||
expansion_data: expansion_data,
|
||||
|
@ -9,19 +9,23 @@
|
||||
// except according to those terms.
|
||||
|
||||
use Resolver;
|
||||
use rustc::middle::cstore::LoadedMacro;
|
||||
use rustc::util::nodemap::FnvHashMap;
|
||||
use std::cell::RefCell;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast::{self, Name};
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::ext::base::{self, LoadedMacro, MultiModifier, MultiDecorator};
|
||||
use syntax::ext::base::{NormalTT, SyntaxExtension};
|
||||
use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier};
|
||||
use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension};
|
||||
use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
|
||||
use syntax::ext::hygiene::Mark;
|
||||
use syntax::parse::token::intern;
|
||||
use syntax::ext::tt::macro_rules;
|
||||
use syntax::feature_gate::{self, emit_feature_err};
|
||||
use syntax::parse::token::{self, intern};
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
use syntax::visit::{self, Visitor};
|
||||
use syntax_pos::Span;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct ExpansionData {
|
||||
@ -37,10 +41,6 @@ struct ModuleData {
|
||||
}
|
||||
|
||||
impl<'a> base::Resolver for Resolver<'a> {
|
||||
fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro> {
|
||||
self.crate_loader.load_macros(extern_crate, allows_macros)
|
||||
}
|
||||
|
||||
fn next_node_id(&mut self) -> ast::NodeId {
|
||||
self.session.next_node_id()
|
||||
}
|
||||
@ -52,7 +52,18 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
});
|
||||
}
|
||||
|
||||
fn add_macro(&mut self, scope: Mark, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
|
||||
fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
|
||||
if def.use_locally {
|
||||
let ext = macro_rules::compile(&self.session.parse_sess, &def);
|
||||
self.add_ext(scope, def.ident, Rc::new(ext));
|
||||
}
|
||||
if def.export {
|
||||
def.id = self.next_node_id();
|
||||
self.exported_macros.push(def);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_ext(&mut self, scope: Mark, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
|
||||
if let NormalTT(..) = *ext {
|
||||
self.macro_names.insert(ident.name);
|
||||
}
|
||||
@ -116,6 +127,10 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
err.emit();
|
||||
None
|
||||
}
|
||||
|
||||
fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>> {
|
||||
self.derive_modes.get(&ident.name).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Resolver<'a> {
|
||||
@ -128,6 +143,17 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_custom_derive(&mut self, name: &str, ext: Rc<MultiItemModifier>, sp: Span) {
|
||||
if !self.session.features.borrow().rustc_macro {
|
||||
let diagnostic = &self.session.parse_sess.span_diagnostic;
|
||||
let msg = "loading custom derive macro crates is experimentally supported";
|
||||
emit_feature_err(diagnostic, "rustc_macro", sp, feature_gate::GateIssue::Language, msg);
|
||||
}
|
||||
if self.derive_modes.insert(token::intern(name), ext).is_some() {
|
||||
self.session.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ExpansionVisitor<'b, 'a: 'b> {
|
||||
@ -201,6 +227,21 @@ impl<'a, 'b> Visitor for ExpansionVisitor<'a, 'b> {
|
||||
visit::walk_item(self, item);
|
||||
self.current_module = orig_module;
|
||||
}
|
||||
ast::ItemKind::ExternCrate(..) => {
|
||||
// We need to error on `#[macro_use] extern crate` when it isn't at the
|
||||
// crate root, because `$crate` won't work properly.
|
||||
// FIXME(jseyfried): This will be nicer once `ModuleData` is merged with `ModuleS`.
|
||||
let is_crate_root = self.current_module.parent.as_ref().unwrap().parent.is_none();
|
||||
for def in self.resolver.crate_loader.load_macros(item, is_crate_root) {
|
||||
match def {
|
||||
LoadedMacro::Def(def) => self.resolver.add_macro(Mark::root(), def),
|
||||
LoadedMacro::CustomDerive(name, ext) => {
|
||||
self.resolver.insert_custom_derive(&name, ext, item.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
visit::walk_item(self, item);
|
||||
}
|
||||
_ => visit::walk_item(self, item),
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,7 @@ use syntax_pos::{Span, ExpnId, NO_EXPANSION};
|
||||
use errors::DiagnosticBuilder;
|
||||
use ext::expand::{self, Invocation, Expansion};
|
||||
use ext::hygiene::Mark;
|
||||
use ext::tt::macro_rules;
|
||||
use fold;
|
||||
use fold::{self, Folder};
|
||||
use parse;
|
||||
use parse::parser::{self, Parser};
|
||||
use parse::token;
|
||||
@ -26,10 +25,7 @@ use parse::token::{InternedString, str_to_ident};
|
||||
use ptr::P;
|
||||
use std_inject;
|
||||
use util::small_vector::SmallVector;
|
||||
use fold::Folder;
|
||||
use feature_gate;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::default::Default;
|
||||
@ -659,35 +655,30 @@ pub enum SyntaxExtension {
|
||||
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
|
||||
|
||||
pub trait Resolver {
|
||||
fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro>;
|
||||
fn next_node_id(&mut self) -> ast::NodeId;
|
||||
|
||||
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
|
||||
fn add_macro(&mut self, scope: Mark, ident: ast::Ident, ext: Rc<SyntaxExtension>);
|
||||
fn add_macro(&mut self, scope: Mark, def: ast::MacroDef);
|
||||
fn add_ext(&mut self, scope: Mark, ident: ast::Ident, ext: Rc<SyntaxExtension>);
|
||||
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
|
||||
|
||||
fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
|
||||
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<SyntaxExtension>>;
|
||||
}
|
||||
|
||||
pub enum LoadedMacro {
|
||||
Def(ast::MacroDef),
|
||||
CustomDerive(String, Box<MultiItemModifier>),
|
||||
fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>>;
|
||||
}
|
||||
|
||||
pub struct DummyResolver;
|
||||
|
||||
impl Resolver for DummyResolver {
|
||||
fn load_crate(&mut self, _extern_crate: &ast::Item, _allows_macros: bool) -> Vec<LoadedMacro> {
|
||||
Vec::new()
|
||||
}
|
||||
fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID }
|
||||
|
||||
fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
|
||||
fn add_macro(&mut self, _scope: Mark, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
|
||||
fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef) {}
|
||||
fn add_ext(&mut self, _scope: Mark, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
|
||||
fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
|
||||
|
||||
fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
|
||||
fn resolve_derive_mode(&mut self, _ident: ast::Ident) -> Option<Rc<MultiItemModifier>> { None }
|
||||
fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
|
||||
None
|
||||
}
|
||||
@ -717,8 +708,6 @@ pub struct ExtCtxt<'a> {
|
||||
pub ecfg: expand::ExpansionConfig<'a>,
|
||||
pub crate_root: Option<&'static str>,
|
||||
pub resolver: &'a mut Resolver,
|
||||
pub exported_macros: Vec<ast::MacroDef>,
|
||||
pub derive_modes: HashMap<InternedString, Box<MultiItemModifier>>,
|
||||
pub current_expansion: ExpansionData,
|
||||
}
|
||||
|
||||
@ -732,9 +721,7 @@ impl<'a> ExtCtxt<'a> {
|
||||
cfg: cfg,
|
||||
ecfg: ecfg,
|
||||
crate_root: None,
|
||||
exported_macros: Vec::new(),
|
||||
resolver: resolver,
|
||||
derive_modes: HashMap::new(),
|
||||
current_expansion: ExpansionData {
|
||||
mark: Mark::root(),
|
||||
depth: 0,
|
||||
@ -811,31 +798,6 @@ impl<'a> ExtCtxt<'a> {
|
||||
}
|
||||
pub fn bt_pop(&mut self) {}
|
||||
|
||||
pub fn insert_macro(&mut self, def: ast::MacroDef) {
|
||||
if def.export {
|
||||
self.exported_macros.push(def.clone());
|
||||
}
|
||||
if def.use_locally {
|
||||
let ext = macro_rules::compile(self.parse_sess, &def);
|
||||
self.resolver.add_macro(self.current_expansion.mark, def.ident, Rc::new(ext));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_custom_derive(&mut self, name: &str, ext: Box<MultiItemModifier>, sp: Span) {
|
||||
if !self.ecfg.enable_rustc_macro() {
|
||||
feature_gate::emit_feature_err(&self.parse_sess.span_diagnostic,
|
||||
"rustc_macro",
|
||||
sp,
|
||||
feature_gate::GateIssue::Language,
|
||||
"loading custom derive macro crates \
|
||||
is experimentally supported");
|
||||
}
|
||||
let name = token::intern_and_get_ident(name);
|
||||
if self.derive_modes.insert(name.clone(), ext).is_some() {
|
||||
self.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn struct_span_warn(&self,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
@ -922,7 +884,7 @@ impl<'a> ExtCtxt<'a> {
|
||||
|
||||
for (name, extension) in user_exts {
|
||||
let ident = ast::Ident::with_empty_ctxt(name);
|
||||
self.resolver.add_macro(Mark::root(), ident, Rc::new(extension));
|
||||
self.resolver.add_ext(Mark::root(), ident, Rc::new(extension));
|
||||
}
|
||||
|
||||
let mut module = ModuleData {
|
||||
|
@ -199,11 +199,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
krate.exported_macros = mem::replace(&mut self.cx.exported_macros, Vec::new());
|
||||
|
||||
for def in &mut krate.exported_macros {
|
||||
def.id = self.cx.resolver.next_node_id()
|
||||
}
|
||||
|
||||
if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
|
||||
self.cx.parse_sess.span_diagnostic.abort_if_errors();
|
||||
@ -672,20 +667,6 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||
self.cx.current_expansion.module = orig_module;
|
||||
return result;
|
||||
}
|
||||
ast::ItemKind::ExternCrate(..) => {
|
||||
// We need to error on `#[macro_use] extern crate` when it isn't at the
|
||||
// crate root, because `$crate` won't work properly.
|
||||
let is_crate_root = self.cx.current_expansion.module.mod_path.len() == 1;
|
||||
for def in self.cx.resolver.load_crate(&*item, is_crate_root) {
|
||||
match def {
|
||||
LoadedMacro::Def(def) => self.cx.insert_macro(def),
|
||||
LoadedMacro::CustomDerive(name, ext) => {
|
||||
self.cx.insert_custom_derive(&name, ext, item.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
noop_fold_item(item, self)
|
||||
},
|
||||
_ => noop_fold_item(item, self),
|
||||
}
|
||||
}
|
||||
|
@ -262,14 +262,15 @@ impl IdentMacroExpander for MacroRulesExpander {
|
||||
attrs: attrs,
|
||||
};
|
||||
|
||||
cx.insert_macro(def.clone());
|
||||
|
||||
// If keep_macs is true, expands to a MacEager::items instead.
|
||||
if cx.ecfg.keep_macs {
|
||||
let result = if cx.ecfg.keep_macs {
|
||||
MacEager::items(placeholders::reconstructed_macro_rules(&def).make_items())
|
||||
} else {
|
||||
MacEager::items(placeholders::macro_scope_placeholder().make_items())
|
||||
}
|
||||
};
|
||||
|
||||
cx.resolver.add_macro(cx.current_expansion.mark, def);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,8 @@ pub fn expand_derive(cx: &mut ExtCtxt,
|
||||
// If custom derive extensions end up threading through the `#[derive]`
|
||||
// attribute, we'll get called again later on to continue expanding
|
||||
// those modes.
|
||||
} else if let Some(ext) = cx.derive_modes.remove(&tname) {
|
||||
} else if let Some(ext) =
|
||||
cx.resolver.resolve_derive_mode(ast::Ident::with_empty_ctxt(intern(&tname))) {
|
||||
let remaining_derives = iter.cloned().collect::<Vec<_>>();
|
||||
if remaining_derives.len() > 0 {
|
||||
let list = cx.meta_list(titem.span,
|
||||
@ -214,7 +215,6 @@ pub fn expand_derive(cx: &mut ExtCtxt,
|
||||
let item = Annotatable::Item(item);
|
||||
let mut items = ext.expand(cx, mitem.span, &mitem, item);
|
||||
items.extend(other_items);
|
||||
cx.derive_modes.insert(tname.clone(), ext);
|
||||
return items
|
||||
|
||||
// If we've gotten this far then it means that we're in the territory of
|
||||
|
@ -57,7 +57,7 @@ use syntax::parse::token::intern;
|
||||
|
||||
pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quotes: bool) {
|
||||
let mut register = |name, ext| {
|
||||
resolver.add_macro(Mark::root(), ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext));
|
||||
resolver.add_ext(Mark::root(), ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext));
|
||||
};
|
||||
|
||||
register("macro_rules", IdentTT(Box::new(MacroRulesExpander), None, false));
|
||||
|
Loading…
Reference in New Issue
Block a user