]>
git.proxmox.com Git - rustc.git/blob - src/librustc/metadata/macro_import.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Used by `rustc` when loading a crate with exported macros.
14 use metadata
::creader
::CrateReader
;
16 use std
::collections
::{HashSet, HashMap}
;
19 use syntax
::codemap
::Span
;
20 use syntax
::parse
::token
;
22 use syntax
::visit
::Visitor
;
23 use syntax
::attr
::AttrMetaMethods
;
25 struct MacroLoader
<'a
> {
27 span_whitelist
: HashSet
<Span
>,
28 reader
: CrateReader
<'a
>,
29 macros
: Vec
<ast
::MacroDef
>,
32 impl<'a
> MacroLoader
<'a
> {
33 fn new(sess
: &'a Session
) -> MacroLoader
<'a
> {
36 span_whitelist
: HashSet
::new(),
37 reader
: CrateReader
::new(sess
),
43 /// Read exported macros.
44 pub fn read_macro_defs(sess
: &Session
, krate
: &ast
::Crate
) -> Vec
<ast
::MacroDef
> {
45 let mut loader
= MacroLoader
::new(sess
);
47 // We need to error on `#[macro_use] extern crate` when it isn't at the
48 // crate root, because `$crate` won't work properly. Identify these by
49 // spans, because the crate map isn't set up yet.
50 for item
in &krate
.module
.items
{
51 if let ast
::ItemExternCrate(_
) = item
.node
{
52 loader
.span_whitelist
.insert(item
.span
);
56 visit
::walk_crate(&mut loader
, krate
);
61 pub type MacroSelection
= HashMap
<token
::InternedString
, Span
>;
63 // note that macros aren't expanded yet, and therefore macros can't add macro imports.
64 impl<'a
, 'v
> Visitor
<'v
> for MacroLoader
<'a
> {
65 fn visit_item(&mut self, item
: &ast
::Item
) {
66 // We're only interested in `extern crate`.
68 ast
::ItemExternCrate(_
) => {}
70 visit
::walk_item(self, item
);
75 // Parse the attributes relating to macros.
76 let mut import
= Some(HashMap
::new()); // None => load all
77 let mut reexport
= HashMap
::new();
79 for attr
in &item
.attrs
{
81 match &attr
.name()[..] {
83 let names
= attr
.meta_item_list();
85 // no names => load all
88 if let (Some(sel
), Some(names
)) = (import
.as_mut(), names
) {
90 if let ast
::MetaWord(ref name
) = attr
.node
{
91 sel
.insert(name
.clone(), attr
.span
);
93 self.sess
.span_err(attr
.span
, "bad macro import");
99 let names
= match attr
.meta_item_list() {
100 Some(names
) => names
,
102 self.sess
.span_err(attr
.span
, "bad macro reexport");
108 if let ast
::MetaWord(ref name
) = attr
.node
{
109 reexport
.insert(name
.clone(), attr
.span
);
111 self.sess
.span_err(attr
.span
, "bad macro reexport");
118 attr
::mark_used(attr
);
122 self.load_macros(item
, import
, reexport
)
125 fn visit_mac(&mut self, _
: &ast
::Mac
) {
126 // bummer... can't see macro imports inside macros.
131 impl<'a
> MacroLoader
<'a
> {
132 fn load_macros
<'b
>(&mut self,
134 import
: Option
<MacroSelection
>,
135 reexport
: MacroSelection
) {
136 if let Some(sel
) = import
.as_ref() {
137 if sel
.is_empty() && reexport
.is_empty() {
142 if !self.span_whitelist
.contains(&vi
.span
) {
143 self.sess
.span_err(vi
.span
, "an `extern crate` loading macros must be at \
148 let macros
= self.reader
.read_exported_macros(vi
);
149 let mut seen
= HashSet
::new();
151 for mut def
in macros
{
152 let name
= token
::get_ident(def
.ident
);
153 seen
.insert(name
.clone());
155 def
.use_locally
= match import
.as_ref() {
157 Some(sel
) => sel
.contains_key(&name
),
159 def
.export
= reexport
.contains_key(&name
);
160 def
.allow_internal_unstable
= attr
::contains_name(&def
.attrs
,
161 "allow_internal_unstable");
162 debug
!("load_macros: loaded: {:?}", def
);
163 self.macros
.push(def
);
166 if let Some(sel
) = import
.as_ref() {
167 for (name
, span
) in sel
{
168 if !seen
.contains(name
) {
169 self.sess
.span_err(*span
, "imported macro not found");
174 for (name
, span
) in &reexport
{
175 if !seen
.contains(name
) {
176 self.sess
.span_err(*span
, "reexported macro not found");