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