]> git.lizzy.rs Git - rust.git/commitdiff
rustc: Remove a number of mutable fields in cstore
authorAlex Crichton <alex@alexcrichton.com>
Wed, 30 Aug 2017 21:48:57 +0000 (14:48 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Tue, 5 Sep 2017 14:37:28 +0000 (07:37 -0700)
This commit started by moving methods from `CrateStore` to queries, but it ended
up necessitating some deeper refactorings to move more items in general to
queries.

Before this commit the *resolver* would walk over the AST and process foreign
modules (`extern { .. }` blocks) and collect `#[link]` annotations. It would
then also process the command line `-l` directives and such. This information
was then stored as precalculated lists in the `CrateStore` object for iterating
over later.

After this, commit, however, this pass no longer happens during resolution but
now instead happens through queries. A query for the linked libraries of a crate
will crawl the crate for `extern` blocks and then process the linkage
annotations at that time.

19 files changed:
src/librustc/dep_graph/dep_node.rs
src/librustc/middle/cstore.rs
src/librustc/ty/maps.rs
src/librustc_driver/driver.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_metadata/diagnostics.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/lib.rs
src/librustc_metadata/link_args.rs [new file with mode: 0644]
src/librustc_metadata/native_libs.rs [new file with mode: 0644]
src/librustc_trans/back/link.rs
src/librustc_trans/base.rs
src/librustc_trans/callee.rs
src/librustc_trans/consts.rs
src/librustc_trans/lib.rs
src/test/compile-fail/empty-linkname.rs
src/test/compile-fail/feature-gate-static-nobundle.rs

index a3e38e5b8ad77288905174c3dd3c2038284e1b2f..9646d3a7b3bf21005766d52691345e34aded1ab4 100644 (file)
@@ -545,6 +545,11 @@ pub fn to_dep_node(self, tcx: TyCtxt, kind: DepKind) -> DepNode {
 
     [] ImplementationsOfTrait { krate: CrateNum, trait_id: DefId },
     [] AllTraitImplementations(CrateNum),
+
+    [] IsDllimportForeignItem(DefId),
+    [] IsStaticallyIncludedForeignItem(DefId),
+    [] NativeLibraryKind(DefId),
+    [] LinkArgs,
 );
 
 trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
index 495b357b613d8409abc5b4bf1f7a51a5e6a8cf92..97b047474101ffeb2bc09713b99c57035bc4e3b7 100644 (file)
@@ -236,10 +236,6 @@ pub trait CrateStore {
     // trait/impl-item info
     fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem;
 
-    // flags
-    fn is_dllimport_foreign_item(&self, def: DefId) -> bool;
-    fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool;
-
     // crate metadata
     fn dep_kind(&self, cnum: CrateNum) -> DepKind;
     fn export_macros(&self, cnum: CrateNum);
@@ -265,8 +261,6 @@ fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
     // This is basically a 1-based range of ints, which is a little
     // silly - I may fix that.
     fn crates(&self) -> Vec<CrateNum>;
-    fn used_libraries(&self) -> Vec<NativeLibrary>;
-    fn used_link_args(&self) -> Vec<String>;
 
     // utility functions
     fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>;
@@ -329,10 +323,6 @@ fn item_generics_cloned(&self, def: DefId) -> ty::Generics
     fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem
         { bug!("associated_item_cloned") }
 
-    // flags
-    fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false }
-    fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool { false }
-
     // crate metadata
     fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>
         { bug!("lang_items") }
@@ -368,8 +358,6 @@ fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
     // This is basically a 1-based range of ints, which is a little
     // silly - I may fix that.
     fn crates(&self) -> Vec<CrateNum> { vec![] }
-    fn used_libraries(&self) -> Vec<NativeLibrary> { vec![] }
-    fn used_link_args(&self) -> Vec<String> { vec![] }
 
     // utility functions
     fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>
index 41caaa30b5c8d7fd5756120dd984d5806766ba3c..1312bd3a7a6beaaf38f322262bb61c82b266c559 100644 (file)
@@ -17,6 +17,7 @@
 use lint;
 use middle::const_val;
 use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary};
+use middle::cstore::NativeLibraryKind;
 use middle::privacy::AccessLevels;
 use middle::region;
 use mir;
@@ -642,6 +643,12 @@ fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
     }
 }
 
