diff options
| author | Jeffrey Seyfried <jeffrey.seyfried@gmail.com> | 2016-06-02 01:14:33 +0000 |
|---|---|---|
| committer | Jeffrey Seyfried <jeffrey.seyfried@gmail.com> | 2016-06-09 00:44:17 +0000 |
| commit | 51499b6e1fd892b68eeb28eaec9031f01a6a9409 (patch) | |
| tree | 361d32543f114cabe7113ab5229fe6e8fd35c20f /src | |
| parent | 0d531bfb881e6d303d09de9f212eaac72a9a218d (diff) | |
| download | rust-51499b6e1fd892b68eeb28eaec9031f01a6a9409.tar.gz rust-51499b6e1fd892b68eeb28eaec9031f01a6a9409.zip | |
Load macros from `extern crate`s during expansion.
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc_driver/driver.rs | 9 | ||||
| -rw-r--r-- | src/librustc_metadata/macro_import.rs | 75 | ||||
| -rw-r--r-- | src/libsyntax/ext/base.rs | 21 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 41 | ||||
| -rw-r--r-- | src/libsyntax/test.rs | 6 | ||||
| -rw-r--r-- | src/test/compile-fail-fulldeps/qquote.rs | 3 | ||||
| -rw-r--r-- | src/test/run-fail-fulldeps/qquote.rs | 4 | ||||
| -rw-r--r-- | src/test/run-pass-fulldeps/qquote.rs | 4 |
8 files changed, 73 insertions, 90 deletions
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c63122948ff..386496b071d 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -604,10 +604,6 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session, syntax::std_inject::maybe_inject_crates_ref(krate, sess.opts.alt_std_name.clone()) }); - let macros = time(time_passes, - "macro loading", - || macro_import::read_macro_defs(sess, &cstore, &krate, crate_name)); - let mut addl_plugins = Some(addl_plugins); let registrars = time(time_passes, "plugin loading", || { plugin::load::load_plugins(sess, @@ -696,13 +692,14 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session, recursion_limit: sess.recursion_limit.get(), trace_mac: sess.opts.debugging_opts.trace_macros, }; + let mut loader = macro_import::MacroLoader::new(sess, &cstore, crate_name); let mut ecx = syntax::ext::base::ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, - &mut feature_gated_cfgs); + &mut feature_gated_cfgs, + &mut loader); syntax_ext::register_builtins(&mut ecx.syntax_env); let (ret, macro_names) = syntax::ext::expand::expand_crate(ecx, - macros, syntax_exts, krate); if cfg!(windows) { diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index 911ca7e315c..1c7d37709c2 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -20,24 +20,19 @@ use syntax::codemap::Span; use syntax::parse::token; use syntax::ast; use syntax::attr; -use syntax::visit; -use syntax::visit::Visitor; use syntax::attr::AttrMetaMethods; +use syntax::ext; -struct MacroLoader<'a> { +pub struct MacroLoader<'a> { sess: &'a Session, - span_whitelist: HashSet<Span>, reader: CrateReader<'a>, - macros: Vec<ast::MacroDef>, } impl<'a> MacroLoader<'a> { - fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> MacroLoader<'a> { + pub fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> MacroLoader<'a> { MacroLoader { sess: sess, - span_whitelist: HashSet::new(), reader: CrateReader::new(sess, cstore, crate_name), - macros: vec![], } } } @@ -46,48 +41,15 @@ pub fn call_bad_macro_reexport(a: &Session, b: Span) { span_err!(a, b, E0467, "bad macro reexport"); } -/// Read exported macros. -pub fn read_macro_defs(sess: &Session, - cstore: &CStore, - krate: &ast::Crate, - crate_name: &str) - -> Vec<ast::MacroDef> -{ - let mut loader = MacroLoader::new(sess, cstore, crate_name); - - // We need to error on `#[macro_use] extern crate` when it isn't at the - // crate root, because `$crate` won't work properly. Identify these by - // spans, because the crate map isn't set up yet. - for item in &krate.module.items { - if let ast::ItemKind::ExternCrate(_) = item.node { - loader.span_whitelist.insert(item.span); - } - } - - visit::walk_crate(&mut loader, krate); - - loader.macros -} - pub type MacroSelection = HashMap<token::InternedString, Span>; -// note that macros aren't expanded yet, and therefore macros can't add macro imports. -impl<'a, 'v> Visitor<'v> for MacroLoader<'a> { - fn visit_item(&mut self, item: &ast::Item) { - // We're only interested in `extern crate`. - match item.node { - ast::ItemKind::ExternCrate(_) => {} - _ => { - visit::walk_item(self, item); - return; - } - } - +impl<'a> ext::base::MacroLoader for MacroLoader<'a> { + fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<ast::MacroDef> { // Parse the attributes relating to macros. let mut import = Some(HashMap::new()); // None => load all let mut reexport = HashMap::new(); - for attr in &item.attrs { + for attr in &extern_crate.attrs { let mut used = true; match &attr.name()[..] { "macro_use" => { @@ -130,36 +92,33 @@ impl<'a, 'v> Visitor<'v> for MacroLoader<'a> { } } - self.load_macros(item, import, reexport) - } - - fn visit_mac(&mut self, _: &ast::Mac) { - // bummer... can't see macro imports inside macros. - // do nothing. + self.load_macros(extern_crate, allows_macros, import, reexport) } } impl<'a> MacroLoader<'a> { fn load_macros<'b>(&mut self, vi: &ast::Item, + allows_macros: bool, import: Option<MacroSelection>, - reexport: MacroSelection) { + reexport: MacroSelection) + -> Vec<ast::MacroDef> { if let Some(sel) = import.as_ref() { if sel.is_empty() && reexport.is_empty() { - return; + return Vec::new(); } } - if !self.span_whitelist.contains(&vi.span) { + if !allows_macros { span_err!(self.sess, vi.span, E0468, "an `extern crate` loading macros must be at the crate root"); - return; + return Vec::new(); } - let macros = self.reader.read_exported_macros(vi); + let mut macros = Vec::new(); let mut seen = HashSet::new(); - for mut def in macros { + for mut def in self.reader.read_exported_macros(vi) { let name = def.ident.name.as_str(); def.use_locally = match import.as_ref() { @@ -170,7 +129,7 @@ impl<'a> MacroLoader<'a> { def.allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable"); debug!("load_macros: loaded: {:?}", def); - self.macros.push(def); + macros.push(def); seen.insert(name); } @@ -189,5 +148,7 @@ impl<'a> MacroLoader<'a> { "reexported macro not found"); } } + + macros } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 303187aeba8..4b7086695eb 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -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 + } } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 7fee27c5dd4..c581a149f43 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -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 diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 6fbbed2ee98..2ac4aac65de 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -25,7 +25,7 @@ use codemap; use errors; use config; use entry::{self, EntryPointType}; -use ext::base::ExtCtxt; +use ext::base::{ExtCtxt, DummyMacroLoader}; use ext::build::AstBuilder; use ext::expand::ExpansionConfig; use fold::Folder; @@ -271,12 +271,14 @@ fn generate_test_harness(sess: &ParseSess, let krate = cleaner.fold_crate(krate); let mut feature_gated_cfgs = vec![]; + let mut loader = DummyMacroLoader; let mut cx: TestCtxt = TestCtxt { sess: sess, span_diagnostic: sd, ext_cx: ExtCtxt::new(sess, vec![], ExpansionConfig::default("test".to_string()), - &mut feature_gated_cfgs), + &mut feature_gated_cfgs, + &mut loader), path: Vec::new(), testfns: Vec::new(), reexport_test_harness_main: reexport_test_harness_main, diff --git a/src/test/compile-fail-fulldeps/qquote.rs b/src/test/compile-fail-fulldeps/qquote.rs index 3e153a21e5d..ca896266411 100644 --- a/src/test/compile-fail-fulldeps/qquote.rs +++ b/src/test/compile-fail-fulldeps/qquote.rs @@ -21,10 +21,11 @@ use syntax::print::pprust; fn main() { let ps = syntax::parse::ParseSess::new(); + let mut loader = syntax::ext::base::DummyMacroLoader; let mut cx = syntax::ext::base::ExtCtxt::new( &ps, vec![], syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), - &mut Vec::new()); + &mut Vec::new(), &mut loader); cx.bt_push(syntax::codemap::ExpnInfo { call_site: DUMMY_SP, callee: syntax::codemap::NameAndSpan { diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs index 41a6fd05c37..fa6ee98317a 100644 --- a/src/test/run-fail-fulldeps/qquote.rs +++ b/src/test/run-fail-fulldeps/qquote.rs @@ -23,11 +23,11 @@ use syntax::print::pprust; fn main() { let ps = syntax::parse::ParseSess::new(); - let mut feature_gated_cfgs = vec![]; + let (mut feature_gated_cfgs, mut loader) = (vec![], syntax::ext::base::DummyMacroLoader); let mut cx = syntax::ext::base::ExtCtxt::new( &ps, vec![], syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), - &mut feature_gated_cfgs); + &mut feature_gated_cfgs, &mut loader); cx.bt_push(syntax::codemap::ExpnInfo { call_site: DUMMY_SP, callee: syntax::codemap::NameAndSpan { diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index 0bb3e610020..efc1989a4fb 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -20,11 +20,11 @@ use syntax::parse::token::intern; fn main() { let ps = syntax::parse::ParseSess::new(); - let mut feature_gated_cfgs = vec![]; + let (mut feature_gated_cfgs, mut loader) = (vec![], syntax::ext::base::DummyMacroLoader); let mut cx = syntax::ext::base::ExtCtxt::new( &ps, vec![], syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), - &mut feature_gated_cfgs); + &mut feature_gated_cfgs, &mut loader); cx.bt_push(syntax::codemap::ExpnInfo { call_site: DUMMY_SP, callee: syntax::codemap::NameAndSpan { |
