about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-08-16 10:13:18 -0700
committerGitHub <noreply@github.com>2016-08-16 10:13:18 -0700
commitdb7300d4149256023f9ede6828afef321170c07f (patch)
tree98cdaf68499b853bd8c97bb8a2d9fac918e69400
parent1de5b7e8c2cc276c0a55c5b9f387185e7d48522e (diff)
parente9964056964706fa3746c7e1135c34a45f2f467f (diff)
downloadrust-db7300d4149256023f9ede6828afef321170c07f.tar.gz
rust-db7300d4149256023f9ede6828afef321170c07f.zip
Auto merge of #35637 - japaric:no-builtins-lto, r=alexcrichton
exclude `#![no_builtins]` crates from LTO

this prevents intrinsics like `memcpy` from being mis-optimized to
infinite recursive calls when LTO is used.

fixes #31544
closes #35540

---

r? @alexcrichton
cc @Amanieu
-rw-r--r--src/librustc/middle/cstore.rs2
-rw-r--r--src/librustc_metadata/csearch.rs4
-rw-r--r--src/librustc_trans/back/link.rs24
-rw-r--r--src/librustc_trans/back/lto.rs7
-rw-r--r--src/test/run-make/no-builtins-lto/Makefile9
-rw-r--r--src/test/run-make/no-builtins-lto/main.rs13
-rw-r--r--src/test/run-make/no-builtins-lto/no_builtins.rs12
7 files changed, 61 insertions, 10 deletions
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index dec6f360847..481fd332404 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -227,6 +227,7 @@ pub trait CrateStore<'tcx> {
     fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option<DefId>;
     fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, String)>;
     fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId>;
+    fn is_no_builtins(&self, cnum: ast::CrateNum) -> bool;
 
     // resolve
     fn def_index_for_def_key(&self,
@@ -428,6 +429,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, String)>
         { bug!("native_libraries") }
     fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId> { bug!("reachable_ids") }
+    fn is_no_builtins(&self, cnum: ast::CrateNum) -> bool { bug!("is_no_builtins") }
 
     // resolve
     fn def_key(&self, def: DefId) -> hir_map::DefKey { bug!("def_key") }
diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs
index 7ee6e54a666..2cdbd1b8601 100644
--- a/src/librustc_metadata/csearch.rs
+++ b/src/librustc_metadata/csearch.rs
@@ -409,6 +409,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         decoder::get_reachable_ids(&cdata)
     }
 
+    fn is_no_builtins(&self, cnum: ast::CrateNum) -> bool {
+        attr::contains_name(&self.crate_attrs(cnum), "no_builtins")
+    }
+
     fn def_index_for_def_key(&self,
                              cnum: ast::CrateNum,
                              def: DefKey)
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index f17d1a7f1cf..68a176a3781 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -940,7 +940,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
             Linkage::IncludedFromDylib => {}
             Linkage::Static => {
                 add_static_crate(cmd, sess, tmpdir, crate_type,
-                                 &src.rlib.unwrap().0)
+                                 &src.rlib.unwrap().0, sess.cstore.is_no_builtins(cnum))
             }
             Linkage::Dynamic => {
                 add_dynamic_crate(cmd, sess, &src.dylib.unwrap().0)
@@ -964,12 +964,16 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
     // * For LTO, we remove upstream object files.
     // * For dylibs we remove metadata and bytecode from upstream rlibs
     //
-    // When performing LTO, all of the bytecode from the upstream libraries has
-    // already been included in our object file output. As a result we need to
-    // remove the object files in the upstream libraries so the linker doesn't
-    // try to include them twice (or whine about duplicate symbols). We must
-    // continue to include the rest of the rlib, however, as it may contain
-    // static native libraries which must be linked in.
+    // When performing LTO, almost(*) all of the bytecode from the upstream
+    // libraries has already been included in our object file output. As a
+    // result we need to remove the object files in the upstream libraries so
+    // the linker doesn't try to include them twice (or whine about duplicate
+    // symbols). We must continue to include the rest of the rlib, however, as
+    // it may contain static native libraries which must be linked in.
+    //
+    // (*) Crates marked with `#![no_builtins]` don't participate in LTO and
+    // their bytecode wasn't included. The object files in those libraries must
+    // still be passed to the linker.
     //
     // When making a dynamic library, linkers by default don't include any
     // object files in an archive if they're not necessary to resolve the link.
@@ -989,7 +993,8 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
                         sess: &Session,
                         tmpdir: &Path,
                         crate_type: config::CrateType,
-                        cratepath: &Path) {
+                        cratepath: &Path,
+                        is_a_no_builtins_crate: bool) {
         if !sess.lto() && crate_type != config::CrateTypeDylib {
             cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
             return
@@ -1013,7 +1018,8 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
                 }
                 let canonical = f.replace("-", "_");
                 let canonical_name = name.replace("-", "_");
-                if sess.lto() && canonical.starts_with(&canonical_name) &&
+                if sess.lto() && !is_a_no_builtins_crate &&
+                   canonical.starts_with(&canonical_name) &&
                    canonical.ends_with(".o") {
                     let num = &f[name.len()..f.len() - 2];
                     if num.len() > 0 && num[1..].parse::<u32>().is_ok() {
diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs
index 69e4a50804f..522864c6ec3 100644
--- a/src/librustc_trans/back/lto.rs
+++ b/src/librustc_trans/back/lto.rs
@@ -52,7 +52,12 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
     // For each of our upstream dependencies, find the corresponding rlib and
     // load the bitcode from the archive. Then merge it into the current LLVM
     // module that we've got.
-    link::each_linked_rlib(sess, &mut |_, path| {
+    link::each_linked_rlib(sess, &mut |cnum, path| {
+        // `#![no_builtins]` crates don't participate in LTO.
+        if sess.cstore.is_no_builtins(cnum) {
+            return;
+        }
+
         let archive = ArchiveRO::open(&path).expect("wanted an rlib");
         let bytecodes = archive.iter().filter_map(|child| {
             child.ok().and_then(|c| c.name().map(|name| (name, c)))
diff --git a/src/test/run-make/no-builtins-lto/Makefile b/src/test/run-make/no-builtins-lto/Makefile
new file mode 100644
index 00000000000..3f70de5f76c
--- /dev/null
+++ b/src/test/run-make/no-builtins-lto/Makefile
@@ -0,0 +1,9 @@
+-include ../tools.mk
+
+all:
+	# Compile a `#![no_builtins]` rlib crate
+	$(RUSTC) no_builtins.rs
+	# Build an executable that depends on that crate using LTO. The no_builtins crate doesn't
+	# participate in LTO, so its rlib must be explicitly linked into the final binary. Verify this by
+	# grepping the linker arguments.
+	$(RUSTC) main.rs -C lto -Z print-link-args | grep 'libno_builtins.rlib'
diff --git a/src/test/run-make/no-builtins-lto/main.rs b/src/test/run-make/no-builtins-lto/main.rs
new file mode 100644
index 00000000000..e960c726a98
--- /dev/null
+++ b/src/test/run-make/no-builtins-lto/main.rs
@@ -0,0 +1,13 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate no_builtins;
+
+fn main() {}
diff --git a/src/test/run-make/no-builtins-lto/no_builtins.rs b/src/test/run-make/no-builtins-lto/no_builtins.rs
new file mode 100644
index 00000000000..be95e7c5521
--- /dev/null
+++ b/src/test/run-make/no-builtins-lto/no_builtins.rs
@@ -0,0 +1,12 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "lib"]
+#![no_builtins]