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.
13 use errors::FatalError;
14 use proc_macro::{TokenStream, __internal};
15 use syntax::ast::{self, ItemKind, Attribute, Mac};
16 use syntax::attr::{mark_used, mark_known};
17 use syntax::codemap::Span;
18 use syntax::ext::base::*;
19 use syntax::fold::Folder;
20 use syntax::visit::Visitor;
22 struct MarkAttrs<'a>(&'a [ast::Name]);
24 impl<'a> Visitor<'a> for MarkAttrs<'a> {
25 fn visit_attribute(&mut self, attr: &Attribute) {
26 if let Some(name) = attr.name() {
27 if self.0.contains(&name) {
34 fn visit_mac(&mut self, _mac: &Mac) {}
37 pub struct ProcMacroDerive {
38 inner: fn(TokenStream) -> TokenStream,
39 attrs: Vec<ast::Name>,
42 impl ProcMacroDerive {
43 pub fn new(inner: fn(TokenStream) -> TokenStream, attrs: Vec<ast::Name>) -> ProcMacroDerive {
44 ProcMacroDerive { inner: inner, attrs: attrs }
48 impl MultiItemModifier for ProcMacroDerive {
52 _meta_item: &ast::MetaItem,
55 let item = match item {
56 Annotatable::Item(item) => item,
57 Annotatable::ImplItem(_) |
58 Annotatable::TraitItem(_) => {
59 ecx.span_err(span, "proc-macro derives may only be \
60 applied to struct/enum items");
65 ItemKind::Struct(..) |
66 ItemKind::Enum(..) => {},
68 ecx.span_err(span, "proc-macro derives may only be \
69 applied to struct/enum items");
74 // Mark attributes as known, and used.
75 MarkAttrs(&self.attrs).visit_item(&item);
77 let input = __internal::new_token_stream(ecx.resolver.eliminate_crate_var(item.clone()));
78 let res = __internal::set_parse_sess(&ecx.parse_sess, || {
79 let inner = self.inner;
80 panic::catch_unwind(panic::AssertUnwindSafe(|| inner(input)))
83 let stream = match res {
86 let msg = "proc-macro derive panicked";
87 let mut err = ecx.struct_span_fatal(span, msg);
88 if let Some(s) = e.downcast_ref::<String>() {
89 err.help(&format!("message: {}", s));
91 if let Some(s) = e.downcast_ref::<&'static str>() {
92 err.help(&format!("message: {}", s));
100 let new_items = __internal::set_parse_sess(&ecx.parse_sess, || {
101 match __internal::token_stream_parse_items(stream) {
102 Ok(new_items) => new_items,
104 // FIXME: handle this better
105 let msg = "proc-macro derive produced unparseable tokens";
106 ecx.struct_span_fatal(span, msg).emit();
112 // Reassign spans of all expanded items to the input `item`
113 // for better errors here.
114 new_items.into_iter().map(|item| {
115 Annotatable::Item(ChangeSpan { span: span }.fold_item(item).expect_one(""))