]> git.lizzy.rs Git - rust.git/blob - src/test/incremental/thinlto/cgu_invalidated_when_import_removed.rs
Rollup merge of #70038 - DutchGhost:const-forget-tests, r=RalfJung
[rust.git] / src / test / incremental / thinlto / cgu_invalidated_when_import_removed.rs
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
11 // to`B` into `A`; thus `A` ended up with a external reference to the symbol `D`
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
33 fn main() {
34     foo::foo();
35     bar::baz();
36 }
37
38 mod 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
44     // the object file still containing a call to the now non-existent bar().
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
65 mod bar {
66
67     #[inline(never)]
68     pub fn baz() {
69         #[cfg(cfail1)]
70         {
71             crate::foo::bar();
72         }
73     }
74 }