summaryrefslogtreecommitdiffstats
path: root/tests/ui/lto
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/lto')
-rw-r--r--tests/ui/lto/all-crates.rs8
-rw-r--r--tests/ui/lto/auxiliary/debuginfo-lto-aux.rs29
-rw-r--r--tests/ui/lto/auxiliary/dylib.rs6
-rw-r--r--tests/ui/lto/auxiliary/lto-duplicate-symbols1.rs6
-rw-r--r--tests/ui/lto/auxiliary/lto-duplicate-symbols2.rs6
-rw-r--r--tests/ui/lto/auxiliary/lto-rustc-loads-linker-plugin.rs6
-rw-r--r--tests/ui/lto/auxiliary/msvc-imp-present.rs11
-rw-r--r--tests/ui/lto/auxiliary/thin-lto-inlines-aux.rs7
-rw-r--r--tests/ui/lto/auxiliary/thinlto-dylib.rs23
-rw-r--r--tests/ui/lto/debuginfo-lto.rs25
-rw-r--r--tests/ui/lto/dylib-works.rs9
-rw-r--r--tests/ui/lto/fat-lto.rs7
-rw-r--r--tests/ui/lto/issue-100772.rs11
-rw-r--r--tests/ui/lto/issue-105637.rs28
-rw-r--r--tests/ui/lto/issue-105637.run.stderr1
-rw-r--r--tests/ui/lto/issue-11154.rs6
-rw-r--r--tests/ui/lto/issue-11154.stderr6
-rw-r--r--tests/ui/lto/lto-and-no-bitcode-in-rlib.rs3
-rw-r--r--tests/ui/lto/lto-and-no-bitcode-in-rlib.stderr2
-rw-r--r--tests/ui/lto/lto-duplicate-symbols.rs11
-rw-r--r--tests/ui/lto/lto-duplicate-symbols.stderr6
-rw-r--r--tests/ui/lto/lto-many-codegen-units.rs6
-rw-r--r--tests/ui/lto/lto-opt-level-s.rs7
-rw-r--r--tests/ui/lto/lto-opt-level-z.rs7
-rw-r--r--tests/ui/lto/lto-rustc-loads-linker-plugin.rs17
-rw-r--r--tests/ui/lto/lto-still-runs-thread-dtors.rs34
-rw-r--r--tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs13
-rw-r--r--tests/ui/lto/msvc-imp-present.rs22
-rw-r--r--tests/ui/lto/thin-lto-global-allocator.rs7
-rw-r--r--tests/ui/lto/thin-lto-inlines.rs30
-rw-r--r--tests/ui/lto/thin-lto-inlines2.rs28
-rw-r--r--tests/ui/lto/weak-works.rs28
32 files changed, 416 insertions, 0 deletions
diff --git a/tests/ui/lto/all-crates.rs b/tests/ui/lto/all-crates.rs
new file mode 100644
index 000000000..e910b2a9f
--- /dev/null
+++ b/tests/ui/lto/all-crates.rs
@@ -0,0 +1,8 @@
+// run-pass
+
+// compile-flags: -Clto=thin
+// no-prefer-dynamic
+
+fn main() {
+ println!("hello!");
+}
diff --git a/tests/ui/lto/auxiliary/debuginfo-lto-aux.rs b/tests/ui/lto/auxiliary/debuginfo-lto-aux.rs
new file mode 100644
index 000000000..dd471154b
--- /dev/null
+++ b/tests/ui/lto/auxiliary/debuginfo-lto-aux.rs
@@ -0,0 +1,29 @@
+// compile-flags: -g --crate-type=rlib
+
+pub struct StructWithLifetime<'a>(&'a i32);
+pub fn mk_struct_with_lt<'a>(x: &'a i32) -> StructWithLifetime<'a> {
+ StructWithLifetime(x)
+}
+
+pub struct RegularStruct(u32);
+pub fn mk_regular_struct(x: u32) -> RegularStruct {
+ RegularStruct(x)
+}
+
+pub fn take_fn(f: fn(i32) -> i32, x: i32) -> i32 {
+ f(x)
+}
+
+pub fn with_closure(x: i32) -> i32 {
+ let closure = |i| { x + i };
+
+ closure(1) + closure(2)
+}
+
+pub fn generic_fn<T>(x: T) -> (T, u32) {
+ (x, 1)
+}
+
+pub fn user_of_generic_fn(x: f32) -> (f32, u32) {
+ generic_fn(x)
+}
diff --git a/tests/ui/lto/auxiliary/dylib.rs b/tests/ui/lto/auxiliary/dylib.rs
new file mode 100644
index 000000000..e8b7f8f9f
--- /dev/null
+++ b/tests/ui/lto/auxiliary/dylib.rs
@@ -0,0 +1,6 @@
+// compile-flags: -Z thinlto -C codegen-units=8
+
+#[inline]
+pub fn foo(b: u8) {
+ b.to_string();
+}
diff --git a/tests/ui/lto/auxiliary/lto-duplicate-symbols1.rs b/tests/ui/lto/auxiliary/lto-duplicate-symbols1.rs
new file mode 100644
index 000000000..ec6d05603
--- /dev/null
+++ b/tests/ui/lto/auxiliary/lto-duplicate-symbols1.rs
@@ -0,0 +1,6 @@
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+#[no_mangle]
+pub extern "C" fn foo() {}
diff --git a/tests/ui/lto/auxiliary/lto-duplicate-symbols2.rs b/tests/ui/lto/auxiliary/lto-duplicate-symbols2.rs
new file mode 100644
index 000000000..ec6d05603
--- /dev/null
+++ b/tests/ui/lto/auxiliary/lto-duplicate-symbols2.rs
@@ -0,0 +1,6 @@
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+#[no_mangle]
+pub extern "C" fn foo() {}
diff --git a/tests/ui/lto/auxiliary/lto-rustc-loads-linker-plugin.rs b/tests/ui/lto/auxiliary/lto-rustc-loads-linker-plugin.rs
new file mode 100644
index 000000000..d24375b2d
--- /dev/null
+++ b/tests/ui/lto/auxiliary/lto-rustc-loads-linker-plugin.rs
@@ -0,0 +1,6 @@
+// compile-flags: -Clinker-plugin-lto
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn foo() {}
diff --git a/tests/ui/lto/auxiliary/msvc-imp-present.rs b/tests/ui/lto/auxiliary/msvc-imp-present.rs
new file mode 100644
index 000000000..933af050a
--- /dev/null
+++ b/tests/ui/lto/auxiliary/msvc-imp-present.rs
@@ -0,0 +1,11 @@
+// no-prefer-dynamic
+// compile-flags: -Z thinlto -C codegen-units=8 -C prefer-dynamic
+
+#![crate_type = "rlib"]
+#![crate_type = "dylib"]
+
+pub static A: u32 = 43;
+
+pub mod a {
+ pub static A: u32 = 43;
+}
diff --git a/tests/ui/lto/auxiliary/thin-lto-inlines-aux.rs b/tests/ui/lto/auxiliary/thin-lto-inlines-aux.rs
new file mode 100644
index 000000000..5fd3f1996
--- /dev/null
+++ b/tests/ui/lto/auxiliary/thin-lto-inlines-aux.rs
@@ -0,0 +1,7 @@
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn bar() -> u32 {
+ 3
+}
diff --git a/tests/ui/lto/auxiliary/thinlto-dylib.rs b/tests/ui/lto/auxiliary/thinlto-dylib.rs
new file mode 100644
index 000000000..9d17c35da
--- /dev/null
+++ b/tests/ui/lto/auxiliary/thinlto-dylib.rs
@@ -0,0 +1,23 @@
+// Auxiliary crate for test issue-105637: the LTOed dylib which had duplicate symbols from libstd,
+// breaking the panic hook feature.
+//
+// This simulates the `rustc_driver` crate, and the main crate simulates rustc's main binary hooking
+// into this driver.
+
+// compile-flags: -Zdylib-lto -C lto=thin
+
+use std::panic;
+
+pub fn main() {
+ // Install the hook we want to see executed
+ panic::set_hook(Box::new(|_| {
+ eprintln!("LTOed auxiliary crate panic hook");
+ }));
+
+ // Trigger the panic hook with an ICE
+ run_compiler();
+}
+
+fn run_compiler() {
+ panic!("ICEing");
+}
diff --git a/tests/ui/lto/debuginfo-lto.rs b/tests/ui/lto/debuginfo-lto.rs
new file mode 100644
index 000000000..43f75b034
--- /dev/null
+++ b/tests/ui/lto/debuginfo-lto.rs
@@ -0,0 +1,25 @@
+// run-pass
+// This test case makes sure that we don't run into LLVM's dreaded
+// "possible ODR violation" assertion when compiling with LTO + Debuginfo.
+// It covers cases that have traditionally been prone to cause this error.
+// If new cases emerge, add them to this file.
+
+// aux-build:debuginfo-lto-aux.rs
+// compile-flags: -C lto -g
+// no-prefer-dynamic
+// ignore-asmjs wasm2js does not support source maps yet
+
+extern crate debuginfo_lto_aux;
+
+fn some_fn(x: i32) -> i32 {
+ x + 1
+}
+
+fn main() {
+ let i = 0;
+ let _ = debuginfo_lto_aux::mk_struct_with_lt(&i);
+ let _ = debuginfo_lto_aux::mk_regular_struct(1);
+ let _ = debuginfo_lto_aux::take_fn(some_fn, 1);
+ let _ = debuginfo_lto_aux::with_closure(22);
+ let _ = debuginfo_lto_aux::generic_fn(0f32);
+}
diff --git a/tests/ui/lto/dylib-works.rs b/tests/ui/lto/dylib-works.rs
new file mode 100644
index 000000000..9e0782b59
--- /dev/null
+++ b/tests/ui/lto/dylib-works.rs
@@ -0,0 +1,9 @@
+// run-pass
+
+// aux-build:dylib.rs
+
+extern crate dylib;
+
+fn main() {
+ dylib::foo(1);
+}
diff --git a/tests/ui/lto/fat-lto.rs b/tests/ui/lto/fat-lto.rs
new file mode 100644
index 000000000..c8d8095a2
--- /dev/null
+++ b/tests/ui/lto/fat-lto.rs
@@ -0,0 +1,7 @@
+// run-pass
+// compile-flags: -Clto=fat
+// no-prefer-dynamic
+
+fn main() {
+ println!("hello!");
+}
diff --git a/tests/ui/lto/issue-100772.rs b/tests/ui/lto/issue-100772.rs
new file mode 100644
index 000000000..d6b067192
--- /dev/null
+++ b/tests/ui/lto/issue-100772.rs
@@ -0,0 +1,11 @@
+// run-pass
+// needs-sanitizer-cfi
+// compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
+// no-prefer-dynamic
+// only-x86_64-unknown-linux-gnu
+
+#![feature(allocator_api)]
+
+fn main() {
+ let _ = Box::new_in(&[0, 1], &std::alloc::Global);
+}
diff --git a/tests/ui/lto/issue-105637.rs b/tests/ui/lto/issue-105637.rs
new file mode 100644
index 000000000..0d9f0bec0
--- /dev/null
+++ b/tests/ui/lto/issue-105637.rs
@@ -0,0 +1,28 @@
+// Regression test for issue #105637: `-Zdylib-lto` with LTO duplicated symbols from other dylibs,
+// in this case from libstd.
+//
+// That manifested as both `rustc_driver` and rustc's "main" (`compiler/rustc`) having their own
+// `std::panicking::HOOK` static, and the hook in rustc's main (the default stdlib's) being executed
+// when rustc ICEs, instead of the overriden hook from `rustc_driver` (which also displays the query
+// stack and information on how to open a GH issue for the encountered ICE).
+//
+// In this test, we reproduce this setup by installing a panic hook in both the main and an LTOed
+// dylib: the last hook set should be the one being executed, the dylib's.
+
+// aux-build: thinlto-dylib.rs
+// run-fail
+// check-run-results
+
+extern crate thinlto_dylib;
+
+use std::panic;
+
+fn main() {
+ // We don't want to see this panic hook executed
+ std::panic::set_hook(Box::new(|_| {
+ eprintln!("main crate panic hook");
+ }));
+
+ // Have the LTOed dylib install its own hook and panic, we want to see its hook executed.
+ thinlto_dylib::main();
+}
diff --git a/tests/ui/lto/issue-105637.run.stderr b/tests/ui/lto/issue-105637.run.stderr
new file mode 100644
index 000000000..43388e776
--- /dev/null
+++ b/tests/ui/lto/issue-105637.run.stderr
@@ -0,0 +1 @@
+LTOed auxiliary crate panic hook
diff --git a/tests/ui/lto/issue-11154.rs b/tests/ui/lto/issue-11154.rs
new file mode 100644
index 000000000..e11cdc82f
--- /dev/null
+++ b/tests/ui/lto/issue-11154.rs
@@ -0,0 +1,6 @@
+// build-fail
+// compile-flags: -C lto -C prefer-dynamic
+
+// error-pattern: cannot prefer dynamic linking
+
+fn main() {}
diff --git a/tests/ui/lto/issue-11154.stderr b/tests/ui/lto/issue-11154.stderr
new file mode 100644
index 000000000..8eec8b37c
--- /dev/null
+++ b/tests/ui/lto/issue-11154.stderr
@@ -0,0 +1,6 @@
+error: cannot prefer dynamic linking when performing LTO
+
+note: only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lto/lto-and-no-bitcode-in-rlib.rs b/tests/ui/lto/lto-and-no-bitcode-in-rlib.rs
new file mode 100644
index 000000000..f381240e7
--- /dev/null
+++ b/tests/ui/lto/lto-and-no-bitcode-in-rlib.rs
@@ -0,0 +1,3 @@
+// compile-flags: -C lto -C embed-bitcode=no
+
+fn main() {}
diff --git a/tests/ui/lto/lto-and-no-bitcode-in-rlib.stderr b/tests/ui/lto/lto-and-no-bitcode-in-rlib.stderr
new file mode 100644
index 000000000..11e370e91
--- /dev/null
+++ b/tests/ui/lto/lto-and-no-bitcode-in-rlib.stderr
@@ -0,0 +1,2 @@
+error: options `-C embed-bitcode=no` and `-C lto` are incompatible
+
diff --git a/tests/ui/lto/lto-duplicate-symbols.rs b/tests/ui/lto/lto-duplicate-symbols.rs
new file mode 100644
index 000000000..e540094a3
--- /dev/null
+++ b/tests/ui/lto/lto-duplicate-symbols.rs
@@ -0,0 +1,11 @@
+// build-fail
+// aux-build:lto-duplicate-symbols1.rs
+// aux-build:lto-duplicate-symbols2.rs
+// error-pattern:Linking globals named 'foo': symbol multiply defined!
+// compile-flags: -C lto
+// no-prefer-dynamic
+// normalize-stderr-test: "lto-duplicate-symbols2\.lto_duplicate_symbols2\.[0-9a-zA-Z]+-cgu" -> "lto-duplicate-symbols2.lto_duplicate_symbols2.HASH-cgu"
+extern crate lto_duplicate_symbols1;
+extern crate lto_duplicate_symbols2;
+
+fn main() {}
diff --git a/tests/ui/lto/lto-duplicate-symbols.stderr b/tests/ui/lto/lto-duplicate-symbols.stderr
new file mode 100644
index 000000000..f66afa94f
--- /dev/null
+++ b/tests/ui/lto/lto-duplicate-symbols.stderr
@@ -0,0 +1,6 @@
+warning: Linking globals named 'foo': symbol multiply defined!
+
+error: failed to load bitcode of module "lto-duplicate-symbols2.lto_duplicate_symbols2.HASH-cgu.0.rcgu.o":
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/ui/lto/lto-many-codegen-units.rs b/tests/ui/lto/lto-many-codegen-units.rs
new file mode 100644
index 000000000..f0f461ffe
--- /dev/null
+++ b/tests/ui/lto/lto-many-codegen-units.rs
@@ -0,0 +1,6 @@
+// run-pass
+// compile-flags: -C lto -C codegen-units=8
+// no-prefer-dynamic
+
+fn main() {
+}
diff --git a/tests/ui/lto/lto-opt-level-s.rs b/tests/ui/lto/lto-opt-level-s.rs
new file mode 100644
index 000000000..a7d9d5024
--- /dev/null
+++ b/tests/ui/lto/lto-opt-level-s.rs
@@ -0,0 +1,7 @@
+// compile-flags: -Clinker-plugin-lto -Copt-level=s
+// build-pass
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn foo() {}
diff --git a/tests/ui/lto/lto-opt-level-z.rs b/tests/ui/lto/lto-opt-level-z.rs
new file mode 100644
index 000000000..bf1f5e2b2
--- /dev/null
+++ b/tests/ui/lto/lto-opt-level-z.rs
@@ -0,0 +1,7 @@
+// compile-flags: -Clinker-plugin-lto -Copt-level=z
+// build-pass
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn foo() {}
diff --git a/tests/ui/lto/lto-rustc-loads-linker-plugin.rs b/tests/ui/lto/lto-rustc-loads-linker-plugin.rs
new file mode 100644
index 000000000..6ef1d4540
--- /dev/null
+++ b/tests/ui/lto/lto-rustc-loads-linker-plugin.rs
@@ -0,0 +1,17 @@
+// compile-flags: -C lto
+// aux-build:lto-rustc-loads-linker-plugin.rs
+// run-pass
+// no-prefer-dynamic
+
+// This test ensures that if a dependency was compiled with
+// `-Clinker-plugin-lto` then we can compile with `-Clto` and still link against
+// that upstream rlib. This should work because LTO implies we're not actually
+// linking against upstream rlibs since we're generating the object code
+// locally. This test will fail if rustc can't find bytecode in rlibs compiled
+// with `-Clinker-plugin-lto`.
+
+extern crate lto_rustc_loads_linker_plugin;
+
+fn main() {
+ lto_rustc_loads_linker_plugin::foo();
+}
diff --git a/tests/ui/lto/lto-still-runs-thread-dtors.rs b/tests/ui/lto/lto-still-runs-thread-dtors.rs
new file mode 100644
index 000000000..1c7368b36
--- /dev/null
+++ b/tests/ui/lto/lto-still-runs-thread-dtors.rs
@@ -0,0 +1,34 @@
+// run-pass
+// compile-flags: -C lto
+// no-prefer-dynamic
+// ignore-emscripten no threads support
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
+use std::thread;
+
+static mut HIT: usize = 0;
+
+thread_local!(static A: Foo = Foo);
+
+struct Foo;
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ unsafe {
+ HIT += 1;
+ }
+ }
+}
+
+fn main() {
+ unsafe {
+ assert_eq!(HIT, 0);
+ thread::spawn(|| {
+ assert_eq!(HIT, 0);
+ A.with(|_| ());
+ assert_eq!(HIT, 0);
+ }).join().unwrap();
+ assert_eq!(HIT, 1);
+ }
+}
diff --git a/tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs b/tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs
new file mode 100644
index 000000000..4d54ce32f
--- /dev/null
+++ b/tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs
@@ -0,0 +1,13 @@
+// compile-flags: -C lto=thin
+// aux-build:lto-rustc-loads-linker-plugin.rs
+// run-pass
+// no-prefer-dynamic
+
+// Same as the adjacent `lto-thin-rustc-loads-linker-plugin.rs` test, only with
+// ThinLTO.
+
+extern crate lto_rustc_loads_linker_plugin;
+
+fn main() {
+ lto_rustc_loads_linker_plugin::foo();
+}
diff --git a/tests/ui/lto/msvc-imp-present.rs b/tests/ui/lto/msvc-imp-present.rs
new file mode 100644
index 000000000..5498afb29
--- /dev/null
+++ b/tests/ui/lto/msvc-imp-present.rs
@@ -0,0 +1,22 @@
+// run-pass
+
+// aux-build:msvc-imp-present.rs
+// compile-flags: -Z thinlto -C codegen-units=8
+// no-prefer-dynamic
+
+// On MSVC we have a "hack" where we emit symbols that look like `_imp_$name`
+// for all exported statics. This is done because we apply `dllimport` to all
+// imported constants and this allows everything to actually link correctly.
+//
+// The ThinLTO passes aggressively remove symbols if they can, and this test
+// asserts that the ThinLTO passes don't remove these compiler-generated
+// `_imp_*` symbols. The external library that we link in here is compiled with
+// ThinLTO and multiple codegen units and has a few exported constants. Note
+// that we also namely compile the library as both a dylib and an rlib, but we
+// link the rlib to ensure that we assert those generated symbols exist.
+
+extern crate msvc_imp_present as bar;
+
+fn main() {
+ println!("{}", bar::A);
+}
diff --git a/tests/ui/lto/thin-lto-global-allocator.rs b/tests/ui/lto/thin-lto-global-allocator.rs
new file mode 100644
index 000000000..e00c5caf9
--- /dev/null
+++ b/tests/ui/lto/thin-lto-global-allocator.rs
@@ -0,0 +1,7 @@
+// run-pass
+// compile-flags: -Z thinlto -C codegen-units=2
+
+#[global_allocator]
+static A: std::alloc::System = std::alloc::System;
+
+fn main() {}
diff --git a/tests/ui/lto/thin-lto-inlines.rs b/tests/ui/lto/thin-lto-inlines.rs
new file mode 100644
index 000000000..dca791807
--- /dev/null
+++ b/tests/ui/lto/thin-lto-inlines.rs
@@ -0,0 +1,30 @@
+// run-pass
+
+// compile-flags: -Z thinlto -C codegen-units=8 -O
+// ignore-emscripten can't inspect instructions on emscripten
+
+// We want to assert here that ThinLTO will inline across codegen units. There's
+// not really a great way to do that in general so we sort of hack around it by
+// praying two functions go into separate codegen units and then assuming that
+// if inlining *doesn't* happen the first byte of the functions will differ.
+
+pub fn foo() -> u32 {
+ bar::bar()
+}
+
+mod bar {
+ pub fn bar() -> u32 {
+ 3
+ }
+}
+
+fn main() {
+ println!("{} {}", foo(), bar::bar());
+
+ unsafe {
+ let foo = foo as usize as *const u8;
+ let bar = bar::bar as usize as *const u8;
+
+ assert_eq!(*foo, *bar);
+ }
+}
diff --git a/tests/ui/lto/thin-lto-inlines2.rs b/tests/ui/lto/thin-lto-inlines2.rs
new file mode 100644
index 000000000..1eb29657c
--- /dev/null
+++ b/tests/ui/lto/thin-lto-inlines2.rs
@@ -0,0 +1,28 @@
+// run-pass
+
+// compile-flags: -C codegen-units=8 -O -C lto=thin
+// aux-build:thin-lto-inlines-aux.rs
+// no-prefer-dynamic
+// ignore-emscripten can't inspect instructions on emscripten
+
+// We want to assert here that ThinLTO will inline across codegen units. There's
+// not really a great way to do that in general so we sort of hack around it by
+// praying two functions go into separate codegen units and then assuming that
+// if inlining *doesn't* happen the first byte of the functions will differ.
+
+extern crate thin_lto_inlines_aux as bar;
+
+pub fn foo() -> u32 {
+ bar::bar()
+}
+
+fn main() {
+ println!("{} {}", foo(), bar::bar());
+
+ unsafe {
+ let foo = foo as usize as *const u8;
+ let bar = bar::bar as usize as *const u8;
+
+ assert_eq!(*foo, *bar);
+ }
+}
diff --git a/tests/ui/lto/weak-works.rs b/tests/ui/lto/weak-works.rs
new file mode 100644
index 000000000..163a38702
--- /dev/null
+++ b/tests/ui/lto/weak-works.rs
@@ -0,0 +1,28 @@
+// run-pass
+
+// compile-flags: -C codegen-units=8 -Z thinlto
+// ignore-windows
+
+#![feature(linkage)]
+
+pub mod foo {
+ #[linkage = "weak"]
+ #[no_mangle]
+ pub extern "C" fn FOO() -> i32 {
+ 0
+ }
+}
+
+mod bar {
+ extern "C" {
+ fn FOO() -> i32;
+ }
+
+ pub fn bar() -> i32 {
+ unsafe { FOO() }
+ }
+}
+
+fn main() {
+ bar::bar();
+}