]>
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 creader
::CrateReader
;
16 use rustc
::session
::Session
;
18 use std
::collections
::{HashSet, HashMap}
;
19 use syntax
::codemap
::Span
;
20 use syntax
::parse
::token
;
24 use syntax
::visit
::Visitor
;
25 use syntax
::attr
::AttrMetaMethods
;
27 struct MacroLoader
<'a
> {
29 span_whitelist
: HashSet
<Span
>,
30 reader
: CrateReader
<'a
>,
31 macros
: Vec
<ast
::MacroDef
>,
34 impl<'a
> MacroLoader
<'a
> {
35 fn new(sess
: &'a Session
, cstore
: &'a CStore
, crate_name
: &str) -> MacroLoader
<'a
> {
38 span_whitelist
: HashSet
::new(),
39 reader
: CrateReader
::new(sess
, cstore
, crate_name
),
45 pub fn call_bad_macro_reexport(a
: &Session
, b
: Span
) {
46 span_err
!(a
, b
, E0467
, "bad macro reexport");
49 /// Read exported macros.
50 pub fn read_macro_defs(sess
: &Session
,
56 let mut loader
= MacroLoader
::new(sess
, cstore
, crate_name
);
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
);
67 visit
::walk_crate(&mut loader
, krate
);
72 pub type MacroSelection
= HashMap
<token
::InternedString
, Span
>;
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`.
79 ast
::ItemKind
::ExternCrate(_
) => {}
81 visit
::walk_item(self, item
);
86 // Parse the attributes relating to macros.
87 let mut import
= Some(HashMap
::new()); // None => load all
88 let mut reexport
= HashMap
::new();
90 for attr
in &item
.attrs
{
92 match &attr
.name()[..] {
94 let names
= attr
.meta_item_list();
96 // no names => load all
99 if let (Some(sel
), Some(names
)) = (import
.as_mut(), names
) {
101 if let ast
::MetaItemKind
::Word(ref name
) = attr
.node
{
102 sel
.insert(name
.clone(), attr
.span
);
104 span_err
!(self.sess
, attr
.span
, E0466
, "bad macro import");
109 "macro_reexport" => {
110 let names
= match attr
.meta_item_list() {
111 Some(names
) => names
,
113 call_bad_macro_reexport(self.sess
, attr
.span
);
119 if let ast
::MetaItemKind
::Word(ref name
) = attr
.node
{
120 reexport
.insert(name
.clone(), attr
.span
);
122 call_bad_macro_reexport(self.sess
, attr
.span
);
129 attr
::mark_used(attr
);
133 self.load_macros(item
, import
, reexport
)
136 fn visit_mac(&mut self, _
: &ast
::Mac
) {
137 // bummer... can't see macro imports inside macros.
142 impl<'a
> MacroLoader
<'a
> {
143 fn load_macros
<'b
>(&mut self,
145 import
: Option
<MacroSelection
>,
146 reexport
: MacroSelection
) {
147 if let Some(sel
) = import
.as_ref() {
148 if sel
.is_empty() && reexport
.is_empty() {
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");
159 let macros
= self.reader
.read_exported_macros(vi
);
160 let mut seen
= HashSet
::new();
162 for mut def
in macros
{
163 let name
= def
.ident
.name
.as_str();
165 def
.use_locally
= match import
.as_ref() {
167 Some(sel
) => sel
.contains_key(&name
),
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
);
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");
186 for (name
, span
) in &reexport
{
187 if !seen
.contains(&name
) {
188 span_err
!(self.sess
, *span
, E0470
,
189 "reexported macro not found");