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;
-> 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") }
})
}
+ 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()
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;
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))
}
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
}
// 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 {
// 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.
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)))
});
// 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,
--- /dev/null
+// 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))
+}
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;
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.
}
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(),
}
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);
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;
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;
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.
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,
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);
}
}
// 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,
}
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 {
(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))
-}
pub mod linker;
pub mod link;
pub mod lto;
+ pub mod symbol_export;
pub mod symbol_names;
pub mod write;
pub mod msvc;
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
$(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" ]