about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2020-05-18 08:00:44 -0700
committerAlex Crichton <alex@alexcrichton.com>2020-05-18 08:00:44 -0700
commitcc91041f26fa90920cc96c13c431610153a61586 (patch)
tree7d37e33ef28b2a702c8ce5164ce93104c02d1e30
parent9e2a6a29ce82e4fc5decad86dab7911a38582438 (diff)
downloadrust-cc91041f26fa90920cc96c13c431610153a61586.tar.gz
rust-cc91041f26fa90920cc96c13c431610153a61586.zip
Always generated object code for `#![no_builtins]`
This commit updates the code generation for `#![no_builtins]` to always
produce object files instead of conditionally respecting
`-Clinker-plugin-lto` and sometimes producing bitcode. This is intended
to address rust-lang/cargo#8239.

The issue at hand here is that Cargo has tried to get "smarter" about
codegen in whole crate graph scenarios. When LTO is enabled it attempts
to avoid codegen on as many crates as possible, opting to pass
`-Clinker-plugin-lto` where it can to only generate bitcode. When this
is combined with `-Zbuild-std`, however, it means that
`compiler-builtins` only generates LLVM bitcode instead of object files.
Rustc's own LTO passes then explicitly skip `compiler-builtins` (because
it wouldn't work anyway) which means that LLVM bitcode gets sent to the
linker, which chokes most of the time.

The fix in this PR is to not actually respect `-Clinker-plugin-lto` for
`#![no_builtins]` crates. These crates, even if slurped up by the linker
rather than rustc, will not work with LTO. They define symbols which are
only referenced as part of codegen, so LTO's aggressive internalization
would trivially remove the symbols only to have the linker realize later
that the symbol is undefined. Since pure-bitcode never makes sense for
these libraries, the `-Clinker-plugin-lto` flag is silently ignored.
-rw-r--r--src/librustc_codegen_ssa/back/write.rs16
1 files changed, 15 insertions, 1 deletions
diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs
index 53dfe7cb749..f9ee7d8c5de 100644
--- a/src/librustc_codegen_ssa/back/write.rs
+++ b/src/librustc_codegen_ssa/back/write.rs
@@ -142,8 +142,22 @@ impl ModuleConfig {
         let emit_obj = if !should_emit_obj {
             EmitObj::None
         } else if sess.target.target.options.obj_is_bitcode
-            || sess.opts.cg.linker_plugin_lto.enabled()
+            || (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins)
         {
+            // This case is selected if the target uses objects as bitcode, or
+            // if linker plugin LTO is enabled. In the linker plugin LTO case
+            // the assumption is that the final link-step will read the bitcode
+            // and convert it to object code. This may be done by either the
+            // native linker or rustc itself.
+            //
+            // Note, however, that the linker-plugin-lto requested here is
+            // explicitly ignored for `#![no_builtins]` crates. These crates are
+            // specifically ignored by rustc's LTO passes and wouldn't work if
+            // loaded into the linker. These crates define symbols that LLVM
+            // lowers intrinsics to, and these symbol dependencies aren't known
+            // until after codegen. As a result any crate marked
+            // `#![no_builtins]` is assumed to not participate in LTO and
+            // instead goes on to generate object code.
             EmitObj::Bitcode
         } else if need_bitcode_in_object(sess) {
             EmitObj::ObjectCode(BitcodeSection::Full)