Load macros from extern crates during expansion.
This commit is contained in:
parent
0d531bfb88
commit
51499b6e1f
8 changed files with 73 additions and 90 deletions
|
|
@ -536,6 +536,17 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>)
|
|||
syntax_expanders
|
||||
}
|
||||
|
||||
pub trait MacroLoader {
|
||||
fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<ast::MacroDef>;
|
||||
}
|
||||
|
||||
pub struct DummyMacroLoader;
|
||||
impl MacroLoader for DummyMacroLoader {
|
||||
fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec<ast::MacroDef> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// One of these is made during expansion and incrementally updated as we go;
|
||||
/// when a macro expansion occurs, the resulting nodes have the backtrace()
|
||||
/// -> expn_info of their expansion context stored into their span.
|
||||
|
|
@ -546,6 +557,7 @@ pub struct ExtCtxt<'a> {
|
|||
pub ecfg: expand::ExpansionConfig<'a>,
|
||||
pub crate_root: Option<&'static str>,
|
||||
pub feature_gated_cfgs: &'a mut Vec<GatedCfgAttr>,
|
||||
pub loader: &'a mut MacroLoader,
|
||||
|
||||
pub mod_path: Vec<ast::Ident> ,
|
||||
pub exported_macros: Vec<ast::MacroDef>,
|
||||
|
|
@ -561,7 +573,9 @@ pub struct ExtCtxt<'a> {
|
|||
impl<'a> ExtCtxt<'a> {
|
||||
pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
|
||||
ecfg: expand::ExpansionConfig<'a>,
|
||||
feature_gated_cfgs: &'a mut Vec<GatedCfgAttr>) -> ExtCtxt<'a> {
|
||||
feature_gated_cfgs: &'a mut Vec<GatedCfgAttr>,
|
||||
loader: &'a mut MacroLoader)
|
||||
-> ExtCtxt<'a> {
|
||||
let env = initial_syntax_expander_table(&ecfg);
|
||||
ExtCtxt {
|
||||
parse_sess: parse_sess,
|
||||
|
|
@ -572,6 +586,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
crate_root: None,
|
||||
feature_gated_cfgs: feature_gated_cfgs,
|
||||
exported_macros: Vec::new(),
|
||||
loader: loader,
|
||||
syntax_env: env,
|
||||
recursion_count: 0,
|
||||
|
||||
|
|
@ -925,4 +940,8 @@ impl SyntaxEnv {
|
|||
let last_chain_index = self.chain.len() - 1;
|
||||
&mut self.chain[last_chain_index].info
|
||||
}
|
||||
|
||||
pub fn is_crate_root(&mut self) -> bool {
|
||||
self.chain.len() == 2
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -750,6 +750,15 @@ fn expand_annotatable(a: Annotatable,
|
|||
}
|
||||
result.into_iter().map(|i| Annotatable::Item(i)).collect()
|
||||
},
|
||||
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 allows_macros = fld.cx.syntax_env.is_crate_root();
|
||||
for def in fld.cx.loader.load_crate(&it, allows_macros) {
|
||||
fld.cx.insert_macro(def);
|
||||
}
|
||||
SmallVector::one(Annotatable::Item(it))
|
||||
},
|
||||
_ => noop_fold_item(it, fld).into_iter().map(|i| Annotatable::Item(i)).collect(),
|
||||
},
|
||||
|
||||
|
|
@ -1137,8 +1146,6 @@ impl<'feat> ExpansionConfig<'feat> {
|
|||
}
|
||||
|
||||
pub fn expand_crate(mut cx: ExtCtxt,
|
||||
// these are the macros being imported to this crate:
|
||||
imported_macros: Vec<ast::MacroDef>,
|
||||
user_exts: Vec<NamedSyntaxExtension>,
|
||||
c: Crate) -> (Crate, HashSet<Name>) {
|
||||
if std_inject::no_core(&c) {
|
||||
|
|
@ -1151,10 +1158,6 @@ pub fn expand_crate(mut cx: ExtCtxt,
|
|||
let ret = {
|
||||
let mut expander = MacroExpander::new(&mut cx);
|
||||
|
||||
for def in imported_macros {
|
||||
expander.cx.insert_macro(def);
|
||||
}
|
||||
|
||||
for (name, extension) in user_exts {
|
||||
expander.cx.syntax_env.insert(name, extension);
|
||||
}
|
||||
|
|
@ -1220,7 +1223,7 @@ mod tests {
|
|||
use ast;
|
||||
use ast::Name;
|
||||
use codemap;
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::base::{ExtCtxt, DummyMacroLoader};
|
||||
use ext::mtwt;
|
||||
use fold::Folder;
|
||||
use parse;
|
||||
|
|
@ -1291,9 +1294,9 @@ mod tests {
|
|||
src,
|
||||
Vec::new(), &sess).unwrap();
|
||||
// should fail:
|
||||
let mut gated_cfgs = vec![];
|
||||
let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs);
|
||||
expand_crate(ecx, vec![], vec![], crate_ast);
|
||||
let (mut gated_cfgs, mut loader) = (vec![], DummyMacroLoader);
|
||||
let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs, &mut loader);
|
||||
expand_crate(ecx, vec![], crate_ast);
|
||||
}
|
||||
|
||||
// make sure that macros can't escape modules
|
||||
|
|
@ -1306,9 +1309,9 @@ mod tests {
|
|||
"<test>".to_string(),
|
||||
src,
|
||||
Vec::new(), &sess).unwrap();
|
||||
let mut gated_cfgs = vec![];
|
||||
let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs);
|
||||
expand_crate(ecx, vec![], vec![], crate_ast);
|
||||
let (mut gated_cfgs, mut loader) = (vec![], DummyMacroLoader);
|
||||
let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs, &mut loader);
|
||||
expand_crate(ecx, vec![], crate_ast);
|
||||
}
|
||||
|
||||
// macro_use modules should allow macros to escape
|
||||
|
|
@ -1320,18 +1323,18 @@ mod tests {
|
|||
"<test>".to_string(),
|
||||
src,
|
||||
Vec::new(), &sess).unwrap();
|
||||
let mut gated_cfgs = vec![];
|
||||
let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs);
|
||||
expand_crate(ecx, vec![], vec![], crate_ast);
|
||||
let (mut gated_cfgs, mut loader) = (vec![], DummyMacroLoader);
|
||||
let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs, &mut loader);
|
||||
expand_crate(ecx, vec![], crate_ast);
|
||||
}
|
||||
|
||||
fn expand_crate_str(crate_str: String) -> ast::Crate {
|
||||
let ps = parse::ParseSess::new();
|
||||
let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
|
||||
// the cfg argument actually does matter, here...
|
||||
let mut gated_cfgs = vec![];
|
||||
let ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut gated_cfgs);
|
||||
expand_crate(ecx, vec![], vec![], crate_ast).0
|
||||
let (mut gated_cfgs, mut loader) = (vec![], DummyMacroLoader);
|
||||
let ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut gated_cfgs, &mut loader);
|
||||
expand_crate(ecx, vec![], crate_ast).0
|
||||
}
|
||||
|
||||
// find the pat_ident paths in a crate
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue