diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index ea63ff7bfc46a..e678557008133 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -11,32 +11,11 @@ use {rustc_ast as ast, rustc_proc_macro as pm}; use crate::base::{self, *}; use crate::{errors, proc_macro_server}; -struct MessagePipe { - tx: std::sync::mpsc::SyncSender, - rx: std::sync::mpsc::Receiver, -} - -impl pm::bridge::server::MessagePipe for MessagePipe { - fn new() -> (Self, Self) { - let (tx1, rx1) = std::sync::mpsc::sync_channel(1); - let (tx2, rx2) = std::sync::mpsc::sync_channel(1); - (MessagePipe { tx: tx1, rx: rx2 }, MessagePipe { tx: tx2, rx: rx1 }) - } - - fn send(&mut self, value: T) { - self.tx.send(value).unwrap(); - } - - fn recv(&mut self) -> Option { - self.rx.recv().ok() - } -} - fn exec_strategy(sess: &Session) -> impl pm::bridge::server::ExecutionStrategy + 'static { - pm::bridge::server::MaybeCrossThread::>::new( - sess.opts.unstable_opts.proc_macro_execution_strategy + pm::bridge::server::MaybeCrossThread { + cross_thread: sess.opts.unstable_opts.proc_macro_execution_strategy == ProcMacroExecutionStrategy::CrossThread, - ) + } } pub struct BangProcMacro { diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 02a408802b6fa..696cd4ee3d887 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -98,7 +98,7 @@ pub(crate) use super::symbol::Symbol; macro_rules! define_client_side { ( - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* ) => { impl Methods { $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)? { diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 6a9027046af00..603adf720789f 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -133,7 +133,7 @@ impl !Sync for BridgeConfig<'_> {} macro_rules! declare_tags { ( - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* ) => { #[allow(non_camel_case_types)] pub(super) enum ApiTags { diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index a3c6a232264e0..1151798fccf40 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -1,7 +1,7 @@ //! Server-side traits. use std::cell::Cell; -use std::marker::PhantomData; +use std::sync::mpsc; use super::*; @@ -53,14 +53,9 @@ impl Decode<'_, '_, HandleStore> for MarkedSpan { } } -struct Dispatcher { - handle_store: HandleStore, - server: S, -} - macro_rules! define_server { ( - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* ) => { pub trait Server { type TokenStream: 'static + Clone + Default; @@ -81,16 +76,17 @@ macro_rules! define_server { } with_api!(define_server, Self::TokenStream, Self::Span, Self::Symbol); +// FIXME(eddyb) `pub` only for `ExecutionStrategy` below. +pub struct Dispatcher { + handle_store: HandleStore, + server: S, +} + macro_rules! define_dispatcher { ( - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* ) => { - // FIXME(eddyb) `pub` only for `ExecutionStrategy` below. - pub trait DispatcherTrait { - fn dispatch(&mut self, buf: Buffer) -> Buffer; - } - - impl DispatcherTrait for Dispatcher { + impl Dispatcher { fn dispatch(&mut self, mut buf: Buffer) -> Buffer { let Dispatcher { handle_store, server } = self; @@ -100,9 +96,7 @@ macro_rules! define_dispatcher { let mut call_method = || { $(let $arg = <$arg_ty>::decode(&mut reader, handle_store).unmark();)* let r = server.$method($($arg),*); - $( - let r: $ret_ty = Mark::mark(r); - )* + $(let r: $ret_ty = Mark::mark(r);)? r }; // HACK(eddyb) don't use `panic::catch_unwind` in a panic. @@ -127,10 +121,13 @@ macro_rules! define_dispatcher { } with_api!(define_dispatcher, MarkedTokenStream, MarkedSpan, MarkedSymbol); +// This trait is currently only implemented and used once, inside of this crate. +// We keep it public to allow implementing more complex execution strategies in +// the future, such as wasm proc-macros. pub trait ExecutionStrategy { fn run_bridge_and_client( &self, - dispatcher: &mut impl DispatcherTrait, + dispatcher: &mut Dispatcher, input: Buffer, run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, @@ -169,110 +166,78 @@ impl Drop for RunningSameThreadGuard { } } -pub struct MaybeCrossThread

{ - cross_thread: bool, - marker: PhantomData

, +pub struct MaybeCrossThread { + pub cross_thread: bool, } -impl

MaybeCrossThread

{ - pub const fn new(cross_thread: bool) -> Self { - MaybeCrossThread { cross_thread, marker: PhantomData } - } -} +pub const SAME_THREAD: MaybeCrossThread = MaybeCrossThread { cross_thread: false }; +pub const CROSS_THREAD: MaybeCrossThread = MaybeCrossThread { cross_thread: true }; -impl

ExecutionStrategy for MaybeCrossThread

-where - P: MessagePipe + Send + 'static, -{ +impl ExecutionStrategy for MaybeCrossThread { fn run_bridge_and_client( &self, - dispatcher: &mut impl DispatcherTrait, + dispatcher: &mut Dispatcher, input: Buffer, run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Buffer { if self.cross_thread || ALREADY_RUNNING_SAME_THREAD.get() { - >::new().run_bridge_and_client( - dispatcher, - input, - run_client, - force_show_panics, - ) - } else { - SameThread.run_bridge_and_client(dispatcher, input, run_client, force_show_panics) - } - } -} - -pub struct SameThread; - -impl ExecutionStrategy for SameThread { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - let _guard = RunningSameThreadGuard::new(); - - let mut dispatch = |buf| dispatcher.dispatch(buf); - - run_client(BridgeConfig { input, dispatch: (&mut dispatch).into(), force_show_panics }) - } -} - -pub struct CrossThread

(PhantomData

); - -impl

CrossThread

{ - pub const fn new() -> Self { - CrossThread(PhantomData) - } -} + let (mut server, mut client) = MessagePipe::new(); + + let join_handle = thread::spawn(move || { + let mut dispatch = |b: Buffer| -> Buffer { + client.send(b); + client.recv().expect("server died while client waiting for reply") + }; + + run_client(BridgeConfig { + input, + dispatch: (&mut dispatch).into(), + force_show_panics, + }) + }); + + while let Some(b) = server.recv() { + server.send(dispatcher.dispatch(b)); + } -impl

ExecutionStrategy for CrossThread

-where - P: MessagePipe + Send + 'static, -{ - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - let (mut server, mut client) = P::new(); + join_handle.join().unwrap() + } else { + let _guard = RunningSameThreadGuard::new(); - let join_handle = thread::spawn(move || { - let mut dispatch = |b: Buffer| -> Buffer { - client.send(b); - client.recv().expect("server died while client waiting for reply") - }; + let mut dispatch = |buf| dispatcher.dispatch(buf); run_client(BridgeConfig { input, dispatch: (&mut dispatch).into(), force_show_panics }) - }); - - while let Some(b) = server.recv() { - server.send(dispatcher.dispatch(b)); } - - join_handle.join().unwrap() } } /// A message pipe used for communicating between server and client threads. -pub trait MessagePipe: Sized { +struct MessagePipe { + tx: mpsc::SyncSender, + rx: mpsc::Receiver, +} + +impl MessagePipe { /// Creates a new pair of endpoints for the message pipe. - fn new() -> (Self, Self); + fn new() -> (Self, Self) { + let (tx1, rx1) = mpsc::sync_channel(1); + let (tx2, rx2) = mpsc::sync_channel(1); + (MessagePipe { tx: tx1, rx: rx2 }, MessagePipe { tx: tx2, rx: rx1 }) + } /// Send a message to the other endpoint of this pipe. - fn send(&mut self, value: T); + fn send(&mut self, value: T) { + self.tx.send(value).unwrap(); + } /// Receive a message from the other endpoint of this pipe. /// /// Returns `None` if the other end of the pipe has been destroyed, and no /// message was received. - fn recv(&mut self) -> Option; + fn recv(&mut self) -> Option { + self.rx.recv().ok() + } } fn run_server< diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs index 76c5097101c70..4065dbd0b49bc 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs @@ -30,7 +30,7 @@ impl ProcMacros { if *trait_name == macro_name => { let res = client.run( - &bridge::server::SameThread, + &bridge::server::SAME_THREAD, S::make_server(call_site, def_site, mixed_site, callback), macro_body, cfg!(debug_assertions), @@ -39,7 +39,7 @@ impl ProcMacros { } bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { let res = client.run( - &bridge::server::SameThread, + &bridge::server::SAME_THREAD, S::make_server(call_site, def_site, mixed_site, callback), macro_body, cfg!(debug_assertions), @@ -48,7 +48,7 @@ impl ProcMacros { } bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { let res = client.run( - &bridge::server::SameThread, + &bridge::server::SAME_THREAD, S::make_server(call_site, def_site, mixed_site, callback), parsed_attributes, macro_body,