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