1 use crate::base::{self, *};
2 use crate::proc_macro_server;
7 use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
8 use rustc_data_structures::sync::Lrc;
9 use rustc_errors::ErrorReported;
10 use rustc_parse::nt_to_tokenstream;
11 use rustc_parse::parser::ForceCollect;
12 use rustc_span::{Span, DUMMY_SP};
14 const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
16 pub struct BangProcMacro {
17 pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
20 impl base::ProcMacro for BangProcMacro {
23 ecx: &'cx mut ExtCtxt<'_>,
26 ) -> Result<TokenStream, ErrorReported> {
27 let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
28 let server = proc_macro_server::Rustc::new(ecx);
29 self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace).map_err(|e| {
30 let mut err = ecx.struct_span_err(span, "proc macro panicked");
31 if let Some(s) = e.as_str() {
32 err.help(&format!("message: {}", s));
40 pub struct AttrProcMacro {
41 pub client: pm::bridge::client::Client<fn(pm::TokenStream, pm::TokenStream) -> pm::TokenStream>,
44 impl base::AttrProcMacro for AttrProcMacro {
47 ecx: &'cx mut ExtCtxt<'_>,
49 annotation: TokenStream,
50 annotated: TokenStream,
51 ) -> Result<TokenStream, ErrorReported> {
52 let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
53 let server = proc_macro_server::Rustc::new(ecx);
55 .run(&EXEC_STRATEGY, server, annotation, annotated, proc_macro_backtrace)
57 let mut err = ecx.struct_span_err(span, "custom attribute panicked");
58 if let Some(s) = e.as_str() {
59 err.help(&format!("message: {}", s));
67 pub struct ProcMacroDerive {
68 pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
71 impl MultiItemModifier for ProcMacroDerive {
74 ecx: &mut ExtCtxt<'_>,
76 _meta_item: &ast::MetaItem,
78 ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
79 // We need special handling for statement items
80 // (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
81 let mut is_stmt = false;
82 let item = match item {
83 Annotatable::Item(item) => token::NtItem(item),
84 Annotatable::Stmt(stmt) => {
86 assert!(stmt.is_item());
88 // A proc macro can't observe the fact that we're passing
89 // them an `NtStmt` - it can only see the underlying tokens
90 // of the wrapped item
91 token::NtStmt(stmt.into_inner())
95 let input = if crate::base::pretty_printing_compatibility_hack(&item, &ecx.sess.parse_sess)
97 TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into()
99 nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::No)
102 let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
103 let server = proc_macro_server::Rustc::new(ecx);
104 let stream = match self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace) {
105 Ok(stream) => stream,
107 let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
108 if let Some(s) = e.as_str() {
109 err.help(&format!("message: {}", s));
112 return ExpandResult::Ready(vec![]);
116 let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count();
118 rustc_parse::stream_to_parser(&ecx.sess.parse_sess, stream, Some("proc-macro derive"));
119 let mut items = vec![];
122 match parser.parse_item(ForceCollect::No) {
126 items.push(Annotatable::Stmt(P(ecx.stmt_item(span, item))));
128 items.push(Annotatable::Item(item));
138 // fail if there have been errors emitted
139 if ecx.sess.parse_sess.span_diagnostic.err_count() > error_count_before {
140 ecx.struct_span_err(span, "proc-macro derive produced unparseable tokens").emit();
143 ExpandResult::Ready(items)