diff options
| author | Jeffrey Seyfried <jeffrey.seyfried@gmail.com> | 2016-10-17 07:46:25 +0000 |
|---|---|---|
| committer | Jeffrey Seyfried <jeffrey.seyfried@gmail.com> | 2016-10-24 00:43:12 +0000 |
| commit | e4baeaa30da3736d9a85f24509319d7148c2feea (patch) | |
| tree | 1b17a11b3a47a93413e1578d76512e4fd73718df | |
| parent | 4845adde360c306624faa3305ea95f95cd11e2b4 (diff) | |
| download | rust-e4baeaa30da3736d9a85f24509319d7148c2feea.tar.gz rust-e4baeaa30da3736d9a85f24509319d7148c2feea.zip | |
Import macros in `resolve` instead of in `metadata::macro_import`.
| -rw-r--r-- | src/librustc/middle/cstore.rs | 15 | ||||
| -rw-r--r-- | src/librustc_metadata/creader.rs | 77 | ||||
| -rw-r--r-- | src/librustc_metadata/diagnostics.rs | 179 | ||||
| -rw-r--r-- | src/librustc_metadata/lib.rs | 1 | ||||
| -rw-r--r-- | src/librustc_metadata/macro_import.rs | 235 | ||||
| -rw-r--r-- | src/librustc_resolve/build_reduced_graph.rs | 215 | ||||
| -rw-r--r-- | src/librustc_resolve/diagnostics.rs | 179 |
7 files changed, 410 insertions, 491 deletions
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index b54862ae0ad..4e0e561f661 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -37,7 +37,7 @@ use util::nodemap::{NodeSet, DefIdMap}; use std::path::PathBuf; use syntax::ast; use syntax::attr; -use syntax::ext::base::MultiItemModifier; +use syntax::ext::base::SyntaxExtension; use syntax::ptr::P; use syntax::parse::token::InternedString; use syntax_pos::Span; @@ -417,18 +417,13 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } } -pub struct LoadedMacro { - pub import_site: Span, - pub kind: LoadedMacroKind, -} - -pub enum LoadedMacroKind { - Def(ast::MacroDef), - CustomDerive(String, Box<MultiItemModifier>), +pub enum LoadedMacros { + MacroRules(Vec<ast::MacroDef>), + ProcMacros(Vec<(ast::Name, SyntaxExtension)>), } pub trait CrateLoader { - fn load_macros(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro>; + fn load_macros(&mut self, extern_crate: &ast::Item) -> LoadedMacros; fn process_item(&mut self, item: &ast::Item, defs: &Definitions); fn postprocess(&mut self, krate: &ast::Crate); } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 7ae3f6f8107..ad2a7afbc8b 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -12,12 +12,11 @@ use cstore::{self, CStore, CrateSource, MetadataBlob}; use locator::{self, CratePaths}; -use macro_import; use schema::CrateRoot; use rustc::hir::def_id::{CrateNum, DefIndex}; use rustc::hir::svh::Svh; -use rustc::middle::cstore::LoadedMacro; +use rustc::middle::cstore::LoadedMacros; use rustc::session::{config, Session}; use rustc_back::PanicStrategy; use rustc::session::search_paths::PathKind; @@ -36,7 +35,8 @@ use syntax::ast; use syntax::abi::Abi; use syntax::parse; 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 log; @@ -591,15 +591,14 @@ impl<'a> CrateLoader<'a> { ret.macro_rules.push(ast::MacroDef { ident: ast::Ident::with_empty_ctxt(def.name), - attrs: def.attrs, id: ast::DUMMY_NODE_ID, span: local_span, imported_from: Some(item.ident), // overridden in plugin/load.rs export: false, use_locally: false, - allow_internal_unstable: false, - + allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"), + attrs: def.attrs, body: body, }); self.sess.imported_macro_spans.borrow_mut() @@ -639,6 +638,58 @@ impl<'a> CrateLoader<'a> { 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, span: Span, macros: &Macros, index: DefIndex) + -> 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 = 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(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)); + } + } + + let mut my_registrar = MyRegistrar(Vec::new()); + registrar(&mut my_registrar); + + // 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); + my_registrar.0 + } + /// Look for a plugin registrar. Returns library path, crate /// SVH and DefIndex of the registrar function. pub fn find_plugin_registrar(&mut self, span: Span, name: &str) @@ -1030,7 +1081,17 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { } } - fn load_macros(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro> { - macro_import::load_macros(self, extern_crate, allows_macros) + fn load_macros(&mut self, extern_crate: &ast::Item) -> LoadedMacros { + let macros = self.read_macros(extern_crate); + + if let Some(index) = macros.custom_derive_registrar { + // custom derive crates currently should not have any macro_rules! + // exported macros, enforced elsewhere + assert_eq!(macros.macro_rules.len(), 0); + let custom_derives = self.load_derive_macros(extern_crate.span, ¯os, index); + LoadedMacros::ProcMacros(custom_derives) + } else { + LoadedMacros::MacroRules(macros.macro_rules) + } } } diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index c03375bf825..b2f4760727a 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -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. "##, -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! { diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index c0fc1a7065c..300c5f0dec7 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -59,6 +59,5 @@ mod schema; pub mod creader; pub mod cstore; pub mod locator; -pub mod macro_import; __build_diagnostic_array! { librustc_metadata, DIAGNOSTICS } diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs deleted file mode 100644 index ddc254a16d9..00000000000 --- a/src/librustc_metadata/macro_import.rs +++ /dev/null @@ -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); - } -} diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 9ed7be5af4e..69210b98e3a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -21,10 +21,11 @@ use {NameBinding, NameBindingKind, ToNameBinding}; use Resolver; 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_id::{CRATE_DEF_INDEX, DefId}; use rustc::ty; +use rustc::util::nodemap::FnvHashMap; use std::cell::Cell; 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> { /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined; /// otherwise, reports an error. @@ -193,57 +202,28 @@ impl<'b> Resolver<'b> { } 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.current_module.parent.is_none(); - let import_macro = |this: &mut Self, name, ext, span| { - let shadowing = this.builtin_macros.insert(name, Rc::new(ext)).is_some(); - if shadowing && expansion != Mark::root() { - let msg = format!("`{}` is already in scope", name); - this.session.struct_span_err(span, &msg) - .note("macro-expanded `#[macro_use]`s may not shadow \ - existing macros (see RFC 1560)") - .emit(); - } - }; - - 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); - } + let legacy_imports = self.legacy_macro_imports(&item.attrs); + // `#[macro_use]` and `#[macro_reexport]` are only allowed at the crate root. + if self.current_module.parent.is_some() && { + legacy_imports.import_all.is_some() || !legacy_imports.imports.is_empty() || + !legacy_imports.reexports.is_empty() + } { + if self.current_module.parent.is_some() { + span_err!(self.session, item.span, E0468, + "an `extern crate` loading macros must be at the crate root"); } } - 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); - } + let loaded_macros = if legacy_imports != LegacyMacroImports::default() { + Some(self.crate_loader.load_macros(item)) + } else { + None + }; 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 - 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 { krate: crate_id, index: CRATE_DEF_INDEX, @@ -254,25 +234,21 @@ impl<'b> Resolver<'b> { ..ModuleS::new(Some(parent), ModuleKind::Def(Def::Mod(def_id), name)) }); 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); + module } else { // Define an empty module let def = Def::Mod(self.definitions.local_def_id(item.id)); let module = ModuleS::new(Some(parent), ModuleKind::Def(def, name)); let module = self.arenas.alloc_module(module); 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(), + ); } } @@ -516,6 +492,93 @@ impl<'b> Resolver<'b> { 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"? fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { for attr in attrs { @@ -539,6 +602,42 @@ impl<'b> Resolver<'b> { 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> { diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index f8f90bdb4e7..f2a5aedbb3a 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -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##" A binding shadowed something it shouldn't. |
