1 use crate::base::{self, *};
2 use crate::proc_macro_server;
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;
9 use syntax::tokenstream::{self, TokenStream};
10 use syntax::visit::Visitor;
12 use rustc_data_structures::sync::Lrc;
13 use syntax_pos::{Span, DUMMY_SP};
15 const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
17 pub struct BangProcMacro {
18 pub client: pm::bridge::client::Client<
19 fn(pm::TokenStream) -> pm::TokenStream,
23 impl base::ProcMacro for BangProcMacro {
25 ecx: &'cx mut ExtCtxt<'_>,
29 let server = proc_macro_server::Rustc::new(ecx);
30 match self.client.run(&EXEC_STRATEGY, server, input) {
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));
46 pub struct AttrProcMacro {
47 pub client: pm::bridge::client::Client<fn(pm::TokenStream, pm::TokenStream) -> pm::TokenStream>,
50 impl base::AttrProcMacro for AttrProcMacro {
52 ecx: &'cx mut ExtCtxt<'_>,
54 annotation: TokenStream,
55 annotated: TokenStream)
57 let server = proc_macro_server::Rustc::new(ecx);
58 match self.client.run(&EXEC_STRATEGY, server, annotation, annotated) {
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));
74 pub struct ProcMacroDerive {
75 pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
78 impl MultiItemModifier for ProcMacroDerive {
80 ecx: &mut ExtCtxt<'_>,
82 _meta_item: &ast::MetaItem,
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");
106 ItemKind::Struct(..) |
108 ItemKind::Union(..) => {},
110 ecx.span_err(span, "proc-macro derives may only be \
111 applied to a struct, enum, or union");
116 let token = token::Interpolated(Lrc::new(token::NtItem(item)));
117 let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
119 let server = proc_macro_server::Rustc::new(ecx);
120 let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
121 Ok(stream) => stream,
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));
134 let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
135 let msg = "proc-macro derive produced unparseable tokens";
137 let mut parser = rustc_parse::stream_to_parser(
140 Some("proc-macro derive"),
142 let mut items = vec![];
145 match parser.parse_item() {
148 items.push(Annotatable::Item(item))
151 // FIXME: handle this better
153 ecx.struct_span_fatal(span, msg).emit();
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();
170 crate struct MarkAttrs<'a>(crate &'a [ast::Name]);
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) {
182 fn visit_mac(&mut self, _mac: &Mac) {}
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) {
191 if !attr.is_meta_item_list() {
192 cx.struct_span_err(attr.span, "malformed `derive` attribute input")
195 "missing traits to be derived",
196 "#[derive(Trait1, Trait2, ...)]".to_owned(),
197 Applicability::HasPlaceholders,
202 let parse_derive_paths = |attr: &ast::Attribute| {
203 if attr.get_normal_item().tokens.is_empty() {
204 return Ok(Vec::new());
206 rustc_parse::parse_in_attr(cx.parse_sess, attr, |p| p.parse_derive_paths())
209 match parse_derive_paths(attr) {
211 result.extend(traits);