Auto merge of #127095 - Oneirical:testiary-education, r=jieyouxu · rust-lang/rust@83e9b93 (original) (raw)
``
1
`+
// A typo in rustc caused generic symbol names to be non-deterministic -
`
``
2
`+
// that is, it was possible to compile the same file twice with no changes
`
``
3
`+
// and get outputs with different symbol names.
`
``
4
`+
// This test compiles each of the two crates twice, and checks that each output
`
``
5
`+
// contains exactly the same symbol names.
`
``
6
`+
// Additionally, both crates should agree on the same symbol names for monomorphic
`
``
7
`+
// functions.
`
``
8
`+
// See https://github.com/rust-lang/rust/issues/32554
`
``
9
+
``
10
`+
use std::collections::HashSet;
`
``
11
+
``
12
`+
use run_make_support::{llvm_readobj, regex, rfs, rust_lib_name, rustc};
`
``
13
+
``
14
`+
static LEGACY_PATTERN: std::sync::OnceLockregex::Regex = std::sync::OnceLock::new();
`
``
15
`+
static V0_PATTERN: std::sync::OnceLockregex::Regex = std::sync::OnceLock::new();
`
``
16
+
``
17
`+
fn main() {
`
``
18
`+
LEGACY_PATTERN.set(regex::Regex::new(r"_ZN.*E").unwrap()).unwrap();
`
``
19
`+
V0_PATTERN.set(regex::Regex::new(r"R[a-zA-Z0-9]*").unwrap()).unwrap();
`
``
20
`+
// test 1: first file
`
``
21
`+
rustc().input("stable-symbol-names1.rs").run();
`
``
22
`+
let sym1 = process_symbols("stable_symbol_names1", "generic_|mono_");
`
``
23
`+
rfs::remove_file(rust_lib_name("stable_symbol_names1"));
`
``
24
`+
rustc().input("stable-symbol-names1.rs").run();
`
``
25
`+
let sym2 = process_symbols("stable_symbol_names1", "generic_|mono_");
`
``
26
`+
assert_eq!(sym1, sym2);
`
``
27
+
``
28
`+
// test 2: second file
`
``
29
`+
rustc().input("stable-symbol-names2.rs").run();
`
``
30
`+
let sym1 = process_symbols("stable_symbol_names2", "generic_|mono_");
`
``
31
`+
rfs::remove_file(rust_lib_name("stable_symbol_names2"));
`
``
32
`+
rustc().input("stable-symbol-names2.rs").run();
`
``
33
`+
let sym2 = process_symbols("stable_symbol_names2", "generic_|mono_");
`
``
34
`+
assert_eq!(sym1, sym2);
`
``
35
+
``
36
`+
// test 3: crossed files
`
``
37
`+
let sym1 = process_symbols("stable_symbol_names1", "mono_");
`
``
38
`+
let sym2 = process_symbols("stable_symbol_names2", "mono_");
`
``
39
`+
assert_eq!(sym1, sym2);
`
``
40
`+
}
`
``
41
+
``
42
`+
#[track_caller]
`
``
43
`+
fn process_symbols(path: &str, symbol: &str) -> Vec {
`
``
44
`+
// Dump all symbols.
`
``
45
`+
let out = llvm_readobj().input(rust_lib_name(path)).symbols().run().stdout_utf8();
`
``
46
`` +
// Extract only lines containing symbol
.
``
``
47
`+
let symbol_regex = regex::Regex::new(symbol).unwrap();
`
``
48
`+
let out = out.lines().filter(|&line| symbol_regex.find(line).is_some());
`
``
49
+
``
50
`+
// HashSet - duplicates should be excluded!
`
``
51
`+
let mut symbols: HashSet = HashSet::new();
`
``
52
`` +
// From those lines, extract just the symbol name via regex
, which:
``
``
53
`` +
// * always starts with "_ZN" and ends with "E" (legacy
mangling)
``
``
54
`` +
// * always starts with "_R" (v0
mangling)
``
``
55
`+
for line in out {
`
``
56
`+
if let Some(mat) = LEGACY_PATTERN.get().unwrap().find(line) {
`
``
57
`+
symbols.insert(mat.as_str().to_string());
`
``
58
`+
}
`
``
59
`+
if let Some(mat) = V0_PATTERN.get().unwrap().find(line) {
`
``
60
`+
symbols.insert(mat.as_str().to_string());
`
``
61
`+
}
`
``
62
`+
}
`
``
63
+
``
64
`+
let mut symbols: Vec = symbols.into_iter().collect();
`
``
65
`+
// Sort those symbol names for deterministic comparison.
`
``
66
`+
symbols.sort();
`
``
67
`+
symbols
`
``
68
`+
}
`