mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 15:23:46 +00:00
Assert that sysroot ABI version matches exactly
Otherwise, fall back to the multi ABI scheme, except in testing, where it becomes a hard error. This should make it possible to use a rustup-provided rust-analyzer with proc macro dylibs compiled by older rustcs, and it'll also catch changes to the format of `rustc --version` or the `.rustc` section that would make them impossible to compare for equality.
This commit is contained in:
parent
480f555334
commit
fdddd83224
@ -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 {
|
||||
|
@ -102,7 +102,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) }?;
|
||||
|
||||
|
25
crates/proc-macro-srv/build.rs
Normal file
25
crates/proc-macro-srv/build.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use std::{env, fs::File, io::Write, path::PathBuf, process::Command};
|
||||
|
||||
fn main() {
|
||||
// Determine rustc version `proc-macro-srv` (and thus the sysroot ABI) is
|
||||
// build with and make it accessible at runtime for ABI selection.
|
||||
|
||||
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();
|
||||
}
|
@ -29,6 +29,9 @@ mod abi_1_64;
|
||||
#[cfg(feature = "sysroot-abi")]
|
||||
mod abi_sysroot;
|
||||
|
||||
// see `build.rs`
|
||||
include!(concat!(env!("OUT_DIR"), "/rustc_version.rs"));
|
||||
|
||||
// Used by `test/utils.rs`
|
||||
#[cfg(test)]
|
||||
pub(crate) use abi_1_64::TokenStream as TestTokenStream;
|
||||
@ -74,13 +77,37 @@ impl Abi {
|
||||
lib: &Library,
|
||||
symbol_name: String,
|
||||
info: RustCInfo,
|
||||
#[cfg_attr(not(feature = "sysroot-abi"), allow(unused_variables))] version_string: String,
|
||||
) -> Result<Abi, LoadProcMacroDylibError> {
|
||||
// Gated behind an env var for now to avoid a change in behavior for
|
||||
// rustup-installed rust-analyzer
|
||||
// the sysroot ABI relies on `extern proc_macro` with unstable features,
|
||||
// instead of a snapshot of the proc macro bridge's source code. it's only
|
||||
// enabled if we have an exact version match.
|
||||
#[cfg(feature = "sysroot-abi")]
|
||||
if std::env::var("PROC_MACRO_SRV_SYSROOT_ABI").is_ok() {
|
||||
let inner = unsafe { Abi_Sysroot::from_lib(lib, symbol_name) }?;
|
||||
return Ok(Abi::AbiSysroot(inner));
|
||||
{
|
||||
if version_string == RUSTC_VERSION_STRING {
|
||||
let inner = unsafe { Abi_Sysroot::from_lib(lib, symbol_name) }?;
|
||||
return Ok(Abi::AbiSysroot(inner));
|
||||
}
|
||||
|
||||
// if we reached this point, versions didn't match. in testing, we
|
||||
// want that to panic - this could mean that the format of `rustc
|
||||
// --version` no longer matches the format of the version string
|
||||
// stored in the `.rustc` section, and we want to catch that in-tree
|
||||
// with `x.py test`
|
||||
#[cfg(test)]
|
||||
{
|
||||
let allow_mismatch = std::env::var("PROC_MACRO_SRV_ALLOW_SYSROOT_MISMATCH");
|
||||
if let Ok("1") = allow_mismatch.as_deref() {
|
||||
// only used by rust-analyzer developers, when working on the
|
||||
// sysroot ABI from the rust-analyzer repository - which should
|
||||
// only happen pre-subtree. this can be removed later.
|
||||
} else {
|
||||
panic!(
|
||||
"sysroot ABI mismatch: dylib rustc version (read from .rustc section): {:?} != proc-macro-srv version (read from 'rustc --version'): {:?}",
|
||||
version_string, RUSTC_VERSION_STRING
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: this should use exclusive ranges when they're stable
|
||||
|
@ -12,7 +12,7 @@ use libloading::Library;
|
||||
use memmap2::Mmap;
|
||||
use object::Object;
|
||||
use paths::AbsPath;
|
||||
use proc_macro_api::{read_dylib_info, ProcMacroKind};
|
||||
use proc_macro_api::{read_dylib_info, read_version, ProcMacroKind};
|
||||
|
||||
use super::abis::Abi;
|
||||
|
||||
@ -122,9 +122,10 @@ impl ProcMacroLibraryLibloading {
|
||||
invalid_data_err(format!("expected an absolute path, got {}", file.display()))
|
||||
})?;
|
||||
let version_info = read_dylib_info(abs_file)?;
|
||||
let version_string = read_version(abs_file)?;
|
||||
|
||||
let lib = load_library(file).map_err(invalid_data_err)?;
|
||||
let abi = Abi::from_lib(&lib, symbol_name, version_info)?;
|
||||
let abi = Abi::from_lib(&lib, symbol_name, version_info, version_string)?;
|
||||
Ok(ProcMacroLibraryLibloading { _lib: lib, abi })
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user