1 use crate::ast::{self, ItemKind, Attribute, Mac};
2 use crate::attr::{mark_used, mark_known, HasAttrs};
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, Symbol};
9 use crate::tokenstream::{self, TokenStream};
10 use crate::visit::Visitor;
12 use rustc_data_structures::fx::FxHashSet;
13 use rustc_data_structures::sync::Lrc;
14 use syntax_pos::hygiene::{ExpnInfo, ExpnKind};
15 use syntax_pos::{Span, DUMMY_SP};
17 const EXEC_STRATEGY: proc_macro::bridge::server::SameThread =
18 proc_macro::bridge::server::SameThread;
20 pub struct BangProcMacro {
21 pub client: proc_macro::bridge::client::Client<
22 fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
26 impl base::ProcMacro for BangProcMacro {
28 ecx: &'cx mut ExtCtxt<'_>,
32 let server = proc_macro_server::Rustc::new(ecx);
33 match self.client.run(&EXEC_STRATEGY, server, input) {
36 let msg = "proc macro panicked";
37 let mut err = ecx.struct_span_fatal(span, msg);
38 if let Some(s) = e.as_str() {
39 err.help(&format!("message: {}", s));
49 pub struct AttrProcMacro {
50 pub client: proc_macro::bridge::client::Client<
51 fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream,
55 impl base::AttrProcMacro for AttrProcMacro {
57 ecx: &'cx mut ExtCtxt<'_>,
59 annotation: TokenStream,
60 annotated: TokenStream)
62 let server = proc_macro_server::Rustc::new(ecx);
63 match self.client.run(&EXEC_STRATEGY, server, annotation, annotated) {
66 let msg = "custom attribute panicked";
67 let mut err = ecx.struct_span_fatal(span, msg);
68 if let Some(s) = e.as_str() {
69 err.help(&format!("message: {}", s));
79 pub struct ProcMacroDerive {
80 pub client: proc_macro::bridge::client::Client<
81 fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
83 pub attrs: Vec<ast::Name>,
86 impl MultiItemModifier for ProcMacroDerive {
88 ecx: &mut ExtCtxt<'_>,
90 _meta_item: &ast::MetaItem,
93 let item = match item {
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 // Mark attributes as known, and used.
117 MarkAttrs(&self.attrs).visit_item(&item);
119 let token = token::Interpolated(Lrc::new(token::NtItem(item)));
120 let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
122 let server = proc_macro_server::Rustc::new(ecx);
123 let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
124 Ok(stream) => stream,
126 let msg = "proc-macro derive panicked";
127 let mut err = ecx.struct_span_fatal(span, msg);
128 if let Some(s) = e.as_str() {
129 err.help(&format!("message: {}", s));
137 let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
138 let msg = "proc-macro derive produced unparseable tokens";
140 let mut parser = parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
141 let mut items = vec![];
144 match parser.parse_item() {
147 items.push(Annotatable::Item(item))
150 // FIXME: handle this better
152 ecx.struct_span_fatal(span, msg).emit();
159 // fail if there have been errors emitted
160 if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
161 ecx.struct_span_fatal(span, msg).emit();
169 struct MarkAttrs<'a>(&'a [ast::Name]);
171 impl<'a> Visitor<'a> for MarkAttrs<'a> {
172 fn visit_attribute(&mut self, attr: &Attribute) {
173 if let Some(ident) = attr.ident() {
174 if self.0.contains(&ident.name) {
181 fn visit_mac(&mut self, _mac: &Mac) {}
184 pub fn is_proc_macro_attr(attr: &Attribute) -> bool {
185 [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
186 .iter().any(|kind| attr.check_name(*kind))
189 crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
190 let mut result = Vec::new();
191 attrs.retain(|attr| {
192 if attr.path != sym::derive {
195 if !attr.is_meta_item_list() {
196 cx.struct_span_err(attr.span, "malformed `derive` attribute input")
199 "missing traits to be derived",
200 "#[derive(Trait1, Trait2, ...)]".to_owned(),
201 Applicability::HasPlaceholders,
206 match attr.parse_list(cx.parse_sess,
207 |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
209 result.extend(traits);
221 crate fn add_derived_markers<T: HasAttrs>(
222 cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::Path], item: &mut T
224 let (mut names, mut pretty_name) = (FxHashSet::default(), String::new());
225 for (i, path) in traits.iter().enumerate() {
227 pretty_name.push_str(", ");
229 pretty_name.push_str(&path.to_string());
230 names.insert(unwrap_or!(path.segments.get(0), continue).ident.name);
233 let span = span.fresh_expansion(cx.current_expansion.id, ExpnInfo::allow_unstable(
234 ExpnKind::Macro(MacroKind::Derive, Symbol::intern(&pretty_name)), span,
235 cx.parse_sess.edition, cx.allow_derive_markers.clone(),
238 item.visit_attrs(|attrs| {
239 if names.contains(&sym::Eq) && names.contains(&sym::PartialEq) {
240 let meta = cx.meta_word(span, sym::structural_match);
241 attrs.push(cx.attribute(meta));
243 if names.contains(&sym::Copy) {
244 let meta = cx.meta_word(span, sym::rustc_copy_clone_marker);
245 attrs.push(cx.attribute(meta));