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;
12 use rustc_data_structures::sync::Lrc;
13 use syntax_pos::{Span, DUMMY_SP};
15 const EXEC_STRATEGY: proc_macro::bridge::server::SameThread =
16 proc_macro::bridge::server::SameThread;
18 pub struct BangProcMacro {
19 pub client: proc_macro::bridge::client::Client<
20 fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
24 impl base::ProcMacro for BangProcMacro {
26 ecx: &'cx mut ExtCtxt<'_>,
30 let server = proc_macro_server::Rustc::new(ecx);
31 match self.client.run(&EXEC_STRATEGY, server, input) {
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));
47 pub struct AttrProcMacro {
48 pub client: proc_macro::bridge::client::Client<
49 fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream,
53 impl base::AttrProcMacro for AttrProcMacro {
55 ecx: &'cx mut ExtCtxt<'_>,
57 annotation: TokenStream,
58 annotated: TokenStream)
60 let server = proc_macro_server::Rustc::new(ecx);
61 match self.client.run(&EXEC_STRATEGY, server, annotation, annotated) {
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));
77 pub struct ProcMacroDerive {
78 pub client: proc_macro::bridge::client::Client<
79 fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
83 impl MultiItemModifier for ProcMacroDerive {
85 ecx: &mut ExtCtxt<'_>,
87 _meta_item: &ast::MetaItem,
90 let item = match item {
91 Annotatable::Arm(..) |
92 Annotatable::Field(..) |
93 Annotatable::FieldPat(..) |
94 Annotatable::GenericParam(..) |
95 Annotatable::Param(..) |
96 Annotatable::StructField(..) |
97 Annotatable::Variant(..)
98 => panic!("unexpected annotatable"),
99 Annotatable::Item(item) => item,
100 Annotatable::ImplItem(_) |
101 Annotatable::TraitItem(_) |
102 Annotatable::ForeignItem(_) |
103 Annotatable::Stmt(_) |
104 Annotatable::Expr(_) => {
105 ecx.span_err(span, "proc-macro derives may only be \
106 applied to a struct, enum, or union");
111 ItemKind::Struct(..) |
113 ItemKind::Union(..) => {},
115 ecx.span_err(span, "proc-macro derives may only be \
116 applied to a struct, enum, or union");
121 let token = token::Interpolated(Lrc::new(token::NtItem(item)));
122 let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
124 let server = proc_macro_server::Rustc::new(ecx);
125 let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
126 Ok(stream) => stream,
128 let msg = "proc-macro derive panicked";
129 let mut err = ecx.struct_span_fatal(span, msg);
130 if let Some(s) = e.as_str() {
131 err.help(&format!("message: {}", s));
139 let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
140 let msg = "proc-macro derive produced unparseable tokens";
142 let mut parser = parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
143 let mut items = vec![];
146 match parser.parse_item() {
149 items.push(Annotatable::Item(item))
152 // FIXME: handle this better
154 ecx.struct_span_fatal(span, msg).emit();
161 // fail if there have been errors emitted
162 if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
163 ecx.struct_span_fatal(span, msg).emit();
171 crate struct MarkAttrs<'a>(crate &'a [ast::Name]);
173 impl<'a> Visitor<'a> for MarkAttrs<'a> {
174 fn visit_attribute(&mut self, attr: &Attribute) {
175 if let Some(ident) = attr.ident() {
176 if self.0.contains(&ident.name) {
183 fn visit_mac(&mut self, _mac: &Mac) {}
186 pub fn is_proc_macro_attr(attr: &Attribute) -> bool {
187 [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
188 .iter().any(|kind| attr.check_name(*kind))
191 crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
192 let mut result = Vec::new();
193 attrs.retain(|attr| {
194 if attr.path != sym::derive {
197 if !attr.is_meta_item_list() {
198 cx.struct_span_err(attr.span, "malformed `derive` attribute input")
201 "missing traits to be derived",
202 "#[derive(Trait1, Trait2, ...)]".to_owned(),
203 Applicability::HasPlaceholders,
208 match attr.parse_list(cx.parse_sess,
209 |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
211 result.extend(traits);