]>
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.
13 use std
::collections
::HashSet
;
18 use creader
::{CrateLoader, Macros}
;
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
;
29 use syntax
::parse
::token
;
30 use syntax_ext
::deriving
::custom
::CustomDerive
;
33 pub fn call_bad_macro_reexport(a
: &Session
, b
: Span
) {
34 span_err
!(a
, b
, E0467
, "bad macro reexport");
37 pub type MacroSelection
= FnvHashMap
<token
::InternedString
, Span
>;
39 pub fn load_macros(loader
: &mut CrateLoader
, extern_crate
: &ast
::Item
, allows_macros
: bool
)
41 loader
.load_crate(extern_crate
, allows_macros
)
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();
52 for attr
in &extern_crate
.attrs
{
54 match &attr
.name()[..] {
56 let names
= attr
.meta_item_list();
58 // no names => load all
61 if let (Some(sel
), Some(names
)) = (import
.as_mut(), names
) {
63 if let Some(word
) = attr
.word() {
64 sel
.insert(word
.name().clone(), attr
.span());
66 span_err
!(self.sess
, attr
.span(), E0466
, "bad macro import");
72 let names
= match attr
.meta_item_list() {
75 call_bad_macro_reexport(self.sess
, attr
.span
);
81 if let Some(word
) = attr
.word() {
82 reexport
.insert(word
.name().clone(), attr
.span());
84 call_bad_macro_reexport(self.sess
, attr
.span());
91 attr
::mark_used(attr
);
95 self.load_macros(extern_crate
, allows_macros
, import
, reexport
)
98 fn load_macros
<'b
>(&mut self,
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() {
111 span_err
!(self.sess
, vi
.span
, E0468
,
112 "an `extern crate` loading macros must be at the crate root");
116 let mut macros
= self.creader
.read_macros(vi
);
117 let mut ret
= Vec
::new();
118 let mut seen
= HashSet
::new();
120 for mut def
in macros
.macro_rules
.drain(..) {
121 let name
= def
.ident
.name
.as_str();
123 def
.use_locally
= match import
.as_ref() {
125 Some(sel
) => sel
.contains_key(&name
),
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
));
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);
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]`");
146 if reexport
.len() > 0 {
147 self.sess
.span_err(vi
.span
, "`rustc-macro` crates cannot be \
151 self.load_derive_macros(vi
.span
, ¯os
, index
, &mut ret
);
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");
163 for (name
, span
) in &reexport
{
164 if !seen
.contains(&name
) {
165 span_err
!(self.sess
, *span
, E0470
,
166 "reexported macro not found");
173 /// Load the custom derive macros into the list of macros we're loading.
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,
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
)) {
190 Err(err
) => self.sess
.span_fatal(span
, &err
),
193 let sym
= self.sess
.generate_derive_registrar_symbol(¯os
.svh
, index
);
194 let registrar
= unsafe {
195 let sym
= match lib
.symbol(&sym
) {
197 Err(err
) => self.sess
.span_fatal(span
, &err
),
199 mem
::transmute
::<*mut u8, fn(&mut Registry
)>(sym
)
202 struct MyRegistrar
<'a
>(&'a
mut Vec
<LoadedMacro
>);
204 impl<'a
> Registry
for MyRegistrar
<'a
> {
205 fn register_custom_derive(&mut self,
207 expand
: fn(TokenStream
) -> TokenStream
) {
208 let derive
= Rc
::new(CustomDerive
::new(expand
));
209 self.0.push(LoadedMacro
::CustomDerive(trait_name
.to_string(), derive
));
213 registrar(&mut MyRegistrar(ret
));
215 // Intentionally leak the dynamic library. We can't ever unload it
216 // since the library can make things that will live arbitrarily long.