Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit fdddd83

Browse files
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.
1 parent 480f555 commit fdddd83

File tree

5 files changed

+62
-9
lines changed

5 files changed

+62
-9
lines changed

crates/proc-macro-api/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::{
2626
process::ProcMacroProcessSrv,
2727
};
2828

29-
pub use version::{read_dylib_info, RustCInfo};
29+
pub use version::{read_dylib_info, read_version, RustCInfo};
3030

3131
#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
3232
pub enum ProcMacroKind {

crates/proc-macro-api/src/version.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ fn read_section<'a>(dylib_binary: &'a [u8], section_name: &str) -> io::Result<&'
102102
/// * [some more bytes that we don't really care but about still there] :-)
103103
/// Check this issue for more about the bytes layout:
104104
/// <https://github.com/rust-lang/rust-analyzer/issues/6174>
105-
fn read_version(dylib_path: &AbsPath) -> io::Result<String> {
105+
pub fn read_version(dylib_path: &AbsPath) -> io::Result<String> {
106106
let dylib_file = File::open(dylib_path)?;
107107
let dylib_mmaped = unsafe { Mmap::map(&dylib_file) }?;
108108

crates/proc-macro-srv/build.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use std::{env, fs::File, io::Write, path::PathBuf, process::Command};
2+
3+
fn main() {
4+
// Determine rustc version `proc-macro-srv` (and thus the sysroot ABI) is
5+
// build with and make it accessible at runtime for ABI selection.
6+
7+
let mut path = PathBuf::from(env::var_os("OUT_DIR").unwrap());
8+
path.push("rustc_version.rs");
9+
let mut f = File::create(&path).unwrap();
10+
11+
let rustc = env::var("RUSTC").expect("proc-macro-srv's build script expects RUSTC to be set");
12+
let output = Command::new(rustc).arg("--version").output().expect("rustc --version must run");
13+
let version_string = std::str::from_utf8(&output.stdout[..])
14+
.expect("rustc --version output must be UTF-8")
15+
.trim();
16+
17+
write!(
18+
f,
19+
"
20+
#[allow(dead_code)]
21+
pub(crate) const RUSTC_VERSION_STRING: &str = {version_string:?};
22+
"
23+
)
24+
.unwrap();
25+
}

crates/proc-macro-srv/src/abis/mod.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ mod abi_1_64;
2929
#[cfg(feature = "sysroot-abi")]
3030
mod abi_sysroot;
3131

32+
// see `build.rs`
33+
include!(concat!(env!("OUT_DIR"), "/rustc_version.rs"));
34+
3235
// Used by `test/utils.rs`
3336
#[cfg(test)]
3437
pub(crate) use abi_1_64::TokenStream as TestTokenStream;
@@ -74,13 +77,37 @@ impl Abi {
7477
lib: &Library,
7578
symbol_name: String,
7679
info: RustCInfo,
80+
#[cfg_attr(not(feature = "sysroot-abi"), allow(unused_variables))] version_string: String,
7781
) -> Result<Abi, LoadProcMacroDylibError> {
78-
// Gated behind an env var for now to avoid a change in behavior for
79-
// rustup-installed rust-analyzer
82+
// the sysroot ABI relies on `extern proc_macro` with unstable features,
83+
// instead of a snapshot of the proc macro bridge's source code. it's only
84+
// enabled if we have an exact version match.
8085
#[cfg(feature = "sysroot-abi")]
81-
if std::env::var("PROC_MACRO_SRV_SYSROOT_ABI").is_ok() {
82-
let inner = unsafe { Abi_Sysroot::from_lib(lib, symbol_name) }?;
83-
return Ok(Abi::AbiSysroot(inner));
86+
{
87+
if version_string == RUSTC_VERSION_STRING {
88+
let inner = unsafe { Abi_Sysroot::from_lib(lib, symbol_name) }?;
89+
return Ok(Abi::AbiSysroot(inner));
90+
}
91+
92+
// if we reached this point, versions didn't match. in testing, we
93+
// want that to panic - this could mean that the format of `rustc
94+
// --version` no longer matches the format of the version string
95+
// stored in the `.rustc` section, and we want to catch that in-tree
96+
// with `x.py test`
97+
#[cfg(test)]
98+
{
99+
let allow_mismatch = std::env::var("PROC_MACRO_SRV_ALLOW_SYSROOT_MISMATCH");
100+
if let Ok("1") = allow_mismatch.as_deref() {
101+
// only used by rust-analyzer developers, when working on the
102+
// sysroot ABI from the rust-analyzer repository - which should
103+
// only happen pre-subtree. this can be removed later.
104+
} else {
105+
panic!(
106+
"sysroot ABI mismatch: dylib rustc version (read from .rustc section): {:?} != proc-macro-srv version (read from 'rustc --version'): {:?}",
107+
version_string, RUSTC_VERSION_STRING
108+
);
109+
}
110+
}
84111
}
85112

86113
// FIXME: this should use exclusive ranges when they're stable

crates/proc-macro-srv/src/dylib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use libloading::Library;
1212
use memmap2::Mmap;
1313
use object::Object;
1414
use paths::AbsPath;
15-
use proc_macro_api::{read_dylib_info, ProcMacroKind};
15+
use proc_macro_api::{read_dylib_info, read_version, ProcMacroKind};
1616

1717
use super::abis::Abi;
1818

@@ -122,9 +122,10 @@ impl ProcMacroLibraryLibloading {
122122
invalid_data_err(format!("expected an absolute path, got {}", file.display()))
123123
})?;
124124
let version_info = read_dylib_info(abs_file)?;
125+
let version_string = read_version(abs_file)?;
125126

126127
let lib = load_library(file).map_err(invalid_data_err)?;
127-
let abi = Abi::from_lib(&lib, symbol_name, version_info)?;
128+
let abi = Abi::from_lib(&lib, symbol_name, version_info, version_string)?;
128129
Ok(ProcMacroLibraryLibloading { _lib: lib, abi })
129130
}
130131
}

0 commit comments

Comments
 (0)