From b9f6dfef0bebd2c2c4d871c4d02f4c5a70844fe9 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Sun, 19 Apr 2020 20:49:38 +1000
Subject: [PATCH 1/4] Remove an old in-progress comment from a previous PR.

This comment wasn't supposed to have landed.
---
 src/librustc_middle/mir/cache.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/librustc_middle/mir/cache.rs b/src/librustc_middle/mir/cache.rs
index af0f7efc3e354..12822cea418d7 100644
--- a/src/librustc_middle/mir/cache.rs
+++ b/src/librustc_middle/mir/cache.rs
@@ -60,7 +60,6 @@ impl Cache {
     }
 
     /// This will recompute the predecessors cache if it is not available
-    // njn: typedef?
     fn predecessors(
         &mut self,
         body: &Body<'_>,

From ae322ff651cb43d8242d8375563e7a252885921e Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Sun, 19 Apr 2020 20:48:43 +1000
Subject: [PATCH 2/4] Add a new option `-Cbitcode-in-rlib`.

It defaults to true, but Cargo will set this to false whenever it can to
reduce compile times.
---
 src/doc/rustc/src/codegen-options/index.md | 20 ++++++++++++++++++++
 src/librustc_codegen_ssa/back/write.rs     |  3 ++-
 src/librustc_interface/tests.rs            |  4 ++++
 src/librustc_session/config.rs             | 10 ++++++++++
 src/librustc_session/options.rs            |  2 ++
 5 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index 5dda5ec2cb890..eb7e34ad9ed2e 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -387,6 +387,26 @@ It takes one of the following values:
 For example, for gcc flavor linkers, this issues the `-nodefaultlibs` flag to
 the linker.
 
+## bitcode-in-rlib
+
+This flag controls whether or not the compiler puts compressed LLVM bitcode
+into generated rlibs. It takes one of the following values:
+
+* `y`, `yes`, `on`, or no value: put bitcode in rlibs (the default).
+* `n`, `no`, or `off`: omit bitcode from rlibs.
+
+LLVM bitcode is only needed when link-time optimization (LTO) is being
+performed, but it is enabled by default for backwards compatibility reasons.
+
+The use of `-C bitcode-in-rlib=no` can significantly improve compile times and
+reduce generated file sizes. For these reasons, Cargo uses `-C
+bitcode-in-rlib=no` whenever possible. Likewise, if you are building directly
+with `rustc` we recommend using `-C bitcode-in-rlib=no` whenever you are not
+using LTO.
+
+If combined with `-C lto`, `-C bitcode-in-rlib=no` will cause `rustc` to abort
+at start-up, because the combination is invalid.
+
 [option-emit]: ../command-line-arguments.md#option-emit
 [option-o-optimize]: ../command-line-arguments.md#option-o-optimize
 [profile-guided optimization]: ../profile-guided-optimization.md
diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs
index d81a767abd447..db60760e4596f 100644
--- a/src/librustc_codegen_ssa/back/write.rs
+++ b/src/librustc_codegen_ssa/back/write.rs
@@ -378,7 +378,8 @@ pub struct CompiledModules {
 }
 
 fn need_crate_bitcode_for_rlib(sess: &Session) -> bool {
-    sess.crate_types.borrow().contains(&config::CrateType::Rlib)
+    sess.opts.cg.bitcode_in_rlib
+        && sess.crate_types.borrow().contains(&config::CrateType::Rlib)
         && sess.opts.output_types.contains_key(&OutputType::Exe)
 }
 
diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs
index 13c0c8f46b9b0..02fad11d9b879 100644
--- a/src/librustc_interface/tests.rs
+++ b/src/librustc_interface/tests.rs
@@ -505,6 +505,10 @@ fn test_codegen_options_tracking_hash() {
     opts = reference.clone();
     opts.cg.linker_plugin_lto = LinkerPluginLto::LinkerPluginAuto;
     assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+    opts = reference.clone();
+    opts.cg.bitcode_in_rlib = false;
+    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
 }
 
 #[test]
diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs
index 2513cfa73e56c..f6d7e091e00d6 100644
--- a/src/librustc_session/config.rs
+++ b/src/librustc_session/config.rs
@@ -1685,6 +1685,16 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         );
     }
 
+    if !cg.bitcode_in_rlib {
+        match cg.lto {
+            LtoCli::No | LtoCli::Unspecified => {}
+            LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
+                error_format,
+                "options `-C bitcode-in-rlib=no` and `-C lto` are incompatible",
+            ),
+        }
+    }
+
     let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
 
     let cg = cg;
diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs
index 5e17fc989856b..62eb3fca59531 100644
--- a/src/librustc_session/options.rs
+++ b/src/librustc_session/options.rs
@@ -703,6 +703,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
         "compile the program with profiling instrumentation"),
     profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
         "use the given `.profdata` file for profile-guided optimization"),
+    bitcode_in_rlib: bool = (true, parse_bool, [TRACKED],
+        "emit bitcode in rlibs (default: yes)"),
 }
 
 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,