+impl<'tcx> QueryDescription for queries::link_args<'tcx> {
+    fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+        format!("looking up link arguments for a crate")
+    }
+}
+
 // If enabled, send a message to the profile-queries thread
 macro_rules! profq_msg {
     ($tcx:expr, $msg:expr) => {
@@ -1230,6 +1237,12 @@ fn default() -> Self {
         -> Rc<Vec<DefId>>,
     [] fn all_trait_implementations: AllTraitImplementations(CrateNum)
         -> Rc<Vec<DefId>>,
+
+    [] is_dllimport_foreign_item: IsDllimportForeignItem(DefId) -> bool,
+    [] is_statically_included_foreign_item: IsStaticallyIncludedForeignItem(DefId) -> bool,
+    [] native_library_kind: NativeLibraryKind(DefId)
+        -> Option<NativeLibraryKind>,
+    [] link_args: link_args_node(CrateNum) -> Rc<Vec<String>>,
 }
 
 fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
@@ -1315,3 +1328,7 @@ fn implementations_of_trait_node<'tcx>((krate, trait_id): (CrateNum, DefId))
 {
     DepConstructor::ImplementationsOfTrait { krate, trait_id }
 }
+
+fn link_args_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
+    DepConstructor::LinkArgs
+}
index 000d89241a427b756ba8b578d7c0b6ea94b3d9c9..10b591432eeede6df36781a5878cd8c8ac812d79 100644 (file)
@@ -694,7 +694,6 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
     // this back at some point.
     let _ignore = sess.dep_graph.in_ignore();
     let mut crate_loader = CrateLoader::new(sess, &cstore, crate_name);
-    crate_loader.preprocess(&krate);
     let resolver_arenas = Resolver::arenas();
     let mut resolver = Resolver::new(sess,
                                      &krate,
index 4c25d03b441eaba7a9961c9804e4484a7cb0714f..aba5949c5a74975a32b87a93bceda1d9310d9bc7 100644 (file)
@@ -12,6 +12,7 @@
 
 use cstore::{self, CStore, CrateSource, MetadataBlob};
 use locator::{self, CratePaths};
+use native_libs::relevant_lib;
 use schema::{CrateRoot, Tracked};
 
 use rustc::hir::def_id::{CrateNum, DefIndex};
@@ -26,7 +27,6 @@
 use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
 use rustc::util::common::record_time;
 use rustc::util::nodemap::FxHashSet;
-use rustc::middle::cstore::NativeLibrary;
 use rustc::hir::map::Definitions;
 
 use std::cell::{RefCell, Cell};
 use std::{cmp, fs};
 
 use syntax::ast;
-use syntax::abi::Abi;
 use syntax::attr;
 use syntax::ext::base::SyntaxExtension;
-use syntax::feature_gate::{self, GateIssue};
 use syntax::symbol::Symbol;
 use syntax::visit;
 use syntax_pos::{Span, DUMMY_SP};
@@ -81,56 +79,6 @@ struct ExternCrateInfo {
     dep_kind: DepKind,
 }
 
-fn register_native_lib(sess: &Session,
-                       cstore: &CStore,
-                       span: Option<Span>,
-                       lib: NativeLibrary) {
-    if lib.name.as_str().is_empty() {
-        match span {
-            Some(span) => {
-                struct_span_err!(sess, span, E0454,
-                                 "#[link(name = \"\")] given with empty name")
-                    .span_label(span, "empty name given")
-                    .emit();
-            }
-            None => {
-                sess.err("empty library name given via `-l`");
-            }
-        }
-        return
-    }
-    let is_osx = sess.target.target.options.is_like_osx;
-    if lib.kind == cstore::NativeFramework && !is_osx {
-        let msg = "native frameworks are only available on macOS targets";
-        match span {
-            Some(span) => span_err!(sess, span, E0455, "{}", msg),
-            None => sess.err(msg),
-        }
-    }
-    if lib.cfg.is_some() && !sess.features.borrow().link_cfg {
-        feature_gate::emit_feature_err(&sess.parse_sess,
-                                       "link_cfg",
-                                       span.unwrap(),
-                                       GateIssue::Language,
-                                       "is feature gated");
-    }
-    if lib.kind == cstore::NativeStaticNobundle && !sess.features.borrow().static_nobundle {
-        feature_gate::emit_feature_err(&sess.parse_sess,
-                                       "static_nobundle",
-                                       span.unwrap(),
-                                       GateIssue::Language,
-                                       "kind=\"static-nobundle\" is feature gated");
-    }
-    cstore.add_used_library(lib);
-}
-
-fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
-    match lib.cfg {
-        Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None),
-        None => true,
-    }
-}
-
 // Extra info about a crate loaded for plugins or exported macros.
 struct ExtensionCrate {
     metadata: PMDSource,
@@ -721,33 +669,6 @@ pub fn find_plugin_registrar(&mut self,
         }
     }
 
-    fn get_foreign_items_of_kind(&self, kind: cstore::NativeLibraryKind) -> Vec<DefIndex> {
-        let mut items = vec![];
-        let libs = self.cstore.get_used_libraries();
-        for lib in libs.borrow().iter() {
-            if relevant_lib(self.sess, lib) && lib.kind == kind {
-                items.extend(&lib.foreign_items);
-            }
-        }
-        items
-    }
-
-    fn register_statically_included_foreign_items(&mut self) {
-        for id in self.get_foreign_items_of_kind(cstore::NativeStatic) {
-            self.cstore.add_statically_included_foreign_item(id);
-        }
-        for id in self.get_foreign_items_of_kind(cstore::NativeStaticNobundle) {
-            self.cstore.add_statically_included_foreign_item(id);
-        }
-    }
-
-    fn register_dllimport_foreign_items(&mut self) {
-        let mut dllimports = self.cstore.dllimport_foreign_items.borrow_mut();
-        for id in self.get_foreign_items_of_kind(cstore::NativeUnknown) {
-            dllimports.insert(id);
-        }
-    }
-
     fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
         // If we're only compiling an rlib, then there's no need to select a
         // panic runtime, so we just skip this section entirely.
