1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
15 use monomorphize::Instance;
16 use rustc::hir::def_id::CrateNum;
17 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
18 use rustc::middle::exported_symbols::SymbolExportLevel;
19 use rustc::session::config;
20 use rustc::ty::TyCtxt;
21 use rustc::ty::maps::Providers;
22 use rustc::util::nodemap::FxHashMap;
23 use rustc_allocator::ALLOCATOR_METHODS;
25 pub type ExportedSymbols = FxHashMap<
27 Arc<Vec<(String, Option<DefId>, SymbolExportLevel)>>,
30 pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel {
31 crates_export_threshold(&tcx.sess.crate_types.borrow())
34 pub fn metadata_symbol_name(tcx: TyCtxt) -> String {
35 format!("rust_metadata_{}_{}",
36 tcx.crate_name(LOCAL_CRATE),
37 tcx.crate_disambiguator(LOCAL_CRATE))
40 fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel {
42 config::CrateTypeExecutable |
43 config::CrateTypeStaticlib |
44 config::CrateTypeProcMacro |
45 config::CrateTypeCdylib => SymbolExportLevel::C,
46 config::CrateTypeRlib |
47 config::CrateTypeDylib => SymbolExportLevel::Rust,
51 pub fn crates_export_threshold(crate_types: &[config::CrateType])
52 -> SymbolExportLevel {
53 if crate_types.iter().any(|&crate_type| {
54 crate_export_threshold(crate_type) == SymbolExportLevel::Rust
56 SymbolExportLevel::Rust
62 pub fn provide_local(providers: &mut Providers) {
63 providers.exported_symbol_ids = |tcx, cnum| {
64 let export_threshold = threshold(tcx);
65 Rc::new(tcx.exported_symbols(cnum)
67 .filter_map(|&(_, id, level)| {
69 if level.is_below_threshold(export_threshold) {
79 providers.is_exported_symbol = |tcx, id| {
80 // FIXME(#42293) needs red/green to not break a bunch of incremental
82 tcx.exported_symbol_ids(id.krate).contains(&id)
85 providers.exported_symbols = |tcx, cnum| {
86 assert_eq!(cnum, LOCAL_CRATE);
87 let local_exported_symbols = base::find_exported_symbols(tcx);
89 let mut local_crate: Vec<_> = local_exported_symbols
92 tcx.hir.local_def_id(node_id)
95 let name = tcx.symbol_name(Instance::mono(tcx, def_id));
96 let export_level = export_level(tcx, def_id);
97 debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level);
98 (str::to_owned(&name), Some(def_id), export_level)
102 if let Some(_) = *tcx.sess.entry_fn.borrow() {
103 local_crate.push(("main".to_string(),
105 SymbolExportLevel::C));
108 if tcx.sess.allocator_kind.get().is_some() {
109 for method in ALLOCATOR_METHODS {
110 local_crate.push((format!("__rust_{}", method.name),
112 SymbolExportLevel::Rust));
116 if let Some(id) = tcx.sess.derive_registrar_fn.get() {
117 let def_id = tcx.hir.local_def_id(id);
118 let idx = def_id.index;
119 let disambiguator = tcx.sess.local_crate_disambiguator();
120 let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator, idx);
121 local_crate.push((registrar, Some(def_id), SymbolExportLevel::C));
124 if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
125 local_crate.push((metadata_symbol_name(tcx),
127 SymbolExportLevel::Rust));
129 Arc::new(local_crate)
133 pub fn provide_extern(providers: &mut Providers) {
134 providers.exported_symbols = |tcx, cnum| {
135 // If this crate is a plugin and/or a custom derive crate, then
136 // we're not even going to link those in so we skip those crates.
137 if tcx.plugin_registrar_fn(cnum).is_some() ||
138 tcx.derive_registrar_fn(cnum).is_some() {
139 return Arc::new(Vec::new())
142 // Check to see if this crate is a "special runtime crate". These
143 // crates, implementation details of the standard library, typically
144 // have a bunch of `pub extern` and `#[no_mangle]` functions as the
145 // ABI between them. We don't want their symbols to have a `C`
146 // export level, however, as they're just implementation details.
147 // Down below we'll hardwire all of the symbols to the `Rust` export
149 let special_runtime_crate =
150 tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum);
152 let crate_exports = tcx
153 .exported_symbol_ids(cnum)
156 let name = tcx.symbol_name(Instance::mono(tcx, def_id));
157 let export_level = if special_runtime_crate {
158 // We can probably do better here by just ensuring that
159 // it has hidden visibility rather than public
160 // visibility, as this is primarily here to ensure it's
161 // not stripped during LTO.
163 // In general though we won't link right if these
164 // symbols are stripped, and LTO currently strips them.
165 if &*name == "rust_eh_personality" ||
166 &*name == "rust_eh_register_frames" ||
167 &*name == "rust_eh_unregister_frames" {
170 SymbolExportLevel::Rust
173 export_level(tcx, def_id)
175 debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level);
176 (str::to_owned(&name), Some(def_id), export_level)
180 Arc::new(crate_exports)
184 fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
185 if tcx.contains_extern_indicator(sym_def_id) {
188 SymbolExportLevel::Rust