1 use crate::proc_macro_impl::EXEC_STRATEGY;
2 use crate::proc_macro_server;
4 use errors::FatalError;
5 use syntax::ast::{self, ItemKind, Attribute, Mac};
6 use syntax::attr::{mark_used, mark_known};
7 use syntax::source_map::Span;
8 use syntax::ext::base::*;
10 use syntax::parse::token::{self, Token};
11 use syntax::tokenstream;
12 use syntax::visit::Visitor;
13 use syntax_pos::DUMMY_SP;
15 struct MarkAttrs<'a>(&'a [ast::Name]);
17 impl<'a> Visitor<'a> for MarkAttrs<'a> {
18 fn visit_attribute(&mut self, attr: &Attribute) {
19 if self.0.contains(&attr.name()) {
25 fn visit_mac(&mut self, _mac: &Mac) {}
28 pub struct ProcMacroDerive {
29 pub client: proc_macro::bridge::client::Client<
30 fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
32 pub attrs: Vec<ast::Name>,
35 impl MultiItemModifier for ProcMacroDerive {
37 ecx: &mut ExtCtxt<'_>,
39 _meta_item: &ast::MetaItem,
42 let item = match item {
43 Annotatable::Item(item) => item,
44 Annotatable::ImplItem(_) |
45 Annotatable::TraitItem(_) |
46 Annotatable::ForeignItem(_) |
47 Annotatable::Stmt(_) |
48 Annotatable::Expr(_) => {
49 ecx.span_err(span, "proc-macro derives may only be \
50 applied to a struct, enum, or union");
55 ItemKind::Struct(..) |
57 ItemKind::Union(..) => {},
59 ecx.span_err(span, "proc-macro derives may only be \
60 applied to a struct, enum, or union");
65 // Mark attributes as known, and used.
66 MarkAttrs(&self.attrs).visit_item(&item);
68 let token = Token::interpolated(token::NtItem(item));
69 let input = tokenstream::TokenTree::Token(DUMMY_SP, token).into();
71 let server = proc_macro_server::Rustc::new(ecx);
72 let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
75 let msg = "proc-macro derive panicked";
76 let mut err = ecx.struct_span_fatal(span, msg);
77 if let Some(s) = e.as_str() {
78 err.help(&format!("message: {}", s));
86 let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
87 let msg = "proc-macro derive produced unparseable tokens";
89 let mut parser = parse::stream_to_parser(ecx.parse_sess, stream);
90 let mut items = vec![];
93 match parser.parse_item() {
96 items.push(Annotatable::Item(item))
99 // FIXME: handle this better
101 ecx.struct_span_fatal(span, msg).emit();
108 // fail if there have been errors emitted
109 if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
110 ecx.struct_span_fatal(span, msg).emit();