]> git.lizzy.rs Git - rust.git/commitdiff
Refactor symbol export list generation.
authorMichael Woerister <michaelwoerister@posteo.net>
Wed, 30 Nov 2016 15:03:42 +0000 (10:03 -0500)
committerMichael Woerister <michaelwoerister@posteo.net>
Mon, 5 Dec 2016 16:05:25 +0000 (11:05 -0500)
src/librustc/middle/cstore.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_trans/back/linker.rs
src/librustc_trans/back/lto.rs
src/librustc_trans/back/symbol_export.rs [new file with mode: 0644]
src/librustc_trans/back/write.rs
src/librustc_trans/base.rs
src/librustc_trans/lib.rs
src/test/run-make/sepcomp-inlining/Makefile

index 34224b924b948f2128fa6140abd9f30250ef8cd5..4357518b332cc64a911958b2c3980314dcf9e1e5 100644 (file)
@@ -328,6 +328,7 @@ fn dylib_dependency_formats(&self, cnum: CrateNum)
     fn crate_hash(&self, cnum: CrateNum) -> Svh;
     fn crate_disambiguator(&self, cnum: CrateNum) -> Symbol;
     fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>;
+    fn derive_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>;
     fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>;
     fn exported_symbols(&self, cnum: CrateNum) -> Vec<DefId>;
     fn is_no_builtins(&self, cnum: CrateNum) -> bool;
@@ -491,6 +492,8 @@ fn crate_disambiguator(&self, cnum: CrateNum)
                            -> Symbol { bug!("crate_disambiguator") }
     fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>
         { bug!("plugin_registrar_fn") }
+    fn derive_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>
+        { bug!("derive_registrar_fn") }
     fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>
         { bug!("native_libraries") }
     fn exported_symbols(&self, cnum: CrateNum) -> Vec<DefId> { bug!("exported_symbols") }
index 2965e545eca4e1421590fa7dba4f9fdfb63d03e0..aca1d2f76128128f92e1d2236a3d1c05f5af2d49 100644 (file)
@@ -306,6 +306,14 @@ fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>
         })
     }
 
