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::build::AstBuilder;
6 use crate::ext::proc_macro_server;
7 use crate::parse::{self, token};
8 use crate::parse::parser::PathStyle;
9 use crate::symbol::{sym, Symbol};
10 use crate::tokenstream::{self, TokenStream};
11 use crate::visit::Visitor;
13 use rustc_data_structures::fx::FxHashSet;
14 use rustc_data_structures::sync::Lrc;
15 use syntax_pos::hygiene::{ExpnInfo, ExpnKind};
16 use syntax_pos::{Span, DUMMY_SP};
18 const EXEC_STRATEGY: proc_macro::bridge::server::SameThread =
19 proc_macro::bridge::server::SameThread;
21 pub struct BangProcMacro {
22 pub client: proc_macro::bridge::client::Client<
23 fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
27 impl base::ProcMacro for BangProcMacro {
29 ecx: &'cx mut ExtCtxt<'_>,
33 let server = proc_macro_server::Rustc::new(ecx);
34 match self.client.run(&EXEC_STRATEGY, server, input) {
37 let msg = "proc macro panicked";
38 let mut err = ecx.struct_span_fatal(span, msg);
39 if let Some(s) = e.as_str() {
40 err.help(&format!("message: {}", s));
50 pub struct AttrProcMacro {
51 pub client: proc_macro::bridge::client::Client<
52 fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream,
56 impl base::AttrProcMacro for AttrProcMacro {
58 ecx: &'cx mut ExtCtxt<'_>,
60 annotation: TokenStream,
61 annotated: TokenStream)
63 let server = proc_macro_server::Rustc::new(ecx);
64 match self.client.run(&EXEC_STRATEGY, server, annotation, annotated) {
67 let msg = "custom attribute panicked";
68 let mut err = ecx.struct_span_fatal(span, msg);
69 if let Some(s) = e.as_str() {
70 err.help(&format!("message: {}", s));
80 pub struct ProcMacroDerive {
81 pub client: proc_macro::bridge::client::Client<
82 fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
84 pub attrs: Vec<ast::Name>,
87 impl MultiItemModifier for ProcMacroDerive {
89 ecx: &mut ExtCtxt<'_>,
91 _meta_item: &ast::MetaItem,
94 let item = match item {
95 Annotatable::Item(item) => item,
96 Annotatable::ImplItem(_) |
97 Annotatable::TraitItem(_) |
98 Annotatable::ForeignItem(_) |
99 Annotatable::Stmt(_) |
100 Annotatable::Expr(_) => {
101 ecx.span_err(span, "proc-macro derives may only be \
102 applied to a struct, enum, or union");
107 ItemKind::Struct(..) |
109 ItemKind::Union(..) => {},
111 ecx.span_err(span, "proc-macro derives may only be \
112 applied to a struct, enum, or union");
117 // Mark attributes as known, and used.
118 MarkAttrs(&self.attrs).visit_item(&item);
120 let token = token::Interpolated(Lrc::new(token::NtItem(item)));
121 let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
123 let server = proc_macro_server::Rustc::new(ecx);
124 let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
125 Ok(stream) => stream,
127 let msg = "proc-macro derive panicked";
128 let mut err = ecx.struct_span_fatal(span, msg);
129 if let Some(s) = e.as_str() {
130 err.help(&format!("message: {}", s));
138 let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
139 let msg = "proc-macro derive produced unparseable tokens";
141 let mut parser = parse::stream_to_parser(ecx.parse_sess, stream, 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 struct MarkAttrs<'a>(&'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 pub fn is_proc_macro_attr(attr: &Attribute) -> bool {
186 [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
187 .iter().any(|kind| attr.check_name(*kind))
190 crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
191 let mut result = Vec::new();
192 attrs.retain(|attr| {
193 if attr.path != sym::derive {
196 if !attr.is_meta_item_list() {
197 cx.struct_span_err(attr.span, "malformed `derive` attribute input")
200 "missing traits to be derived",
201 "#[derive(Trait1, Trait2, ...)]".to_owned(),
202 Applicability::HasPlaceholders,
207 match attr.parse_list(cx.parse_sess,
208 |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
210 result.extend(traits);
222 crate fn add_derived_markers<T: HasAttrs>(
223 cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::Path], item: &mut T
225 let (mut names, mut pretty_name) = (FxHashSet::default(), String::new());
226 for (i, path) in traits.iter().enumerate() {
228 pretty_name.push_str(", ");
230 pretty_name.push_str(&path.to_string());
231 names.insert(unwrap_or!(path.segments.get(0), continue).ident.name);
234 let span = span.fresh_expansion(cx.current_expansion.id, ExpnInfo::allow_unstable(
235 ExpnKind::Macro(MacroKind::Derive, Symbol::intern(&pretty_name)), span,
236 cx.parse_sess.edition, cx.allow_derive_markers.clone(),
239 item.visit_attrs(|attrs| {
240 if names.contains(&sym::Eq) && names.contains(&sym::PartialEq) {
241 let meta = cx.meta_word(span, sym::structural_match);
242 attrs.push(cx.attribute(meta));
244 if names.contains(&sym::Copy) {
245 let meta = cx.meta_word(span, sym::rustc_copy_clone_marker);
246 attrs.push(cx.attribute(meta));