Skip to content

Commit

Permalink
Auto merge of #12835 - fasterthanlime:sysroot-abi, r=fasterthanlime
Browse files Browse the repository at this point in the history
Introduce proc-macro-srv/sysroot-abi

Still a WIP.

This change is tracked by:

  * #12818
  • Loading branch information
bors committed Jul 22, 2022
2 parents 84a6fac + e591ff3 commit cb8a3be
Show file tree
Hide file tree
Showing 14 changed files with 1,053 additions and 10 deletions.
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

0 comments on commit cb8a3be

Please sign in to comment.