@@ -1152,84 +1073,6 @@ fn inject_dependency_if(&self,
     }
 }
 
-impl<'a> CrateLoader<'a> {
-    pub fn preprocess(&mut self, krate: &ast::Crate) {
-        for attr in &krate.attrs {
-            if attr.path == "link_args" {
-                if let Some(linkarg) = attr.value_str() {
-                    self.cstore.add_used_link_args(&linkarg.as_str());
-                }
-            }
-        }
-    }
-
-    fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod,
-                           definitions: &Definitions) {
-        if fm.abi == Abi::Rust || fm.abi == Abi::RustIntrinsic || fm.abi == Abi::PlatformIntrinsic {
-            return;
-        }
-
-        // First, add all of the custom #[link_args] attributes
-        for m in i.attrs.iter().filter(|a| a.check_name("link_args")) {
-            if let Some(linkarg) = m.value_str() {
-                self.cstore.add_used_link_args(&linkarg.as_str());
-            }
-        }
-
-        // Next, process all of the #[link(..)]-style arguments
-        for m in i.attrs.iter().filter(|a| a.check_name("link")) {
-            let items = match m.meta_item_list() {
-                Some(item) => item,
-                None => continue,
-            };
-            let kind = items.iter().find(|k| {
-                k.check_name("kind")
-            }).and_then(|a| a.value_str()).map(Symbol::as_str);
-            let kind = match kind.as_ref().map(|s| &s[..]) {
-                Some("static") => cstore::NativeStatic,
-                Some("static-nobundle") => cstore::NativeStaticNobundle,
-                Some("dylib") => cstore::NativeUnknown,
-                Some("framework") => cstore::NativeFramework,
-                Some(k) => {
-                    struct_span_err!(self.sess, m.span, E0458,
-                              "unknown kind: `{}`", k)
-                        .span_label(m.span, "unknown kind").emit();
-                    cstore::NativeUnknown
-                }
-                None => cstore::NativeUnknown
-            };
-            let n = items.iter().find(|n| {
-                n.check_name("name")
-            }).and_then(|a| a.value_str());
-            let n = match n {
-                Some(n) => n,
-                None => {
-                    struct_span_err!(self.sess, m.span, E0459,
-                                     "#[link(...)] specified without `name = \"foo\"`")
-                        .span_label(m.span, "missing `name` argument").emit();
-                    Symbol::intern("foo")
-                }
-            };
-            let cfg = items.iter().find(|k| {
-                k.check_name("cfg")
-            }).and_then(|a| a.meta_item_list());
-            let cfg = cfg.map(|list| {
-                list[0].meta_item().unwrap().clone()
-            });
-            let foreign_items = fm.items.iter()
-                .map(|it| definitions.opt_def_index(it.id).unwrap())
-                .collect();
-            let lib = NativeLibrary {
-                name: n,
-                kind,
-                cfg,
-                foreign_items,
-            };
-            register_native_lib(self.sess, self.cstore, Some(m.span), lib);
-        }
-    }
-}
-
 impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
     fn postprocess(&mut self, krate: &ast::Crate) {
         // inject the sanitizer runtime before the allocator runtime because all
@@ -1242,72 +1085,10 @@ fn postprocess(&mut self, krate: &ast::Crate) {
         if log_enabled!(log::LogLevel::Info) {
             dump_crates(&self.cstore);
         }
-
-        // Process libs passed on the command line
-        // First, check for errors
-        let mut renames = FxHashSet();
-        for &(ref name, ref new_name, _) in &self.sess.opts.libs {
-            if let &Some(ref new_name) = new_name {
-                if new_name.is_empty() {
-                    self.sess.err(
-                        &format!("an empty renaming target was specified for library `{}`",name));
-                } else if !self.cstore.get_used_libraries().borrow().iter()
-                                                           .any(|lib| lib.name == name as &str) {
-                    self.sess.err(&format!("renaming of the library `{}` was specified, \
-                                            however this crate contains no #[link(...)] \
-                                            attributes referencing this library.", name));
-                } else if renames.contains(name) {
-                    self.sess.err(&format!("multiple renamings were specified for library `{}` .",
-                                            name));
-                } else {
-                    renames.insert(name);
-                }
-            }
-        }
-        // Update kind and, optionally, the name of all native libaries
-        // (there may be more than one) with the specified name.
-        for &(ref name, ref new_name, kind) in &self.sess.opts.libs {
-            let mut found = false;
-            for lib in self.cstore.get_used_libraries().borrow_mut().iter_mut() {
-                if lib.name == name as &str {
-                    let mut changed = false;
-                    if let Some(k) = kind {
-                        lib.kind = k;
-                        changed = true;
-                    }
-                    if let &Some(ref new_name) = new_name {
-                        lib.name = Symbol::intern(new_name);
-                        changed = true;
-                    }
-                    if !changed {
-                        self.sess.warn(&format!("redundant linker flag specified for library `{}`",
-                                                name));
-                    }
-
-                    found = true;
-                }
-            }
-            if !found {
-                // Add if not found
-                let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
-                let lib = NativeLibrary {
-                    name: Symbol::intern(new_name.unwrap_or(name)),
-                    kind: if let Some(k) = kind { k } else { cstore::NativeUnknown },
-                    cfg: None,
-                    foreign_items: Vec::new(),
-                };
-                register_native_lib(self.sess, self.cstore, None, lib);
-            }
-        }
-        self.register_statically_included_foreign_items();
-        self.register_dllimport_foreign_items();
     }
 
     fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) {
         match item.node {
-            ast::ItemKind::ForeignMod(ref fm) => {
-                self.process_foreign_mod(item, fm, definitions)
-            },
             ast::ItemKind::ExternCrate(_) => {
                 let info = self.extract_crate_info(item).unwrap();
                 let (cnum, ..) = self.resolve_crate(
index 1933949e92264adda6c3a116c0dbfb82f4148244..543d257018d0aaf0b03dd3735d9c2a728daba439 100644 (file)
@@ -14,7 +14,7 @@
 use schema::{self, Tracked};
 
 use rustc::dep_graph::DepGraph;
-use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefIndex, DefId};
+use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, DefId};
 use rustc::hir::map::definitions::{DefPathTable, GlobalMetaDataKind};
 use rustc::hir::svh::Svh;
 use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader};
@@ -95,10 +95,6 @@ pub struct CStore {
     metas: RefCell<FxHashMap<CrateNum, Rc<CrateMetadata>>>,
     /// Map from NodeId's of local extern crate statements to crate numbers
     extern_mod_crate_map: RefCell<NodeMap<CrateNum>>,
-    used_libraries: RefCell<Vec<NativeLibrary>>,
-    used_link_args: RefCell<Vec<String>>,
-    statically_included_foreign_items: RefCell<FxHashSet<DefIndex>>,
-    pub dllimport_foreign_items: RefCell<FxHashSet<DefIndex>>,
     pub visible_parent_map: RefCell<DefIdMap<DefId>>,
     pub metadata_loader: Box<MetadataLoader>,
 }
@@ -109,10 +105,6 @@ pub fn new(dep_graph: &DepGraph, metadata_loader: Box<MetadataLoader>) -> CStore
             dep_graph: dep_graph.clone(),
             metas: RefCell::new(FxHashMap()),
             extern_mod_crate_map: RefCell::new(FxHashMap()),
-            used_libraries: RefCell::new(Vec::new()),
-            used_link_args: RefCell::new(Vec::new()),
-            statically_included_foreign_items: RefCell::new(FxHashSet()),
-            dllimport_foreign_items: RefCell::new(FxHashSet()),
             visible_parent_map: RefCell::new(FxHashMap()),
             metadata_loader,
         }
