]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_ext/deriving/custom.rs
Auto merge of #58406 - Disasm:rv64-support, r=nagisa
[rust.git] / src / libsyntax_ext / deriving / custom.rs
1 use crate::proc_macro_impl::EXEC_STRATEGY;
2 use crate::proc_macro_server;
3
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::*;
9 use syntax::parse;
10 use syntax::parse::token::{self, Token};
11 use syntax::tokenstream;
12 use syntax::visit::Visitor;
13 use syntax_pos::DUMMY_SP;
14
15 struct MarkAttrs<'a>(&'a [ast::Name]);
16
17 impl<'a> Visitor<'a> for MarkAttrs<'a> {
18     fn visit_attribute(&mut self, attr: &Attribute) {
19         if self.0.contains(&attr.name()) {
20             mark_used(attr);
21             mark_known(attr);
22         }
23     }
24
25     fn visit_mac(&mut self, _mac: &Mac) {}
26 }
27
28 pub struct ProcMacroDerive {
29     pub client: proc_macro::bridge::client::Client<
30         fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
31     >,
32     pub attrs: Vec<ast::Name>,
33 }
34
35 impl MultiItemModifier for ProcMacroDerive {
36     fn expand(&self,
37               ecx: &mut ExtCtxt<'_>,
38               span: Span,
39               _meta_item: &ast::MetaItem,
40               item: Annotatable)
41               -> Vec<Annotatable> {
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");
51                 return Vec::new()
52             }
53         };
54         match item.node {
55             ItemKind::Struct(..) |
56             ItemKind::Enum(..) |
57             ItemKind::Union(..) => {},
58             _ => {
59                 ecx.span_err(span, "proc-macro derives may only be \
60                                     applied to a struct, enum, or union");
61                 return Vec::new()
62             }
63         }
64
65         // Mark attributes as known, and used.
66         MarkAttrs(&self.attrs).visit_item(&item);
67
68         let token = Token::interpolated(token::NtItem(item));
69         let input = tokenstream::TokenTree::Token(DUMMY_SP, token).into();
70
71         let server = proc_macro_server::Rustc::new(ecx);
72         let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
73             Ok(stream) => stream,
74             Err(e) => {
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));
79                 }
80
81                 err.emit();
82                 FatalError.raise();
83             }
84         };
85
86         let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
87         let msg = "proc-macro derive produced unparseable tokens";
88
89         let mut parser = parse::stream_to_parser(ecx.parse_sess, stream);
90         let mut items = vec![];
91
92         loop {
93             match parser.parse_item() {
94                 Ok(None) => break,
95                 Ok(Some(item)) => {
96                     items.push(Annotatable::Item(item))
97                 }
98                 Err(mut err) => {
99                     // FIXME: handle this better
100                     err.cancel();
101                     ecx.struct_span_fatal(span, msg).emit();
102                     FatalError.raise();
103                 }
104             }
105         }
106
107
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();
111             FatalError.raise();
112         }
113
114         items
115     }
116 }