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 /src/librustc_metadata | |
| parent | 4845adde360c306624faa3305ea95f95cd11e2b4 (diff) | |
| download | rust-e4baeaa30da3736d9a85f24509319d7148c2feea.tar.gz rust-e4baeaa30da3736d9a85f24509319d7148c2feea.zip | |
Import macros in `resolve` instead of in `metadata::macro_import`.
Diffstat (limited to 'src/librustc_metadata')
| -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 |
4 files changed, 69 insertions, 423 deletions
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); - } -} |