@@ -208,38 +200,10 @@ pub fn do_get_used_crates(&self,
         libs
     }
 
-    pub fn add_used_library(&self, lib: NativeLibrary) {
-        assert!(!lib.name.as_str().is_empty());
-        self.used_libraries.borrow_mut().push(lib);
-    }
-
-    pub fn get_used_libraries(&self) -> &RefCell<Vec<NativeLibrary>> {
-        &self.used_libraries
-    }
-
-    pub fn add_used_link_args(&self, args: &str) {
-        for s in args.split(' ').filter(|s| !s.is_empty()) {
-            self.used_link_args.borrow_mut().push(s.to_string());
-        }
-    }
-
-    pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell<Vec<String>> {
-        &self.used_link_args
-    }
-
     pub fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) {
         self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
     }
 
-    pub fn add_statically_included_foreign_item(&self, id: DefIndex) {
-        self.statically_included_foreign_items.borrow_mut().insert(id);
-    }
-
-    pub fn do_is_statically_included_foreign_item(&self, def_id: DefId) -> bool {
-        assert!(def_id.krate == LOCAL_CRATE);
-        self.statically_included_foreign_items.borrow().contains(&def_id.index)
-    }
-
     pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
         self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
     }
index 67fe62d69beea6ef4111136603bbf489a12849af..3f7a314c755d60403ab544146c124de31aceef0a 100644 (file)
 
 use cstore;
 use encoder;
+use link_args;
+use native_libs;
 use schema;
 
 use rustc::ty::maps::QueryConfig;
 use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind,
-                            NativeLibrary, MetadataLoader, LinkMeta,
+                            MetadataLoader, LinkMeta,
                             LinkagePreference, LoadedMacro, EncodedMetadata,
