1 use crate::base::{self, *};
2 use crate::proc_macro_server;
4 use rustc_data_structures::sync::Lrc;
5 use rustc_errors::{Applicability, FatalError};
6 use rustc_span::symbol::sym;
7 use rustc_span::{Span, DUMMY_SP};
8 use syntax::ast::{self, ItemKind, MetaItemKind, NestedMetaItem};
10 use syntax::tokenstream::{self, TokenStream};
12 const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
14 pub struct BangProcMacro {
15 pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
18 impl base::ProcMacro for BangProcMacro {
21 ecx: &'cx mut ExtCtxt<'_>,
25 let server = proc_macro_server::Rustc::new(ecx);
26 match self.client.run(&EXEC_STRATEGY, server, input) {
29 let msg = "proc macro panicked";
30 let mut err = ecx.struct_span_fatal(span, msg);
31 if let Some(s) = e.as_str() {
32 err.help(&format!("message: {}", s));
42 pub struct AttrProcMacro {
43 pub client: pm::bridge::client::Client<fn(pm::TokenStream, pm::TokenStream) -> pm::TokenStream>,
46 impl base::AttrProcMacro for AttrProcMacro {
49 ecx: &'cx mut ExtCtxt<'_>,
51 annotation: TokenStream,
52 annotated: TokenStream,
54 let server = proc_macro_server::Rustc::new(ecx);
55 match self.client.run(&EXEC_STRATEGY, server, annotation, annotated) {
58 let msg = "custom attribute panicked";
59 let mut err = ecx.struct_span_fatal(span, msg);
60 if let Some(s) = e.as_str() {
61 err.help(&format!("message: {}", s));
71 pub struct ProcMacroDerive {
72 pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
75 impl MultiItemModifier for ProcMacroDerive {
78 ecx: &mut ExtCtxt<'_>,
80 _meta_item: &ast::MetaItem,
82 ) -> Vec<Annotatable> {
83 let item = match item {
85 | Annotatable::Field(..)
86 | Annotatable::FieldPat(..)
87 | Annotatable::GenericParam(..)
88 | Annotatable::Param(..)
89 | Annotatable::StructField(..)
90 | Annotatable::Variant(..) => panic!("unexpected annotatable"),
91 Annotatable::Item(item) => item,
92 Annotatable::ImplItem(_)
93 | Annotatable::TraitItem(_)
94 | Annotatable::ForeignItem(_)
95 | Annotatable::Stmt(_)
96 | Annotatable::Expr(_) => {
99 "proc-macro derives may only be \
100 applied to a struct, enum, or union",
106 ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..) => {}
110 "proc-macro derives may only be \
111 applied to a struct, enum, or union",
117 let token = token::Interpolated(Lrc::new(token::NtItem(item)));
118 let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
120 let server = proc_macro_server::Rustc::new(ecx);
121 let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
122 Ok(stream) => stream,
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));
135 let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
136 let msg = "proc-macro derive produced unparseable tokens";
139 rustc_parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
140 let mut items = vec![];
143 match parser.parse_item() {
145 Ok(Some(item)) => items.push(Annotatable::Item(item)),
147 // FIXME: handle this better
149 ecx.struct_span_fatal(span, msg).emit();
155 // fail if there have been errors emitted
156 if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
157 ecx.struct_span_fatal(span, msg).emit();
165 crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
166 let mut result = Vec::new();
167 attrs.retain(|attr| {
168 if !attr.has_name(sym::derive) {
172 // 1) First let's ensure that it's a meta item.
173 let nmis = match attr.meta_item_list() {
175 cx.struct_span_err(attr.span, "malformed `derive` attribute input")
178 "missing traits to be derived",
179 "#[derive(Trait1, Trait2, ...)]".to_owned(),
180 Applicability::HasPlaceholders,
188 let mut error_reported_filter_map = false;
189 let mut error_reported_map = false;
192 // 2) Moreover, let's ensure we have a path and not `#[derive("foo")]`.
193 .filter_map(|nmi| match nmi {
194 NestedMetaItem::Literal(lit) => {
195 error_reported_filter_map = true;
196 cx.struct_span_err(lit.span, "expected path to a trait, found literal")
197 .help("for example, write `#[derive(Debug)]` for `Debug`")
201 NestedMetaItem::MetaItem(mi) => Some(mi),
203 // 3) Finally, we only accept `#[derive($path_0, $path_1, ..)]`
204 // but not e.g. `#[derive($path_0 = "value", $path_1(abc))]`.
205 // In this case we can still at least determine that the user
206 // wanted this trait to be derived, so let's keep it.
208 let mut traits_dont_accept = |title, action| {
209 error_reported_map = true;
210 let sp = mi.span.with_lo(mi.path.span.hi());
211 cx.struct_span_err(sp, title)
216 Applicability::MachineApplicable,
221 MetaItemKind::List(..) => traits_dont_accept(
222 "traits in `#[derive(...)]` don't accept arguments",
223 "remove the arguments",
225 MetaItemKind::NameValue(..) => traits_dont_accept(
226 "traits in `#[derive(...)]` don't accept values",
229 MetaItemKind::Word => {}
234 result.extend(traits);
235 !error_reported_filter_map && !error_reported_map