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

`+

}

`