]>
Commit | Line | Data |
---|---|---|
e74abb32 | 1 | use crate::base::{self, *}; |
9ffffee4 | 2 | use crate::errors; |
e74abb32 XL |
3 | use crate::proc_macro_server; |
4 | ||
6a06907d | 5 | use rustc_ast as ast; |
fc512014 | 6 | use rustc_ast::ptr::P; |
74b04a01 | 7 | use rustc_ast::token; |
064997fb | 8 | use rustc_ast::tokenstream::TokenStream; |
dfeec247 | 9 | use rustc_data_structures::sync::Lrc; |
5e7ed085 | 10 | use rustc_errors::ErrorGuaranteed; |
5869c6ff | 11 | use rustc_parse::parser::ForceCollect; |
064997fb | 12 | use rustc_session::config::ProcMacroExecutionStrategy; |
04454e1e | 13 | use rustc_span::profiling::SpannedEventArgRecorder; |
dfeec247 | 14 | use rustc_span::{Span, DUMMY_SP}; |
416331ca | 15 | |
064997fb FG |
16 | struct CrossbeamMessagePipe<T> { |
17 | tx: crossbeam_channel::Sender<T>, | |
18 | rx: crossbeam_channel::Receiver<T>, | |
19 | } | |
20 | ||
21 | impl<T> pm::bridge::server::MessagePipe<T> for CrossbeamMessagePipe<T> { | |
22 | fn new() -> (Self, Self) { | |
23 | let (tx1, rx1) = crossbeam_channel::bounded(1); | |
24 | let (tx2, rx2) = crossbeam_channel::bounded(1); | |
25 | (CrossbeamMessagePipe { tx: tx1, rx: rx2 }, CrossbeamMessagePipe { tx: tx2, rx: rx1 }) | |
26 | } | |
27 | ||
28 | fn send(&mut self, value: T) { | |
29 | self.tx.send(value).unwrap(); | |
30 | } | |
31 | ||
32 | fn recv(&mut self) -> Option<T> { | |
33 | self.rx.recv().ok() | |
34 | } | |
35 | } | |
36 | ||
37 | fn exec_strategy(ecx: &ExtCtxt<'_>) -> impl pm::bridge::server::ExecutionStrategy { | |
38 | pm::bridge::server::MaybeCrossThread::<CrossbeamMessagePipe<_>>::new( | |
39 | ecx.sess.opts.unstable_opts.proc_macro_execution_strategy | |
40 | == ProcMacroExecutionStrategy::CrossThread, | |
41 | ) | |
42 | } | |
416331ca XL |
43 | |
44 | pub struct BangProcMacro { | |
923072b8 | 45 | pub client: pm::bridge::client::Client<pm::TokenStream, pm::TokenStream>, |
416331ca XL |
46 | } |
47 | ||
923072b8 | 48 | impl base::BangProcMacro for BangProcMacro { |
dfeec247 XL |
49 | fn expand<'cx>( |
50 | &self, | |
51 | ecx: &'cx mut ExtCtxt<'_>, | |
52 | span: Span, | |
53 | input: TokenStream, | |
5e7ed085 | 54 | ) -> Result<TokenStream, ErrorGuaranteed> { |
04454e1e FG |
55 | let _timer = |
56 | ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| { | |
353b0b11 | 57 | recorder.record_arg_with_span(ecx.sess.source_map(), ecx.expansion_descr(), span); |
04454e1e FG |
58 | }); |
59 | ||
3c0e092e | 60 | let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; |
064997fb | 61 | let strategy = exec_strategy(ecx); |
136023e0 | 62 | let server = proc_macro_server::Rustc::new(ecx); |
064997fb | 63 | self.client.run(&strategy, server, input, proc_macro_backtrace).map_err(|e| { |
9ffffee4 FG |
64 | ecx.sess.emit_err(errors::ProcMacroPanicked { |
65 | span, | |
66 | message: e | |
67 | .as_str() | |
68 | .map(|message| errors::ProcMacroPanickedHelp { message: message.into() }), | |
69 | }) | |
ba9703b0 | 70 | }) |
416331ca XL |
71 | } |
72 | } | |
73 | ||
74 | pub struct AttrProcMacro { | |
923072b8 | 75 | pub client: pm::bridge::client::Client<(pm::TokenStream, pm::TokenStream), pm::TokenStream>, |
416331ca XL |
76 | } |
77 | ||
78 | impl base::AttrProcMacro for AttrProcMacro { | |
dfeec247 XL |
79 | fn expand<'cx>( |
80 | &self, | |
81 | ecx: &'cx mut ExtCtxt<'_>, | |
82 | span: Span, | |
83 | annotation: TokenStream, | |
84 | annotated: TokenStream, | |
5e7ed085 | 85 | ) -> Result<TokenStream, ErrorGuaranteed> { |
04454e1e FG |
86 | let _timer = |
87 | ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| { | |
353b0b11 | 88 | recorder.record_arg_with_span(ecx.sess.source_map(), ecx.expansion_descr(), span); |
04454e1e FG |
89 | }); |
90 | ||
3c0e092e | 91 | let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; |
064997fb | 92 | let strategy = exec_strategy(ecx); |
136023e0 | 93 | let server = proc_macro_server::Rustc::new(ecx); |
064997fb FG |
94 | self.client.run(&strategy, server, annotation, annotated, proc_macro_backtrace).map_err( |
95 | |e| { | |
1b1a35ee XL |
96 | let mut err = ecx.struct_span_err(span, "custom attribute panicked"); |
97 | if let Some(s) = e.as_str() { | |
49aad941 | 98 | err.help(format!("message: {}", s)); |
1b1a35ee | 99 | } |
5e7ed085 | 100 | err.emit() |
064997fb FG |
101 | }, |
102 | ) | |
416331ca XL |
103 | } |
104 | } | |
105 | ||
923072b8 FG |
106 | pub struct DeriveProcMacro { |
107 | pub client: pm::bridge::client::Client<pm::TokenStream, pm::TokenStream>, | |
416331ca XL |
108 | } |
109 | ||
923072b8 | 110 | impl MultiItemModifier for DeriveProcMacro { |
dfeec247 XL |
111 | fn expand( |
112 | &self, | |
113 | ecx: &mut ExtCtxt<'_>, | |
114 | span: Span, | |
115 | _meta_item: &ast::MetaItem, | |
116 | item: Annotatable, | |
487cf647 | 117 | _is_derive_const: bool, |
ba9703b0 | 118 | ) -> ExpandResult<Vec<Annotatable>, Annotatable> { |
fc512014 XL |
119 | // We need special handling for statement items |
120 | // (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`) | |
04454e1e FG |
121 | let is_stmt = matches!(item, Annotatable::Stmt(..)); |
122 | let hack = crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess.parse_sess); | |
123 | let input = if hack { | |
124 | let nt = match item { | |
125 | Annotatable::Item(item) => token::NtItem(item), | |
126 | Annotatable::Stmt(stmt) => token::NtStmt(stmt), | |
127 | _ => unreachable!(), | |
128 | }; | |
064997fb | 129 | TokenStream::token_alone(token::Interpolated(Lrc::new(nt)), DUMMY_SP) |
f035d41b | 130 | } else { |
923072b8 | 131 | item.to_tokens() |
f035d41b | 132 | }; |
416331ca | 133 | |
04454e1e FG |
134 | let stream = { |
135 | let _timer = | |
136 | ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| { | |
353b0b11 FG |
137 | recorder.record_arg_with_span( |
138 | ecx.sess.source_map(), | |
139 | ecx.expansion_descr(), | |
140 | span, | |
141 | ); | |
04454e1e FG |
142 | }); |
143 | let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; | |
064997fb | 144 | let strategy = exec_strategy(ecx); |
04454e1e | 145 | let server = proc_macro_server::Rustc::new(ecx); |
064997fb | 146 | match self.client.run(&strategy, server, input, proc_macro_backtrace) { |
04454e1e FG |
147 | Ok(stream) => stream, |
148 | Err(e) => { | |
149 | let mut err = ecx.struct_span_err(span, "proc-macro derive panicked"); | |
150 | if let Some(s) = e.as_str() { | |
49aad941 | 151 | err.help(format!("message: {}", s)); |
04454e1e FG |
152 | } |
153 | err.emit(); | |
154 | return ExpandResult::Ready(vec![]); | |
416331ca | 155 | } |
3c0e092e XL |
156 | } |
157 | }; | |
416331ca | 158 | |
3dfed10e | 159 | let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count(); |
dfeec247 | 160 | let mut parser = |
3dfed10e | 161 | rustc_parse::stream_to_parser(&ecx.sess.parse_sess, stream, Some("proc-macro derive")); |
416331ca XL |
162 | let mut items = vec![]; |
163 | ||
164 | loop { | |
5869c6ff | 165 | match parser.parse_item(ForceCollect::No) { |
416331ca | 166 | Ok(None) => break, |
fc512014 XL |
167 | Ok(Some(item)) => { |
168 | if is_stmt { | |
169 | items.push(Annotatable::Stmt(P(ecx.stmt_item(span, item)))); | |
170 | } else { | |
171 | items.push(Annotatable::Item(item)); | |
172 | } | |
173 | } | |
416331ca | 174 | Err(mut err) => { |
ba9703b0 XL |
175 | err.emit(); |
176 | break; | |
416331ca XL |
177 | } |
178 | } | |
179 | } | |
180 | ||
416331ca | 181 | // fail if there have been errors emitted |
3dfed10e | 182 | if ecx.sess.parse_sess.span_diagnostic.err_count() > error_count_before { |
9ffffee4 | 183 | ecx.sess.emit_err(errors::ProcMacroDeriveTokens { span }); |
416331ca XL |
184 | } |
185 | ||
ba9703b0 | 186 | ExpandResult::Ready(items) |
416331ca XL |
187 | } |
188 | } |