Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #157683 - jhpratt:rollup-n3DkSzN, r=jhpratt
Rollup of 17 pull requests Successful merges: - rust-lang/rust#157166 (Change type of async context parameter after state transform.) - rust-lang/rust#157335 (bootstrap: Handle dotted table keys when parsing bootstrap.toml) - rust-lang/rust#157503 (Disable `tests/debuginfo/pretty-std.rs` `OsString` cdb check) - rust-lang/rust#157571 (Remove ProcMacro enum from proc macro ABI) - rust-lang/rust#148183 (rustdoc: Test & document `test_harness` code block attribute) - rust-lang/rust#153847 (Fix marker trait winnowing depending on impl order) - rust-lang/rust#156067 (Fix async drop glue for Box<T>) - rust-lang/rust#156399 (fix improper ctypes in Znext solver) - rust-lang/rust#157338 (Make `Literal::byte_character_value` work with bytes as well) - rust-lang/rust#157410 (Implement rustc_public::CrateDef{,Type} for FieldDef) - rust-lang/rust#157605 (Arg splat experiment - syntax impl) - rust-lang/rust#157630 (Add multibyte JSON diagnostic regression test) - rust-lang/rust#157633 (Reorder `impl` restriction rendering and add bottom margin) - rust-lang/rust#157642 (Report duplicate relaxed bounds during ast lowering) - rust-lang/rust#157652 (fix doc for unicode normalization faq on `casefold` APIs) - rust-lang/rust#157661 (Update to ar_archive_writer v0.5.2) - rust-lang/rust#157668 (Add test for matches in `rustc_must_match_exhaustively`) Failed merges: - rust-lang/rust#157670 (Rename `errors.rs` file to `diagnostics.rs` (4/N))
bors 5 weeks ago
parent 9356d06 · parent 2386ecb · commit de50c5d
-rw-r--r--crates/proc-macro-srv/Cargo.toml3
-rw-r--r--crates/proc-macro-srv/src/dylib.rs57
-rw-r--r--crates/proc-macro-srv/src/dylib/proc_macros.rs43
-rw-r--r--crates/proc-macro-srv/src/dylib/version.rs168
-rw-r--r--crates/proc-macro-srv/src/lib.rs6
5 files changed, 76 insertions, 201 deletions
diff --git a/crates/proc-macro-srv/Cargo.toml b/crates/proc-macro-srv/Cargo.toml
index a161d79693..72d394d37b 100644
--- a/crates/proc-macro-srv/Cargo.toml
+++ b/crates/proc-macro-srv/Cargo.toml
@@ -35,8 +35,7 @@ line-index.workspace = true
proc-macro-test.path = "./proc-macro-test"
[features]
-default = []
-# default = ["in-rust-tree"]
+default = ["in-rust-tree"]
in-rust-tree = []
[lints]
diff --git a/crates/proc-macro-srv/src/dylib.rs b/crates/proc-macro-srv/src/dylib.rs
index 96daa2c462..f654d21cfe 100644
--- a/crates/proc-macro-srv/src/dylib.rs
+++ b/crates/proc-macro-srv/src/dylib.rs
@@ -1,9 +1,14 @@
//! Handles dynamic library loading for proc macro
mod proc_macros;
-mod version;
+use rustc_codegen_ssa::back::metadata::DefaultMetadataLoader;
+use rustc_interface::util::rustc_version_str;
+use rustc_metadata::locator::MetadataError;
use rustc_proc_macro::bridge;
+use rustc_session::config::host_tuple;
+use rustc_target::spec::{Target, TargetTuple};
+use std::path::Path;
use std::{fmt, fs, io, time::SystemTime};
use temp_dir::TempDir;
@@ -13,7 +18,8 @@ use paths::{Utf8Path, Utf8PathBuf};
use crate::{
PanicMessage, ProcMacroClientHandle, ProcMacroKind, ProcMacroSrvSpan, TrackedEnv,
- dylib::proc_macros::ProcMacros, token_stream::TokenStream,
+ dylib::proc_macros::{ProcMacroClients, ProcMacros},
+ token_stream::TokenStream,
};
pub(crate) struct Expander {
@@ -76,18 +82,15 @@ impl Expander {
pub enum LoadProcMacroDylibError {
Io(io::Error),
LibLoading(libloading::Error),
- AbiMismatch(String),
+ MetadataError(MetadataError<'static>),
}
impl fmt::Display for LoadProcMacroDylibError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(e) => e.fmt(f),
- Self::AbiMismatch(v) => {
- use crate::RUSTC_VERSION_STRING;
- write!(f, "mismatched ABI expected: `{RUSTC_VERSION_STRING}`, got `{v}`")
- }
Self::LibLoading(e) => e.fmt(f),
+ Self::MetadataError(e) => e.fmt(f),
}
}
}
@@ -104,25 +107,44 @@ impl From<libloading::Error> for LoadProcMacroDylibError {
}
}
+impl From<MetadataError<'_>> for LoadProcMacroDylibError {
+ fn from(e: MetadataError<'_>) -> Self {
+ LoadProcMacroDylibError::MetadataError(match e {
+ MetadataError::NotPresent(path) => MetadataError::NotPresent(path.into_owned().into()),
+ MetadataError::LoadFailure(err) => MetadataError::LoadFailure(err),
+ MetadataError::VersionMismatch { expected_version, found_version } => {
+ MetadataError::VersionMismatch { expected_version, found_version }
+ }
+ })
+ }
+}
+
struct ProcMacroLibrary {
- // 'static is actually the lifetime of library, so make sure this drops before _lib
- proc_macros: &'static ProcMacros,
+ // this contains references to the library, so make sure this drops before _lib
+ proc_macros: ProcMacros,
// Hold on to the library so it doesn't unload
_lib: Library,
}
impl ProcMacroLibrary {
fn open(path: &Utf8Path) -> Result<Self, LoadProcMacroDylibError> {
+ let proc_macro_kinds = rustc_span::create_default_session_globals_then(|| {
+ let (target, _) =
+ Target::search(&TargetTuple::from_tuple(host_tuple()), Path::new(""), false)
+ .unwrap();
+ rustc_metadata::locator::get_proc_macro_info(
+ &target,
+ path.as_ref(),
+ &DefaultMetadataLoader,
+ rustc_version_str().unwrap_or("unknown"),
+ )
+ })?;
+
let file = fs::File::open(path)?;
#[allow(clippy::undocumented_unsafe_blocks)] // FIXME
let file = unsafe { memmap2::Mmap::map(&file) }?;
let obj = object::File::parse(&*file)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
- let version_info = version::read_dylib_info(&obj)?;
- if version_info.version_string != crate::RUSTC_VERSION_STRING {
- return Err(LoadProcMacroDylibError::AbiMismatch(version_info.version_string));
- }
-
let symbol_name =
find_registrar_symbol(&obj).map_err(invalid_data_err)?.ok_or_else(|| {
invalid_data_err(format!("Cannot find registrar symbol in file {path}"))
@@ -135,9 +157,12 @@ impl ProcMacroLibrary {
// due to self-referentiality
// But we make sure that we do not drop it before the symbol is dropped
let proc_macros =
- unsafe { lib.get::<&'static &'static ProcMacros>(symbol_name.as_bytes()) };
+ unsafe { lib.get::<&'static &'static ProcMacroClients>(symbol_name.as_bytes()) };
match proc_macros {
- Ok(proc_macros) => Ok(ProcMacroLibrary { proc_macros: *proc_macros, _lib: lib }),
+ Ok(proc_macros) => Ok(ProcMacroLibrary {
+ proc_macros: ProcMacros::new(*proc_macros, proc_macro_kinds),
+ _lib: lib,
+ }),
Err(e) => Err(e.into()),
}
}
diff --git a/crates/proc-macro-srv/src/dylib/proc_macros.rs b/crates/proc-macro-srv/src/dylib/proc_macros.rs
index 4ed32f8e6c..ef6752d816 100644
--- a/crates/proc-macro-srv/src/dylib/proc_macros.rs
+++ b/crates/proc-macro-srv/src/dylib/proc_macros.rs
@@ -5,7 +5,7 @@ use crate::{
use rustc_proc_macro::bridge;
#[repr(transparent)]
-pub(crate) struct ProcMacros([bridge::client::ProcMacro]);
+pub(crate) struct ProcMacroClients([bridge::client::Client]);
impl From<bridge::PanicMessage> for crate::PanicMessage {
fn from(p: bridge::PanicMessage) -> Self {
@@ -13,7 +13,16 @@ impl From<bridge::PanicMessage> for crate::PanicMessage {
}
}
+pub(crate) struct ProcMacros(Vec<(bridge::client::Client, rustc_metadata::ProcMacroKind)>);
+
impl ProcMacros {
+ pub(super) fn new(
+ clients: &ProcMacroClients,
+ kinds: Vec<rustc_metadata::ProcMacroKind>,
+ ) -> Self {
+ ProcMacros(clients.0.iter().copied().zip(kinds).collect::<Vec<_>>())
+ }
+
pub(crate) fn expand<'a, S: ProcMacroSrvSpan>(
&self,
macro_name: &str,
@@ -27,12 +36,12 @@ impl ProcMacros {
) -> Result<TokenStream<S>, crate::PanicMessage> {
let parsed_attributes = attribute.unwrap_or_default();
- for proc_macro in &self.0 {
- match proc_macro {
- bridge::client::ProcMacro::CustomDerive { trait_name, client, .. }
- if *trait_name == macro_name =>
+ for (client, kind) in &self.0 {
+ match kind {
+ rustc_metadata::ProcMacroKind::CustomDerive { trait_name, .. }
+ if trait_name.as_str() == macro_name =>
{
- let res = client.run(
+ let res = client.run1(
&bridge::server::SAME_THREAD,
S::make_server(call_site, def_site, mixed_site, tracked_env, callback),
macro_body,
@@ -40,8 +49,8 @@ impl ProcMacros {
);
return res.map_err(crate::PanicMessage::from);
}
- bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => {
- let res = client.run(
+ rustc_metadata::ProcMacroKind::Bang { name } if name.as_str() == macro_name => {
+ let res = client.run1(
&bridge::server::SAME_THREAD,
S::make_server(call_site, def_site, mixed_site, tracked_env, callback),
macro_body,
@@ -49,8 +58,8 @@ impl ProcMacros {
);
return res.map_err(crate::PanicMessage::from);
}
- bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => {
- let res = client.run(
+ rustc_metadata::ProcMacroKind::Attr { name } if name.as_str() == macro_name => {
+ let res = client.run2(
&bridge::server::SAME_THREAD,
S::make_server(call_site, def_site, mixed_site, tracked_env, callback),
parsed_attributes,
@@ -67,12 +76,16 @@ impl ProcMacros {
}
pub(crate) fn list_macros(&self) -> impl Iterator<Item = (&str, ProcMacroKind)> {
- self.0.iter().map(|proc_macro| match *proc_macro {
- bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
- (trait_name, ProcMacroKind::CustomDerive)
+ self.0.iter().map(|(_client, kind)| match kind {
+ rustc_metadata::ProcMacroKind::CustomDerive { trait_name, .. } => {
+ (trait_name.as_str(), ProcMacroKind::CustomDerive)
+ }
+ rustc_metadata::ProcMacroKind::Bang { name, .. } => {
+ (name.as_str(), ProcMacroKind::Bang)
+ }
+ rustc_metadata::ProcMacroKind::Attr { name, .. } => {
+ (name.as_str(), ProcMacroKind::Attr)
}
- bridge::client::ProcMacro::Bang { name, .. } => (name, ProcMacroKind::Bang),
- bridge::client::ProcMacro::Attr { name, .. } => (name, ProcMacroKind::Attr),
})
}
}
diff --git a/crates/proc-macro-srv/src/dylib/version.rs b/crates/proc-macro-srv/src/dylib/version.rs
deleted file mode 100644
index 209693b4da..0000000000
--- a/crates/proc-macro-srv/src/dylib/version.rs
+++ /dev/null
@@ -1,168 +0,0 @@
-//! Reading proc-macro rustc version information from binary data
-
-use std::io::{self, Read};
-
-use object::read::{Object, ObjectSection};
-
-#[derive(Debug)]
-pub struct RustCInfo {
- #[allow(dead_code)]
- pub version: (usize, usize, usize),
- #[allow(dead_code)]
- pub channel: String,
- #[allow(dead_code)]
- pub commit: Option<String>,
- #[allow(dead_code)]
- pub date: Option<String>,
- // something like "rustc 1.58.1 (db9d1b20b 2022-01-20)"
- pub version_string: String,
-}
-
-/// Read rustc dylib information
-pub fn read_dylib_info(obj: &object::File<'_>) -> io::Result<RustCInfo> {
- macro_rules! err {
- ($e:literal) => {
- io::Error::new(io::ErrorKind::InvalidData, $e)
- };
- }
-
- let ver_str = read_version(obj)?;
- let mut items = ver_str.split_whitespace();
- let tag = items.next().ok_or_else(|| err!("version format error"))?;
- if tag != "rustc" {
- return Err(err!("no rustc tag"));
- }
-
- let version_part = items.next().ok_or_else(|| err!("no version string"))?;
- let mut version_parts = version_part.split('-');
- let version = version_parts.next().ok_or_else(|| err!("no version"))?;
- let channel = version_parts.next().unwrap_or_default().to_owned();
-
- let commit = match items.next() {
- Some(commit) => {
- match commit.len() {
- 0 => None,
- _ => Some(commit[1..].to_string() /* remove ( */),
- }
- }
- None => None,
- };
- let date = match items.next() {
- Some(date) => {
- match date.len() {
- 0 => None,
- _ => Some(date[0..date.len() - 2].to_string() /* remove ) */),
- }
- }
- None => None,
- };
-
- let version_numbers = version
- .split('.')
- .map(|it| it.parse::<usize>())
- .collect::<Result<Vec<_>, _>>()
- .map_err(|_| err!("version number error"))?;
-
- if version_numbers.len() != 3 {
- return Err(err!("version number format error"));
- }
- let version = (version_numbers[0], version_numbers[1], version_numbers[2]);
-
- Ok(RustCInfo { version, channel, commit, date, version_string: ver_str })
-}
-
-/// This is used inside read_version() to locate the ".rustc" section
-/// from a proc macro crate's binary file.
-fn read_section<'a>(obj: &object::File<'a>, section_name: &str) -> io::Result<&'a [u8]> {
- obj.section_by_name(section_name)
- .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "section read error"))?
- .data()
- .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
-}
-
-/// Check the version of rustc that was used to compile a proc macro crate's
-/// binary file.
-///
-/// A proc macro crate binary's ".rustc" section has following byte layout:
-/// * [b'r',b'u',b's',b't',0,0,0,5] is the first 8 bytes
-/// * ff060000 734e6150 is followed, it's the snappy format magic bytes,
-/// means bytes from here (including this sequence) are compressed in
-/// snappy compression format. Version info is inside here, so decompress
-/// this.
-///
-/// The bytes you get after decompressing the snappy format portion has
-/// following layout:
-/// * [b'r',b'u',b's',b't',0,0,0,5] is the first 8 bytes(again)
-/// * [crate root bytes] next 8 bytes (4 in old versions) is to store
-/// crate root position, according to rustc's source code comment
-/// * [length byte] next 1 byte tells us how many bytes we should read next
-/// for the version string's utf8 bytes
-/// * [version string bytes encoded in utf8] <- GET THIS BOI
-/// * [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>
-pub fn read_version(obj: &object::File<'_>) -> io::Result<String> {
- let dot_rustc = read_section(obj, ".rustc")?;
-
- // check if magic is valid
- if &dot_rustc[0..4] != b"rust" {
- return Err(io::Error::new(
- io::ErrorKind::InvalidData,
- format!("unknown metadata magic, expected `rust`, found `{:?}`", &dot_rustc[0..4]),
- ));
- }
- let version = u32::from_be_bytes([dot_rustc[4], dot_rustc[5], dot_rustc[6], dot_rustc[7]]);
- // Last version with breaking changes is:
- // https://github.com/rust-lang/rust/commit/b94cfefc860715fb2adf72a6955423d384c69318
- let (mut metadata_portion, bytes_before_version) = match version {
- 8 => {
- let len_bytes = &dot_rustc[8..12];
- let data_len = u32::from_be_bytes(len_bytes.try_into().unwrap()) as usize;
- (&dot_rustc[12..data_len + 12], 13)
- }
- 9 | 10 => {
- let len_bytes = &dot_rustc[8..16];
- let data_len = u64::from_le_bytes(len_bytes.try_into().unwrap()) as usize;
- (&dot_rustc[16..data_len + 12], 17)
- }
- _ => {
- return Err(io::Error::new(
- io::ErrorKind::InvalidData,
- format!("unsupported metadata version {version}"),
- ));
- }
- };
-
- // We're going to skip over the bytes before the version string, so basically:
- // 8 bytes for [b'r',b'u',b's',b't',0,0,0,5]
- // 4 or 8 bytes for [crate root bytes]
- // 1 byte for length of version string
- // so 13 or 17 bytes in total, and we should check the last of those bytes
- // to know the length
- let mut bytes = [0u8; 17];
- metadata_portion.read_exact(&mut bytes[..bytes_before_version])?;
- let length = bytes[bytes_before_version - 1];
-
- let mut version_string_utf8 = vec![0u8; length as usize];
- metadata_portion.read_exact(&mut version_string_utf8)?;
- let version_string = String::from_utf8(version_string_utf8);
- version_string.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
-}
-
-#[test]
-fn test_version_check() {
- let info = read_dylib_info(
- &object::File::parse(&*std::fs::read(crate::proc_macro_test_dylib_path()).unwrap())
- .unwrap(),
- )
- .unwrap();
-
- assert_eq!(
- info.version_string,
- crate::RUSTC_VERSION_STRING,
- "sysroot ABI mismatch: dylib rustc version (read from .rustc section): {:?} != proc-macro-srv version (read from 'rustc --version'): {:?}",
- info.version_string,
- crate::RUSTC_VERSION_STRING,
- );
-}
diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs
index 7562a2e664..b8cd3621d6 100644
--- a/crates/proc-macro-srv/src/lib.rs
+++ b/crates/proc-macro-srv/src/lib.rs
@@ -14,9 +14,15 @@
#![allow(unused_features, unused_crate_dependencies)]
#![deny(deprecated_safe, clippy::undocumented_unsafe_blocks)]
+extern crate rustc_codegen_ssa;
extern crate rustc_driver as _;
+extern crate rustc_interface;
extern crate rustc_lexer;
+extern crate rustc_metadata;
extern crate rustc_proc_macro;
+extern crate rustc_session;
+extern crate rustc_span;
+extern crate rustc_target;
mod bridge;
mod dylib;