]> git.proxmox.com Git - rustc.git/blame - src/test/incremental/thinlto/cgu_invalidated_when_import_removed.rs
Update unsuspicious file list
[rustc.git] / src / test / incremental / thinlto / cgu_invalidated_when_import_removed.rs
CommitLineData
dfeec247
XL
1// revisions: cfail1 cfail2
2// compile-flags: -O -Zhuman-readable-cgu-names -Cllvm-args=-import-instr-limit=10
3// build-pass
4
5// rust-lang/rust#59535:
6//
7// Consider a call-graph like `[A] -> [B -> D] <- [C]` (where the letters are
8// functions and the modules are enclosed in `[]`)
9//
10// In our specific instance, the earlier compilations were inlining the call
94222f64 11// to`B` into `A`; thus `A` ended up with an external reference to the symbol `D`
dfeec247
XL
12// in its object code, to be resolved at subsequent link time. The LTO import
13// information provided by LLVM for those runs reflected that information: it
14// explicitly says during those runs, `B` definition and `D` declaration were
15// imported into `[A]`.
16//
17// The change between incremental builds was that the call `D <- C` was removed.
18//
19// That change, coupled with other decisions within `rustc`, made the compiler
20// decide to make `D` an internal symbol (since it was no longer accessed from
21// other codegen units, this makes sense locally). And then the definition of
22// `D` was inlined into `B` and `D` itself was eliminated entirely.
23//
24// The current LTO import information reported that `B` alone is imported into
25// `[A]` for the *current compilation*. So when the Rust compiler surveyed the
26// dependence graph, it determined that nothing `[A]` imports changed since the
27// last build (and `[A]` itself has not changed either), so it chooses to reuse
28// the object code generated during the previous compilation.
29//
30// But that previous object code has an unresolved reference to `D`, and that
31// causes a link time failure!
32
33fn main() {
34 foo::foo();
35 bar::baz();
36}
37
38mod foo {
39
40 // In cfail1, foo() gets inlined into main.
41 // In cfail2, ThinLTO decides that foo() does not get inlined into main, and
42 // instead bar() gets inlined into foo(). But faulty logic in our incr.
43 // ThinLTO implementation thought that `main()` is unchanged and thus reused
74b04a01 44 // the object file still containing a call to the now non-existent bar().
dfeec247
XL
45 pub fn foo(){
46 bar()
47 }
48
49 // This function needs to be big so that it does not get inlined by ThinLTO
50 // but *does* get inlined into foo() once it is declared `internal` in
51 // cfail2.
52 pub fn bar(){
53 println!("quux1");
54 println!("quux2");
55 println!("quux3");
56 println!("quux4");
57 println!("quux5");
58 println!("quux6");
59 println!("quux7");
60 println!("quux8");
61 println!("quux9");
62 }
63}
64
65mod bar {
66
67 #[inline(never)]
68 pub fn baz() {
69 #[cfg(cfail1)]
70 {
71 crate::foo::bar();
72 }
73 }
74}