69 lines
2.9 KiB
Rust
69 lines
2.9 KiB
Rust
|
// A typo in rustc caused generic symbol names to be non-deterministic -
|
||
|
// that is, it was possible to compile the same file twice with no changes
|
||
|
// and get outputs with different symbol names.
|
||
|
// This test compiles each of the two crates twice, and checks that each output
|
||
|
// contains exactly the same symbol names.
|
||
|
// Additionally, both crates should agree on the same symbol names for monomorphic
|
||
|
// functions.
|
||
|
// See https://github.com/rust-lang/rust/issues/32554
|
||
|
|
||
|
use std::collections::HashSet;
|
||
|
|
||
|
use run_make_support::{llvm_readobj, regex, rfs, rust_lib_name, rustc};
|
||
|
|
||
|
static LEGACY_PATTERN: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
|
||
|
static V0_PATTERN: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
|
||
|
|
||
|
fn main() {
|
||
|
LEGACY_PATTERN.set(regex::Regex::new(r"_ZN.*E").unwrap()).unwrap();
|
||
|
V0_PATTERN.set(regex::Regex::new(r"_R[a-zA-Z0-9_]*").unwrap()).unwrap();
|
||
|
// test 1: first file
|
||
|
rustc().input("stable-symbol-names1.rs").run();
|
||
|
let sym1 = process_symbols("stable_symbol_names1", "generic_|mono_");
|
||
|
rfs::remove_file(rust_lib_name("stable_symbol_names1"));
|
||
|
rustc().input("stable-symbol-names1.rs").run();
|
||
|
let sym2 = process_symbols("stable_symbol_names1", "generic_|mono_");
|
||
|
assert_eq!(sym1, sym2);
|
||
|
|
||
|
// test 2: second file
|
||
|
rustc().input("stable-symbol-names2.rs").run();
|
||
|
let sym1 = process_symbols("stable_symbol_names2", "generic_|mono_");
|
||
|
rfs::remove_file(rust_lib_name("stable_symbol_names2"));
|
||
|
rustc().input("stable-symbol-names2.rs").run();
|
||
|
let sym2 = process_symbols("stable_symbol_names2", "generic_|mono_");
|
||
|
assert_eq!(sym1, sym2);
|
||
|
|
||
|
// test 3: crossed files
|
||
|
let sym1 = process_symbols("stable_symbol_names1", "mono_");
|
||
|
let sym2 = process_symbols("stable_symbol_names2", "mono_");
|
||
|
assert_eq!(sym1, sym2);
|
||
|
}
|
||
|
|
||
|
#[track_caller]
|
||
|
fn process_symbols(path: &str, symbol: &str) -> Vec<String> {
|
||
|
// Dump all symbols.
|
||
|
let out = llvm_readobj().input(rust_lib_name(path)).symbols().run().stdout_utf8();
|
||
|
// Extract only lines containing `symbol`.
|
||
|
let symbol_regex = regex::Regex::new(symbol).unwrap();
|
||
|
let out = out.lines().filter(|&line| symbol_regex.find(line).is_some());
|
||
|
|
||
|
// HashSet - duplicates should be excluded!
|
||
|
let mut symbols: HashSet<String> = HashSet::new();
|
||
|
// From those lines, extract just the symbol name via `regex`, which:
|
||
|
// * always starts with "_ZN" and ends with "E" (`legacy` mangling)
|
||
|
// * always starts with "_R" (`v0` mangling)
|
||
|
for line in out {
|
||
|
if let Some(mat) = LEGACY_PATTERN.get().unwrap().find(line) {
|
||
|
symbols.insert(mat.as_str().to_string());
|
||
|
}
|
||
|
if let Some(mat) = V0_PATTERN.get().unwrap().find(line) {
|
||
|
symbols.insert(mat.as_str().to_string());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let mut symbols: Vec<String> = symbols.into_iter().collect();
|
||
|
// Sort those symbol names for deterministic comparison.
|
||
|
symbols.sort();
|
||
|
symbols
|
||
|
}
|