]> git.proxmox.com Git - rustc.git/blob - src/librustc_metadata/macro_import.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / 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.
4 //
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.
10
11 //! Used by `rustc` when loading a crate with exported macros.
12
13 use creader::CrateReader;
14 use cstore::CStore;
15
16 use rustc::session::Session;
17
18 use std::collections::{HashSet, HashMap};
19 use syntax::codemap::Span;
20 use syntax::parse::token;
21 use syntax::ast;
22 use syntax::attr;
23 use syntax::visit;
24 use syntax::visit::Visitor;
25 use syntax::attr::AttrMetaMethods;
26
27 struct MacroLoader<'a> {
28 sess: &'a Session,
29 span_whitelist: HashSet<Span>,
30 reader: CrateReader<'a>,
31 macros: Vec<ast::MacroDef>,
32 }
33
34 impl<'a> MacroLoader<'a> {
35 fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> MacroLoader<'a> {
36 MacroLoader {
37 sess: sess,
38 span_whitelist: HashSet::new(),
39 reader: CrateReader::new(sess, cstore, crate_name),
40 macros: vec![],
41 }
42 }
43 }
44
45 pub fn call_bad_macro_reexport(a: &Session, b: Span) {
46 span_err!(a, b, E0467, "bad macro reexport");
47 }
48
49 /// Read exported macros.
50 pub fn read_macro_defs(sess: &Session,
51 cstore: &CStore,
52 krate: &ast::Crate,
53 crate_name: &str)
54 -> Vec<ast::MacroDef>
55 {
56 let mut loader = MacroLoader::new(sess, cstore, crate_name);
57
58 // We need to error on `#[macro_use] extern crate` when it isn't at the
59 // crate root, because `$crate` won't work properly. Identify these by
60 // spans, because the crate map isn't set up yet.
61 for item in &krate.module.items {
62 if let ast::ItemKind::ExternCrate(_) = item.node {
63 loader.span_whitelist.insert(item.span);
64 }
65 }
66
67 visit::walk_crate(&mut loader, krate);
68
69 loader.macros
70 }
71
72 pub type MacroSelection = HashMap<token::InternedString, Span>;
73
74 // note that macros aren't expanded yet, and therefore macros can't add macro imports.
75 impl<'a, 'v> Visitor<'v> for MacroLoader<'a> {
76 fn visit_item(&mut self, item: &ast::Item) {
77 // We're only interested in `extern crate`.
78 match item.node {
79 ast::ItemKind::ExternCrate(_) => {}
80 _ => {
81 visit::walk_item(self, item);
82 return;
83 }
84 }
85
86 // Parse the attributes relating to macros.
87 let mut import = Some(HashMap::new()); // None => load all
88 let mut reexport = HashMap::new();
89
90 for attr in &item.attrs {
91 let mut used = true;
92 match &attr.name()[..] {
93 "macro_use" => {
94 let names = attr.meta_item_list();
95 if names.is_none() {
96 // no names => load all
97 import = None;
98 }
99 if let (Some(sel), Some(names)) = (import.as_mut(), names) {
100 for attr in names {
101 if let ast::MetaItemKind::Word(ref name) = attr.node {
102 sel.insert(name.clone(), attr.span);
103 } else {
104 span_err!(self.sess, attr.span, E0466, "bad macro import");
105 }
106 }
107 }
108 }
109 "macro_reexport" => {
110 let names = match attr.meta_item_list() {
111 Some(names) => names,
112 None => {
113 call_bad_macro_reexport(self.sess, attr.span);
114 continue;
115 }
116 };
117
118 for attr in names {
119 if let ast::MetaItemKind::Word(ref name) = attr.node {
120 reexport.insert(name.clone(), attr.span);
121 } else {
122 call_bad_macro_reexport(self.sess, attr.span);
123 }
124 }
125 }
126 _ => used = false,
127 }
128 if used {
129 attr::mark_used(attr);
130 }
131 }
132
133 self.load_macros(item, import, reexport)
134 }
135
136 fn visit_mac(&mut self, _: &ast::Mac) {
137 // bummer... can't see macro imports inside macros.
138 // do nothing.
139 }
140 }
141
142 impl<'a> MacroLoader<'a> {
143 fn load_macros<'b>(&mut self,
144 vi: &ast::Item,
145 import: Option<MacroSelection>,
146 reexport: MacroSelection) {
147 if let Some(sel) = import.as_ref() {
148 if sel.is_empty() && reexport.is_empty() {
149 return;
150 }
151 }
152
153 if !self.span_whitelist.contains(&vi.span) {
154 span_err!(self.sess, vi.span, E0468,
155 "an `extern crate` loading macros must be at the crate root");
156 return;
157 }
158
159 let macros = self.reader.read_exported_macros(vi);
160 let mut seen = HashSet::new();
161
162 for mut def in macros {
163 let name = def.ident.name.as_str();
164
165 def.use_locally = match import.as_ref() {
166 None => true,
167 Some(sel) => sel.contains_key(&name),
168 };
169 def.export = reexport.contains_key(&name);
170 def.allow_internal_unstable = attr::contains_name(&def.attrs,
171 "allow_internal_unstable");
172 debug!("load_macros: loaded: {:?}", def);
173 self.macros.push(def);
174 seen.insert(name);
175 }
176
177 if let Some(sel) = import.as_ref() {
178 for (name, span) in sel {
179 if !seen.contains(&name) {
180 span_err!(self.sess, *span, E0469,
181 "imported macro not found");
182 }
183 }
184 }
185
186 for (name, span) in &reexport {
187 if !seen.contains(&name) {
188 span_err!(self.sess, *span, E0470,
189 "reexported macro not found");
190 }
191 }
192 }
193 }