Import macros in resolve instead of in metadata::macro_import.

This commit is contained in:
Jeffrey Seyfried 2016-10-17 07:46:25 +00:00
parent 4845adde36
commit e4baeaa30d
7 changed files with 411 additions and 492 deletions

View file

@ -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);
}

View file

@ -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(&macros.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, &macros, index);
LoadedMacros::ProcMacros(custom_derives)
} else {
LoadedMacros::MacroRules(macros.macro_rules)
}
}
}

View file

@ -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! {

View file

@ -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 }

View file

@ -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, &macros, 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(&macros.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);
}
}

View file

@ -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 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");
}
}
let loaded_macros = if legacy_imports != LegacyMacroImports::default() {
Some(self.crate_loader.load_macros(item))
} else {
None
};
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);
}
}
}
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);
}
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> {

View file

@ -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.