]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_expand/src/proc_macro.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_expand / src / proc_macro.rs
CommitLineData
e74abb32 1use crate::base::{self, *};
9ffffee4 2use crate::errors;
e74abb32
XL
3use crate::proc_macro_server;
4
6a06907d 5use rustc_ast as ast;
fc512014 6use rustc_ast::ptr::P;
74b04a01 7use rustc_ast::token;
064997fb 8use rustc_ast::tokenstream::TokenStream;
dfeec247 9use rustc_data_structures::sync::Lrc;
5e7ed085 10use rustc_errors::ErrorGuaranteed;
5869c6ff 11use rustc_parse::parser::ForceCollect;
064997fb 12use rustc_session::config::ProcMacroExecutionStrategy;
04454e1e 13use rustc_span::profiling::SpannedEventArgRecorder;
dfeec247 14use rustc_span::{Span, DUMMY_SP};
416331ca 15
064997fb
FG
16struct CrossbeamMessagePipe<T> {
17 tx: crossbeam_channel::Sender<T>,
18 rx: crossbeam_channel::Receiver<T>,
19}
20
21impl<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
37fn 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
44pub struct BangProcMacro {
923072b8 45 pub client: pm::bridge::client::Client<pm::TokenStream, pm::TokenStream>,
416331ca
XL
46}
47
923072b8 48impl 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
74pub struct AttrProcMacro {
923072b8 75 pub client: pm::bridge::client::Client<(pm::TokenStream, pm::TokenStream), pm::TokenStream>,
416331ca
XL
76}
77
78impl 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() {
98 err.help(&format!("message: {}", s));
99 }
5e7ed085 100 err.emit()
064997fb
FG
101 },
102 )
416331ca
XL
103 }
104}
105
923072b8
FG
106pub struct DeriveProcMacro {
107 pub client: pm::bridge::client::Client<pm::TokenStream, pm::TokenStream>,
416331ca
XL
108}
109
923072b8 110impl 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() {
151 err.help(&format!("message: {}", s));
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}