]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_expand/proc_macro.rs
Add hooks for Miri panic unwinding
[rust.git] / src / libsyntax_expand / proc_macro.rs
1 use crate::base::{self, *};
2 use crate::proc_macro_server;
3
4 use syntax::ast::{self, ItemKind, Attribute, Mac};
5 use syntax::attr::{mark_used, mark_known};
6 use syntax::errors::{Applicability, FatalError};
7 use syntax::symbol::sym;
8 use syntax::token;
9 use syntax::tokenstream::{self, TokenStream};
10 use syntax::visit::Visitor;
11
12 use rustc_data_structures::sync::Lrc;
13 use syntax_pos::{Span, DUMMY_SP};
14
15 const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
16
17 pub struct BangProcMacro {
18     pub client: pm::bridge::client::Client<
19         fn(pm::TokenStream) -> pm::TokenStream,
20     >,
21 }
22
23 impl base::ProcMacro for BangProcMacro {
24     fn expand<'cx>(&self,
25                    ecx: &'cx mut ExtCtxt<'_>,
26                    span: Span,
27                    input: TokenStream)
28                    -> TokenStream {
29         let server = proc_macro_server::Rustc::new(ecx);
30         match self.client.run(&EXEC_STRATEGY, server, input) {
31             Ok(stream) => stream,
32             Err(e) => {
33                 let msg = "proc macro panicked";
34                 let mut err = ecx.struct_span_fatal(span, msg);
35                 if let Some(s) = e.as_str() {
36                     err.help(&format!("message: {}", s));
37                 }
38
39                 err.emit();
40                 FatalError.raise();
41             }
42         }
43     }
44 }
45
46 pub struct AttrProcMacro {
47     pub client: pm::bridge::client::Client<fn(pm::TokenStream, pm::TokenStream) -> pm::TokenStream>,
48 }
49
50 impl base::AttrProcMacro for AttrProcMacro {
51     fn expand<'cx>(&self,
52                    ecx: &'cx mut ExtCtxt<'_>,
53                    span: Span,
54                    annotation: TokenStream,
55                    annotated: TokenStream)
56                    -> TokenStream {
57         let server = proc_macro_server::Rustc::new(ecx);
58         match self.client.run(&EXEC_STRATEGY, server, annotation, annotated) {
59             Ok(stream) => stream,
60             Err(e) => {
61                 let msg = "custom attribute panicked";
62                 let mut err = ecx.struct_span_fatal(span, msg);
63                 if let Some(s) = e.as_str() {
64                     err.help(&format!("message: {}", s));
65                 }
66
67                 err.emit();
68                 FatalError.raise();
69             }
70         }
71     }
72 }
73
74 pub struct ProcMacroDerive {
75     pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
76 }
77
78 impl MultiItemModifier for ProcMacroDerive {
79     fn expand(&self,
80               ecx: &mut ExtCtxt<'_>,
81               span: Span,
82               _meta_item: &ast::MetaItem,
83               item: Annotatable)
84               -> Vec<Annotatable> {
85         let item = match item {
86             Annotatable::Arm(..) |
87             Annotatable::Field(..) |
88             Annotatable::FieldPat(..) |
89             Annotatable::GenericParam(..) |
90             Annotatable::Param(..) |
91             Annotatable::StructField(..) |
92             Annotatable::Variant(..)
93                 => panic!("unexpected annotatable"),
94             Annotatable::Item(item) => item,
95             Annotatable::ImplItem(_) |
96             Annotatable::TraitItem(_) |
97             Annotatable::ForeignItem(_) |
98             Annotatable::Stmt(_) |
99             Annotatable::Expr(_) => {
100                 ecx.span_err(span, "proc-macro derives may only be \
101                                     applied to a struct, enum, or union");
102                 return Vec::new()
103             }
104         };
105         match item.kind {
106             ItemKind::Struct(..) |
107             ItemKind::Enum(..) |
108             ItemKind::Union(..) => {},
109             _ => {
110                 ecx.span_err(span, "proc-macro derives may only be \
111                                     applied to a struct, enum, or union");
112                 return Vec::new()
113             }
114         }
115
116         let token = token::Interpolated(Lrc::new(token::NtItem(item)));
117         let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
118
119         let server = proc_macro_server::Rustc::new(ecx);
120         let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
121             Ok(stream) => stream,
122             Err(e) => {
123                 let msg = "proc-macro derive panicked";
124                 let mut err = ecx.struct_span_fatal(span, msg);
125                 if let Some(s) = e.as_str() {
126                     err.help(&format!("message: {}", s));
127                 }
128
129                 err.emit();
130                 FatalError.raise();
131             }
132         };
133
134         let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
135         let msg = "proc-macro derive produced unparseable tokens";
136
137         let mut parser = rustc_parse::stream_to_parser(
138             ecx.parse_sess,
139             stream,
140             Some("proc-macro derive"),
141         );
142         let mut items = vec![];
143
144         loop {
145             match parser.parse_item() {
146                 Ok(None) => break,
147                 Ok(Some(item)) => {
148                     items.push(Annotatable::Item(item))
149                 }
150                 Err(mut err) => {
151                     // FIXME: handle this better
152                     err.cancel();
153                     ecx.struct_span_fatal(span, msg).emit();
154                     FatalError.raise();
155                 }
156             }
157         }
158
159
160         // fail if there have been errors emitted
161         if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
162             ecx.struct_span_fatal(span, msg).emit();
163             FatalError.raise();
164         }
165
166         items
167     }
168 }
169
170 crate struct MarkAttrs<'a>(crate &'a [ast::Name]);
171
172 impl<'a> Visitor<'a> for MarkAttrs<'a> {
173     fn visit_attribute(&mut self, attr: &Attribute) {
174         if let Some(ident) = attr.ident() {
175             if self.0.contains(&ident.name) {
176                 mark_used(attr);
177                 mark_known(attr);
178             }
179         }
180     }
181
182     fn visit_mac(&mut self, _mac: &Mac) {}
183 }
184
185 crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
186     let mut result = Vec::new();
187     attrs.retain(|attr| {
188         if !attr.has_name(sym::derive) {
189             return true;
190         }
191         if !attr.is_meta_item_list() {
192             cx.struct_span_err(attr.span, "malformed `derive` attribute input")
193                 .span_suggestion(
194                     attr.span,
195                     "missing traits to be derived",
196                     "#[derive(Trait1, Trait2, ...)]".to_owned(),
197                     Applicability::HasPlaceholders,
198                 ).emit();
199             return false;
200         }
201
202         let parse_derive_paths = |attr: &ast::Attribute| {
203             if attr.get_normal_item().tokens.is_empty() {
204                 return Ok(Vec::new());
205             }
206             rustc_parse::parse_in_attr(cx.parse_sess, attr, |p| p.parse_derive_paths())
207         };
208
209         match parse_derive_paths(attr) {
210             Ok(traits) => {
211                 result.extend(traits);
212                 true
213             }
214             Err(mut e) => {
215                 e.emit();
216                 false
217             }
218         }
219     });
220     result
221 }