-                            EncodedMetadataHashes};
+                            EncodedMetadataHashes, NativeLibraryKind};
 use rustc::hir::def;
 use rustc::middle::lang_items;
 use rustc::session::Session;
 use rustc::ty::{self, TyCtxt};
 use rustc::ty::maps::Providers;
-use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, CRATE_DEF_INDEX};
 use rustc::hir::map::{DefKey, DefPath, DefPathHash};
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::hir::map::definitions::{DefPathTable, GlobalMetaDataKind};
@@ -199,6 +201,10 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
         cdata.get_implementations_for_trait(None, &tcx.dep_graph, &mut result);
         Rc::new(result)
     }
+
+    is_dllimport_foreign_item => {
+        cdata.is_dllimport_foreign_item(def_id.index, &tcx.dep_graph)
+    }
 }
 
 pub fn provide_local<'tcx>(providers: &mut Providers<'tcx>) {
@@ -215,6 +221,31 @@ fn is_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
 
     *providers = Providers {
         is_const_fn,
+        is_dllimport_foreign_item: |tcx, id| {
+            tcx.native_library_kind(id) == Some(NativeLibraryKind::NativeUnknown)
+        },
+        is_statically_included_foreign_item: |tcx, id| {
+            match tcx.native_library_kind(id) {
+                Some(NativeLibraryKind::NativeStatic) |
+                Some(NativeLibraryKind::NativeStaticNobundle) => true,
+                _ => false,
+            }
+        },
+        native_library_kind: |tcx, id| {
+            tcx.native_libraries(id.krate)
+                .iter()
+                .filter(|lib| native_libs::relevant_lib(&tcx.sess, lib))
+                .find(|l| l.foreign_items.contains(&id.index))
+                .map(|l| l.kind)
+        },
+        native_libraries: |tcx, cnum| {
+            assert_eq!(cnum, LOCAL_CRATE);
+            Rc::new(native_libs::collect(tcx))
+        },
+        link_args: |tcx, cnum| {
+            assert_eq!(cnum, LOCAL_CRATE);
+            Rc::new(link_args::collect(tcx))
+        },
         ..*providers
     };
 }
@@ -244,20 +275,6 @@ fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem
         self.get_crate_data(def.krate).get_associated_item(def.index)
     }
 
-    fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool
-    {
-        self.do_is_statically_included_foreign_item(def_id)
-    }
-
-    fn is_dllimport_foreign_item(&self, def_id: DefId) -> bool {
-        if def_id.krate == LOCAL_CRATE {
-            self.dllimport_foreign_items.borrow().contains(&def_id.index)
-        } else {
-            self.get_crate_data(def_id.krate)
-                .is_dllimport_foreign_item(def_id.index, &self.dep_graph)
-        }
-    }
-
     fn dep_kind(&self, cnum: CrateNum) -> DepKind
     {
         let data = self.get_crate_data(cnum);
@@ -400,15 +417,6 @@ fn crates(&self) -> Vec<CrateNum>
         result
     }
 
