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,
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) {
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![],
}
}
}
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" => {
}
}
- 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() {
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);
}
"reexported macro not found");
}
}
+
+ macros
}
}
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.
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>,
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,
crate_root: None,
feature_gated_cfgs: feature_gated_cfgs,
exported_macros: Vec::new(),
+ loader: loader,
syntax_env: env,
recursion_count: 0,
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
+ }
}
}
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(),
},
}
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) {
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);
}
use ast;
use ast::Name;
use codemap;
- use ext::base::ExtCtxt;
+ use ext::base::{ExtCtxt, DummyMacroLoader};
use ext::mtwt;
use fold::Folder;
use parse;
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
"<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
"<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
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;
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,
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 {
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 {
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 {