]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/back/symbol_export.rs
e1f97e2c923db17d42ce32aab2a4be64fdc7363d
[rust.git] / src / librustc_trans / back / symbol_export.rs
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.
4 //
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.
10
11 use std::rc::Rc;
12 use std::sync::Arc;
13
14 use base;
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;
24
25 pub type ExportedSymbols = FxHashMap<
26     CrateNum,
27     Arc<Vec<(String, Option<DefId>, SymbolExportLevel)>>,
28 >;
29
30 pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel {
31     crates_export_threshold(&tcx.sess.crate_types.borrow())
32 }
33
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))
38 }
39
40 fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel {
41     match crate_type {
42         config::CrateTypeExecutable |
43         config::CrateTypeStaticlib  |
44         config::CrateTypeProcMacro  |
45         config::CrateTypeCdylib     => SymbolExportLevel::C,
46         config::CrateTypeRlib       |
47         config::CrateTypeDylib      => SymbolExportLevel::Rust,
48     }
49 }
50
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
55     }) {
56         SymbolExportLevel::Rust
57     } else {
58         SymbolExportLevel::C
59     }
60 }
61
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)
66             .iter()
67             .filter_map(|&(_, id, level)| {
68                 id.and_then(|id| {
69                     if level.is_below_threshold(export_threshold) {
70                         Some(id)
71                     } else {
72                         None
73                     }
74                 })
75             })
76             .collect())
77     };
78
79     providers.is_exported_symbol = |tcx, id| {
80         // FIXME(#42293) needs red/green to not break a bunch of incremental
81         // tests
82         tcx.dep_graph.with_ignore(|| {
83             tcx.exported_symbol_ids(id.krate).contains(&id)
84         })
85     };
86
87     providers.exported_symbols = |tcx, cnum| {
88         assert_eq!(cnum, LOCAL_CRATE);
89         let local_exported_symbols = base::find_exported_symbols(tcx);
90
91         let mut local_crate: Vec<_> = local_exported_symbols
92             .iter()
93             .map(|&node_id| {
94                 tcx.hir.local_def_id(node_id)
95             })
96             .map(|def_id| {
97                 let name = tcx.symbol_name(Instance::mono(tcx, def_id));
98                 let export_level = export_level(tcx, def_id);
99                 debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level);
100                 (str::to_owned(&name), Some(def_id), export_level)
101             })
102             .collect();
103
104         if let Some(_) = *tcx.sess.entry_fn.borrow() {
105             local_crate.push(("main".to_string(),
106                               None,
107                               SymbolExportLevel::C));
108         }
109
110         if tcx.sess.allocator_kind.get().is_some() {
111             for method in ALLOCATOR_METHODS {
112                 local_crate.push((format!("__rust_{}", method.name),
113                                   None,
114                                   SymbolExportLevel::Rust));
115             }
116         }
117
118         if let Some(id) = tcx.sess.derive_registrar_fn.get() {
119             let def_id = tcx.hir.local_def_id(id);
120             let idx = def_id.index;
121             let disambiguator = tcx.sess.local_crate_disambiguator();
122             let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator, idx);
123             local_crate.push((registrar, Some(def_id), SymbolExportLevel::C));
124         }
125
126         if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
127             local_crate.push((metadata_symbol_name(tcx),
128                               None,
129                               SymbolExportLevel::Rust));
130         }
131         Arc::new(local_crate)
132     };
133 }
134
135 pub fn provide_extern(providers: &mut Providers) {
136     providers.exported_symbols = |tcx, cnum| {
137         // If this crate is a plugin and/or a custom derive crate, then
138         // we're not even going to link those in so we skip those crates.
139         if tcx.plugin_registrar_fn(cnum).is_some() ||
140            tcx.derive_registrar_fn(cnum).is_some() {
141             return Arc::new(Vec::new())
142         }
143
144         // Check to see if this crate is a "special runtime crate". These
145         // crates, implementation details of the standard library, typically
146         // have a bunch of `pub extern` and `#[no_mangle]` functions as the
147         // ABI between them. We don't want their symbols to have a `C`
148         // export level, however, as they're just implementation details.
149         // Down below we'll hardwire all of the symbols to the `Rust` export
150         // level instead.
151         let special_runtime_crate =
152             tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum);
153
154         let crate_exports = tcx
155             .exported_symbol_ids(cnum)
156             .iter()
157             .map(|&def_id| {
158                 let name = tcx.symbol_name(Instance::mono(tcx, def_id));
159                 let export_level = if special_runtime_crate {
160                     // We can probably do better here by just ensuring that
161                     // it has hidden visibility rather than public
162                     // visibility, as this is primarily here to ensure it's
163                     // not stripped during LTO.
164                     //
165                     // In general though we won't link right if these
166                     // symbols are stripped, and LTO currently strips them.
167                     if &*name == "rust_eh_personality" ||
168                        &*name == "rust_eh_register_frames" ||
169                        &*name == "rust_eh_unregister_frames" {
170                         SymbolExportLevel::C
171                     } else {
172                         SymbolExportLevel::Rust
173                     }
174                 } else {
175                     export_level(tcx, def_id)
176                 };
177                 debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level);
178                 (str::to_owned(&name), Some(def_id), export_level)
179             })
180             .collect();
181
182         Arc::new(crate_exports)
183     };
184 }
185
186 fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
187     if tcx.contains_extern_indicator(sym_def_id) {
188         SymbolExportLevel::C
189     } else {
190         SymbolExportLevel::Rust
191     }
192 }