1 use crate::proc_macro_impl::EXEC_STRATEGY;
2 use crate::proc_macro_server;
4 use errors::FatalError;
5 use rustc_data_structures::sync::Lrc;
6 use syntax::ast::{self, ItemKind, Attribute, Mac};
7 use syntax::attr::{mark_used, mark_known};
8 use syntax::source_map::Span;
9 use syntax::ext::base::*;
11 use syntax::parse::token;
12 use syntax::tokenstream;
13 use syntax::visit::Visitor;
14 use syntax_pos::DUMMY_SP;
16 struct MarkAttrs<'a>(&'a [ast::Name]);
18 impl<'a> Visitor<'a> for MarkAttrs<'a> {
19 fn visit_attribute(&mut self, attr: &Attribute) {
20 if let Some(ident) = attr.ident() {
21 if self.0.contains(&ident.name) {
28 fn visit_mac(&mut self, _mac: &Mac) {}
31 pub struct ProcMacroDerive {
32 pub client: proc_macro::bridge::client::Client<
33 fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
35 pub attrs: Vec<ast::Name>,
38 impl MultiItemModifier for ProcMacroDerive {
40 ecx: &mut ExtCtxt<'_>,
42 _meta_item: &ast::MetaItem,
45 let item = match item {
46 Annotatable::Item(item) => item,
47 Annotatable::ImplItem(_) |
48 Annotatable::TraitItem(_) |
49 Annotatable::ForeignItem(_) |
50 Annotatable::Stmt(_) |
51 Annotatable::Expr(_) => {
52 ecx.span_err(span, "proc-macro derives may only be \
53 applied to a struct, enum, or union");
58 ItemKind::Struct(..) |
60 ItemKind::Union(..) => {},
62 ecx.span_err(span, "proc-macro derives may only be \
63 applied to a struct, enum, or union");
68 // Mark attributes as known, and used.
69 MarkAttrs(&self.attrs).visit_item(&item);
71 let token = token::Interpolated(Lrc::new(token::NtItem(item)));
72 let input = tokenstream::TokenTree::Token(DUMMY_SP, token).into();
74 let server = proc_macro_server::Rustc::new(ecx);
75 let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
78 let msg = "proc-macro derive panicked";
79 let mut err = ecx.struct_span_fatal(span, msg);
80 if let Some(s) = e.as_str() {
81 err.help(&format!("message: {}", s));
89 let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
90 let msg = "proc-macro derive produced unparseable tokens";
92 let mut parser = parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
93 let mut items = vec![];
96 match parser.parse_item() {
99 items.push(Annotatable::Item(item))
102 // FIXME: handle this better
104 ecx.struct_span_fatal(span, msg).emit();
111 // fail if there have been errors emitted
112 if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
113 ecx.struct_span_fatal(span, msg).emit();