diff --git a/crates/proc_macro_srv/src/abis/abi_1_47/mod.rs b/crates/proc_macro_srv/src/abis/abi_1_47/mod.rs new file mode 100644 index 0000000000..6bbdcc5868 --- /dev/null +++ b/crates/proc_macro_srv/src/abis/abi_1_47/mod.rs @@ -0,0 +1,106 @@ +//! Macro ABI for version 1.47 of rustc + +#[allow(dead_code)] +#[doc(hidden)] +mod proc_macro; + +#[allow(dead_code)] +#[doc(hidden)] +mod rustc_server; +use libloading::Library; + +use proc_macro_api::ProcMacroKind; + +use super::PanicMessage; + +pub use rustc_server::TokenStream; + +pub(crate) struct Abi { + exported_macros: Vec, +} + +impl From for PanicMessage { + fn from(p: proc_macro::bridge::PanicMessage) -> Self { + Self { message: p.as_str().map(|s| s.to_string()) } + } +} + +impl Abi { + pub unsafe fn from_lib(lib: &Library, symbol_name: String) -> Result { + let macros: libloading::Symbol<&&[proc_macro::bridge::client::ProcMacro]> = + lib.get(symbol_name.as_bytes())?; + Ok(Self { exported_macros: macros.to_vec() }) + } + + pub fn expand( + &self, + macro_name: &str, + macro_body: &tt::Subtree, + attributes: Option<&tt::Subtree>, + ) -> Result { + let parsed_body = rustc_server::TokenStream::with_subtree(macro_body.clone()); + + let parsed_attributes = attributes.map_or(rustc_server::TokenStream::new(), |attr| { + rustc_server::TokenStream::with_subtree(attr.clone()) + }); + + for proc_macro in &self.exported_macros { + match proc_macro { + proc_macro::bridge::client::ProcMacro::CustomDerive { + trait_name, client, .. + } if *trait_name == macro_name => { + let res = client.run( + &proc_macro::bridge::server::SameThread, + rustc_server::Rustc::default(), + parsed_body, + false, + ); + return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); + } + proc_macro::bridge::client::ProcMacro::Bang { name, client } + if *name == macro_name => + { + let res = client.run( + &proc_macro::bridge::server::SameThread, + rustc_server::Rustc::default(), + parsed_body, + false, + ); + return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); + } + proc_macro::bridge::client::ProcMacro::Attr { name, client } + if *name == macro_name => + { + let res = client.run( + &proc_macro::bridge::server::SameThread, + rustc_server::Rustc::default(), + parsed_attributes, + parsed_body, + false, + ); + return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); + } + _ => continue, + } + } + + Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into()) + } + + pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { + self.exported_macros + .iter() + .map(|proc_macro| match proc_macro { + proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { + (trait_name.to_string(), ProcMacroKind::CustomDerive) + } + proc_macro::bridge::client::ProcMacro::Bang { name, .. } => { + (name.to_string(), ProcMacroKind::FuncLike) + } + proc_macro::bridge::client::ProcMacro::Attr { name, .. } => { + (name.to_string(), ProcMacroKind::Attr) + } + }) + .collect() + } +} diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/buffer.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/buffer.rs similarity index 100% rename from crates/proc_macro_srv/src/proc_macro/bridge/buffer.rs rename to crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/buffer.rs diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/client.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/client.rs similarity index 93% rename from crates/proc_macro_srv/src/proc_macro/bridge/client.rs rename to crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/client.rs index c135cf7a23..9f74fb0668 100644 --- a/crates/proc_macro_srv/src/proc_macro/bridge/client.rs +++ b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/client.rs @@ -3,6 +3,7 @@ //! Copy from //! augmented with removing unstable features +use super::super::TokenStream as CrateTokenStream; use super::*; macro_rules! define_handles { @@ -401,26 +402,26 @@ fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( b } -impl Client crate::TokenStream> { - pub fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self { +impl Client CrateTokenStream> { + pub fn expand1(f: fn(CrateTokenStream) -> CrateTokenStream) -> Self { extern "C" fn run( bridge: Bridge<'_>, - f: impl FnOnce(crate::TokenStream) -> crate::TokenStream, + f: impl FnOnce(CrateTokenStream) -> CrateTokenStream, ) -> Buffer { - run_client(bridge, |input| f(crate::TokenStream(input)).0) + run_client(bridge, |input| f(CrateTokenStream(input)).0) } Client { get_handle_counters: HandleCounters::get, run, f } } } -impl Client crate::TokenStream> { - pub fn expand2(f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream) -> Self { +impl Client CrateTokenStream> { + pub fn expand2(f: fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream) -> Self { extern "C" fn run( bridge: Bridge<'_>, - f: impl FnOnce(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, + f: impl FnOnce(CrateTokenStream, CrateTokenStream) -> CrateTokenStream, ) -> Buffer { run_client(bridge, |(input, input2)| { - f(crate::TokenStream(input), crate::TokenStream(input2)).0 + f(CrateTokenStream(input), CrateTokenStream(input2)).0 }) } Client { get_handle_counters: HandleCounters::get, run, f } @@ -433,17 +434,17 @@ pub enum ProcMacro { CustomDerive { trait_name: &'static str, attributes: &'static [&'static str], - client: Client crate::TokenStream>, + client: Client CrateTokenStream>, }, Attr { name: &'static str, - client: Client crate::TokenStream>, + client: Client CrateTokenStream>, }, Bang { name: &'static str, - client: Client crate::TokenStream>, + client: Client CrateTokenStream>, }, } @@ -465,19 +466,19 @@ impl ProcMacro { pub fn custom_derive( trait_name: &'static str, attributes: &'static [&'static str], - expand: fn(crate::TokenStream) -> crate::TokenStream, + expand: fn(CrateTokenStream) -> CrateTokenStream, ) -> Self { ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } } pub fn attr( name: &'static str, - expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, + expand: fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream, ) -> Self { ProcMacro::Attr { name, client: Client::expand2(expand) } } - pub fn bang(name: &'static str, expand: fn(crate::TokenStream) -> crate::TokenStream) -> Self { + pub fn bang(name: &'static str, expand: fn(CrateTokenStream) -> CrateTokenStream) -> Self { ProcMacro::Bang { name, client: Client::expand1(expand) } } } diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/closure.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/closure.rs similarity index 100% rename from crates/proc_macro_srv/src/proc_macro/bridge/closure.rs rename to crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/closure.rs diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/handle.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/handle.rs similarity index 100% rename from crates/proc_macro_srv/src/proc_macro/bridge/handle.rs rename to crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/handle.rs diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/mod.rs similarity index 99% rename from crates/proc_macro_srv/src/proc_macro/bridge/mod.rs rename to crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/mod.rs index 375396d1b4..be5402d6ee 100644 --- a/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs +++ b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/mod.rs @@ -13,7 +13,7 @@ #![deny(unsafe_code)] -pub use crate::proc_macro::{Delimiter, Level, LineColumn, Spacing}; +pub use super::{Delimiter, Level, LineColumn, Spacing}; use std::fmt; use std::hash::Hash; use std::marker; diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/rpc.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/rpc.rs similarity index 100% rename from crates/proc_macro_srv/src/proc_macro/bridge/rpc.rs rename to crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/rpc.rs diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/scoped_cell.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/scoped_cell.rs similarity index 100% rename from crates/proc_macro_srv/src/proc_macro/bridge/scoped_cell.rs rename to crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/scoped_cell.rs diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/server.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/server.rs similarity index 98% rename from crates/proc_macro_srv/src/proc_macro/bridge/server.rs rename to crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/server.rs index 731d302196..a580419fd1 100644 --- a/crates/proc_macro_srv/src/proc_macro/bridge/server.rs +++ b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/server.rs @@ -3,6 +3,7 @@ //! Copy from //! augmented with removing unstable features +use super::super::TokenStream as ProcMacroTokenStream; use super::*; // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. @@ -308,7 +309,7 @@ fn run_server< Result::decode(&mut &b[..], &mut dispatcher.handle_store) } -impl client::Client crate::TokenStream> { +impl client::Client ProcMacroTokenStream> { pub fn run( &self, strategy: &impl ExecutionStrategy, @@ -330,7 +331,7 @@ impl client::Client crate::TokenStream> { } } -impl client::Client crate::TokenStream> { +impl client::Client ProcMacroTokenStream> { pub fn run( &self, strategy: &impl ExecutionStrategy, diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/diagnostic.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/diagnostic.rs similarity index 100% rename from crates/proc_macro_srv/src/proc_macro_nightly/diagnostic.rs rename to crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/diagnostic.rs diff --git a/crates/proc_macro_srv/src/proc_macro/mod.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/mod.rs similarity index 99% rename from crates/proc_macro_srv/src/proc_macro/mod.rs rename to crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/mod.rs index b7c1d04b50..aaa7103756 100644 --- a/crates/proc_macro_srv/src/proc_macro/mod.rs +++ b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/mod.rs @@ -133,7 +133,7 @@ impl Extend for TokenStream { /// Public implementation details for the `TokenStream` type, such as iterators. pub mod token_stream { - use crate::proc_macro::{bridge, Group, Ident, Literal, Punct, TokenStream, TokenTree}; + use super::{bridge, Group, Ident, Literal, Punct, TokenStream, TokenTree}; /// An iterator over `TokenStream`'s `TokenTree`s. /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/abis/abi_1_47/rustc_server.rs similarity index 99% rename from crates/proc_macro_srv/src/rustc_server.rs rename to crates/proc_macro_srv/src/abis/abi_1_47/rustc_server.rs index e252e89a56..088cc694e8 100644 --- a/crates/proc_macro_srv/src/rustc_server.rs +++ b/crates/proc_macro_srv/src/abis/abi_1_47/rustc_server.rs @@ -8,7 +8,7 @@ //! //! FIXME: No span and source file information is implemented yet -use crate::proc_macro::bridge::{self, server}; +use super::proc_macro::bridge::{self, server}; use std::collections::HashMap; use std::hash::Hash; @@ -97,9 +97,9 @@ impl Extend for TokenStream { } } -type Level = crate::proc_macro::Level; -type LineColumn = crate::proc_macro::LineColumn; -type SourceFile = crate::proc_macro::SourceFile; +type Level = super::proc_macro::Level; +type LineColumn = super::proc_macro::LineColumn; +type SourceFile = super::proc_macro::SourceFile; /// A structure representing a diagnostic message and associated children /// messages. @@ -734,8 +734,8 @@ impl server::MultiSpan for Rustc { #[cfg(test)] mod tests { + use super::super::proc_macro::bridge::server::Literal; use super::*; - use crate::proc_macro::bridge::server::Literal; #[test] fn test_rustc_server_literals() { diff --git a/crates/proc_macro_srv/src/abis/abi_1_55/mod.rs b/crates/proc_macro_srv/src/abis/abi_1_55/mod.rs new file mode 100644 index 0000000000..8126016207 --- /dev/null +++ b/crates/proc_macro_srv/src/abis/abi_1_55/mod.rs @@ -0,0 +1,104 @@ +//! Macro ABI for version 1.55 of rustc + +#[allow(dead_code)] +#[doc(hidden)] +mod proc_macro; + +#[allow(dead_code)] +#[doc(hidden)] +mod rustc_server; +use libloading::Library; + +use proc_macro_api::ProcMacroKind; + +use super::PanicMessage; + +pub(crate) struct Abi { + exported_macros: Vec, +} + +impl From for PanicMessage { + fn from(p: proc_macro::bridge::PanicMessage) -> Self { + Self { message: p.as_str().map(|s| s.to_string()) } + } +} + +impl Abi { + pub unsafe fn from_lib(lib: &Library, symbol_name: String) -> Result { + let macros: libloading::Symbol<&&[proc_macro::bridge::client::ProcMacro]> = + lib.get(symbol_name.as_bytes())?; + Ok(Self { exported_macros: macros.to_vec() }) + } + + pub fn expand( + &self, + macro_name: &str, + macro_body: &tt::Subtree, + attributes: Option<&tt::Subtree>, + ) -> Result { + let parsed_body = rustc_server::TokenStream::with_subtree(macro_body.clone()); + + let parsed_attributes = attributes.map_or(rustc_server::TokenStream::new(), |attr| { + rustc_server::TokenStream::with_subtree(attr.clone()) + }); + + for proc_macro in &self.exported_macros { + match proc_macro { + proc_macro::bridge::client::ProcMacro::CustomDerive { + trait_name, client, .. + } if *trait_name == macro_name => { + let res = client.run( + &proc_macro::bridge::server::SameThread, + rustc_server::Rustc::default(), + parsed_body, + false, + ); + return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); + } + proc_macro::bridge::client::ProcMacro::Bang { name, client } + if *name == macro_name => + { + let res = client.run( + &proc_macro::bridge::server::SameThread, + rustc_server::Rustc::default(), + parsed_body, + false, + ); + return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); + } + proc_macro::bridge::client::ProcMacro::Attr { name, client } + if *name == macro_name => + { + let res = client.run( + &proc_macro::bridge::server::SameThread, + rustc_server::Rustc::default(), + parsed_attributes, + parsed_body, + false, + ); + return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); + } + _ => continue, + } + } + + Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into()) + } + + pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { + self.exported_macros + .iter() + .map(|proc_macro| match proc_macro { + proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { + (trait_name.to_string(), ProcMacroKind::CustomDerive) + } + proc_macro::bridge::client::ProcMacro::Bang { name, .. } => { + (name.to_string(), ProcMacroKind::FuncLike) + } + proc_macro::bridge::client::ProcMacro::Attr { name, .. } => { + (name.to_string(), ProcMacroKind::Attr) + } + }) + .collect() + } +} diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/buffer.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/buffer.rs similarity index 100% rename from crates/proc_macro_srv/src/proc_macro_nightly/bridge/buffer.rs rename to crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/buffer.rs diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/client.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/client.rs similarity index 93% rename from crates/proc_macro_srv/src/proc_macro_nightly/bridge/client.rs rename to crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/client.rs index c135cf7a23..9f74fb0668 100644 --- a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/client.rs +++ b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/client.rs @@ -3,6 +3,7 @@ //! Copy from //! augmented with removing unstable features +use super::super::TokenStream as CrateTokenStream; use super::*; macro_rules! define_handles { @@ -401,26 +402,26 @@ fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( b } -impl Client crate::TokenStream> { - pub fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self { +impl Client CrateTokenStream> { + pub fn expand1(f: fn(CrateTokenStream) -> CrateTokenStream) -> Self { extern "C" fn run( bridge: Bridge<'_>, - f: impl FnOnce(crate::TokenStream) -> crate::TokenStream, + f: impl FnOnce(CrateTokenStream) -> CrateTokenStream, ) -> Buffer { - run_client(bridge, |input| f(crate::TokenStream(input)).0) + run_client(bridge, |input| f(CrateTokenStream(input)).0) } Client { get_handle_counters: HandleCounters::get, run, f } } } -impl Client crate::TokenStream> { - pub fn expand2(f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream) -> Self { +impl Client CrateTokenStream> { + pub fn expand2(f: fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream) -> Self { extern "C" fn run( bridge: Bridge<'_>, - f: impl FnOnce(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, + f: impl FnOnce(CrateTokenStream, CrateTokenStream) -> CrateTokenStream, ) -> Buffer { run_client(bridge, |(input, input2)| { - f(crate::TokenStream(input), crate::TokenStream(input2)).0 + f(CrateTokenStream(input), CrateTokenStream(input2)).0 }) } Client { get_handle_counters: HandleCounters::get, run, f } @@ -433,17 +434,17 @@ pub enum ProcMacro { CustomDerive { trait_name: &'static str, attributes: &'static [&'static str], - client: Client crate::TokenStream>, + client: Client CrateTokenStream>, }, Attr { name: &'static str, - client: Client crate::TokenStream>, + client: Client CrateTokenStream>, }, Bang { name: &'static str, - client: Client crate::TokenStream>, + client: Client CrateTokenStream>, }, } @@ -465,19 +466,19 @@ impl ProcMacro { pub fn custom_derive( trait_name: &'static str, attributes: &'static [&'static str], - expand: fn(crate::TokenStream) -> crate::TokenStream, + expand: fn(CrateTokenStream) -> CrateTokenStream, ) -> Self { ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } } pub fn attr( name: &'static str, - expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, + expand: fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream, ) -> Self { ProcMacro::Attr { name, client: Client::expand2(expand) } } - pub fn bang(name: &'static str, expand: fn(crate::TokenStream) -> crate::TokenStream) -> Self { + pub fn bang(name: &'static str, expand: fn(CrateTokenStream) -> CrateTokenStream) -> Self { ProcMacro::Bang { name, client: Client::expand1(expand) } } } diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/closure.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/closure.rs similarity index 100% rename from crates/proc_macro_srv/src/proc_macro_nightly/bridge/closure.rs rename to crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/closure.rs diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/handle.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/handle.rs similarity index 100% rename from crates/proc_macro_srv/src/proc_macro_nightly/bridge/handle.rs rename to crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/handle.rs diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/mod.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/mod.rs similarity index 100% rename from crates/proc_macro_srv/src/proc_macro_nightly/bridge/mod.rs rename to crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/mod.rs diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/rpc.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/rpc.rs similarity index 100% rename from crates/proc_macro_srv/src/proc_macro_nightly/bridge/rpc.rs rename to crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/rpc.rs diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/scoped_cell.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/scoped_cell.rs similarity index 100% rename from crates/proc_macro_srv/src/proc_macro_nightly/bridge/scoped_cell.rs rename to crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/scoped_cell.rs diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/server.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/server.rs similarity index 98% rename from crates/proc_macro_srv/src/proc_macro_nightly/bridge/server.rs rename to crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/server.rs index cc9afd84b1..21563fe604 100644 --- a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/server.rs +++ b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/server.rs @@ -3,6 +3,7 @@ //! Copy from //! augmented with removing unstable features +use super::super::TokenStream as CrateTokenStream; use super::*; // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. @@ -302,7 +303,7 @@ fn run_server< Result::decode(&mut &b[..], &mut dispatcher.handle_store) } -impl client::Client crate::TokenStream> { +impl client::Client CrateTokenStream> { pub fn run( &self, strategy: &impl ExecutionStrategy, @@ -324,7 +325,7 @@ impl client::Client crate::TokenStream> { } } -impl client::Client crate::TokenStream> { +impl client::Client CrateTokenStream> { pub fn run( &self, strategy: &impl ExecutionStrategy, diff --git a/crates/proc_macro_srv/src/proc_macro/diagnostic.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/diagnostic.rs similarity index 94% rename from crates/proc_macro_srv/src/proc_macro/diagnostic.rs rename to crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/diagnostic.rs index 3c5b7bc016..6953b1ecf4 100644 --- a/crates/proc_macro_srv/src/proc_macro/diagnostic.rs +++ b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/diagnostic.rs @@ -3,7 +3,7 @@ //! Copy from //! augmented with removing unstable features -use crate::proc_macro::Span; +use super::Span; /// An enum representing a diagnostic level. #[derive(Copy, Clone, Debug)] @@ -146,15 +146,15 @@ impl Diagnostic { /// Emit the diagnostic. pub fn emit(self) { - fn to_internal(spans: Vec) -> crate::proc_macro::bridge::client::MultiSpan { - let mut multi_span = crate::proc_macro::bridge::client::MultiSpan::new(); + fn to_internal(spans: Vec) -> super::bridge::client::MultiSpan { + let mut multi_span = super::bridge::client::MultiSpan::new(); for span in spans { multi_span.push(span.0); } multi_span } - let mut diag = crate::proc_macro::bridge::client::Diagnostic::new( + let mut diag = super::bridge::client::Diagnostic::new( self.level, &self.message[..], to_internal(self.spans), diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/mod.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/mod.rs similarity index 100% rename from crates/proc_macro_srv/src/proc_macro_nightly/mod.rs rename to crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/mod.rs diff --git a/crates/proc_macro_srv/src/rustc_server_nightly.rs b/crates/proc_macro_srv/src/abis/abi_1_55/rustc_server.rs similarity index 99% rename from crates/proc_macro_srv/src/rustc_server_nightly.rs rename to crates/proc_macro_srv/src/abis/abi_1_55/rustc_server.rs index 2f7a4a31c3..8dfd65ade1 100644 --- a/crates/proc_macro_srv/src/rustc_server_nightly.rs +++ b/crates/proc_macro_srv/src/abis/abi_1_55/rustc_server.rs @@ -8,7 +8,7 @@ //! //! FIXME: No span and source file information is implemented yet -use crate::proc_macro_nightly::bridge::{self, server}; +use super::proc_macro::bridge::{self, server}; use std::collections::HashMap; use std::hash::Hash; @@ -97,9 +97,9 @@ impl Extend for TokenStream { } } -type Level = crate::proc_macro_nightly::Level; -type LineColumn = crate::proc_macro_nightly::LineColumn; -type SourceFile = crate::proc_macro_nightly::SourceFile; +type Level = super::proc_macro::Level; +type LineColumn = super::proc_macro::LineColumn; +type SourceFile = super::proc_macro::SourceFile; /// A structure representing a diagnostic message and associated children /// messages. @@ -737,8 +737,8 @@ impl server::MultiSpan for Rustc { #[cfg(test)] mod tests { + use super::super::proc_macro::bridge::server::Literal; use super::*; - use crate::proc_macro_nightly::bridge::server::Literal; #[test] fn test_rustc_server_literals() { diff --git a/crates/proc_macro_srv/src/abis/mod.rs b/crates/proc_macro_srv/src/abis/mod.rs new file mode 100644 index 0000000000..3b30aaa90b --- /dev/null +++ b/crates/proc_macro_srv/src/abis/mod.rs @@ -0,0 +1,97 @@ +//! Procedural macros are implemented by compiling the macro providing crate +//! to a dynamic library with a particular ABI which the compiler uses to expand +//! macros. Unfortunately this ABI is not specified and can change from version +//! to version of the compiler. To support this we copy the ABI from the rust +//! compiler into submodules of this module (e.g proc_macro_srv::abis::abi_1_47). +//! +//! All of these ABIs are subsumed in the `Abi` enum, which exposes a simple +//! interface the rest of rust analyzer can use to talk to the macro +//! provider. +//! +//! # Adding a new ABI +//! +//! To add a new ABI you'll need to copy the source of the target proc_macro +//! crate from the source tree of the Rust compiler into this directory tree. +//! Then you'll need to modify it +//! - Remove any feature! or other things which won't compile on stable +//! - change any absolute imports to relative imports within the ABI tree +//! +//! Then you'll need to add a branch to the `Abi` enum and an implementation of +//! `Abi::expand`, `Abi::list_macros` and `Abi::from_lib` for the new ABI. See +//! `proc_macro_srv/src/abis/abi_1_47/mod.rs` for an example. Finally you'll +//! need to update the conditionals in `Abi::from_lib` to return your new ABI +//! for the relevant versions of the rust compiler +//! + +// pub(crate) so tests can use the TokenStream, more notes in test/utils.rs +pub(crate) mod abi_1_47; +mod abi_1_55; + +use super::dylib::LoadProcMacroDylibError; +pub(crate) use abi_1_47::Abi as Abi_1_47; +pub(crate) use abi_1_55::Abi as Abi_1_55; +use libloading::Library; +use proc_macro_api::{ProcMacroKind, RustCInfo}; + +pub struct PanicMessage { + message: Option, +} + +impl PanicMessage { + pub fn as_str(&self) -> Option { + self.message.clone() + } +} + +pub(crate) enum Abi { + Abi1_47(Abi_1_47), + Abi1_55(Abi_1_55), +} + +impl Abi { + /// Load a new ABI. + /// + /// # Arguments + /// + /// *`lib` - The dynamic library containing the macro implementations + /// *`symbol_name` - The symbol name the macros can be found attributes + /// *`info` - RustCInfo about the compiler that was used to compile the + /// macro crate. This is the information we use to figure out + /// which ABI to return + pub fn from_lib( + lib: &Library, + symbol_name: String, + info: RustCInfo, + ) -> Result { + if info.version.0 != 1 { + Err(LoadProcMacroDylibError::UnsupportedABI) + } else if info.version.1 < 47 { + Err(LoadProcMacroDylibError::UnsupportedABI) + } else if info.version.1 < 54 { + let inner = unsafe { Abi_1_47::from_lib(lib, symbol_name) }?; + Ok(Abi::Abi1_47(inner)) + } else { + let inner = unsafe { Abi_1_55::from_lib(lib, symbol_name) }?; + Ok(Abi::Abi1_55(inner)) + } + } + + pub fn expand( + &self, + macro_name: &str, + macro_body: &tt::Subtree, + attributes: Option<&tt::Subtree>, + ) -> Result { + match self { + Self::Abi1_55(abi) => abi.expand(macro_name, macro_body, attributes), + Self::Abi1_47(abi) => abi.expand(macro_name, macro_body, attributes), + } + } + + pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { + match self { + Self::Abi1_47(abi) => abi.list_macros(), + Self::Abi1_55(abi) => abi.list_macros(), + } + } +} diff --git a/crates/proc_macro_srv/src/dylib.rs b/crates/proc_macro_srv/src/dylib.rs index 69a645119f..5f0b0b061e 100644 --- a/crates/proc_macro_srv/src/dylib.rs +++ b/crates/proc_macro_srv/src/dylib.rs @@ -1,7 +1,6 @@ //! Handles dynamic library loading for proc macro use std::{ - convert::{TryFrom, TryInto}, fmt, fs::File, io, @@ -11,16 +10,9 @@ use std::{ use libloading::Library; use memmap2::Mmap; use object::Object; -use proc_macro_api::{read_dylib_info, ProcMacroKind, RustCInfo}; +use proc_macro_api::{read_dylib_info, ProcMacroKind}; -use crate::{ - proc_macro::bridge::{self as stable_bridge, client::ProcMacro as StableProcMacro}, - rustc_server::TokenStream as StableTokenStream, -}; -use crate::{ - proc_macro_nightly::bridge::{self as nightly_bridge, client::ProcMacro as NightlyProcMacro}, - rustc_server_nightly::TokenStream as NightlyTokenStream, -}; +use super::abis::Abi; const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_"; @@ -83,30 +75,10 @@ fn load_library(file: &Path) -> Result { unsafe { UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) } } -enum ProcMacroABI { - Stable, - Nightly, -} - -impl TryFrom for ProcMacroABI { - type Error = LoadProcMacroDylibError; - - fn try_from(info: RustCInfo) -> Result { - if info.version.0 != 1 { - Err(LoadProcMacroDylibError::UnsupportedABI) - } else if info.version.1 < 47 { - Err(LoadProcMacroDylibError::UnsupportedABI) - } else if info.version.1 < 54 { - Ok(ProcMacroABI::Stable) - } else { - Ok(ProcMacroABI::Nightly) - } - } -} - #[derive(Debug)] pub enum LoadProcMacroDylibError { Io(io::Error), + LibLoading(libloading::Error), UnsupportedABI, } @@ -115,6 +87,7 @@ impl fmt::Display for LoadProcMacroDylibError { match self { Self::Io(e) => e.fmt(f), Self::UnsupportedABI => write!(f, "unsupported ABI version"), + Self::LibLoading(e) => e.fmt(f), } } } @@ -125,15 +98,16 @@ impl From for LoadProcMacroDylibError { } } -enum ProcMacroLibraryLibloading { - StableProcMacroLibrary { - _lib: Library, - exported_macros: Vec, - }, - NightlyProcMacroLibrary { - _lib: Library, - exported_macros: Vec, - }, +impl From for LoadProcMacroDylibError { + fn from(e: libloading::Error) -> Self { + LoadProcMacroDylibError::LibLoading(e) + } +} + +struct ProcMacroLibraryLibloading { + // Hold on to the library so it doesn't unload + _lib: Library, + abi: Abi, } impl ProcMacroLibraryLibloading { @@ -143,57 +117,10 @@ impl ProcMacroLibraryLibloading { })?; let version_info = read_dylib_info(file)?; - let macro_abi: ProcMacroABI = version_info.try_into()?; let lib = load_library(file).map_err(invalid_data_err)?; - match macro_abi { - ProcMacroABI::Stable => { - let macros: libloading::Symbol<&&[crate::proc_macro::bridge::client::ProcMacro]> = - unsafe { lib.get(symbol_name.as_bytes()) }.map_err(invalid_data_err)?; - let macros_vec = macros.to_vec(); - Ok(ProcMacroLibraryLibloading::StableProcMacroLibrary { - _lib: lib, - exported_macros: macros_vec, - }) - } - ProcMacroABI::Nightly => { - let macros: libloading::Symbol< - &&[crate::proc_macro_nightly::bridge::client::ProcMacro], - > = unsafe { lib.get(symbol_name.as_bytes()) }.map_err(invalid_data_err)?; - let macros_vec = macros.to_vec(); - Ok(ProcMacroLibraryLibloading::NightlyProcMacroLibrary { - _lib: lib, - exported_macros: macros_vec, - }) - } - } - } -} - -#[derive(Debug)] -pub enum PanicMessage { - Stable(stable_bridge::PanicMessage), - Nightly(nightly_bridge::PanicMessage), -} - -impl From for PanicMessage { - fn from(p: stable_bridge::PanicMessage) -> Self { - PanicMessage::Stable(p) - } -} - -impl From for PanicMessage { - fn from(p: nightly_bridge::PanicMessage) -> Self { - PanicMessage::Nightly(p) - } -} - -impl PanicMessage { - pub fn as_str(&self) -> Option<&str> { - match self { - Self::Stable(p) => p.as_str(), - Self::Nightly(p) => p.as_str(), - } + let abi = Abi::from_lib(&lib, symbol_name, version_info)?; + Ok(ProcMacroLibraryLibloading { _lib: lib, abi }) } } @@ -219,28 +146,13 @@ impl Expander { macro_name: &str, macro_body: &tt::Subtree, attributes: Option<&tt::Subtree>, - ) -> Result { - match &self.inner { - ProcMacroLibraryLibloading::StableProcMacroLibrary { exported_macros, .. } => { - expand_stable(macro_name, macro_body, attributes, &exported_macros[..]) - .map_err(PanicMessage::from) - } - ProcMacroLibraryLibloading::NightlyProcMacroLibrary { exported_macros, .. } => { - expand_nightly(macro_name, macro_body, attributes, &exported_macros[..]) - .map_err(PanicMessage::from) - } - } + ) -> Result { + let result = self.inner.abi.expand(macro_name, macro_body, attributes); + result.map_err(|e| e.as_str().unwrap_or_else(|| "".to_string())) } pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { - match &self.inner { - ProcMacroLibraryLibloading::StableProcMacroLibrary { exported_macros, .. } => { - list_macros_stable(&exported_macros[..]) - } - ProcMacroLibraryLibloading::NightlyProcMacroLibrary { exported_macros, .. } => { - list_macros_nightly(&exported_macros[..]) - } - } + self.inner.abi.list_macros() } } @@ -276,153 +188,3 @@ fn ensure_file_with_lock_free_access(path: &Path) -> io::Result { fn ensure_file_with_lock_free_access(path: &Path) -> io::Result { Ok(path.to_path_buf()) } - -fn expand_nightly( - macro_name: &str, - macro_body: &tt::Subtree, - attributes: Option<&tt::Subtree>, - macros: &[NightlyProcMacro], -) -> Result { - let parsed_body = NightlyTokenStream::with_subtree(macro_body.clone()); - - let parsed_attributes = attributes - .map_or(crate::rustc_server_nightly::TokenStream::new(), |attr| { - NightlyTokenStream::with_subtree(attr.clone()) - }); - - for proc_macro in macros { - match proc_macro { - crate::proc_macro_nightly::bridge::client::ProcMacro::CustomDerive { - trait_name, - client, - .. - } if *trait_name == macro_name => { - let res = client.run( - &crate::proc_macro_nightly::bridge::server::SameThread, - crate::rustc_server_nightly::Rustc::default(), - parsed_body, - false, - ); - return res.map(|it| it.into_subtree()); - } - crate::proc_macro_nightly::bridge::client::ProcMacro::Bang { name, client } - if *name == macro_name => - { - let res = client.run( - &crate::proc_macro_nightly::bridge::server::SameThread, - crate::rustc_server_nightly::Rustc::default(), - parsed_body, - false, - ); - return res.map(|it| it.into_subtree()); - } - crate::proc_macro_nightly::bridge::client::ProcMacro::Attr { name, client } - if *name == macro_name => - { - let res = client.run( - &crate::proc_macro_nightly::bridge::server::SameThread, - crate::rustc_server_nightly::Rustc::default(), - parsed_attributes, - parsed_body, - false, - ); - return res.map(|it| it.into_subtree()); - } - _ => continue, - } - } - - Err(crate::proc_macro_nightly::bridge::PanicMessage::String("Nothing to expand".to_string())) -} - -fn expand_stable( - macro_name: &str, - macro_body: &tt::Subtree, - attributes: Option<&tt::Subtree>, - macros: &[StableProcMacro], -) -> Result { - let parsed_body = StableTokenStream::with_subtree(macro_body.clone()); - - let parsed_attributes = attributes.map_or(crate::rustc_server::TokenStream::new(), |attr| { - StableTokenStream::with_subtree(attr.clone()) - }); - - for proc_macro in macros { - match proc_macro { - crate::proc_macro::bridge::client::ProcMacro::CustomDerive { - trait_name, - client, - .. - } if *trait_name == macro_name => { - let res = client.run( - &crate::proc_macro::bridge::server::SameThread, - crate::rustc_server::Rustc::default(), - parsed_body, - false, - ); - return res.map(|it| it.into_subtree()); - } - crate::proc_macro::bridge::client::ProcMacro::Bang { name, client } - if *name == macro_name => - { - let res = client.run( - &crate::proc_macro::bridge::server::SameThread, - crate::rustc_server::Rustc::default(), - parsed_body, - false, - ); - return res.map(|it| it.into_subtree()); - } - crate::proc_macro::bridge::client::ProcMacro::Attr { name, client } - if *name == macro_name => - { - let res = client.run( - &crate::proc_macro::bridge::server::SameThread, - crate::rustc_server::Rustc::default(), - parsed_attributes, - parsed_body, - false, - ); - return res.map(|it| it.into_subtree()); - } - _ => continue, - } - } - - Err(crate::proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string())) -} - -pub fn list_macros_stable(macros: &[StableProcMacro]) -> Vec<(String, ProcMacroKind)> { - macros - .iter() - .map(|proc_macro| match proc_macro { - crate::proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { - (trait_name.to_string(), ProcMacroKind::CustomDerive) - } - crate::proc_macro::bridge::client::ProcMacro::Bang { name, .. } => { - (name.to_string(), ProcMacroKind::FuncLike) - } - crate::proc_macro::bridge::client::ProcMacro::Attr { name, .. } => { - (name.to_string(), ProcMacroKind::Attr) - } - }) - .collect() -} - -pub fn list_macros_nightly(macros: &[NightlyProcMacro]) -> Vec<(String, ProcMacroKind)> { - macros - .iter() - .map(|proc_macro| match proc_macro { - crate::proc_macro_nightly::bridge::client::ProcMacro::CustomDerive { - trait_name, - .. - } => (trait_name.to_string(), ProcMacroKind::CustomDerive), - crate::proc_macro_nightly::bridge::client::ProcMacro::Bang { name, .. } => { - (name.to_string(), ProcMacroKind::FuncLike) - } - crate::proc_macro_nightly::bridge::client::ProcMacro::Attr { name, .. } => { - (name.to_string(), ProcMacroKind::Attr) - } - }) - .collect() -} diff --git a/crates/proc_macro_srv/src/lib.rs b/crates/proc_macro_srv/src/lib.rs index deb1d1e526..eb9080e998 100644 --- a/crates/proc_macro_srv/src/lib.rs +++ b/crates/proc_macro_srv/src/lib.rs @@ -11,23 +11,10 @@ //! rustc rather than `unstable`. (Although in general ABI compatibility is still an issue)… #![allow(unreachable_pub)] -#[allow(dead_code)] -#[doc(hidden)] -mod proc_macro; - -#[allow(dead_code)] -#[doc(hidden)] -mod proc_macro_nightly; - -#[doc(hidden)] -mod rustc_server; - -#[doc(hidden)] -mod rustc_server_nightly; - mod dylib; -use proc_macro::bridge::client::TokenStream; +mod abis; + use proc_macro_api::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask}; use std::{ collections::{hash_map::Entry, HashMap}, @@ -62,10 +49,7 @@ impl ProcMacroSrv { match result { Ok(expansion) => Ok(ExpansionResult { expansion }), - Err(msg) => { - let msg = msg.as_str().unwrap_or(""); - Err(format!("proc-macro panicked: {}", msg)) - } + Err(msg) => Err(format!("proc-macro panicked: {}", msg)), } } diff --git a/crates/proc_macro_srv/src/tests/utils.rs b/crates/proc_macro_srv/src/tests/utils.rs index 2c093aa0ad..150e26fe75 100644 --- a/crates/proc_macro_srv/src/tests/utils.rs +++ b/crates/proc_macro_srv/src/tests/utils.rs @@ -12,8 +12,14 @@ pub mod fixtures { } } -fn parse_string(code: &str) -> Option { - Some(crate::rustc_server::TokenStream::from_str(code).unwrap()) +fn parse_string(code: &str) -> Option { + // This is a bit strange. We need to parse a string into a token stream into + // order to create a tt::SubTree from it in fixtures. `into_subtree` is + // implemented by all the ABIs we have so we arbitrarily choose one ABI to + // write a `parse_string` function for and use that. The tests don't really + // care which ABI we're using as the `into_subtree` function isn't part of + // the ABI and shouldn't change between ABI versions. + crate::abis::abi_1_47::TokenStream::from_str(code).ok() } pub fn assert_expand(macro_name: &str, ra_fixture: &str, expect: Expect) {