1 //! lib-proc-macro Client-side types.
2 //!
3 //! Copy from <https://github.com/rust-lang/rust/blob/6050e523bae6de61de4e060facc43dc512adaccd/src/libproc_macro/bridge/client.rs>
4 //! augmented with removing unstable features
5
6 use super::super::TokenStream as CrateTokenStream;
7 use super::*;
8
9 macro_rules! define_handles {
10 (
11 'owned: $($oty:ident,)*
12 'interned: $($ity:ident,)*
13 ) => {
14 #[repr(C)]
15 #[allow(non_snake_case)]
16 pub struct HandleCounters {
17 $($oty: AtomicUsize,)*
18 $($ity: AtomicUsize,)*
19 }
20
21 impl HandleCounters {
22 // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
23 // a wrapper `fn` pointer, once `const fn` can reference `static`s.
24 extern "C" fn get() -> &'static Self {
25 static COUNTERS: HandleCounters = HandleCounters {
26 $($oty: AtomicUsize::new(1),)*
27 $($ity: AtomicUsize::new(1),)*
28 };
29 &COUNTERS
30 }
31 }
32
33 // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`.
34 #[repr(C)]
35 #[allow(non_snake_case)]
36 pub(super) struct HandleStore<S: server::Types> {
37 $($oty: handle::OwnedStore<S::$oty>,)*
38 $($ity: handle::InternedStore<S::$ity>,)*
39 }
40
41 impl<S: server::Types> HandleStore<S> {
42 pub(super) fn new(handle_counters: &'static HandleCounters) -> Self {
43 HandleStore {
44 $($oty: handle::OwnedStore::new(&handle_counters.$oty),)*
45 $($ity: handle::InternedStore::new(&handle_counters.$ity),)*
46 }
47 }
48 }
49
50 $(
51 #[repr(C)]
52 pub struct $oty(pub(crate) handle::Handle);
53 // impl !Send for $oty {}
54 // impl !Sync for $oty {}
55
56 // Forward `Drop::drop` to the inherent `drop` method.
57 impl Drop for $oty {
58 fn drop(&mut self) {
59 $oty(self.0).drop();
60 }
61 }
62
63 impl<S> Encode<S> for $oty {
64 fn encode(self, w: &mut Writer, s: &mut S) {
65 let handle = self.0;
66 mem::forget(self);
67 handle.encode(w, s);
68 }
69 }
70
71 impl<S: server::Types> DecodeMut<'_, '_, HandleStore<server::MarkedTypes<S>>>
72 for Marked<S::$oty, $oty>
73 {
74 fn decode(r: &mut Reader<'_>, s: &mut HandleStore<server::MarkedTypes<S>>) -> Self {
75 s.$oty.take(handle::Handle::decode(r, &mut ()))
76 }
77 }
78
79 impl<S> Encode<S> for &$oty {
80 fn encode(self, w: &mut Writer, s: &mut S) {
81 self.0.encode(w, s);
82 }
83 }
84
85 impl<'s, S: server::Types,> Decode<'_, 's, HandleStore<server::MarkedTypes<S>>>
86 for &'s Marked<S::$oty, $oty>
87 {
88 fn decode(r: &mut Reader<'_>, s: &'s HandleStore<server::MarkedTypes<S>>) -> Self {
89 &s.$oty[handle::Handle::decode(r, &mut ())]
90 }
91 }
92
93 impl<S> Encode<S> for &mut $oty {
94 fn encode(self, w: &mut Writer, s: &mut S) {
95 self.0.encode(w, s);
96 }
97 }
98
99 impl<'s, S: server::Types> DecodeMut<'_, 's, HandleStore<server::MarkedTypes<S>>>
100 for &'s mut Marked<S::$oty, $oty>
101 {
102 fn decode(
103 r: &mut Reader<'_>,
104 s: &'s mut HandleStore<server::MarkedTypes<S>>
105 ) -> Self {
106 &mut s.$oty[handle::Handle::decode(r, &mut ())]
107 }
108 }
109
110 impl<S: server::Types> Encode<HandleStore<server::MarkedTypes<S>>>
111 for Marked<S::$oty, $oty>
112 {
113 fn encode(self, w: &mut Writer, s: &mut HandleStore<server::MarkedTypes<S>>) {
114 s.$oty.alloc(self).encode(w, s);
115 }
116 }
117
118 impl<S> DecodeMut<'_, '_, S> for $oty {
119 fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
120 $oty(handle::Handle::decode(r, s))
121 }
122 }
123 )*
124
125 $(
126 #[repr(C)]
127 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
128 pub(crate) struct $ity(handle::Handle);
129 // impl !Send for $ity {}
130 // impl !Sync for $ity {}
131
132 impl<S> Encode<S> for $ity {
133 fn encode(self, w: &mut Writer, s: &mut S) {
134 self.0.encode(w, s);
135 }
136 }
137
138 impl<S: server::Types> DecodeMut<'_, '_, HandleStore<server::MarkedTypes<S>>>
139 for Marked<S::$ity, $ity>
140 {
141 fn decode(r: &mut Reader<'_>, s: &mut HandleStore<server::MarkedTypes<S>>) -> Self {
142 s.$ity.copy(handle::Handle::decode(r, &mut ()))
143 }
144 }
145
146 impl<S: server::Types> Encode<HandleStore<server::MarkedTypes<S>>>
147 for Marked<S::$ity, $ity>
148 {
149 fn encode(self, w: &mut Writer, s: &mut HandleStore<server::MarkedTypes<S>>) {
150 s.$ity.alloc(self).encode(w, s);
151 }
152 }
153
154 impl<S> DecodeMut<'_, '_, S> for $ity {
155 fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
156 $ity(handle::Handle::decode(r, s))
157 }
158 }
159 )*
160 }
161 }
162 define_handles! {
163 'owned:
164 FreeFunctions,
165 TokenStream,
166 TokenStreamBuilder,
167 TokenStreamIter,
168 Group,
169 Literal,
170 SourceFile,
171 MultiSpan,
172 Diagnostic,
173
174 'interned:
175 Punct,
176 Ident,
177 Span,
178 }
179
180 // FIXME(eddyb) generate these impls by pattern-matching on the
181 // names of methods - also could use the presence of `fn drop`
182 // to distinguish between 'owned and 'interned, above.
183 // Alternatively, special 'modes" could be listed of types in with_api
184 // instead of pattern matching on methods, here and in server decl.
185
186 impl Clone for TokenStream {
clone(&self) -> Self187 fn clone(&self) -> Self {
188 self.clone()
189 }
190 }
191
192 impl Clone for TokenStreamIter {
clone(&self) -> Self193 fn clone(&self) -> Self {
194 self.clone()
195 }
196 }
197
198 impl Clone for Group {
clone(&self) -> Self199 fn clone(&self) -> Self {
200 self.clone()
201 }
202 }
203
204 impl Clone for Literal {
clone(&self) -> Self205 fn clone(&self) -> Self {
206 self.clone()
207 }
208 }
209
210 impl fmt::Debug for Literal {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212 f.debug_struct("Literal")
213 // format the kind without quotes, as in `kind: Float`
214 // .field("kind", &format_args!("{}", &self.debug_kind()))
215 .field("symbol", &self.symbol())
216 // format `Some("...")` on one line even in {:#?} mode
217 // .field("suffix", &format_args!("{:?}", &self.suffix()))
218 .field("span", &self.span())
219 .finish()
220 }
221 }
222
223 impl Clone for SourceFile {
clone(&self) -> Self224 fn clone(&self) -> Self {
225 self.clone()
226 }
227 }
228
229 impl fmt::Debug for Span {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 f.write_str(&self.debug())
232 }
233 }
234
235 macro_rules! define_client_side {
236 ($($name:ident {
237 $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
238 }),* $(,)?) => {
239 $(impl $name {
240 #[allow(unused)]
241 $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* {
242 panic!("crates should be linked against the sysroot version of proc_macro, not this one from rust-analyzer");
243 // Bridge::with(|bridge| {
244 // let mut b = bridge.cached_buffer.take();
245
246 // b.clear();
247 // api_tags::Method::$name(api_tags::$name::$method).encode(&mut b, &mut ());
248 // reverse_encode!(b; $($arg),*);
249
250 // b = bridge.dispatch.call(b);
251
252 // let r = Result::<_, PanicMessage>::decode(&mut &b[..], &mut ());
253
254 // bridge.cached_buffer = b;
255
256 // r.unwrap_or_else(|e| panic::resume_unwind(e.into()))
257 // })
258 })*
259 })*
260 }
261 }
262 with_api!(self, self, define_client_side);
263
264 enum BridgeState<'a> {
265 /// No server is currently connected to this client.
266 NotConnected,
267
268 /// A server is connected and available for requests.
269 Connected(Bridge<'a>),
270
271 /// Access to the bridge is being exclusively acquired
272 /// (e.g., during `BridgeState::with`).
273 InUse,
274 }
275
276 enum BridgeStateL {}
277
278 impl<'a> scoped_cell::ApplyL<'a> for BridgeStateL {
279 type Out = BridgeState<'a>;
280 }
281
282 thread_local! {
283 static BRIDGE_STATE: scoped_cell::ScopedCell<BridgeStateL> =
284 scoped_cell::ScopedCell::new(BridgeState::NotConnected);
285 }
286
287 impl BridgeState<'_> {
288 /// Take exclusive control of the thread-local
289 /// `BridgeState`, and pass it to `f`, mutably.
290 /// The state will be restored after `f` exits, even
291 /// by panic, including modifications made to it by `f`.
292 ///
293 /// N.B., while `f` is running, the thread-local state
294 /// is `BridgeState::InUse`.
with<R>(f: impl FnOnce(&mut BridgeState<'_>) -> R) -> R295 fn with<R>(f: impl FnOnce(&mut BridgeState<'_>) -> R) -> R {
296 BRIDGE_STATE.with(|state| {
297 state.replace(BridgeState::InUse, |mut state| {
298 // FIXME(#52812) pass `f` directly to `replace` when `RefMutL` is gone
299 f(&mut *state)
300 })
301 })
302 }
303 }
304
305 impl Bridge<'_> {
enter<R>(self, f: impl FnOnce() -> R) -> R306 fn enter<R>(self, f: impl FnOnce() -> R) -> R {
307 let force_show_panics = self.force_show_panics;
308
309 // Hide the default panic output within `proc_macro` expansions.
310 // NB. the server can't do this because it may use a different libstd.
311 static HIDE_PANICS_DURING_EXPANSION: Once = Once::new();
312 HIDE_PANICS_DURING_EXPANSION.call_once(|| {
313 let prev = panic::take_hook();
314 panic::set_hook(Box::new(move |info| {
315 let show = BridgeState::with(|state| match state {
316 BridgeState::NotConnected => true,
317 // Something weird is going on, so don't suppress any backtraces
318 BridgeState::InUse => true,
319 BridgeState::Connected(bridge) => force_show_panics,
320 });
321 if show {
322 prev(info)
323 }
324 }));
325 });
326
327 BRIDGE_STATE.with(|state| state.set(BridgeState::Connected(self), f))
328 }
329
with<R>(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R330 fn with<R>(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R {
331 BridgeState::with(|state| match state {
332 BridgeState::NotConnected => {
333 panic!("procedural macro API is used outside of a procedural macro");
334 }
335 BridgeState::InUse => {
336 panic!("procedural macro API is used while it's already in use");
337 }
338 BridgeState::Connected(bridge) => f(bridge),
339 })
340 }
341 }
342
343 /// A client-side "global object" (usually a function pointer),
344 /// which may be using a different `proc_macro` from the one
345 /// used by the server, but can be interacted with compatibly.
346 ///
347 /// N.B., `F` must have FFI-friendly memory layout (e.g., a pointer).
348 /// The call ABI of function pointers used for `F` doesn't
349 /// need to match between server and client, since it's only
350 /// passed between them and (eventually) called by the client.
351 #[repr(C)]
352 #[derive(Copy, Clone)]
353 pub struct Client<F> {
354 // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
355 // a wrapper `fn` pointer, once `const fn` can reference `static`s.
356 pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters,
357 pub(super) run: extern "C" fn(Bridge<'_>, F) -> Buffer<u8>,
358 pub(super) f: F,
359 }
360
361 /// Client-side helper for handling client panics, entering the bridge,
362 /// deserializing input and serializing output.
363 // FIXME(eddyb) maybe replace `Bridge::enter` with this?
run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>( mut bridge: Bridge<'_>, f: impl FnOnce(A) -> R, ) -> Buffer<u8>364 fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>(
365 mut bridge: Bridge<'_>,
366 f: impl FnOnce(A) -> R,
367 ) -> Buffer<u8> {
368 // The initial `cached_buffer` contains the input.
369 let mut b = bridge.cached_buffer.take();
370
371 panic::catch_unwind(panic::AssertUnwindSafe(|| {
372 bridge.enter(|| {
373 let reader = &mut &b[..];
374 let input = A::decode(reader, &mut ());
375
376 // Put the `cached_buffer` back in the `Bridge`, for requests.
377 Bridge::with(|bridge| bridge.cached_buffer = b.take());
378
379 let output = f(input);
380
381 // Take the `cached_buffer` back out, for the output value.
382 b = Bridge::with(|bridge| bridge.cached_buffer.take());
383
384 // HACK(eddyb) Separate encoding a success value (`Ok(output)`)
385 // from encoding a panic (`Err(e: PanicMessage)`) to avoid
386 // having handles outside the `bridge.enter(|| ...)` scope, and
387 // to catch panics that could happen while encoding the success.
388 //
389 // Note that panics should be impossible beyond this point, but
390 // this is defensively trying to avoid any accidental panicking
391 // reaching the `extern "C"` (which should `abort` but may not
392 // at the moment, so this is also potentially preventing UB).
393 b.clear();
394 Ok::<_, ()>(output).encode(&mut b, &mut ());
395 })
396 }))
397 .map_err(PanicMessage::from)
398 .unwrap_or_else(|e| {
399 b.clear();
400 Err::<(), _>(e).encode(&mut b, &mut ());
401 });
402 b
403 }
404
405 impl Client<fn(CrateTokenStream) -> CrateTokenStream> {
expand1(f: fn(CrateTokenStream) -> CrateTokenStream) -> Self406 pub fn expand1(f: fn(CrateTokenStream) -> CrateTokenStream) -> Self {
407 extern "C" fn run(
408 bridge: Bridge<'_>,
409 f: impl FnOnce(CrateTokenStream) -> CrateTokenStream,
410 ) -> Buffer<u8> {
411 run_client(bridge, |input| f(CrateTokenStream(input)).0)
412 }
413 Client { get_handle_counters: HandleCounters::get, run, f }
414 }
415 }
416
417 impl Client<fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream> {
expand2(f: fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream) -> Self418 pub fn expand2(f: fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream) -> Self {
419 extern "C" fn run(
420 bridge: Bridge<'_>,
421 f: impl FnOnce(CrateTokenStream, CrateTokenStream) -> CrateTokenStream,
422 ) -> Buffer<u8> {
423 run_client(bridge, |(input, input2)| {
424 f(CrateTokenStream(input), CrateTokenStream(input2)).0
425 })
426 }
427 Client { get_handle_counters: HandleCounters::get, run, f }
428 }
429 }
430
431 #[repr(C)]
432 #[derive(Copy, Clone)]
433 pub enum ProcMacro {
434 CustomDerive {
435 trait_name: &'static str,
436 attributes: &'static [&'static str],
437 client: Client<fn(CrateTokenStream) -> CrateTokenStream>,
438 },
439
440 Attr {
441 name: &'static str,
442 client: Client<fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream>,
443 },
444
445 Bang {
446 name: &'static str,
447 client: Client<fn(CrateTokenStream) -> CrateTokenStream>,
448 },
449 }
450
451 impl std::fmt::Debug for ProcMacro {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result452 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
453 write!(f, "ProcMacro {{ name: {} }}", self.name())
454 }
455 }
456
457 impl ProcMacro {
name(&self) -> &'static str458 pub fn name(&self) -> &'static str {
459 match self {
460 ProcMacro::CustomDerive { trait_name, .. } => trait_name,
461 ProcMacro::Attr { name, .. } => name,
462 ProcMacro::Bang { name, .. } => name,
463 }
464 }
465
custom_derive( trait_name: &'static str, attributes: &'static [&'static str], expand: fn(CrateTokenStream) -> CrateTokenStream, ) -> Self466 pub fn custom_derive(
467 trait_name: &'static str,
468 attributes: &'static [&'static str],
469 expand: fn(CrateTokenStream) -> CrateTokenStream,
470 ) -> Self {
471 ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
472 }
473
attr( name: &'static str, expand: fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream, ) -> Self474 pub fn attr(
475 name: &'static str,
476 expand: fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream,
477 ) -> Self {
478 ProcMacro::Attr { name, client: Client::expand2(expand) }
479 }
480
bang(name: &'static str, expand: fn(CrateTokenStream) -> CrateTokenStream) -> Self481 pub fn bang(name: &'static str, expand: fn(CrateTokenStream) -> CrateTokenStream) -> Self {
482 ProcMacro::Bang { name, client: Client::expand1(expand) }
483 }
484 }
485