-    fn used_libraries(&self) -> Vec<NativeLibrary>
-    {
-        self.get_used_libraries().borrow().clone()
-    }
-
-    fn used_link_args(&self) -> Vec<String>
-    {
-        self.get_used_link_args().borrow().clone()
-    }
     fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>
     {
         self.do_get_used_crates(prefer)
index 1fa1a896dd6b65b48eca7335b0fb3034563567cf..8ff2acbac9d5fc45a90593952bd10fc3165ee428 100644 (file)
@@ -14,7 +14,7 @@
 E0454: r##"
 A link name was given with an empty name. Erroneous code example:
 
-```compile_fail,E0454
+```ignore (cannot-test-this-because-???)
 #[link(name = "")] extern {} // error: #[link(name = "")] given with empty name
 ```
 
@@ -51,7 +51,7 @@
 E0458: r##"
 An unknown "kind" was specified for a link attribute. Erroneous code example:
 
-```compile_fail,E0458
+```ignore (cannot-test-this-because-???)
 #[link(kind = "wonderful_unicorn")] extern {}
 // error: unknown kind: `wonderful_unicorn`
 ```
@@ -67,7 +67,7 @@
 E0459: r##"
 A link was used without a name parameter. Erroneous code example:
 
-```compile_fail,E0459
+```ignore (cannot-test-this-because-???)
 #[link(kind = "dylib")] extern {}
 // error: #[link(...)] specified without `name = "foo"`
 ```
index 76ad9555d7e4ab8d03f7183592c8d83b358308f2..4fd610ac79b82f176383201490d913512fde24bd 100644 (file)
@@ -1283,8 +1283,8 @@ fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq<ast::Attrib
     }
 
     fn encode_native_libraries(&mut self, _: ()) -> LazySeq<NativeLibrary> {
-        let used_libraries = self.tcx.sess.cstore.used_libraries();
-        self.lazy_seq(used_libraries)
+        let used_libraries = self.tcx.native_libraries(LOCAL_CRATE);
+        self.lazy_seq(used_libraries.iter().cloned())
     }
 
     fn encode_crate_deps(&mut self, _: ()) -> LazySeq<CrateDep> {
index f4e6f57c43777e8cf4a3186ab312404f28c7181f..54dbb68667b3a4aabeb268103806471d1b88bbf5 100644 (file)
@@ -50,6 +50,8 @@
 mod cstore_impl;
 mod isolated_encoder;
 mod schema;
+mod native_libs;
+mod link_args;
 
 pub mod creader;
 pub mod cstore;
diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs
new file mode 100644 (file)
index 0000000..6fafde0
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright 2017 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.
+
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::hir;
+use rustc::ty::TyCtxt;
+use syntax::abi::Abi;
+
+pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec<String> {
+    let mut collector = Collector {
+        args: Vec::new(),
+    };
+    tcx.hir.krate().visit_all_item_likes(&mut collector);
+
+    for attr in tcx.hir.krate().attrs.iter() {
+        if attr.path == "link_args" {
+            if let Some(linkarg) = attr.value_str() {
+                collector.add_link_args(&linkarg.as_str());
+            }
+        }
+    }
+
+    return collector.args
+}
+
+struct Collector {
+    args: Vec<String>,
+}
+
+impl<'tcx> ItemLikeVisitor<'tcx> for Collector {
+    fn visit_item(&mut self, it: &'tcx hir::Item) {
+        let fm = match it.node {
+            hir::ItemForeignMod(ref fm) => fm,
+            _ => return,
+        };
+        if fm.abi == Abi::Rust ||
+            fm.abi == Abi::RustIntrinsic ||
+            fm.abi == Abi::PlatformIntrinsic {
+            return
+        }
+
+        // First, add all of the custom #[link_args] attributes
+        for m in it.attrs.iter().filter(|a| a.check_name("link_args")) {
+            if let Some(linkarg) = m.value_str() {
+                self.add_link_args(&linkarg.as_str());
+            }
+        }
+    }
+
+    fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem) {}
+    fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem) {}
+}
+
+impl Collector {
+    fn add_link_args(&mut self, args: &str) {
+        self.args.extend(args.split(' ').filter(|s| !s.is_empty()).map(|s| s.to_string()))
+    }
+}
diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs
new file mode 100644 (file)
index 0000000..669681d
--- /dev/null
@@ -0,0 +1,217 @@
+// Copyright 2017 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.
+
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::hir;
+use rustc::middle::cstore::{self, NativeLibrary};
+use rustc::session::Session;
+use rustc::ty::TyCtxt;
+use rustc::util::nodemap::FxHashSet;
+use syntax::abi::Abi;
+use syntax::attr;
+use syntax::codemap::Span;
+use syntax::feature_gate::{self, GateIssue};
+use syntax::symbol::Symbol;
+
+pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec<NativeLibrary> {
+    let mut collector = Collector {
+        tcx,
+        libs: Vec::new(),
+    };
+    tcx.hir.krate().visit_all_item_likes(&mut collector);
+    collector.process_command_line();
+    return collector.libs
+}
+
+pub fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
+    match lib.cfg {
+        Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None),
+        None => true,
+    }
+}
+
+struct Collector<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    libs: Vec<NativeLibrary>,
+}
+
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> {
+    fn visit_item(&mut self, it: &'tcx hir::Item) {
+        let fm = match it.node {
+            hir::ItemForeignMod(ref fm) => fm,
+            _ => return,
+        };
+
+        if fm.abi == Abi::Rust ||
+            fm.abi == Abi::RustIntrinsic ||
+            fm.abi == Abi::PlatformIntrinsic {
+            return
+        }
+
+        // Process all of the #[link(..)]-style arguments
+        for m in it.attrs.iter().filter(|a| a.check_name("link")) {
+            let items = match m.meta_item_list() {
+                Some(item) => item,
+                None => continue,
+            };
+            let kind = items.iter().find(|k| {
+                k.check_name("kind")
+            }).and_then(|a| a.value_str()).map(Symbol::as_str);
+            let kind = match kind.as_ref().map(|s| &s[..]) {
+                Some("static") => cstore::NativeStatic,
+                Some("static-nobundle") => cstore::NativeStaticNobundle,
+                Some("dylib") => cstore::NativeUnknown,
+                Some("framework") => cstore::NativeFramework,
+                Some(k) => {
+                    struct_span_err!(self.tcx.sess, m.span, E0458,
+                              "unknown kind: `{}`", k)
+                        .span_label(m.span, "unknown kind").emit();
+                    cstore::NativeUnknown
+                }
+                None => cstore::NativeUnknown
+            };
+            let n = items.iter().find(|n| {
+                n.check_name("name")
+            }).and_then(|a| a.value_str());
+            let n = match n {
+                Some(n) => n,
+                None => {
+                    struct_span_err!(self.tcx.sess, m.span, E0459,
+                                     "#[link(...)] specified without `name = \"foo\"`")
+                        .span_label(m.span, "missing `name` argument").emit();
+                    Symbol::intern("foo")
+                }
+            };
+            let cfg = items.iter().find(|k| {
+                k.check_name("cfg")
+            }).and_then(|a| a.meta_item_list());
+            let cfg = cfg.map(|list| {
+                list[0].meta_item().unwrap().clone()
+            });
+            let foreign_items = fm.items.iter()
+                .map(|it| self.tcx.hir.local_def_id(it.id).index)
+                .collect();
+            let lib = NativeLibrary {
+                name: n,
+                kind,
+                cfg,
+                foreign_items,
+            };
+            self.register_native_lib(Some(m.span), lib);
+        }
+    }
+
+    fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem) {}
+    fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem) {}
+}
+
+impl<'a, 'tcx> Collector<'a, 'tcx> {
+    fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLibrary) {
+        if lib.name.as_str().is_empty() {
+            match span {
+                Some(span) => {
+                    struct_span_err!(self.tcx.sess, span, E0454,
+                                     "#[link(name = \"\")] given with empty name")
+                        .span_label(span, "empty name given")
+                        .emit();
+                }
+                None => {
+                    self.tcx.sess.err("empty library name given via `-l`");
+                }
+            }
+            return
+        }
+        let is_osx = self.tcx.sess.target.target.options.is_like_osx;
+        if lib.kind == cstore::NativeFramework && !is_osx {
+            let msg = "native frameworks are only available on macOS targets";
+            match span {
+                Some(span) => span_err!(self.tcx.sess, span, E0455, "{}", msg),
+                None => self.tcx.sess.err(msg),
+            }
+        }
+        if lib.cfg.is_some() && !self.tcx.sess.features.borrow().link_cfg {
+            feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
+                                           "link_cfg",
+                                           span.unwrap(),
+                                           GateIssue::Language,
+                                           "is feature gated");
+        }
+        if lib.kind == cstore::NativeStaticNobundle &&
+           !self.tcx.sess.features.borrow().static_nobundle {
+            feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
+                                           "static_nobundle",
+                                           span.unwrap(),
+                                           GateIssue::Language,
+                                           "kind=\"static-nobundle\" is feature gated");
+        }
+        self.libs.push(lib);
+    }
+
+    // Process libs passed on the command line
+    fn process_command_line(&mut self) {
+        // First, check for errors
+        let mut renames = FxHashSet();
+        for &(ref name, ref new_name, _) in &self.tcx.sess.opts.libs {
+            if let &Some(ref new_name) = new_name {
+                if new_name.is_empty() {
+                    self.tcx.sess.err(
+                        &format!("an empty renaming target was specified for library `{}`",name));
+                } else if !self.libs.iter().any(|lib| lib.name == name as &str) {
+                    self.tcx.sess.err(&format!("renaming of the library `{}` was specified, \
+                                                however this crate contains no #[link(...)] \
+                                                attributes referencing this library.", name));
+                } else if renames.contains(name) {
+                    self.tcx.sess.err(&format!("multiple renamings were \
+                                                specified for library `{}` .",
+                                               name));
+                } else {
+                    renames.insert(name);
+                }
+            }
+        }
+
+        // Update kind and, optionally, the name of all native libaries
+        // (there may be more than one) with the specified name.
+        for &(ref name, ref new_name, kind) in &self.tcx.sess.opts.libs {
+            let mut found = false;
+            for lib in self.libs.iter_mut() {
+                if lib.name == name as &str {
+                    let mut changed = false;
+                    if let Some(k) = kind {
+                        lib.kind = k;
+                        changed = true;
+                    }
+                    if let &Some(ref new_name) = new_name {
+                        lib.name = Symbol::intern(new_name);
+                        changed = true;
+                    }
+                    if !changed {
+                        let msg = format!("redundant linker flag specified for \
+                                           library `{}`", name);
+                        self.tcx.sess.warn(&msg);
+                    }
+
+                    found = true;
+                }
+            }
+            if !found {
+                // Add if not found
+                let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
+                let lib = NativeLibrary {
+                    name: Symbol::intern(new_name.unwrap_or(name)),
+                    kind: if let Some(k) = kind { k } else { cstore::NativeUnknown },
+                    cfg: None,
+                    foreign_items: Vec::new(),
+                };
+                self.register_native_lib(None, lib);
+            }
+        }
+    }
+}
index 20c5b082101f2fdc72c69549f3b5598ac7c0fe2e..d5d980da39f5090ef7a153b02fb04791cf6a0ba6 100644 (file)
@@ -431,7 +431,7 @@ fn link_rlib<'a>(sess: &'a Session,
     // feature then we'll need to figure out how to record what objects were
     // loaded from the libraries found here and then encode that into the
     // metadata of the rlib we're generating somehow.
