Skip to content

Introduce proc-macro-srv/sysroot-abi #12835

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Jul 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/proc-macro-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::{
process::ProcMacroProcessSrv,
};

pub use version::{read_dylib_info, RustCInfo};
pub use version::{read_dylib_info, read_version, RustCInfo};

#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
pub enum ProcMacroKind {
Expand Down
6 changes: 4 additions & 2 deletions crates/proc-macro-api/src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ pub struct RustCInfo {
pub channel: String,
pub commit: Option<String>,
pub date: Option<String>,
// something like "rustc 1.58.1 (db9d1b20b 2022-01-20)"
pub version_string: String,
}

/// Read rustc dylib information
Expand Down Expand Up @@ -68,7 +70,7 @@ pub fn read_dylib_info(dylib_path: &AbsPath) -> io::Result<RustCInfo> {
}
let version = (version_numbers[0], version_numbers[1], version_numbers[2]);

Ok(RustCInfo { version, channel, commit, date })
Ok(RustCInfo { version, channel, commit, date, version_string: ver_str })
}

/// This is used inside read_version() to locate the ".rustc" section
Expand Down Expand Up @@ -102,7 +104,7 @@ fn read_section<'a>(dylib_binary: &'a [u8], section_name: &str) -> io::Result<&'
/// * [some more bytes that we don't really care but about still there] :-)
/// Check this issue for more about the bytes layout:
/// <https://github.com/rust-lang/rust-analyzer/issues/6174>
fn read_version(dylib_path: &AbsPath) -> io::Result<String> {
pub fn read_version(dylib_path: &AbsPath) -> io::Result<String> {
let dylib_file = File::open(dylib_path)?;
let dylib_mmaped = unsafe { Mmap::map(&dylib_file) }?;

Expand Down
4 changes: 4 additions & 0 deletions crates/proc-macro-srv/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ tt = { path = "../tt", version = "0.0.0" }
mbe = { path = "../mbe", version = "0.0.0" }
paths = { path = "../paths", version = "0.0.0" }
proc-macro-api = { path = "../proc-macro-api", version = "0.0.0" }
crossbeam = "0.8.1"

[dev-dependencies]
expect-test = "1.4.0"

# used as proc macro test targets
proc-macro-test = { path = "../proc-macro-test" }

[features]
sysroot-abi = []
25 changes: 25 additions & 0 deletions crates/proc-macro-srv/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! Determine rustc version `proc-macro-srv` (and thus the sysroot ABI) is
//! build with and make it accessible at runtime for ABI selection.

use std::{env, fs::File, io::Write, path::PathBuf, process::Command};

fn main() {
let mut path = PathBuf::from(env::var_os("OUT_DIR").unwrap());
path.push("rustc_version.rs");
let mut f = File::create(&path).unwrap();

let rustc = env::var("RUSTC").expect("proc-macro-srv's build script expects RUSTC to be set");
let output = Command::new(rustc).arg("--version").output().expect("rustc --version must run");
let version_string = std::str::from_utf8(&output.stdout[..])
.expect("rustc --version output must be UTF-8")
.trim();

write!(
f,
"
#[allow(dead_code)]
pub(crate) const RUSTC_VERSION_STRING: &str = {version_string:?};
"
)
.unwrap();
}
102 changes: 102 additions & 0 deletions crates/proc-macro-srv/src/abis/abi_sysroot/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//! Proc macro ABI

extern crate proc_macro;

#[allow(dead_code)]
#[doc(hidden)]
mod ra_server;

use libloading::Library;
use proc_macro_api::ProcMacroKind;

use super::PanicMessage;

pub(crate) struct Abi {
exported_macros: Vec<proc_macro::bridge::client::ProcMacro>,
}

impl From<proc_macro::bridge::PanicMessage> 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<Abi, libloading::Error> {
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<tt::Subtree, PanicMessage> {
let parsed_body = ra_server::TokenStream::with_subtree(macro_body.clone());

let parsed_attributes = attributes.map_or(ra_server::TokenStream::new(), |attr| {
ra_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,
ra_server::RustAnalyzer::default(),
parsed_body,
true,
);
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,
ra_server::RustAnalyzer::default(),
parsed_body,
true,
);
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,
ra_server::RustAnalyzer::default(),
parsed_attributes,
parsed_body,
true,
);
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()
}
}
Loading