// 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 = std::sync::OnceLock::new(); static V0_PATTERN: std::sync::OnceLock = 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 { // 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 = 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 = symbols.into_iter().collect(); // Sort those symbol names for deterministic comparison. symbols.sort(); symbols }