]> git.proxmox.com Git - rustc.git/blob - src/librustc_metadata/macro_import.rs
New upstream version 1.13.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 std::collections::HashSet;
14 use std::rc::Rc;
15 use std::env;
16 use std::mem;
17
18 use creader::{CrateLoader, Macros};
19
20 use rustc::hir::def_id::DefIndex;
21 use rustc::middle::cstore::LoadedMacro;
22 use rustc::session::Session;
23 use rustc::util::nodemap::FnvHashMap;
24 use rustc_back::dynamic_lib::DynamicLibrary;
25 use rustc_macro::TokenStream;
26 use rustc_macro::__internal::Registry;
27 use syntax::ast;
28 use syntax::attr;
29 use syntax::parse::token;
30 use syntax_ext::deriving::custom::CustomDerive;
31 use syntax_pos::Span;
32
33 pub fn call_bad_macro_reexport(a: &Session, b: Span) {
34 span_err!(a, b, E0467, "bad macro reexport");
35 }
36
37 pub type MacroSelection = FnvHashMap<token::InternedString, Span>;
38
39 pub fn load_macros(loader: &mut CrateLoader, extern_crate: &ast::Item, allows_macros: bool)
40 -> Vec<LoadedMacro> {
41 loader.load_crate(extern_crate, allows_macros)
42 }
43
44 impl<'a> CrateLoader<'a> {
45 fn load_crate(&mut self,
46 extern_crate: &ast::Item,
47 allows_macros: bool) -> Vec<LoadedMacro> {
48 // Parse the attributes relating to macros.
49 let mut import = Some(FnvHashMap()); // None => load all
50 let mut reexport = FnvHashMap();
51
52 for attr in &extern_crate.attrs {
53 let mut used = true;
54 match &attr.name()[..] {
55 "macro_use" => {
56 let names = attr.meta_item_list();
57 if names.is_none() {
58 // no names => load all
59 import = None;
60 }
61 if let (Some(sel), Some(names)) = (import.as_mut(), names) {
62 for attr in names {
63 if let Some(word) = attr.word() {
64 sel.insert(word.name().clone(), attr.span());
65 } else {
66 span_err!(self.sess, attr.span(), E0466, "bad macro import");
67 }
68 }
69 }
70 }
71 "macro_reexport" => {
72 let names = match attr.meta_item_list() {
73 Some(names) => names,
74 None => {
75 call_bad_macro_reexport(self.sess, attr.span);
76 continue;
77 }
78 };
79
80 for attr in names {
81 if let Some(word) = attr.word() {
82 reexport.insert(word.name().clone(), attr.span());
83 } else {
84 call_bad_macro_reexport(self.sess, attr.span());
85 }
86 }
87 }
88 _ => used = false,
89 }
90 if used {
91 attr::mark_used(attr);
92 }
93 }
94
95 self.load_macros(extern_crate, allows_macros, import, reexport)
96 }
97
98 fn load_macros<'b>(&mut self,
99 vi: &ast::Item,
100 allows_macros: bool,
101 import: Option<MacroSelection>,
102 reexport: MacroSelection)
103 -> Vec<LoadedMacro> {
104 if let Some(sel) = import.as_ref() {
105 if sel.is_empty() && reexport.is_empty() {
106 return Vec::new();
107 }
108 }
109
110 if !allows_macros {
111 span_err!(self.sess, vi.span, E0468,
112 "an `extern crate` loading macros must be at the crate root");
113 return Vec::new();
114 }
115
116 let mut macros = self.creader.read_macros(vi);
117 let mut ret = Vec::new();
118 let mut seen = HashSet::new();
119
120 for mut def in macros.macro_rules.drain(..) {
121 let name = def.ident.name.as_str();
122
123 def.use_locally = match import.as_ref() {
124 None => true,
125 Some(sel) => sel.contains_key(&name),
126 };
127 def.export = reexport.contains_key(&name);
128 def.allow_internal_unstable = attr::contains_name(&def.attrs,
129 "allow_internal_unstable");
130 debug!("load_macros: loaded: {:?}", def);
131 ret.push(LoadedMacro::Def(def));
132 seen.insert(name);
133 }
134
135 if let Some(index) = macros.custom_derive_registrar {
136 // custom derive crates currently should not have any macro_rules!
137 // exported macros, enforced elsewhere
138 assert_eq!(ret.len(), 0);
139
140 if import.is_some() {
141 self.sess.span_err(vi.span, "`rustc-macro` crates cannot be \
142 selectively imported from, must \
143 use `#[macro_use]`");
144 }
145
146 if reexport.len() > 0 {
147 self.sess.span_err(vi.span, "`rustc-macro` crates cannot be \
148 reexported from");
149 }
150
151 self.load_derive_macros(vi.span, &macros, index, &mut ret);
152 }
153
154 if let Some(sel) = import.as_ref() {
155 for (name, span) in sel {
156 if !seen.contains(&name) {
157 span_err!(self.sess, *span, E0469,
158 "imported macro not found");
159 }
160 }
161 }
162
163 for (name, span) in &reexport {
164 if !seen.contains(&name) {
165 span_err!(self.sess, *span, E0470,
166 "reexported macro not found");
167 }
168 }
169
170 return ret
171 }
172
173 /// Load the custom derive macros into the list of macros we're loading.
174 ///
175 /// Note that this is intentionally similar to how we load plugins today,
176 /// but also intentionally separate. Plugins are likely always going to be
177 /// implemented as dynamic libraries, but we have a possible future where
178 /// custom derive (and other macro-1.1 style features) are implemented via
179 /// executables and custom IPC.
180 fn load_derive_macros(&mut self,
181 span: Span,
182 macros: &Macros,
183 index: DefIndex,
184 ret: &mut Vec<LoadedMacro>) {
185 // Make sure the path contains a / or the linker will search for it.
186 let path = macros.dylib.as_ref().unwrap();
187 let path = env::current_dir().unwrap().join(path);
188 let lib = match DynamicLibrary::open(Some(&path)) {
189 Ok(lib) => lib,
190 Err(err) => self.sess.span_fatal(span, &err),
191 };
192
193 let sym = self.sess.generate_derive_registrar_symbol(&macros.svh, index);
194 let registrar = unsafe {
195 let sym = match lib.symbol(&sym) {
196 Ok(f) => f,
197 Err(err) => self.sess.span_fatal(span, &err),
198 };
199 mem::transmute::<*mut u8, fn(&mut Registry)>(sym)
200 };
201
202 struct MyRegistrar<'a>(&'a mut Vec<LoadedMacro>);
203
204 impl<'a> Registry for MyRegistrar<'a> {
205 fn register_custom_derive(&mut self,
206 trait_name: &str,
207 expand: fn(TokenStream) -> TokenStream) {
208 let derive = Rc::new(CustomDerive::new(expand));
209 self.0.push(LoadedMacro::CustomDerive(trait_name.to_string(), derive));
210 }
211 }
212
213 registrar(&mut MyRegistrar(ret));
214
215 // Intentionally leak the dynamic library. We can't ever unload it
216 // since the library can make things that will live arbitrarily long.
217 mem::forget(lib);
218 }
219 }