From 2984799881aa6f7e443d48cf1322c9dbaa193ff8 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Mon, 20 Apr 2020 10:03:35 +1000
Subject: [PATCH 3/4] Add a simple test.

---
 src/test/ui/lto-and-no-bitcode-in-rlib.rs     | 3 +++
 src/test/ui/lto-and-no-bitcode-in-rlib.stderr | 2 ++
 2 files changed, 5 insertions(+)
 create mode 100644 src/test/ui/lto-and-no-bitcode-in-rlib.rs
 create mode 100644 src/test/ui/lto-and-no-bitcode-in-rlib.stderr

diff --git a/src/test/ui/lto-and-no-bitcode-in-rlib.rs b/src/test/ui/lto-and-no-bitcode-in-rlib.rs
new file mode 100644
index 0000000000000..1dd11ce3d2467
--- /dev/null
+++ b/src/test/ui/lto-and-no-bitcode-in-rlib.rs
@@ -0,0 +1,3 @@
+// compile-flags: -C lto -C bitcode-in-rlib=no
+
+fn main() {}
diff --git a/src/test/ui/lto-and-no-bitcode-in-rlib.stderr b/src/test/ui/lto-and-no-bitcode-in-rlib.stderr
new file mode 100644
index 0000000000000..2221fc1645d61
--- /dev/null
+++ b/src/test/ui/lto-and-no-bitcode-in-rlib.stderr
@@ -0,0 +1,2 @@
+error: options `-C bitcode-in-rlib=no` and `-C lto` are incompatible
+

From a105c5c2c01ea66f59bc6f3f9ade65016af56160 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Sun, 19 Apr 2020 21:17:38 +1000
Subject: [PATCH 4/4] Build libstd with `-Cbitcode-in-rlib=yes`.

So that the rlibs will work with both LTO and non-LTO builds.
---
 src/bootstrap/check.rs   |  2 +-
 src/bootstrap/compile.rs | 16 ++++++++++++++--
 src/bootstrap/doc.rs     |  2 +-
 src/bootstrap/test.rs    |  2 +-
 4 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index b76515763fbdb..586a362b5e3fe 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -45,7 +45,7 @@ impl Step for Std {
         let compiler = builder.compiler(0, builder.config.build);
 
         let mut cargo = builder.cargo(compiler, Mode::Std, target, cargo_subcommand(builder.kind));
-        std_cargo(builder, target, &mut cargo);
+        std_cargo(builder, target, compiler.stage, &mut cargo);
 
         builder.info(&format!("Checking std artifacts ({} -> {})", &compiler.host, target));
         run_cargo(
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index f44096af6dd53..06ab0a9c310af 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -86,7 +86,7 @@ impl Step for Std {
         target_deps.extend(copy_third_party_objects(builder, &compiler, target).into_iter());
 
         let mut cargo = builder.cargo(compiler, Mode::Std, target, "build");
-        std_cargo(builder, target, &mut cargo);
+        std_cargo(builder, target, compiler.stage, &mut cargo);
 
         builder.info(&format!(
             "Building stage{} std artifacts ({} -> {})",
@@ -164,7 +164,7 @@ fn copy_third_party_objects(
 
 /// Configure cargo to compile the standard library, adding appropriate env vars
 /// and such.
-pub fn std_cargo(builder: &Builder<'_>, target: Interned<String>, cargo: &mut Cargo) {
+pub fn std_cargo(builder: &Builder<'_>, target: Interned<String>, stage: u32, cargo: &mut Cargo) {
     if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
         cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
     }
@@ -231,6 +231,18 @@ pub fn std_cargo(builder: &Builder<'_>, target: Interned<String>, cargo: &mut Ca
             }
         }
     }
+
+    // By default, rustc uses `-Cbitcode-in-rlib=yes`, and Cargo overrides that
+    // with `-Cbitcode-in-rlib=no` for non-LTO builds. However, libstd must be
+    // built with bitcode so that the produced rlibs can be used for both LTO
+    // builds (which use bitcode) and non-LTO builds (which use object code).
+    // So we override the override here!
+    //
+    // But we don't bother for the stage 0 compiler because it's never used
+    // with LTO.
+    if stage >= 1 {
+        cargo.rustflag("-Cbitcode-in-rlib=yes");
+    }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 04da3cc1015b8..fc217a707db94 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -394,7 +394,7 @@ impl Step for Std {
 
         let run_cargo_rustdoc_for = |package: &str| {
             let mut cargo = builder.cargo(compiler, Mode::Std, target, "rustdoc");
-            compile::std_cargo(builder, target, &mut cargo);
+            compile::std_cargo(builder, target, compiler.stage, &mut cargo);
 
             // Keep a whitelist so we do not build internal stdlib crates, these will be
             // build by the rustc step later if enabled.
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 85c5d28bb8924..125563b7b6086 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1725,7 +1725,7 @@ impl Step for Crate {
         let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand());
         match mode {
             Mode::Std => {
-                compile::std_cargo(builder, target, &mut cargo);
+                compile::std_cargo(builder, target, compiler.stage, &mut cargo);
             }
             Mode::Rustc => {
                 builder.ensure(compile::Rustc { compiler, target });