]> git.lizzy.rs Git - rust.git/commitdiff
Autodetect the type of allocator crate used
authorMichal 'vorner' Vaner <vorner@vorner.cz>
Sun, 10 Sep 2017 17:59:42 +0000 (19:59 +0200)
committerMichal 'vorner' Vaner <vorner@vorner.cz>
Sun, 10 Sep 2017 17:59:42 +0000 (19:59 +0200)
Annotate the allocator crates (allocator_system, allocator_jemalloc) by
the type of allocator they are. If one is requested as an exe allocator,
detect its type by the flags.

This has the effect that using this (de jure wrong) configuration in the
target spec works instead of producing a really unhelpful and arcane
linker error:

"exe-allocation-crate": "alloc_system"

Fixes #43524.

src/liballoc_jemalloc/lib.rs
src/liballoc_system/lib.rs
src/librustc_metadata/creader.rs

index efefabc974c7fb0c068a422e487de10318daf86d..d153f19c4622f021d78dee45d2453b22b10dc9a5 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![no_std]
+#![allow(unused_attributes)]
 #![unstable(feature = "alloc_jemalloc",
             reason = "this library is unlikely to be stabilized in its current \
                       form or name",
 #![feature(libc)]
 #![feature(linkage)]
 #![feature(staged_api)]
+#![feature(rustc_attrs)]
 #![cfg_attr(dummy_jemalloc, allow(dead_code, unused_extern_crates))]
 #![cfg_attr(not(dummy_jemalloc), feature(allocator_api))]
+#![rustc_alloc_kind = "exe"]
 
 extern crate alloc;
 extern crate alloc_system;
index 599d79104c3b073b51e7ff30c47f0279f69650d3..2eb659699eb9b4839c3615c41c99d47686c6cb22 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![no_std]
+#![allow(unused_attributes)]
 #![deny(warnings)]
 #![unstable(feature = "alloc_system",
             reason = "this library is unlikely to be stabilized in its current \
@@ -19,7 +20,9 @@
 #![feature(alloc)]
 #![feature(core_intrinsics)]
 #![feature(staged_api)]
+#![feature(rustc_attrs)]
 #![cfg_attr(any(unix, target_os = "redox"), feature(libc))]
+#![rustc_alloc_kind = "lib"]
 
 // The minimum alignment guaranteed by the architecture. This value is used to
 // add fast paths for low alignment values. In practice, the alignment is a
index 603c74c2ae4c6f659a549b9f0905f5467af6df9a..dc6c260ec7174abdeab0d398c3f9586794609d19 100644 (file)
@@ -15,7 +15,7 @@
 use native_libs::relevant_lib;
 use schema::CrateRoot;
 
-use rustc::hir::def_id::{CrateNum, DefIndex};
+use rustc::hir::def_id::{CrateNum, DefIndex, CRATE_DEF_INDEX};
 use rustc::hir::svh::Svh;
 use rustc::middle::allocator::AllocatorKind;
 use rustc::middle::cstore::DepKind;
@@ -944,53 +944,80 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
         // (need_lib_alloc and prefer_dynamic) then we select `None`, and if the
         // exe allocation crate doesn't exist for this target then we also
         // select `None`.
-        let exe_allocation_crate =
+        let exe_allocation_crate_data =
             if need_lib_alloc && !self.sess.opts.cg.prefer_dynamic {
                 None
             } else {
-                self.sess.target.target.options.exe_allocation_crate.as_ref()
+                self.sess
+                    .target
+                    .target
+                    .options
+                    .exe_allocation_crate
+                    .as_ref()
+                    .map(|name| {
+                        // We've determined that we're injecting an "exe allocator" which means
+                        // that we're going to load up a whole new crate. An example of this is
+                        // that we're producing a normal binary on Linux which means we need to
+                        // load the `alloc_jemalloc` crate to link as an allocator.
+                        let name = Symbol::intern(name);
+                        let (cnum, data) = self.resolve_crate(&None,
+                                                              name,
+                                                              name,
+                                                              None,
+                                                              DUMMY_SP,
+                                                              PathKind::Crate,
+                                                              DepKind::Implicit);
+                        self.sess.injected_allocator.set(Some(cnum));
+                        data
+                    })
             };
 
-        match exe_allocation_crate {
-            // We've determined that we're injecting an "exe allocator" which
-            // means that we're going to load up a whole new crate. An example
-            // of this is that we're producing a normal binary on Linux which
-            // means we need to load the `alloc_jemalloc` crate to link as an
-            // allocator.
-            Some(krate) => {
-                self.sess.allocator_kind.set(Some(AllocatorKind::DefaultExe));
-                let name = Symbol::intern(krate);
-                let dep_kind = DepKind::Implicit;
-                let (cnum, _data) =
-                    self.resolve_crate(&None,
-                                       name,
-                                       name,
-                                       None,
-                                       DUMMY_SP,
-                                       PathKind::Crate, dep_kind);
-                self.sess.injected_allocator.set(Some(cnum));
+        let allocation_crate_data = exe_allocation_crate_data.or_else(|| {
+            if attr::contains_name(&krate.attrs, "default_lib_allocator") {
+                // Prefer self as the allocator if there's a collision
+                return None;
             }
-
             // We're not actually going to inject an allocator, we're going to
             // require that something in our crate graph is the default lib
             // allocator. This is typically libstd, so this'll rarely be an
             // error.
-            None => {
-                self.sess.allocator_kind.set(Some(AllocatorKind::DefaultLib));
-                let mut found_lib_allocator =
-                    attr::contains_name(&krate.attrs, "default_lib_allocator");
-                self.cstore.iter_crate_data(|_, data| {
-                    if !found_lib_allocator {
-                        if data.has_default_lib_allocator() {
-                            found_lib_allocator = true;
-                        }
+            let mut allocator = None;
+            self.cstore.iter_crate_data(|_, data| {
+                if allocator.is_none() && data.has_default_lib_allocator() {
+                    allocator = Some(data.clone());
+                }
+            });
+            allocator
+        });
+
+        match allocation_crate_data {
+            Some(data) => {
+                // We have an allocator. We detect separately what kind it is, to allow for some
+                // flexibility in misconfiguration.
+                let attrs = data.get_item_attrs(CRATE_DEF_INDEX);
+                let kind_interned = attr::first_attr_value_str_by_name(&attrs, "rustc_alloc_kind")
+                    .map(Symbol::as_str);
+                let kind_str = kind_interned
+                    .as_ref()
+                    .map(|s| s as &str);
+                let alloc_kind = match kind_str {
+                    None |
+                    Some("lib") => AllocatorKind::DefaultLib,
+                    Some("exe") => AllocatorKind::DefaultExe,
+                    Some(other) => {
+                        self.sess.err(&format!("Allocator kind {} not known", other));
+                        return;
                     }
-                });
-                if found_lib_allocator {
-                    return
+                };
+                self.sess.allocator_kind.set(Some(alloc_kind));
+            },
+            None => {
+                if !attr::contains_name(&krate.attrs, "default_lib_allocator") {
+                    self.sess.err("no #[default_lib_allocator] found but one is \
+                                   required; is libstd not linked?");
+                    return;
                 }
-                self.sess.err("no #[default_lib_allocator] found but one is \
-                               required; is libstd not linked?");
+                self.sess.allocator_kind.set(Some(AllocatorKind::DefaultLib));
             }
         }