-    for lib in sess.cstore.used_libraries() {
+    for lib in trans.crate_info.used_libraries.iter() {
         match lib.kind {
             NativeLibraryKind::NativeStatic => {}
             NativeLibraryKind::NativeStaticNobundle |
@@ -930,7 +930,7 @@ fn link_args(cmd: &mut Linker,
         cmd.gc_sections(keep_metadata);
     }
 
-    let used_link_args = sess.cstore.used_link_args();
+    let used_link_args = &trans.crate_info.link_args;
 
     if crate_type == config::CrateTypeExecutable &&
        t.options.position_independent_executables {
@@ -1000,7 +1000,7 @@ fn link_args(cmd: &mut Linker,
     // link line. And finally upstream native libraries can't depend on anything
     // in this DAG so far because they're only dylibs and dylibs can only depend
     // on other dylibs (e.g. other native deps).
-    add_local_native_libraries(cmd, sess);
+    add_local_native_libraries(cmd, sess, trans);
     add_upstream_rust_crates(cmd, sess, trans, crate_type, tmpdir);
     add_upstream_native_libraries(cmd, sess, trans, crate_type);
 
@@ -1057,7 +1057,9 @@ fn link_args(cmd: &mut Linker,
 // Also note that the native libraries linked here are only the ones located
 // in the current crate. Upstream crates with native library dependencies
 // may have their native library pulled in above.
-fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) {
+fn add_local_native_libraries(cmd: &mut Linker,
+                              sess: &Session,
+                              trans: &CrateTranslation) {
     sess.target_filesearch(PathKind::All).for_each_lib_search_path(|path, k| {
         match k {
             PathKind::Framework => { cmd.framework_path(path); }
@@ -1065,7 +1067,7 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) {
         }
     });
 
-    let relevant_libs = sess.cstore.used_libraries().into_iter().filter(|l| {
+    let relevant_libs = trans.crate_info.used_libraries.iter().filter(|l| {
         relevant_lib(sess, l)
     });
 
index ccbd2a7550a2511ce888c276b44775173621005c..28929afc281d696addeadeae8f7c73ef8091195e 100644 (file)
@@ -905,7 +905,7 @@ pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet {
         match tcx.hir.get(id) {
             hir_map::NodeForeignItem(..) => {
                 let def_id = tcx.hir.local_def_id(id);
-                tcx.sess.cstore.is_statically_included_foreign_item(def_id)
+                tcx.is_statically_included_foreign_item(def_id)
             }
 
             // Only consider nodes that actually have exported symbols.
@@ -1516,6 +1516,8 @@ pub fn new(tcx: TyCtxt) -> CrateInfo {
             sanitizer_runtime: None,
             is_no_builtins: FxHashSet(),
             native_libraries: FxHashMap(),
+            used_libraries: tcx.native_libraries(LOCAL_CRATE),
+            link_args: tcx.link_args(LOCAL_CRATE),
         };
 
         for cnum in tcx.sess.cstore.crates() {
@@ -1537,6 +1539,7 @@ pub fn new(tcx: TyCtxt) -> CrateInfo {
             }
         }
 
+
         return info
     }
 }
index 76f94565bae515cebdad2e6550c827cc908f8de1..71d476c31ac3314f4ddc6cfe36a47eb85c33b479 100644 (file)
@@ -125,7 +125,7 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         }
 
         if ccx.use_dll_storage_attrs() &&
-            ccx.sess().cstore.is_dllimport_foreign_item(instance_def_id)
+            tcx.is_dllimport_foreign_item(instance_def_id)
         {
             unsafe {
                 llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
index 310cd6fe9559d8942d4af168ee4603b76bec8fa0..282e960aab3029b2f98c71c403949c69ee2ffda8 100644 (file)
@@ -211,7 +211,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
         g
     };
 
-    if ccx.use_dll_storage_attrs() && ccx.sess().cstore.is_dllimport_foreign_item(def_id) {
+    if ccx.use_dll_storage_attrs() && ccx.tcx().is_dllimport_foreign_item(def_id) {
         // For foreign (native) libs we know the exact storage type to use.
         unsafe {
             llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport);
index 876870914be81b0e7d7a520b0e6e2151f724c825..babc030b59c9272525d548591e17d4c9da5ab31d 100644 (file)
@@ -234,6 +234,8 @@ pub struct CrateInfo {
     sanitizer_runtime: Option<CrateNum>,
     is_no_builtins: FxHashSet<CrateNum>,
     native_libraries: FxHashMap<CrateNum, Rc<Vec<NativeLibrary>>>,
+    used_libraries: Rc<Vec<NativeLibrary>>,
+    link_args: Rc<Vec<String>>,
 }
 
 __build_diagnostic_array! { librustc_trans, DIAGNOSTICS }
index cd5ee1cafecfbbb0dcb44bb54bbfb3413c4db0ea..20e0f9cd0b2516d6dbffee47c3e09f8b0196a009 100644 (file)
@@ -11,3 +11,5 @@
 #[link(name = "")] //~ ERROR: given with empty name
 extern {
 }
+
+fn main() {}
index bc0025c7c958118ca2ebcb3c63506a52855cd2e9..0d13a4937c468ccb397a1e8cefe68687e4709323 100644 (file)
@@ -11,3 +11,5 @@
 #[link(name="foo", kind="static-nobundle")]
 //~^ ERROR: kind="static-nobundle" is feature gated
 extern {}
+
+fn main() {}