1 // Copyright 2016 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.
15 use syntax
::ast
::{self, Ident, NodeId}
;
16 use syntax
::codemap
::{ExpnInfo, NameAndSpan, MacroAttribute}
;
17 use syntax
::ext
::base
::ExtCtxt
;
18 use syntax
::ext
::build
::AstBuilder
;
19 use syntax
::ext
::expand
::ExpansionConfig
;
20 use syntax
::fold
::Folder
;
21 use syntax
::parse
::ParseSess
;
23 use syntax
::symbol
::Symbol
;
24 use syntax
::visit
::{self, Visitor}
;
26 use syntax_pos
::{Span, DUMMY_SP}
;
30 const PROC_MACRO_KINDS
: [&'
static str; 3] =
31 ["proc_macro_derive", "proc_macro_attribute", "proc_macro"];
33 struct ProcMacroDerive
{
34 trait_name
: ast
::Name
,
37 attrs
: Vec
<ast
::Name
>,
45 struct CollectProcMacros
<'a
> {
46 derives
: Vec
<ProcMacroDerive
>,
47 attr_macros
: Vec
<ProcMacroDef
>,
48 bang_macros
: Vec
<ProcMacroDef
>,
50 handler
: &'a errors
::Handler
,
51 is_proc_macro_crate
: bool
,
55 pub fn modify(sess
: &ParseSess
,
56 resolver
: &mut ::syntax
::ext
::base
::Resolver
,
57 mut krate
: ast
::Crate
,
58 is_proc_macro_crate
: bool
,
60 num_crate_types
: usize,
61 handler
: &errors
::Handler
) -> ast
::Crate
{
62 let ecfg
= ExpansionConfig
::default("proc_macro".to_string());
63 let mut cx
= ExtCtxt
::new(sess
, ecfg
, resolver
);
65 let (derives
, attr_macros
, bang_macros
) = {
66 let mut collect
= CollectProcMacros
{
68 attr_macros
: Vec
::new(),
69 bang_macros
: Vec
::new(),
72 is_proc_macro_crate
: is_proc_macro_crate
,
73 is_test_crate
: is_test_crate
,
75 visit
::walk_crate(&mut collect
, &krate
);
76 (collect
.derives
, collect
.attr_macros
, collect
.bang_macros
)
79 if !is_proc_macro_crate
{
83 if num_crate_types
> 1 {
84 handler
.err("cannot mix `proc-macro` crate type with others");
91 krate
.module
.items
.push(mk_registrar(&mut cx
, &derives
, &attr_macros
, &bang_macros
));
96 fn is_proc_macro_attr(attr
: &ast
::Attribute
) -> bool
{
97 PROC_MACRO_KINDS
.iter().any(|kind
| attr
.check_name(kind
))
100 impl<'a
> CollectProcMacros
<'a
> {
101 fn check_not_pub_in_root(&self, vis
: &ast
::Visibility
, sp
: Span
) {
102 if self.is_proc_macro_crate
&&
104 *vis
== ast
::Visibility
::Public
{
105 self.handler
.span_err(sp
,
106 "`proc-macro` crate types cannot \
107 export any items other than functions \
108 tagged with `#[proc_macro_derive]` currently");
112 fn collect_custom_derive(&mut self, item
: &'a ast
::Item
, attr
: &'a ast
::Attribute
) {
113 // Once we've located the `#[proc_macro_derive]` attribute, verify
114 // that it's of the form `#[proc_macro_derive(Foo)]` or
115 // `#[proc_macro_derive(Foo, attributes(A, ..))]`
116 let list
= match attr
.meta_item_list() {
119 self.handler
.span_err(attr
.span(),
120 "attribute must be of form: \
121 #[proc_macro_derive(TraitName)]");
125 if list
.len() != 1 && list
.len() != 2 {
126 self.handler
.span_err(attr
.span(),
127 "attribute must have either one or two arguments");
130 let trait_attr
= &list
[0];
131 let attributes_attr
= list
.get(1);
132 let trait_name
= match trait_attr
.name() {
135 self.handler
.span_err(trait_attr
.span(), "not a meta item");
139 if !trait_attr
.is_word() {
140 self.handler
.span_err(trait_attr
.span(), "must only be one word");
143 if deriving
::is_builtin_trait(trait_name
) {
144 self.handler
.span_err(trait_attr
.span(),
145 "cannot override a built-in #[derive] mode");
148 if self.derives
.iter().any(|d
| d
.trait_name
== trait_name
) {
149 self.handler
.span_err(trait_attr
.span(),
150 "derive mode defined twice in this crate");
153 let proc_attrs
: Vec
<_
> = if let Some(attr
) = attributes_attr
{
154 if !attr
.check_name("attributes") {
155 self.handler
.span_err(attr
.span(), "second argument must be `attributes`")
157 attr
.meta_item_list().unwrap_or_else(|| {
158 self.handler
.span_err(attr
.span(),
159 "attribute must be of form: \
160 `attributes(foo, bar)`");
162 }).into_iter().filter_map(|attr
| {
163 let name
= match attr
.name() {
166 self.handler
.span_err(attr
.span(), "not a meta item");
172 self.handler
.span_err(attr
.span(), "must only be one word");
182 if self.in_root
&& item
.vis
== ast
::Visibility
::Public
{
183 self.derives
.push(ProcMacroDerive
{
185 trait_name
: trait_name
,
186 function_name
: item
.ident
,
190 let msg
= if !self.in_root
{
191 "functions tagged with `#[proc_macro_derive]` must \
192 currently reside in the root of the crate"
194 "functions tagged with `#[proc_macro_derive]` must be `pub`"
196 self.handler
.span_err(item
.span
, msg
);
200 fn collect_attr_proc_macro(&mut self, item
: &'a ast
::Item
, attr
: &'a ast
::Attribute
) {
201 if let Some(_
) = attr
.meta_item_list() {
202 self.handler
.span_err(attr
.span
, "`#[proc_macro_attribute]` attribute
203 does not take any arguments");
207 if self.in_root
&& item
.vis
== ast
::Visibility
::Public
{
208 self.attr_macros
.push(ProcMacroDef
{
210 function_name
: item
.ident
,
213 let msg
= if !self.in_root
{
214 "functions tagged with `#[proc_macro_attribute]` must \
215 currently reside in the root of the crate"
217 "functions tagged with `#[proc_macro_attribute]` must be `pub`"
219 self.handler
.span_err(item
.span
, msg
);
223 fn collect_bang_proc_macro(&mut self, item
: &'a ast
::Item
, attr
: &'a ast
::Attribute
) {
224 if let Some(_
) = attr
.meta_item_list() {
225 self.handler
.span_err(attr
.span
, "`#[proc_macro]` attribute
226 does not take any arguments");
230 if self.in_root
&& item
.vis
== ast
::Visibility
::Public
{
231 self.bang_macros
.push(ProcMacroDef
{
233 function_name
: item
.ident
,
236 let msg
= if !self.in_root
{
237 "functions tagged with `#[proc_macro]` must \
238 currently reside in the root of the crate"
240 "functions tagged with `#[proc_macro]` must be `pub`"
242 self.handler
.span_err(item
.span
, msg
);
247 impl<'a
> Visitor
<'a
> for CollectProcMacros
<'a
> {
248 fn visit_item(&mut self, item
: &'a ast
::Item
) {
249 if let ast
::ItemKind
::MacroDef(..) = item
.node
{
250 if self.is_proc_macro_crate
&&
251 item
.attrs
.iter().any(|attr
| attr
.name() == "macro_export") {
253 "cannot export macro_rules! macros from a `proc-macro` crate type currently";
254 self.handler
.span_err(item
.span
, msg
);
258 // First up, make sure we're checking a bare function. If we're not then
259 // we're just not interested in this item.
261 // If we find one, try to locate a `#[proc_macro_derive]` attribute on
263 let is_fn
= match item
.node
{
264 ast
::ItemKind
::Fn(..) => true,
268 let mut found_attr
: Option
<&'a ast
::Attribute
> = None
;
270 for attr
in &item
.attrs
{
271 if is_proc_macro_attr(&attr
) {
272 if let Some(prev_attr
) = found_attr
{
273 let msg
= if attr
.name() == prev_attr
.name() {
274 format
!("Only one `#[{}]` attribute is allowed on any given function",
277 format
!("`#[{}]` and `#[{}]` attributes cannot both be applied \
278 to the same function", attr
.name(), prev_attr
.name())
281 self.handler
.struct_span_err(attr
.span(), &msg
)
282 .span_note(prev_attr
.span(), "Previous attribute here")
288 found_attr
= Some(attr
);
292 let attr
= match found_attr
{
294 self.check_not_pub_in_root(&item
.vis
, item
.span
);
295 return visit
::walk_item(self, item
);
301 let msg
= format
!("the `#[{}]` attribute may only be used on bare functions",
304 self.handler
.span_err(attr
.span(), &msg
);
308 if self.is_test_crate
{
312 if !self.is_proc_macro_crate
{
313 let msg
= format
!("the `#[{}]` attribute is only usable with crates of the \
314 `proc-macro` crate type", attr
.name());
316 self.handler
.span_err(attr
.span(), &msg
);
320 if attr
.check_name("proc_macro_derive") {
321 self.collect_custom_derive(item
, attr
);
322 } else if attr
.check_name("proc_macro_attribute") {
323 self.collect_attr_proc_macro(item
, attr
);
324 } else if attr
.check_name("proc_macro") {
325 self.collect_bang_proc_macro(item
, attr
);
328 visit
::walk_item(self, item
);
331 fn visit_mod(&mut self, m
: &'a ast
::Mod
, _s
: Span
, id
: NodeId
) {
332 let mut prev_in_root
= self.in_root
;
333 if id
!= ast
::CRATE_NODE_ID
{
334 prev_in_root
= mem
::replace(&mut self.in_root
, false);
336 visit
::walk_mod(self, m
);
337 self.in_root
= prev_in_root
;
340 fn visit_mac(&mut self, mac
: &ast
::Mac
) {
341 visit
::walk_mac(self, mac
)
345 // Creates a new module which looks like:
348 // extern crate proc_macro;
350 // use proc_macro::__internal::Registry;
352 // #[plugin_registrar]
353 // fn registrar(registrar: &mut Registry) {
354 // registrar.register_custom_derive($name_trait1, ::$name1, &[]);
355 // registrar.register_custom_derive($name_trait2, ::$name2, &["attribute_name"]);
359 fn mk_registrar(cx
: &mut ExtCtxt
,
360 custom_derives
: &[ProcMacroDerive
],
361 custom_attrs
: &[ProcMacroDef
],
362 custom_macros
: &[ProcMacroDef
]) -> P
<ast
::Item
> {
363 let eid
= cx
.codemap().record_expansion(ExpnInfo
{
365 callee
: NameAndSpan
{
366 format
: MacroAttribute(Symbol
::intern("proc_macro")),
368 allow_internal_unstable
: true,
371 let span
= Span { expn_id: eid, ..DUMMY_SP }
;
373 let proc_macro
= Ident
::from_str("proc_macro");
374 let krate
= cx
.item(span
,
377 ast
::ItemKind
::ExternCrate(None
));
379 let __internal
= Ident
::from_str("__internal");
380 let registry
= Ident
::from_str("Registry");
381 let registrar
= Ident
::from_str("registrar");
382 let register_custom_derive
= Ident
::from_str("register_custom_derive");
383 let register_attr_proc_macro
= Ident
::from_str("register_attr_proc_macro");
384 let register_bang_proc_macro
= Ident
::from_str("register_bang_proc_macro");
386 let mut stmts
= custom_derives
.iter().map(|cd
| {
387 let path
= cx
.path_global(cd
.span
, vec
![cd
.function_name
]);
388 let trait_name
= cx
.expr_str(cd
.span
, cd
.trait_name
);
389 let attrs
= cx
.expr_vec_slice(
391 cd
.attrs
.iter().map(|&s
| cx
.expr_str(cd
.span
, s
)).collect
::<Vec
<_
>>()
393 let registrar
= cx
.expr_ident(span
, registrar
);
394 let ufcs_path
= cx
.path(span
, vec
![proc_macro
, __internal
, registry
,
395 register_custom_derive
]);
397 cx
.stmt_expr(cx
.expr_call(span
, cx
.expr_path(ufcs_path
),
398 vec
![registrar
, trait_name
, cx
.expr_path(path
), attrs
]))
400 }).collect
::<Vec
<_
>>();
402 stmts
.extend(custom_attrs
.iter().map(|ca
| {
403 let name
= cx
.expr_str(ca
.span
, ca
.function_name
.name
);
404 let path
= cx
.path_global(ca
.span
, vec
![ca
.function_name
]);
405 let registrar
= cx
.expr_ident(ca
.span
, registrar
);
407 let ufcs_path
= cx
.path(span
,
408 vec
![proc_macro
, __internal
, registry
, register_attr_proc_macro
]);
410 cx
.stmt_expr(cx
.expr_call(span
, cx
.expr_path(ufcs_path
),
411 vec
![registrar
, name
, cx
.expr_path(path
)]))
414 stmts
.extend(custom_macros
.iter().map(|cm
| {
415 let name
= cx
.expr_str(cm
.span
, cm
.function_name
.name
);
416 let path
= cx
.path_global(cm
.span
, vec
![cm
.function_name
]);
417 let registrar
= cx
.expr_ident(cm
.span
, registrar
);
419 let ufcs_path
= cx
.path(span
,
420 vec
![proc_macro
, __internal
, registry
, register_bang_proc_macro
]);
422 cx
.stmt_expr(cx
.expr_call(span
, cx
.expr_path(ufcs_path
),
423 vec
![registrar
, name
, cx
.expr_path(path
)]))
426 let path
= cx
.path(span
, vec
![proc_macro
, __internal
, registry
]);
427 let registrar_path
= cx
.ty_path(path
);
428 let arg_ty
= cx
.ty_rptr(span
, registrar_path
, None
, ast
::Mutability
::Mutable
);
429 let func
= cx
.item_fn(span
,
431 vec
![cx
.arg(span
, registrar
, arg_ty
)],
432 cx
.ty(span
, ast
::TyKind
::Tup(Vec
::new())),
433 cx
.block(span
, stmts
));
435 let derive_registrar
= cx
.meta_word(span
, Symbol
::intern("rustc_derive_registrar"));
436 let derive_registrar
= cx
.attribute(span
, derive_registrar
);
437 let func
= func
.map(|mut i
| {
438 i
.attrs
.push(derive_registrar
);
439 i
.vis
= ast
::Visibility
::Public
;
442 let ident
= ast
::Ident
::with_empty_ctxt(Symbol
::gensym("registrar"));
443 let module
= cx
.item_mod(span
, span
, ident
, Vec
::new(), vec
![krate
, func
]).map(|mut i
| {
444 i
.vis
= ast
::Visibility
::Public
;
448 cx
.monotonic_expander().fold_item(module
).pop().unwrap()