diff options
author | Igor Aleksanov <[email protected]> | 2020-08-14 05:34:07 +0100 |
---|---|---|
committer | Igor Aleksanov <[email protected]> | 2020-08-14 05:34:07 +0100 |
commit | c26c911ec1e6c2ad1dcb7d155a6a1d528839ad1a (patch) | |
tree | 7cff36c38234be0afb65273146d8247083a5cfeb /crates/proc_macro_srv/src/proc_macro/bridge/mod.rs | |
parent | 3c018bf84de5c693b5ee1c6bec0fed3b201c2060 (diff) | |
parent | f1f73649a686dc6e6449afc35e0fa6fed00e225d (diff) |
Merge branch 'master' into add-disable-diagnostics
Diffstat (limited to 'crates/proc_macro_srv/src/proc_macro/bridge/mod.rs')
-rw-r--r-- | crates/proc_macro_srv/src/proc_macro/bridge/mod.rs | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs b/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs new file mode 100644 index 000000000..aeb05aad4 --- /dev/null +++ b/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs | |||
@@ -0,0 +1,408 @@ | |||
1 | //! lib-proc-macro Internal interface for communicating between a `proc_macro` client | ||
2 | //! | ||
3 | //! Copy from https://github.com/rust-lang/rust/blob/6050e523bae6de61de4e060facc43dc512adaccd/src/libproc_macro/bridge/mod.rs | ||
4 | //! augmented with removing unstable features | ||
5 | //! | ||
6 | //! Internal interface for communicating between a `proc_macro` client | ||
7 | //! (a proc macro crate) and a `proc_macro` server (a compiler front-end). | ||
8 | //! | ||
9 | //! Serialization (with C ABI buffers) and unique integer handles are employed | ||
10 | //! to allow safely interfacing between two copies of `proc_macro` built | ||
11 | //! (from the same source) by different compilers with potentially mismatching | ||
12 | //! Rust ABIs (e.g., stage0/bin/rustc vs stage1/bin/rustc during bootstrap). | ||
13 | |||
14 | #![deny(unsafe_code)] | ||
15 | |||
16 | pub use crate::proc_macro::{Delimiter, Level, LineColumn, Spacing}; | ||
17 | use std::fmt; | ||
18 | use std::hash::Hash; | ||
19 | use std::marker; | ||
20 | use std::mem; | ||
21 | use std::ops::Bound; | ||
22 | use std::panic; | ||
23 | use std::sync::atomic::AtomicUsize; | ||
24 | use std::sync::Once; | ||
25 | use std::thread; | ||
26 | |||
27 | /// Higher-order macro describing the server RPC API, allowing automatic | ||
28 | /// generation of type-safe Rust APIs, both client-side and server-side. | ||
29 | /// | ||
30 | /// `with_api!(MySelf, my_self, my_macro)` expands to: | ||
31 | /// ```rust,ignore (pseudo-code) | ||
32 | /// my_macro! { | ||
33 | /// // ... | ||
34 | /// Literal { | ||
35 | /// // ... | ||
36 | /// fn character(ch: char) -> MySelf::Literal; | ||
37 | /// // ... | ||
38 | /// fn span(my_self: &MySelf::Literal) -> MySelf::Span; | ||
39 | /// fn set_span(my_self: &mut MySelf::Literal, span: MySelf::Span); | ||
40 | /// }, | ||
41 | /// // ... | ||
42 | /// } | ||
43 | /// ``` | ||
44 | /// | ||
45 | /// The first two arguments serve to customize the arguments names | ||
46 | /// and argument/return types, to enable several different usecases: | ||
47 | /// | ||
48 | /// If `my_self` is just `self`, then each `fn` signature can be used | ||
49 | /// as-is for a method. If it's anything else (`self_` in practice), | ||
50 | /// then the signatures don't have a special `self` argument, and | ||
51 | /// can, therefore, have a different one introduced. | ||
52 | /// | ||
53 | /// If `MySelf` is just `Self`, then the types are only valid inside | ||
54 | /// a trait or a trait impl, where the trait has associated types | ||
55 | /// for each of the API types. If non-associated types are desired, | ||
56 | /// a module name (`self` in practice) can be used instead of `Self`. | ||
57 | macro_rules! with_api { | ||
58 | ($S:ident, $self:ident, $m:ident) => { | ||
59 | $m! { | ||
60 | TokenStream { | ||
61 | fn drop($self: $S::TokenStream); | ||
62 | fn clone($self: &$S::TokenStream) -> $S::TokenStream; | ||
63 | fn new() -> $S::TokenStream; | ||
64 | fn is_empty($self: &$S::TokenStream) -> bool; | ||
65 | fn from_str(src: &str) -> $S::TokenStream; | ||
66 | fn to_string($self: &$S::TokenStream) -> String; | ||
67 | fn from_token_tree( | ||
68 | tree: TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>, | ||
69 | ) -> $S::TokenStream; | ||
70 | fn into_iter($self: $S::TokenStream) -> $S::TokenStreamIter; | ||
71 | }, | ||
72 | TokenStreamBuilder { | ||
73 | fn drop($self: $S::TokenStreamBuilder); | ||
74 | fn new() -> $S::TokenStreamBuilder; | ||
75 | fn push($self: &mut $S::TokenStreamBuilder, stream: $S::TokenStream); | ||
76 | fn build($self: $S::TokenStreamBuilder) -> $S::TokenStream; | ||
77 | }, | ||
78 | TokenStreamIter { | ||
79 | fn drop($self: $S::TokenStreamIter); | ||
80 | fn clone($self: &$S::TokenStreamIter) -> $S::TokenStreamIter; | ||
81 | fn next( | ||
82 | $self: &mut $S::TokenStreamIter, | ||
83 | ) -> Option<TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>>; | ||
84 | }, | ||
85 | Group { | ||
86 | fn drop($self: $S::Group); | ||
87 | fn clone($self: &$S::Group) -> $S::Group; | ||
88 | fn new(delimiter: Delimiter, stream: $S::TokenStream) -> $S::Group; | ||
89 | fn delimiter($self: &$S::Group) -> Delimiter; | ||
90 | fn stream($self: &$S::Group) -> $S::TokenStream; | ||
91 | fn span($self: &$S::Group) -> $S::Span; | ||
92 | fn span_open($self: &$S::Group) -> $S::Span; | ||
93 | fn span_close($self: &$S::Group) -> $S::Span; | ||
94 | fn set_span($self: &mut $S::Group, span: $S::Span); | ||
95 | }, | ||
96 | Punct { | ||
97 | fn new(ch: char, spacing: Spacing) -> $S::Punct; | ||
98 | fn as_char($self: $S::Punct) -> char; | ||
99 | fn spacing($self: $S::Punct) -> Spacing; | ||
100 | fn span($self: $S::Punct) -> $S::Span; | ||
101 | fn with_span($self: $S::Punct, span: $S::Span) -> $S::Punct; | ||
102 | }, | ||
103 | Ident { | ||
104 | fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident; | ||
105 | fn span($self: $S::Ident) -> $S::Span; | ||
106 | fn with_span($self: $S::Ident, span: $S::Span) -> $S::Ident; | ||
107 | }, | ||
108 | Literal { | ||
109 | fn drop($self: $S::Literal); | ||
110 | fn clone($self: &$S::Literal) -> $S::Literal; | ||
111 | fn debug_kind($self: &$S::Literal) -> String; | ||
112 | fn symbol($self: &$S::Literal) -> String; | ||
113 | fn suffix($self: &$S::Literal) -> Option<String>; | ||
114 | fn integer(n: &str) -> $S::Literal; | ||
115 | fn typed_integer(n: &str, kind: &str) -> $S::Literal; | ||
116 | fn float(n: &str) -> $S::Literal; | ||
117 | fn f32(n: &str) -> $S::Literal; | ||
118 | fn f64(n: &str) -> $S::Literal; | ||
119 | fn string(string: &str) -> $S::Literal; | ||
120 | fn character(ch: char) -> $S::Literal; | ||
121 | fn byte_string(bytes: &[u8]) -> $S::Literal; | ||
122 | fn span($self: &$S::Literal) -> $S::Span; | ||
123 | fn set_span($self: &mut $S::Literal, span: $S::Span); | ||
124 | fn subspan( | ||
125 | $self: &$S::Literal, | ||
126 | start: Bound<usize>, | ||
127 | end: Bound<usize>, | ||
128 | ) -> Option<$S::Span>; | ||
129 | }, | ||
130 | SourceFile { | ||
131 | fn drop($self: $S::SourceFile); | ||
132 | fn clone($self: &$S::SourceFile) -> $S::SourceFile; | ||
133 | fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool; | ||
134 | fn path($self: &$S::SourceFile) -> String; | ||
135 | fn is_real($self: &$S::SourceFile) -> bool; | ||
136 | }, | ||
137 | MultiSpan { | ||
138 | fn drop($self: $S::MultiSpan); | ||
139 | fn new() -> $S::MultiSpan; | ||
140 | fn push($self: &mut $S::MultiSpan, span: $S::Span); | ||
141 | }, | ||
142 | Diagnostic { | ||
143 | fn drop($self: $S::Diagnostic); | ||
144 | fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic; | ||
145 | fn sub( | ||
146 | $self: &mut $S::Diagnostic, | ||
147 | level: Level, | ||
148 | msg: &str, | ||
149 | span: $S::MultiSpan, | ||
150 | ); | ||
151 | fn emit($self: $S::Diagnostic); | ||
152 | }, | ||
153 | Span { | ||
154 | fn debug($self: $S::Span) -> String; | ||
155 | fn def_site() -> $S::Span; | ||
156 | fn call_site() -> $S::Span; | ||
157 | fn mixed_site() -> $S::Span; | ||
158 | fn source_file($self: $S::Span) -> $S::SourceFile; | ||
159 | fn parent($self: $S::Span) -> Option<$S::Span>; | ||
160 | fn source($self: $S::Span) -> $S::Span; | ||
161 | fn start($self: $S::Span) -> LineColumn; | ||
162 | fn end($self: $S::Span) -> LineColumn; | ||
163 | fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; | ||
164 | fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; | ||
165 | fn source_text($self: $S::Span) -> Option<String>; | ||
166 | }, | ||
167 | } | ||
168 | }; | ||
169 | } | ||
170 | |||
171 | // FIXME(eddyb) this calls `encode` for each argument, but in reverse, | ||
172 | // to avoid borrow conflicts from borrows started by `&mut` arguments. | ||
173 | macro_rules! reverse_encode { | ||
174 | ($writer:ident;) => {}; | ||
175 | ($writer:ident; $first:ident $(, $rest:ident)*) => { | ||
176 | reverse_encode!($writer; $($rest),*); | ||
177 | $first.encode(&mut $writer, &mut ()); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | // FIXME(eddyb) this calls `decode` for each argument, but in reverse, | ||
182 | // to avoid borrow conflicts from borrows started by `&mut` arguments. | ||
183 | macro_rules! reverse_decode { | ||
184 | ($reader:ident, $s:ident;) => {}; | ||
185 | ($reader:ident, $s:ident; $first:ident: $first_ty:ty $(, $rest:ident: $rest_ty:ty)*) => { | ||
186 | reverse_decode!($reader, $s; $($rest: $rest_ty),*); | ||
187 | let $first = <$first_ty>::decode(&mut $reader, $s); | ||
188 | } | ||
189 | } | ||
190 | |||
191 | #[allow(unsafe_code)] | ||
192 | mod buffer; | ||
193 | #[forbid(unsafe_code)] | ||
194 | pub mod client; | ||
195 | #[allow(unsafe_code)] | ||
196 | mod closure; | ||
197 | #[forbid(unsafe_code)] | ||
198 | mod handle; | ||
199 | #[macro_use] | ||
200 | #[forbid(unsafe_code)] | ||
201 | mod rpc; | ||
202 | #[allow(unsafe_code)] | ||
203 | mod scoped_cell; | ||
204 | #[forbid(unsafe_code)] | ||
205 | pub mod server; | ||
206 | |||
207 | use buffer::Buffer; | ||
208 | pub use rpc::PanicMessage; | ||
209 | use rpc::{Decode, DecodeMut, Encode, Reader, Writer}; | ||
210 | |||
211 | /// An active connection between a server and a client. | ||
212 | /// The server creates the bridge (`Bridge::run_server` in `server.rs`), | ||
213 | /// then passes it to the client through the function pointer in the `run` | ||
214 | /// field of `client::Client`. The client holds its copy of the `Bridge` | ||
215 | /// in TLS during its execution (`Bridge::{enter, with}` in `client.rs`). | ||
216 | #[repr(C)] | ||
217 | pub struct Bridge<'a> { | ||
218 | /// Reusable buffer (only `clear`-ed, never shrunk), primarily | ||
219 | /// used for making requests, but also for passing input to client. | ||
220 | cached_buffer: Buffer<u8>, | ||
221 | |||
222 | /// Server-side function that the client uses to make requests. | ||
223 | dispatch: closure::Closure<'a, Buffer<u8>, Buffer<u8>>, | ||
224 | } | ||
225 | |||
226 | // impl<'a> !Sync for Bridge<'a> {} | ||
227 | // impl<'a> !Send for Bridge<'a> {} | ||
228 | |||
229 | #[forbid(unsafe_code)] | ||
230 | #[allow(non_camel_case_types)] | ||
231 | mod api_tags { | ||
232 | use super::rpc::{DecodeMut, Encode, Reader, Writer}; | ||
233 | |||
234 | macro_rules! declare_tags { | ||
235 | ($($name:ident { | ||
236 | $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* | ||
237 | }),* $(,)?) => { | ||
238 | $( | ||
239 | pub(super) enum $name { | ||
240 | $($method),* | ||
241 | } | ||
242 | rpc_encode_decode!(enum $name { $($method),* }); | ||
243 | )* | ||
244 | |||
245 | |||
246 | pub(super) enum Method { | ||
247 | $($name($name)),* | ||
248 | } | ||
249 | rpc_encode_decode!(enum Method { $($name(m)),* }); | ||
250 | } | ||
251 | } | ||
252 | with_api!(self, self, declare_tags); | ||
253 | } | ||
254 | |||
255 | /// Helper to wrap associated types to allow trait impl dispatch. | ||
256 | /// That is, normally a pair of impls for `T::Foo` and `T::Bar` | ||
257 | /// can overlap, but if the impls are, instead, on types like | ||
258 | /// `Marked<T::Foo, Foo>` and `Marked<T::Bar, Bar>`, they can't. | ||
259 | trait Mark { | ||
260 | type Unmarked; | ||
261 | fn mark(unmarked: Self::Unmarked) -> Self; | ||
262 | } | ||
263 | |||
264 | /// Unwrap types wrapped by `Mark::mark` (see `Mark` for details). | ||
265 | trait Unmark { | ||
266 | type Unmarked; | ||
267 | fn unmark(self) -> Self::Unmarked; | ||
268 | } | ||
269 | |||
270 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] | ||
271 | struct Marked<T, M> { | ||
272 | value: T, | ||
273 | _marker: marker::PhantomData<M>, | ||
274 | } | ||
275 | |||
276 | impl<T, M> Mark for Marked<T, M> { | ||
277 | type Unmarked = T; | ||
278 | fn mark(unmarked: Self::Unmarked) -> Self { | ||
279 | Marked { value: unmarked, _marker: marker::PhantomData } | ||
280 | } | ||
281 | } | ||
282 | impl<T, M> Unmark for Marked<T, M> { | ||
283 | type Unmarked = T; | ||
284 | fn unmark(self) -> Self::Unmarked { | ||
285 | self.value | ||
286 | } | ||
287 | } | ||
288 | impl<'a, T, M> Unmark for &'a Marked<T, M> { | ||
289 | type Unmarked = &'a T; | ||
290 | fn unmark(self) -> Self::Unmarked { | ||
291 | &self.value | ||
292 | } | ||
293 | } | ||
294 | impl<'a, T, M> Unmark for &'a mut Marked<T, M> { | ||
295 | type Unmarked = &'a mut T; | ||
296 | fn unmark(self) -> Self::Unmarked { | ||
297 | &mut self.value | ||
298 | } | ||
299 | } | ||
300 | |||
301 | impl<T: Mark> Mark for Option<T> { | ||
302 | type Unmarked = Option<T::Unmarked>; | ||
303 | fn mark(unmarked: Self::Unmarked) -> Self { | ||
304 | unmarked.map(T::mark) | ||
305 | } | ||
306 | } | ||
307 | impl<T: Unmark> Unmark for Option<T> { | ||
308 | type Unmarked = Option<T::Unmarked>; | ||
309 | fn unmark(self) -> Self::Unmarked { | ||
310 | self.map(T::unmark) | ||
311 | } | ||
312 | } | ||
313 | |||
314 | macro_rules! mark_noop { | ||
315 | ($($ty:ty),* $(,)?) => { | ||
316 | $( | ||
317 | impl Mark for $ty { | ||
318 | type Unmarked = Self; | ||
319 | fn mark(unmarked: Self::Unmarked) -> Self { | ||
320 | unmarked | ||
321 | } | ||
322 | } | ||
323 | impl Unmark for $ty { | ||
324 | type Unmarked = Self; | ||
325 | fn unmark(self) -> Self::Unmarked { | ||
326 | self | ||
327 | } | ||
328 | } | ||
329 | )* | ||
330 | } | ||
331 | } | ||
332 | mark_noop! { | ||
333 | (), | ||
334 | bool, | ||
335 | char, | ||
336 | &'_ [u8], | ||
337 | &'_ str, | ||
338 | String, | ||
339 | Delimiter, | ||
340 | Level, | ||
341 | LineColumn, | ||
342 | Spacing, | ||
343 | Bound<usize>, | ||
344 | } | ||
345 | |||
346 | rpc_encode_decode!( | ||
347 | enum Delimiter { | ||
348 | Parenthesis, | ||
349 | Brace, | ||
350 | Bracket, | ||
351 | None, | ||
352 | } | ||
353 | ); | ||
354 | rpc_encode_decode!( | ||
355 | enum Level { | ||
356 | Error, | ||
357 | Warning, | ||
358 | Note, | ||
359 | Help, | ||
360 | } | ||
361 | ); | ||
362 | rpc_encode_decode!(struct LineColumn { line, column }); | ||
363 | rpc_encode_decode!( | ||
364 | enum Spacing { | ||
365 | Alone, | ||
366 | Joint, | ||
367 | } | ||
368 | ); | ||
369 | |||
370 | #[derive(Clone)] | ||
371 | pub enum TokenTree<G, P, I, L> { | ||
372 | Group(G), | ||
373 | Punct(P), | ||
374 | Ident(I), | ||
375 | Literal(L), | ||
376 | } | ||
377 | |||
378 | impl<G: Mark, P: Mark, I: Mark, L: Mark> Mark for TokenTree<G, P, I, L> { | ||
379 | type Unmarked = TokenTree<G::Unmarked, P::Unmarked, I::Unmarked, L::Unmarked>; | ||
380 | fn mark(unmarked: Self::Unmarked) -> Self { | ||
381 | match unmarked { | ||
382 | TokenTree::Group(tt) => TokenTree::Group(G::mark(tt)), | ||
383 | TokenTree::Punct(tt) => TokenTree::Punct(P::mark(tt)), | ||
384 | TokenTree::Ident(tt) => TokenTree::Ident(I::mark(tt)), | ||
385 | TokenTree::Literal(tt) => TokenTree::Literal(L::mark(tt)), | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | impl<G: Unmark, P: Unmark, I: Unmark, L: Unmark> Unmark for TokenTree<G, P, I, L> { | ||
390 | type Unmarked = TokenTree<G::Unmarked, P::Unmarked, I::Unmarked, L::Unmarked>; | ||
391 | fn unmark(self) -> Self::Unmarked { | ||
392 | match self { | ||
393 | TokenTree::Group(tt) => TokenTree::Group(tt.unmark()), | ||
394 | TokenTree::Punct(tt) => TokenTree::Punct(tt.unmark()), | ||
395 | TokenTree::Ident(tt) => TokenTree::Ident(tt.unmark()), | ||
396 | TokenTree::Literal(tt) => TokenTree::Literal(tt.unmark()), | ||
397 | } | ||
398 | } | ||
399 | } | ||
400 | |||
401 | rpc_encode_decode!( | ||
402 | enum TokenTree<G, P, I, L> { | ||
403 | Group(tt), | ||
404 | Punct(tt), | ||
405 | Ident(tt), | ||
406 | Literal(tt), | ||
407 | } | ||
408 | ); | ||