]> git.lizzy.rs Git - rust.git/commitdiff
exclude `#![no_builtins]` crates from LTO
authorJorge Aparicio <japaricious@gmail.com>
Sat, 13 Aug 2016 02:15:42 +0000 (21:15 -0500)
committerJorge Aparicio <japaricious@gmail.com>
Sat, 13 Aug 2016 02:39:21 +0000 (21:39 -0500)
this prevents intrinsics like `memcpy` from being mis-optimized to
infinite recursive calls when LTO is used.

fixes #31544
closes #35540

src/librustc_trans/back/link.rs
src/librustc_trans/back/lto.rs

index a9f3d2f8a175485b954c016e6d2e207a7c4084ff..d17da74c87f399a014df7d24c644505f21a35005 100644 (file)
@@ -42,7 +42,7 @@
 use std::str;
 use flate;
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
+use syntax::attr::{self, AttrMetaMethods};
 use syntax_pos::Span;
 
 // RLIB LLVM-BYTECODE OBJECT LAYOUT
@@ -938,8 +938,10 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
             Linkage::NotLinked |
             Linkage::IncludedFromDylib => {}
             Linkage::Static => {
+                let is_a_no_builtins_crate =
+                    attr::contains_name(&sess.cstore.crate_attrs(cnum), "no_builtins");
                 add_static_crate(cmd, sess, tmpdir, crate_type,
-                                 &src.rlib.unwrap().0)
+                                 &src.rlib.unwrap().0, is_a_no_builtins_crate)
             }
             Linkage::Dynamic => {
                 add_dynamic_crate(cmd, sess, &src.dylib.unwrap().0)
@@ -963,12 +965,16 @@ fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str {
     // * 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.
@@ -988,7 +994,8 @@ fn add_static_crate(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
@@ -1012,7 +1019,8 @@ fn add_static_crate(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() {
index 69e4a50804fadc5ca4c7a5f917ff4452cf3e9987..016eb7c0cfb3ccdb2cebc5241485137dcf54213c 100644 (file)
@@ -17,6 +17,7 @@
 use rustc::util::common::time;
 use rustc::util::common::path2cstr;
 use back::write::{ModuleConfig, with_llvm_pmb};
+use syntax::attr;
 
 use libc;
 use flate;
@@ -52,7 +53,15 @@ 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| {
+        let is_a_no_builtins_crate =
+            attr::contains_name(&sess.cstore.crate_attrs(cnum), "no_builtins");
+
+        // `#![no_builtins]` crates don't participate in LTO.
+        if is_a_no_builtins_crate {
+            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)))