+    fn derive_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>
+    {
+        self.get_crate_data(cnum).root.macro_derive_registrar.map(|index| DefId {
+            krate: cnum,
+            index: index
+        })
+    }
+
     fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>
     {
         self.get_crate_data(cnum).get_native_libraries()
index b8d5fc9042f10bb53cff0f138b0181917578edb5..933813ac4d9310ffb2bd08df487e8d7b727c14bf 100644 (file)
 use std::process::Command;
 
 use context::SharedCrateContext;
-use monomorphize::Instance;
 
 use back::archive;
+use back::symbol_export::{self, ExportedSymbols};
 use middle::dependency_format::Linkage;
-use rustc::hir::def_id::CrateNum;
+use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
 use session::Session;
 use session::config::CrateType;
 use session::config;
@@ -34,7 +34,7 @@ pub struct LinkerInfo {
 
 impl<'a, 'tcx> LinkerInfo {
     pub fn new(scx: &SharedCrateContext<'a, 'tcx>,
-               exports: &[String]) -> LinkerInfo {
+               exports: &ExportedSymbols) -> LinkerInfo {
         LinkerInfo {
             exports: scx.sess().crate_types.borrow().iter().map(|&c| {
                 (c, exported_symbols(scx, exports, c))
@@ -473,43 +473,29 @@ fn subsystem(&mut self, subsystem: &str) {
 }
 
 fn exported_symbols(scx: &SharedCrateContext,
-                    exported_symbols: &[String],
+                    exported_symbols: &ExportedSymbols,
                     crate_type: CrateType)
                     -> Vec<String> {
-    // See explanation in GnuLinker::export_symbols, for
-    // why we don't ever need dylib symbols on non-MSVC.
-    if crate_type == CrateType::CrateTypeDylib ||
-       crate_type == CrateType::CrateTypeProcMacro {
-        if !scx.sess().target.target.options.is_like_msvc {
-            return vec![];
-        }
-    }
-
-    let mut symbols = exported_symbols.to_vec();
+    let export_threshold = symbol_export::crate_export_threshold(crate_type);
 
-    // If we're producing anything other than a dylib then the `reachable` array
-    // above is the exhaustive set of symbols we should be exporting.
-    //
-    // For dylibs, however, we need to take a look at how all upstream crates
-    // are linked into this dynamic library. For all statically linked
-    // libraries we take all their reachable symbols and emit them as well.
-    if crate_type != CrateType::CrateTypeDylib {
-        return symbols
-    }
+    let mut symbols = Vec::new();
+    exported_symbols.for_each_exported_symbol(LOCAL_CRATE, export_threshold, |name, _| {
+        symbols.push(name.to_owned());
+    });
 
-    let cstore = &scx.sess().cstore;
     let formats = scx.sess().dependency_formats.borrow();
     let deps = formats[&crate_type].iter();
-    symbols.extend(deps.enumerate().filter_map(|(i, f)| {
-        if *f == Linkage::Static {
-            Some(CrateNum::new(i + 1))
-        } else {
-            None
+
+    for (index, dep_format) in deps.enumerate() {
+        let cnum = CrateNum::new(index + 1);
+        // For each dependency that we are linking to statically ...
+        if *dep_format == Linkage::Static {
+            // ... we add its symbol list to our export list.
+            exported_symbols.for_each_exported_symbol(cnum, export_threshold, |name, _| {
+                symbols.push(name.to_owned());
+            })
         }
-    }).flat_map(|cnum| {
-        cstore.exported_symbols(cnum)
-    }).map(|did| -> String {
-        Instance::mono(scx, did).symbol_name(scx)
-    }));
+    }
+
     symbols
 }
index 46b1241de368f9bfaa992d942f5d669a5ffd74da..1960b368278749613cd8d256a888e24083d3ad29 100644 (file)
@@ -8,14 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use super::link;
-use super::write;
+use back::link;
+use back::write;
+use back::symbol_export::{self, ExportedSymbols};
 use rustc::session::{self, config};
 use llvm;
 use llvm::archive_ro::ArchiveRO;
 use llvm::{ModuleRef, TargetMachineRef, True, False};
 use rustc::util::common::time;
 use rustc::util::common::path2cstr;
+use rustc::hir::def_id::LOCAL_CRATE;
 use back::write::{ModuleConfig, with_llvm_pmb};
 
 use libc;
 use std::ffi::CString;
 use std::path::Path;
 
-pub fn run(sess: &session::Session, llmod: ModuleRef,
-           tm: TargetMachineRef, exported_symbols: &[String],
+pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool {
+    match crate_type {
+        config::CrateTypeExecutable |
+        config::CrateTypeStaticlib  |
+        config::CrateTypeCdylib     => true,
+
+        config::CrateTypeDylib     |
+        config::CrateTypeRlib      |
+        config::CrateTypeMetadata  |
+        config::CrateTypeProcMacro => false,
+    }
+}
+
+pub fn run(sess: &session::Session,
+           llmod: ModuleRef,
+           tm: TargetMachineRef,
+           exported_symbols: &ExportedSymbols,
            config: &ModuleConfig,
            temp_no_opt_bc_filename: &Path) {
     if sess.opts.cg.prefer_dynamic {
@@ -38,17 +55,31 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
 
     // Make sure we actually can run LTO
     for crate_type in sess.crate_types.borrow().iter() {
-        match *crate_type {
-            config::CrateTypeExecutable |
-            config::CrateTypeCdylib |
-            config::CrateTypeStaticlib => {}
-            _ => {
-                sess.fatal("lto can only be run for executables and \
+        if !crate_type_allows_lto(*crate_type) {
+            sess.fatal("lto can only be run for executables and \
                             static library outputs");
-            }
         }
     }
 
+    let export_threshold =
+        symbol_export::crates_export_threshold(&sess.crate_types.borrow()[..]);
+
+    let symbol_filter = &|&(ref name, level): &(String, _)| {
+        if symbol_export::is_below_threshold(level, export_threshold) {
+            let mut bytes = Vec::with_capacity(name.len() + 1);
+            bytes.extend(name.bytes());
+            Some(CString::new(bytes).unwrap())
+        } else {
+            None
+        }
+    };
+
+    let mut symbol_white_list: Vec<CString> = exported_symbols
+        .exported_symbols(LOCAL_CRATE)
+        .iter()
+        .filter_map(symbol_filter)
+        .collect();
+
     // 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.
@@ -58,6 +89,11 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
             return;
         }
 
+        symbol_white_list.extend(
+            exported_symbols.exported_symbols(cnum)
+                            .iter()
+                            .filter_map(symbol_filter));
+
         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)))
@@ -119,10 +155,9 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
     });
 
     // Internalize everything but the exported symbols of the current module
-    let cstrs: Vec<CString> = exported_symbols.iter().map(|s| {
-        CString::new(s.clone()).unwrap()
-    }).collect();
-    let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect();
+    let arr: Vec<*const libc::c_char> = symbol_white_list.iter()
+                                                         .map(|c| c.as_ptr())
+                                                         .collect();
     let ptr = arr.as_ptr();
     unsafe {
         llvm::LLVMRustRunRestrictionPass(llmod,
diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs
new file mode 100644 (file)
index 0000000..2290cb0
--- /dev/null
@@ -0,0 +1,185 @@
+// 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.
+
+use context::SharedCrateContext;
+use monomorphize::Instance;
+use symbol_map::SymbolMap;
+use util::nodemap::FxHashMap;
+use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
+use rustc::session::config;
+use syntax::attr;
+use trans_item::TransItem;
+
+/// The SymbolExportLevel of a symbols specifies from which kinds of crates
+/// the symbol will be exported. `C` symbols will be exported from any
+/// kind of crate, including cdylibs which export very few things.
+/// `Rust` will only be exported if the crate produced is a Rust
+/// dylib.
+#[derive(Eq, PartialEq, Debug, Copy, Clone)]
+pub enum SymbolExportLevel {
+    C,
+    Rust,
+}
+
+/// The set of symbols exported from each crate in the crate graph.
+pub struct ExportedSymbols {
+    exports: FxHashMap<CrateNum, Vec<(String, SymbolExportLevel)>>,
+}
+
+impl ExportedSymbols {
+
+    pub fn empty() -> ExportedSymbols {
+        ExportedSymbols {
+            exports: FxHashMap(),
+        }
+    }
+
+    pub fn compute_from<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+                                  symbol_map: &SymbolMap<'tcx>)
+                                  -> ExportedSymbols {
+        let mut local_crate: Vec<_> = scx
+            .exported_symbols()
+            .iter()
+            .map(|&node_id| {
+                scx.tcx().map.local_def_id(node_id)
+            })
+            .map(|def_id| {
+                (symbol_for_def_id(scx, def_id, symbol_map),
+                 export_level(scx, def_id))
+            })
+            .collect();
+
+        if scx.sess().entry_fn.borrow().is_some() {
+            local_crate.push(("main".to_string(), SymbolExportLevel::C));
+        }
+
+        if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) {
+            local_crate.push((scx.metadata_symbol_name(),
+                              SymbolExportLevel::Rust));
+        }
+
+        let mut exports = FxHashMap();
+        exports.insert(LOCAL_CRATE, local_crate);
+
+        for cnum in scx.sess().cstore.crates() {
+            debug_assert!(cnum != LOCAL_CRATE);
+
+            if scx.sess().cstore.plugin_registrar_fn(cnum).is_some() ||
+               scx.sess().cstore.derive_registrar_fn(cnum).is_some() {
+                continue;
+            }
+
+            let crate_exports = scx
+                .sess()
+                .cstore
+                .exported_symbols(cnum)
+                .iter()
+                .map(|&def_id| {
+                    debug!("EXTERN-SYMBOL: {:?}", def_id);
+                    let name = Instance::mono(scx, def_id).symbol_name(scx);
+                    (name, export_level(scx, def_id))
+                })
+                .collect();
+
+            exports.insert(cnum, crate_exports);
+        }
+
+        return ExportedSymbols {
+            exports: exports
+        };
+
+        fn export_level(scx: &SharedCrateContext,
+                        sym_def_id: DefId)
+                        -> SymbolExportLevel {
+            let attrs = scx.tcx().get_attrs(sym_def_id);
+            if attr::contains_extern_indicator(scx.sess().diagnostic(), &attrs) {
+                SymbolExportLevel::C
+            } else {
+                SymbolExportLevel::Rust
+            }
+        }
+    }
+
+    pub fn exported_symbols(&self,
+                            cnum: CrateNum)
+                            -> &[(String, SymbolExportLevel)] {
+        match self.exports.get(&cnum) {
+            Some(exports) => &exports[..],
+            None => &[]
+        }
+    }
+
+    pub fn for_each_exported_symbol<F>(&self,
+                                       cnum: CrateNum,
+                                       export_threshold: SymbolExportLevel,
+                                       mut f: F)
+        where F: FnMut(&str, SymbolExportLevel)
+    {
+        for &(ref name, export_level) in self.exported_symbols(cnum) {
+            if is_below_threshold(export_level, export_threshold) {
+                f(&name[..], export_level)
+            }
+        }
+    }
+}
+
+pub fn crate_export_threshold(crate_type: config::CrateType)
+                                     -> SymbolExportLevel {
+    match crate_type {
+        config::CrateTypeExecutable |
+        config::CrateTypeStaticlib  |
+        config::CrateTypeCdylib     => SymbolExportLevel::C,
+        config::CrateTypeProcMacro  |
+        config::CrateTypeRlib       |
+        config::CrateTypeMetadata   |
+        config::CrateTypeDylib      => SymbolExportLevel::Rust,
+    }
+}
+
+pub fn crates_export_threshold(crate_types: &[config::CrateType])
+                                      -> SymbolExportLevel {
+    if crate_types.iter().any(|&crate_type| {
+        crate_export_threshold(crate_type) == SymbolExportLevel::Rust
+    }) {
+        SymbolExportLevel::Rust
+    } else {
+        SymbolExportLevel::C
+    }
+}
+
+pub fn is_below_threshold(level: SymbolExportLevel,
+                          threshold: SymbolExportLevel)
+                          -> bool {
+    if threshold == SymbolExportLevel::Rust {
+        // We export everything from Rust dylibs
+        true
+    } else {
+        level == SymbolExportLevel::C
+    }
+}
+
+fn symbol_for_def_id<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+                               def_id: DefId,
+                               symbol_map: &SymbolMap<'tcx>)
+                               -> String {
+    // Just try to look things up in the symbol map. If nothing's there, we
+    // recompute.
+    if let Some(node_id) = scx.tcx().map.as_local_node_id(def_id) {
+        if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) {
+            return sym.to_owned();
+        }
+    }
+
+    let instance = Instance::mono(scx, def_id);
+
+    symbol_map.get(TransItem::Fn(instance))
+              .map(str::to_owned)
+              .unwrap_or_else(|| instance.symbol_name(scx))
+}
index 84bba64dd70b2f3813d02d83b559d08ef5a99840..ffab0bde7abde743cff20dce98787caeb0e4df62 100644 (file)
@@ -10,6 +10,7 @@
 
 use back::lto;
 use back::link::{get_linker, remove};
+use back::symbol_export::ExportedSymbols;
 use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
 use session::config::{OutputFilenames, OutputTypes, Passes, SomePasses, AllPasses};
 use session::Session;
@@ -328,7 +329,7 @@ fn set_flags(&mut self, sess: &Session, trans: &CrateTranslation) {
 struct CodegenContext<'a> {
     // Extra resources used for LTO: (sess, reachable).  This will be `None`
     // when running in a worker thread.
-    lto_ctxt: Option<(&'a Session, &'a [String])>,
+    lto_ctxt: Option<(&'a Session, &'a ExportedSymbols)>,
     // Handler to use for diagnostics produced during codegen.
     handler: &'a Handler,
     // LLVM passes added by plugins.
@@ -343,7 +344,9 @@ struct CodegenContext<'a> {
 }
 
 impl<'a> CodegenContext<'a> {
-    fn new_with_session(sess: &'a Session, exported_symbols: &'a [String]) -> CodegenContext<'a> {
+    fn new_with_session(sess: &'a Session,
+                        exported_symbols: &'a ExportedSymbols)
+                        -> CodegenContext<'a> {
         CodegenContext {
             lto_ctxt: Some((sess, exported_symbols)),
             handler: sess.diagnostic(),
@@ -997,7 +1000,7 @@ fn execute_work_item(cgcx: &CodegenContext,
 }
 
 fn run_work_singlethreaded(sess: &Session,
-                           exported_symbols: &[String],
+                           exported_symbols: &ExportedSymbols,
                            work_items: Vec<WorkItem>) {
     let cgcx = CodegenContext::new_with_session(sess, exported_symbols);
 
index 74e6a1dac80b172fcb921f20ba06b2b6f010deb2..a31b61e42c440a2434c0433a4eacc55dc25be3e4 100644 (file)
 use assert_module_sources;
 use back::link;
 use back::linker::LinkerInfo;
+use back::symbol_export::{self, ExportedSymbols};
 use llvm::{Linkage, ValueRef, Vector, get_param};
 use llvm;
-use rustc::hir::def::Def;
-use rustc::hir::def_id::DefId;
+use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
 use rustc::ty::subst::Substs;
 use rustc::traits;
@@ -84,7 +84,6 @@
 use arena::TypedArena;
 use libc::c_uint;
 use std::ffi::{CStr, CString};
-use std::borrow::Cow;
 use std::cell::{Cell, RefCell};
 use std::ptr;
 use std::rc::Rc;
@@ -1313,16 +1312,23 @@ enum MetadataKind {
 fn internalize_symbols<'a, 'tcx>(sess: &Session,
                                  ccxs: &CrateContextList<'a, 'tcx>,
                                  symbol_map: &SymbolMap<'tcx>,
-                                 exported_symbols: &FxHashSet<&str>) {
+                                 exported_symbols: &ExportedSymbols) {
+    let export_threshold =
+        symbol_export::crates_export_threshold(&sess.crate_types.borrow()[..]);
+
+    let exported_symbols = exported_symbols
+        .exported_symbols(LOCAL_CRATE)
+        .iter()
+        .filter(|&&(_, export_level)| {
+            symbol_export::is_below_threshold(export_level, export_threshold)
+        })
+        .map(|&(ref name, _)| &name[..])
+        .collect::<FxHashSet<&str>>();
+
     let scx = ccxs.shared();
     let tcx = scx.tcx();
 
-    // In incr. comp. mode, we can't necessarily see all refs since we
-    // don't generate LLVM IR for reused modules, so skip this
-    // step. Later we should get smarter.
-    if sess.opts.debugging_opts.incremental.is_some() {
-        return;
-    }
+    let incr_comp = sess.opts.debugging_opts.incremental.is_some();
 
     // 'unsafe' because we are holding on to CStr's from the LLVM module within
     // this block.
@@ -1330,34 +1336,43 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session,
         let mut referenced_somewhere = FxHashSet();
 
         // Collect all symbols that need to stay externally visible because they
-        // are referenced via a declaration in some other codegen unit.
-        for ccx in ccxs.iter_need_trans() {
-            for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
-                let linkage = llvm::LLVMRustGetLinkage(val);
-                // We only care about external declarations (not definitions)
-                // and available_externally definitions.
-                let is_available_externally = linkage == llvm::Linkage::AvailableExternallyLinkage;
-                let is_decl = llvm::LLVMIsDeclaration(val) != 0;
-
-                if is_decl || is_available_externally {
-                    let symbol_name = CStr::from_ptr(llvm::LLVMGetValueName(val));
-                    referenced_somewhere.insert(symbol_name);
+        // are referenced via a declaration in some other codegen unit. In
+        // incremental compilation, we don't need to collect. See below for more
+        // information.
+        if !incr_comp {
+            for ccx in ccxs.iter_need_trans() {
+                for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
+                    let linkage = llvm::LLVMRustGetLinkage(val);
+                    // We only care about external declarations (not definitions)
+                    // and available_externally definitions.
+                    let is_available_externally =
+                        linkage == llvm::Linkage::AvailableExternallyLinkage;
+                    let is_decl = llvm::LLVMIsDeclaration(val) == llvm::True;
+
+                    if is_decl || is_available_externally {
+                        let symbol_name = CStr::from_ptr(llvm::LLVMGetValueName(val));
+                        referenced_somewhere.insert(symbol_name);
+                    }
                 }
             }
         }
 
         // Also collect all symbols for which we cannot adjust linkage, because
-        // it is fixed by some directive in the source code (e.g. #[no_mangle]).
-        let linkage_fixed_explicitly: FxHashSet<_> = scx
-            .translation_items()
-            .borrow()
-            .iter()
-            .cloned()
-            .filter(|trans_item|{
-                trans_item.explicit_linkage(tcx).is_some()
-            })
-            .map(|trans_item| symbol_map.get_or_compute(scx, trans_item))
-            .collect();
+        // it is fixed by some directive in the source code.
+        let (locally_defined_symbols, linkage_fixed_explicitly) = {
+            let mut locally_defined_symbols = FxHashSet();
+            let mut linkage_fixed_explicitly = FxHashSet();
+
+            for trans_item in scx.translation_items().borrow().iter() {
+                let symbol_name = symbol_map.get_or_compute(scx, *trans_item);
+                if trans_item.explicit_linkage(tcx).is_some() {
+                    linkage_fixed_explicitly.insert(symbol_name.clone());
+                }
+                locally_defined_symbols.insert(symbol_name);
+            }
+
+            (locally_defined_symbols, linkage_fixed_explicitly)
+        };
 
         // Examine each external definition.  If the definition is not used in
         // any other compilation unit, and is not reachable from other crates,
@@ -1369,23 +1384,46 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session,
                 let is_externally_visible = (linkage == llvm::Linkage::ExternalLinkage) ||
                                             (linkage == llvm::Linkage::LinkOnceODRLinkage) ||
                                             (linkage == llvm::Linkage::WeakODRLinkage);
-                let is_definition = llvm::LLVMIsDeclaration(val) == 0;
-
-                // If this is a definition (as opposed to just a declaration)
-                // and externally visible, check if we can internalize it
-                if is_definition && is_externally_visible {
-                    let name_cstr = CStr::from_ptr(llvm::LLVMGetValueName(val));
-                    let name_str = name_cstr.to_str().unwrap();
-                    let name_cow = Cow::Borrowed(name_str);
-
-                    let is_referenced_somewhere = referenced_somewhere.contains(&name_cstr);
-                    let is_reachable = exported_symbols.contains(&name_str);
-                    let has_fixed_linkage = linkage_fixed_explicitly.contains(&name_cow);
-
-                    if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage {
-                        llvm::LLVMRustSetLinkage(val, llvm::Linkage::InternalLinkage);
-                        llvm::LLVMSetDLLStorageClass(val,
-                                                     llvm::DLLStorageClass::Default);
+
+                if !is_externally_visible {
+                    // This symbol is not visible outside of its codegen unit,
+                    // so there is nothing to do for it.
+                    continue;
+                }
+
+                let name_cstr = CStr::from_ptr(llvm::LLVMGetValueName(val));
+                let name_str = name_cstr.to_str().unwrap();
+
+                if exported_symbols.contains(&name_str) {
+                    // This symbol is explicitly exported, so we can't
+                    // mark it as internal or hidden.
+                    continue;
+                }
+
+                let is_declaration = llvm::LLVMIsDeclaration(val) == llvm::True;
+
+                if is_declaration {
+                    if locally_defined_symbols.contains(name_str) {
+                        // Only mark declarations from the current crate as hidden.
+                        // Otherwise we would mark things as hidden that are
+                        // imported from other crates or native libraries.
+                        llvm::LLVMRustSetVisibility(val, llvm::Visibility::Hidden);
+                    }
+                } else {
+                    let has_fixed_linkage = linkage_fixed_explicitly.contains(name_str);
+
+                    if !has_fixed_linkage {
+                        // In incremental compilation mode, we can't be sure that
+                        // we saw all references because we don't know what's in
+                        // cached compilation units, so we always assume that the
+                        // given item has been referenced.
+                        if incr_comp || referenced_somewhere.contains(&name_cstr) {
+                            llvm::LLVMRustSetVisibility(val, llvm::Visibility::Hidden);
+                        } else {
+                            llvm::LLVMRustSetLinkage(val, llvm::Linkage::InternalLinkage);
+                        }
+
+                        llvm::LLVMSetDLLStorageClass(val, llvm::DLLStorageClass::Default);
                         llvm::UnsetComdat(val);
                     }
                 }
@@ -1602,13 +1640,13 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // Skip crate items and just output metadata in -Z no-trans mode.
     if tcx.sess.opts.debugging_opts.no_trans ||
        tcx.sess.crate_types.borrow().iter().all(|ct| ct == &config::CrateTypeMetadata) {
-        let linker_info = LinkerInfo::new(&shared_ccx, &[]);
+        let linker_info = LinkerInfo::new(&shared_ccx, &ExportedSymbols::empty());
         return CrateTranslation {
             modules: modules,
             metadata_module: metadata_module,
             link: link_meta,
             metadata: metadata,
-            exported_symbols: vec![],
+            exported_symbols: ExportedSymbols::empty(),
             no_builtins: no_builtins,
             linker_info: linker_info,
             windows_subsystem: None,
@@ -1688,56 +1726,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 
     let sess = shared_ccx.sess();
-    let mut exported_symbols = shared_ccx.exported_symbols().iter().map(|&id| {
-        let def_id = shared_ccx.tcx().map.local_def_id(id);
-        symbol_for_def_id(def_id, &shared_ccx, &symbol_map)
-    }).collect::<Vec<_>>();
-
-    if sess.entry_fn.borrow().is_some() {
-        exported_symbols.push("main".to_string());
-    }
-
-    if sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
-        exported_symbols.push(shared_ccx.metadata_symbol_name());
-    }
 
-    // For the purposes of LTO or when creating a cdylib, we add to the
-    // reachable set all of the upstream reachable extern fns. These functions
-    // are all part of the public ABI of the final product, so we need to
-    // preserve them.
-    //
-    // Note that this happens even if LTO isn't requested or we're not creating
-    // a cdylib. In those cases, though, we're not even reading the
-    // `exported_symbols` list later on so it should be ok.
-    for cnum in sess.cstore.crates() {
-        let syms = sess.cstore.exported_symbols(cnum);
-        exported_symbols.extend(syms.into_iter().filter(|&def_id| {
-            let applicable = match sess.cstore.describe_def(def_id) {
-                Some(Def::Static(..)) => true,
-                Some(Def::Fn(_)) => {
-                    shared_ccx.tcx().item_generics(def_id).types.is_empty()
-                }
-                _ => false
-            };
-
-            if applicable {
-                let attrs = shared_ccx.tcx().get_attrs(def_id);
-                attr::contains_extern_indicator(sess.diagnostic(), &attrs)
-            } else {
-                false
-            }
-        }).map(|did| {
-            symbol_for_def_id(did, &shared_ccx, &symbol_map)
-        }));
-    }
+    let exported_symbols = ExportedSymbols::compute_from(&shared_ccx,
+                                                         &symbol_map);
 
+    // Now that we have all symbols that are exported from the CGUs of this
+    // crate, we can run the `internalize_symbols` pass.
     time(shared_ccx.sess().time_passes(), "internalize symbols", || {
         internalize_symbols(sess,
                             &crate_context_list,
                             &symbol_map,
-                            &exported_symbols.iter()
-                                              .map(|s| &s[..])
-                                              .collect())
+                            &exported_symbols);
     });
 
     if tcx.sess.opts.debugging_opts.print_type_sizes {
@@ -2107,22 +2106,3 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
 
     (codegen_units, symbol_map)
 }
-
-fn symbol_for_def_id<'a, 'tcx>(def_id: DefId,
-                               scx: &SharedCrateContext<'a, 'tcx>,
-                               symbol_map: &SymbolMap<'tcx>)
-                               -> String {
-    // Just try to look things up in the symbol map. If nothing's there, we
-    // recompute.
-    if let Some(node_id) = scx.tcx().map.as_local_node_id(def_id) {
-        if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) {
-            return sym.to_owned();
-        }
-    }
-
-    let instance = Instance::mono(scx, def_id);
-
-    symbol_map.get(TransItem::Fn(instance))
-              .map(str::to_owned)
-              .unwrap_or_else(|| instance.symbol_name(scx))
-}
index 8a7ab16ee2b01987e4f00e38e5a47793673b96ac..e2da635b1592ae3ac1992f83e25fdbb95eb102a3 100644 (file)
@@ -78,6 +78,7 @@ pub mod back {
     pub mod linker;
     pub mod link;
     pub mod lto;
+    pub mod symbol_export;
     pub mod symbol_names;
     pub mod write;
     pub mod msvc;
@@ -169,7 +170,7 @@ pub struct CrateTranslation {
     pub metadata_module: ModuleTranslation,
     pub link: middle::cstore::LinkMeta,
     pub metadata: Vec<u8>,
-    pub exported_symbols: Vec<String>,
+    pub exported_symbols: back::symbol_export::ExportedSymbols,
     pub no_builtins: bool,
     pub windows_subsystem: Option<String>,
     pub linker_info: back::linker::LinkerInfo
index ef43b0d97e4170fd98b174b8e18c797e47febbdc..720dfff2c0438cefaa1e7815daf04e9f4be4ed80 100644 (file)
@@ -10,5 +10,5 @@ all:
        $(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3
        [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*inlined)" -eq "0" ]
        [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ internal\ i32\ .*inlined)" -eq "2" ]
-       [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*normal)" -eq "1" ]
-       [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c declare\ i32\ .*normal)" -eq "2" ]
+       [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ hidden\ i32\ .*normal)" -eq "1" ]
+       [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c declare\ hidden\ i32\ .*normal)" -eq "2" ]