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.
11 use rustc_data_structures
::sync
::Lrc
;
14 use monomorphize
::Instance
;
16 use rustc
::hir
::CodegenFnAttrFlags
;
17 use rustc
::hir
::def_id
::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}
;
18 use rustc
::ich
::Fingerprint
;
19 use rustc
::middle
::exported_symbols
::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name}
;
20 use rustc
::session
::config
;
21 use rustc
::ty
::{TyCtxt, SymbolName}
;
22 use rustc
::ty
::query
::Providers
;
23 use rustc
::ty
::subst
::Substs
;
24 use rustc
::util
::nodemap
::{FxHashMap, DefIdMap}
;
25 use rustc_allocator
::ALLOCATOR_METHODS
;
26 use rustc_data_structures
::indexed_vec
::IndexVec
;
27 use std
::collections
::hash_map
::Entry
::*;
29 pub type ExportedSymbols
= FxHashMap
<
31 Arc
<Vec
<(String
, SymbolExportLevel
)>>,
34 pub fn threshold(tcx
: TyCtxt
) -> SymbolExportLevel
{
35 crates_export_threshold(&tcx
.sess
.crate_types
.borrow())
38 fn crate_export_threshold(crate_type
: config
::CrateType
) -> SymbolExportLevel
{
40 config
::CrateTypeExecutable
|
41 config
::CrateTypeStaticlib
|
42 config
::CrateTypeProcMacro
|
43 config
::CrateTypeCdylib
=> SymbolExportLevel
::C
,
44 config
::CrateTypeRlib
|
45 config
::CrateTypeDylib
=> SymbolExportLevel
::Rust
,
49 pub fn crates_export_threshold(crate_types
: &[config
::CrateType
])
50 -> SymbolExportLevel
{
51 if crate_types
.iter().any(|&crate_type
| {
52 crate_export_threshold(crate_type
) == SymbolExportLevel
::Rust
54 SymbolExportLevel
::Rust
60 fn reachable_non_generics_provider
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
62 -> Lrc
<DefIdMap
<SymbolExportLevel
>>
64 assert_eq
!(cnum
, LOCAL_CRATE
);
66 if !tcx
.sess
.opts
.output_types
.should_codegen() {
67 return Lrc
::new(DefIdMap())
70 // Check to see if this crate is a "special runtime crate". These
71 // crates, implementation details of the standard library, typically
72 // have a bunch of `pub extern` and `#[no_mangle]` functions as the
73 // ABI between them. We don't want their symbols to have a `C`
74 // export level, however, as they're just implementation details.
75 // Down below we'll hardwire all of the symbols to the `Rust` export
77 let special_runtime_crate
= tcx
.is_panic_runtime(LOCAL_CRATE
) ||
78 tcx
.is_compiler_builtins(LOCAL_CRATE
);
80 let mut reachable_non_generics
: DefIdMap
<_
> = tcx
.reachable_set(LOCAL_CRATE
).0
82 .filter_map(|&node_id
| {
83 // We want to ignore some FFI functions that are not exposed from
84 // this crate. Reachable FFI functions can be lumped into two
87 // 1. Those that are included statically via a static library
88 // 2. Those included otherwise (e.g. dynamically or via a framework)
90 // Although our LLVM module is not literally emitting code for the
91 // statically included symbols, it's an export of our library which
92 // needs to be passed on to the linker and encoded in the metadata.
94 // As a result, if this id is an FFI item (foreign item) then we only
95 // let it through if it's included statically.
96 match tcx
.hir
.get(node_id
) {
97 hir
::map
::NodeForeignItem(..) => {
98 let def_id
= tcx
.hir
.local_def_id(node_id
);
99 if tcx
.is_statically_included_foreign_item(def_id
) {
106 // Only consider nodes that actually have exported symbols.
107 hir
::map
::NodeItem(&hir
::Item
{
108 node
: hir
::ItemStatic(..),
111 hir
::map
::NodeItem(&hir
::Item
{
112 node
: hir
::ItemFn(..), ..
114 hir
::map
::NodeImplItem(&hir
::ImplItem
{
115 node
: hir
::ImplItemKind
::Method(..),
118 let def_id
= tcx
.hir
.local_def_id(node_id
);
119 let generics
= tcx
.generics_of(def_id
);
120 if !generics
.requires_monomorphization(tcx
) &&
121 // Functions marked with #[inline] are only ever codegened
122 // with "internal" linkage and are never exported.
123 !Instance
::mono(tcx
, def_id
).def
.requires_local(tcx
) {
134 let export_level
= if special_runtime_crate
{
135 let name
= tcx
.symbol_name(Instance
::mono(tcx
, def_id
)).as_str();
136 // We can probably do better here by just ensuring that
137 // it has hidden visibility rather than public
138 // visibility, as this is primarily here to ensure it's
139 // not stripped during LTO.
141 // In general though we won't link right if these
142 // symbols are stripped, and LTO currently strips them.
143 if &*name
== "rust_eh_personality" ||
144 &*name
== "rust_eh_register_frames" ||
145 &*name
== "rust_eh_unregister_frames" {
148 SymbolExportLevel
::Rust
151 symbol_export_level(tcx
, def_id
)
153 debug
!("EXPORTED SYMBOL (local): {} ({:?})",
154 tcx
.symbol_name(Instance
::mono(tcx
, def_id
)),
156 (def_id
, export_level
)
160 if let Some(id
) = *tcx
.sess
.derive_registrar_fn
.get() {
161 let def_id
= tcx
.hir
.local_def_id(id
);
162 reachable_non_generics
.insert(def_id
, SymbolExportLevel
::C
);
165 if let Some(id
) = *tcx
.sess
.plugin_registrar_fn
.get() {
166 let def_id
= tcx
.hir
.local_def_id(id
);
167 reachable_non_generics
.insert(def_id
, SymbolExportLevel
::C
);
170 Lrc
::new(reachable_non_generics
)
173 fn is_reachable_non_generic_provider_local
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
176 let export_threshold
= threshold(tcx
);
178 if let Some(&level
) = tcx
.reachable_non_generics(def_id
.krate
).get(&def_id
) {
179 level
.is_below_threshold(export_threshold
)
185 fn is_reachable_non_generic_provider_extern
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
188 tcx
.reachable_non_generics(def_id
.krate
).contains_key(&def_id
)
191 fn exported_symbols_provider_local
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
193 -> Arc
<Vec
<(ExportedSymbol
<'tcx
>,
196 assert_eq
!(cnum
, LOCAL_CRATE
);
198 if !tcx
.sess
.opts
.output_types
.should_codegen() {
199 return Arc
::new(vec
![])
202 let mut symbols
: Vec
<_
> = tcx
.reachable_non_generics(LOCAL_CRATE
)
204 .map(|(&def_id
, &level
)| {
205 (ExportedSymbol
::NonGeneric(def_id
), level
)
209 if let Some(_
) = *tcx
.sess
.entry_fn
.borrow() {
210 let symbol_name
= "main".to_string();
211 let exported_symbol
= ExportedSymbol
::NoDefId(SymbolName
::new(&symbol_name
));
213 symbols
.push((exported_symbol
, SymbolExportLevel
::C
));
216 if tcx
.sess
.allocator_kind
.get().is_some() {
217 for method
in ALLOCATOR_METHODS
{
218 let symbol_name
= format
!("__rust_{}", method
.name
);
219 let exported_symbol
= ExportedSymbol
::NoDefId(SymbolName
::new(&symbol_name
));
221 symbols
.push((exported_symbol
, SymbolExportLevel
::Rust
));
225 if tcx
.sess
.opts
.debugging_opts
.pgo_gen
.is_some() {
226 // These are weak symbols that point to the profile version and the
227 // profile name, which need to be treated as exported so LTO doesn't nix
229 const PROFILER_WEAK_SYMBOLS
: [&'
static str; 2] = [
230 "__llvm_profile_raw_version",
231 "__llvm_profile_filename",
233 for sym
in &PROFILER_WEAK_SYMBOLS
{
234 let exported_symbol
= ExportedSymbol
::NoDefId(SymbolName
::new(sym
));
235 symbols
.push((exported_symbol
, SymbolExportLevel
::C
));
239 if tcx
.sess
.crate_types
.borrow().contains(&config
::CrateTypeDylib
) {
240 let symbol_name
= metadata_symbol_name(tcx
);
241 let exported_symbol
= ExportedSymbol
::NoDefId(SymbolName
::new(&symbol_name
));
243 symbols
.push((exported_symbol
, SymbolExportLevel
::Rust
));
246 if tcx
.share_generics() && tcx
.local_crate_exports_generics() {
247 use rustc
::mir
::mono
::{Linkage, Visibility, MonoItem}
;
248 use rustc
::ty
::InstanceDef
;
250 // Normally, we require that shared monomorphizations are not hidden,
251 // because if we want to re-use a monomorphization from a Rust dylib, it
252 // needs to be exported.
253 // However, on platforms that don't allow for Rust dylibs, having
254 // external linkage is enough for monomorphization to be linked to.
255 let need_visibility
= tcx
.sess
.target
.target
.options
.dynamic_linking
&&
256 !tcx
.sess
.target
.target
.options
.only_cdylib
;
258 let (_
, cgus
) = tcx
.collect_and_partition_mono_items(LOCAL_CRATE
);
260 for (mono_item
, &(linkage
, visibility
)) in cgus
.iter()
261 .flat_map(|cgu
| cgu
.items().iter()) {
262 if linkage
!= Linkage
::External
{
263 // We can only re-use things with external linkage, otherwise
264 // we'll get a linker error
268 if need_visibility
&& visibility
== Visibility
::Hidden
{
269 // If we potentially share things from Rust dylibs, they must
274 if let &MonoItem
::Fn(Instance
{
275 def
: InstanceDef
::Item(def_id
),
278 if substs
.types().next().is_some() {
279 symbols
.push((ExportedSymbol
::Generic(def_id
, substs
),
280 SymbolExportLevel
::Rust
));
286 // Sort so we get a stable incr. comp. hash.
287 symbols
.sort_unstable_by(|&(ref symbol1
, ..), &(ref symbol2
, ..)| {
288 symbol1
.compare_stable(tcx
, symbol2
)
294 fn upstream_monomorphizations_provider
<'a
, 'tcx
>(
295 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
297 -> Lrc
<DefIdMap
<Lrc
<FxHashMap
<&'tcx Substs
<'tcx
>, CrateNum
>>>>
299 debug_assert
!(cnum
== LOCAL_CRATE
);
301 let cnums
= tcx
.all_crate_nums(LOCAL_CRATE
);
303 let mut instances
= DefIdMap();
305 let cnum_stable_ids
: IndexVec
<CrateNum
, Fingerprint
> = {
306 let mut cnum_stable_ids
= IndexVec
::from_elem_n(Fingerprint
::ZERO
,
309 for &cnum
in cnums
.iter() {
310 cnum_stable_ids
[cnum
] = tcx
.def_path_hash(DefId
{
312 index
: CRATE_DEF_INDEX
,
319 for &cnum
in cnums
.iter() {
320 for &(ref exported_symbol
, _
) in tcx
.exported_symbols(cnum
).iter() {
321 if let &ExportedSymbol
::Generic(def_id
, substs
) = exported_symbol
{
322 let substs_map
= instances
.entry(def_id
)
323 .or_insert_with(|| FxHashMap());
325 match substs_map
.entry(substs
) {
327 // If there are multiple monomorphizations available,
328 // we select one deterministically.
329 let other_cnum
= *e
.get();
330 if cnum_stable_ids
[other_cnum
] > cnum_stable_ids
[cnum
] {
342 Lrc
::new(instances
.into_iter()
343 .map(|(key
, value
)| (key
, Lrc
::new(value
)))
347 fn upstream_monomorphizations_for_provider
<'a
, 'tcx
>(
348 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
350 -> Option
<Lrc
<FxHashMap
<&'tcx Substs
<'tcx
>, CrateNum
>>>
352 debug_assert
!(!def_id
.is_local());
353 tcx
.upstream_monomorphizations(LOCAL_CRATE
)
358 fn is_unreachable_local_definition_provider(tcx
: TyCtxt
, def_id
: DefId
) -> bool
{
359 if let Some(node_id
) = tcx
.hir
.as_local_node_id(def_id
) {
360 !tcx
.reachable_set(LOCAL_CRATE
).0.contains(&node_id
)
362 bug
!("is_unreachable_local_definition called with non-local DefId: {:?}",
367 pub fn provide(providers
: &mut Providers
) {
368 providers
.reachable_non_generics
= reachable_non_generics_provider
;
369 providers
.is_reachable_non_generic
= is_reachable_non_generic_provider_local
;
370 providers
.exported_symbols
= exported_symbols_provider_local
;
371 providers
.upstream_monomorphizations
= upstream_monomorphizations_provider
;
372 providers
.is_unreachable_local_definition
= is_unreachable_local_definition_provider
;
375 pub fn provide_extern(providers
: &mut Providers
) {
376 providers
.is_reachable_non_generic
= is_reachable_non_generic_provider_extern
;
377 providers
.upstream_monomorphizations_for
= upstream_monomorphizations_for_provider
;
380 fn symbol_export_level(tcx
: TyCtxt
, sym_def_id
: DefId
) -> SymbolExportLevel
{
381 // We export anything that's not mangled at the "C" layer as it probably has
382 // to do with ABI concerns. We do not, however, apply such treatment to
383 // special symbols in the standard library for various plumbing between
384 // core/std/allocators/etc. For example symbols used to hook up allocation
385 // are not considered for export
386 let codegen_fn_attrs
= tcx
.codegen_fn_attrs(sym_def_id
);
387 let is_extern
= codegen_fn_attrs
.contains_extern_indicator();
389 codegen_fn_attrs
.flags
.contains(CodegenFnAttrFlags
::RUSTC_STD_INTERNAL_SYMBOL
);
391 if is_extern
&& !std_internal
{
394 SymbolExportLevel
::Rust