1 use std
::collections
::hash_map
::Entry
::*;
4 use rustc
::middle
::codegen_fn_attrs
::CodegenFnAttrFlags
;
5 use rustc
::middle
::exported_symbols
::{metadata_symbol_name, ExportedSymbol, SymbolExportLevel}
;
6 use rustc
::session
::config
::{self, Sanitizer}
;
7 use rustc
::ty
::query
::Providers
;
8 use rustc
::ty
::subst
::{GenericArgKind, SubstsRef}
;
9 use rustc
::ty
::Instance
;
10 use rustc
::ty
::{SymbolName, TyCtxt}
;
11 use rustc_codegen_utils
::symbol_names
;
12 use rustc_data_structures
::fingerprint
::Fingerprint
;
13 use rustc_data_structures
::fx
::FxHashMap
;
15 use rustc_hir
::def_id
::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE}
;
17 use rustc_index
::vec
::IndexVec
;
18 use syntax
::expand
::allocator
::ALLOCATOR_METHODS
;
20 pub fn threshold(tcx
: TyCtxt
<'_
>) -> SymbolExportLevel
{
21 crates_export_threshold(&tcx
.sess
.crate_types
.borrow())
24 fn crate_export_threshold(crate_type
: config
::CrateType
) -> SymbolExportLevel
{
26 config
::CrateType
::Executable
27 | config
::CrateType
::Staticlib
28 | config
::CrateType
::ProcMacro
29 | config
::CrateType
::Cdylib
=> SymbolExportLevel
::C
,
30 config
::CrateType
::Rlib
| config
::CrateType
::Dylib
=> SymbolExportLevel
::Rust
,
34 pub fn crates_export_threshold(crate_types
: &[config
::CrateType
]) -> SymbolExportLevel
{
37 .any(|&crate_type
| crate_export_threshold(crate_type
) == SymbolExportLevel
::Rust
)
39 SymbolExportLevel
::Rust
45 fn reachable_non_generics_provider(
48 ) -> &DefIdMap
<SymbolExportLevel
> {
49 assert_eq
!(cnum
, LOCAL_CRATE
);
51 if !tcx
.sess
.opts
.output_types
.should_codegen() {
52 return tcx
.arena
.alloc(Default
::default());
55 // Check to see if this crate is a "special runtime crate". These
56 // crates, implementation details of the standard library, typically
57 // have a bunch of `pub extern` and `#[no_mangle]` functions as the
58 // ABI between them. We don't want their symbols to have a `C`
59 // export level, however, as they're just implementation details.
60 // Down below we'll hardwire all of the symbols to the `Rust` export
62 let special_runtime_crate
=
63 tcx
.is_panic_runtime(LOCAL_CRATE
) || tcx
.is_compiler_builtins(LOCAL_CRATE
);
65 let mut reachable_non_generics
: DefIdMap
<_
> = tcx
66 .reachable_set(LOCAL_CRATE
)
68 .filter_map(|&hir_id
| {
69 // We want to ignore some FFI functions that are not exposed from
70 // this crate. Reachable FFI functions can be lumped into two
73 // 1. Those that are included statically via a static library
74 // 2. Those included otherwise (e.g., dynamically or via a framework)
76 // Although our LLVM module is not literally emitting code for the
77 // statically included symbols, it's an export of our library which
78 // needs to be passed on to the linker and encoded in the metadata.
80 // As a result, if this id is an FFI item (foreign item) then we only
81 // let it through if it's included statically.
82 match tcx
.hir().get(hir_id
) {
83 Node
::ForeignItem(..) => {
84 let def_id
= tcx
.hir().local_def_id(hir_id
);
85 tcx
.is_statically_included_foreign_item(def_id
).then_some(def_id
)
88 // Only consider nodes that actually have exported symbols.
89 Node
::Item(&hir
::Item { kind: hir::ItemKind::Static(..), .. }
)
90 | Node
::Item(&hir
::Item { kind: hir::ItemKind::Fn(..), .. }
)
91 | Node
::ImplItem(&hir
::ImplItem { kind: hir::ImplItemKind::Method(..), .. }
) => {
92 let def_id
= tcx
.hir().local_def_id(hir_id
);
93 let generics
= tcx
.generics_of(def_id
);
94 if !generics
.requires_monomorphization(tcx
) &&
95 // Functions marked with #[inline] are only ever codegened
96 // with "internal" linkage and are never exported.
97 !Instance
::mono(tcx
, def_id
).def
.generates_cgu_internal_copy(tcx
)
109 let export_level
= if special_runtime_crate
{
110 let name
= tcx
.symbol_name(Instance
::mono(tcx
, def_id
)).name
.as_str();
111 // We can probably do better here by just ensuring that
112 // it has hidden visibility rather than public
113 // visibility, as this is primarily here to ensure it's
114 // not stripped during LTO.
116 // In general though we won't link right if these
117 // symbols are stripped, and LTO currently strips them.
118 if name
== "rust_eh_personality"
119 || name
== "rust_eh_register_frames"
120 || name
== "rust_eh_unregister_frames"
124 SymbolExportLevel
::Rust
127 symbol_export_level(tcx
, def_id
)
130 "EXPORTED SYMBOL (local): {} ({:?})",
131 tcx
.symbol_name(Instance
::mono(tcx
, def_id
)),
134 (def_id
, export_level
)
138 if let Some(id
) = tcx
.proc_macro_decls_static(LOCAL_CRATE
) {
139 reachable_non_generics
.insert(id
, SymbolExportLevel
::C
);
142 if let Some(id
) = tcx
.plugin_registrar_fn(LOCAL_CRATE
) {
143 reachable_non_generics
.insert(id
, SymbolExportLevel
::C
);
146 tcx
.arena
.alloc(reachable_non_generics
)
149 fn is_reachable_non_generic_provider_local(tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> bool
{
150 let export_threshold
= threshold(tcx
);
152 if let Some(&level
) = tcx
.reachable_non_generics(def_id
.krate
).get(&def_id
) {
153 level
.is_below_threshold(export_threshold
)
159 fn is_reachable_non_generic_provider_extern(tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> bool
{
160 tcx
.reachable_non_generics(def_id
.krate
).contains_key(&def_id
)
163 fn exported_symbols_provider_local(
166 ) -> Arc
<Vec
<(ExportedSymbol
<'_
>, SymbolExportLevel
)>> {
167 assert_eq
!(cnum
, LOCAL_CRATE
);
169 if !tcx
.sess
.opts
.output_types
.should_codegen() {
170 return Arc
::new(vec
![]);
173 let mut symbols
: Vec
<_
> = tcx
174 .reachable_non_generics(LOCAL_CRATE
)
176 .map(|(&def_id
, &level
)| (ExportedSymbol
::NonGeneric(def_id
), level
))
179 if tcx
.entry_fn(LOCAL_CRATE
).is_some() {
180 let exported_symbol
= ExportedSymbol
::NoDefId(SymbolName
::new("main"));
182 symbols
.push((exported_symbol
, SymbolExportLevel
::C
));
185 if tcx
.allocator_kind().is_some() {
186 for method
in ALLOCATOR_METHODS
{
187 let symbol_name
= format
!("__rust_{}", method
.name
);
188 let exported_symbol
= ExportedSymbol
::NoDefId(SymbolName
::new(&symbol_name
));
190 symbols
.push((exported_symbol
, SymbolExportLevel
::Rust
));
194 if tcx
.sess
.opts
.cg
.profile_generate
.enabled() {
195 // These are weak symbols that point to the profile version and the
196 // profile name, which need to be treated as exported so LTO doesn't nix
198 const PROFILER_WEAK_SYMBOLS
: [&str; 2] =
199 ["__llvm_profile_raw_version", "__llvm_profile_filename"];
201 symbols
.extend(PROFILER_WEAK_SYMBOLS
.iter().map(|sym
| {
202 let exported_symbol
= ExportedSymbol
::NoDefId(SymbolName
::new(sym
));
203 (exported_symbol
, SymbolExportLevel
::C
)
207 if let Some(Sanitizer
::Memory
) = tcx
.sess
.opts
.debugging_opts
.sanitizer
{
208 // Similar to profiling, preserve weak msan symbol during LTO.
209 const MSAN_WEAK_SYMBOLS
: [&str; 2] = ["__msan_track_origins", "__msan_keep_going"];
211 symbols
.extend(MSAN_WEAK_SYMBOLS
.iter().map(|sym
| {
212 let exported_symbol
= ExportedSymbol
::NoDefId(SymbolName
::new(sym
));
213 (exported_symbol
, SymbolExportLevel
::C
)
217 if tcx
.sess
.crate_types
.borrow().contains(&config
::CrateType
::Dylib
) {
218 let symbol_name
= metadata_symbol_name(tcx
);
219 let exported_symbol
= ExportedSymbol
::NoDefId(SymbolName
::new(&symbol_name
));
221 symbols
.push((exported_symbol
, SymbolExportLevel
::Rust
));
224 if tcx
.sess
.opts
.share_generics() && tcx
.local_crate_exports_generics() {
225 use rustc
::mir
::mono
::{Linkage, MonoItem, Visibility}
;
226 use rustc
::ty
::InstanceDef
;
228 // Normally, we require that shared monomorphizations are not hidden,
229 // because if we want to re-use a monomorphization from a Rust dylib, it
230 // needs to be exported.
231 // However, on platforms that don't allow for Rust dylibs, having
232 // external linkage is enough for monomorphization to be linked to.
233 let need_visibility
= tcx
.sess
.target
.target
.options
.dynamic_linking
234 && !tcx
.sess
.target
.target
.options
.only_cdylib
;
236 let (_
, cgus
) = tcx
.collect_and_partition_mono_items(LOCAL_CRATE
);
238 for (mono_item
, &(linkage
, visibility
)) in cgus
.iter().flat_map(|cgu
| cgu
.items().iter()) {
239 if linkage
!= Linkage
::External
{
240 // We can only re-use things with external linkage, otherwise
241 // we'll get a linker error
245 if need_visibility
&& visibility
== Visibility
::Hidden
{
246 // If we potentially share things from Rust dylibs, they must
252 MonoItem
::Fn(Instance { def: InstanceDef::Item(def_id), substs }
) => {
253 if substs
.non_erasable_generics().next().is_some() {
254 let symbol
= ExportedSymbol
::Generic(def_id
, substs
);
255 symbols
.push((symbol
, SymbolExportLevel
::Rust
));
258 MonoItem
::Fn(Instance { def: InstanceDef::DropGlue(_, Some(ty)), substs }
) => {
259 // A little sanity-check
261 substs
.non_erasable_generics().next(),
262 Some(GenericArgKind
::Type(ty
))
264 symbols
.push((ExportedSymbol
::DropGlue(ty
), SymbolExportLevel
::Rust
));
267 // Any other symbols don't qualify for sharing
273 // Sort so we get a stable incr. comp. hash.
274 symbols
.sort_by_cached_key(|s
| s
.0.symbol_name_for_local_instance(tcx
));
279 fn upstream_monomorphizations_provider(
282 ) -> &DefIdMap
<FxHashMap
<SubstsRef
<'_
>, CrateNum
>> {
283 debug_assert
!(cnum
== LOCAL_CRATE
);
285 let cnums
= tcx
.all_crate_nums(LOCAL_CRATE
);
287 let mut instances
: DefIdMap
<FxHashMap
<_
, _
>> = Default
::default();
289 let cnum_stable_ids
: IndexVec
<CrateNum
, Fingerprint
> = {
290 let mut cnum_stable_ids
= IndexVec
::from_elem_n(Fingerprint
::ZERO
, cnums
.len() + 1);
292 for &cnum
in cnums
.iter() {
293 cnum_stable_ids
[cnum
] =
294 tcx
.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX }
).0;
300 let drop_in_place_fn_def_id
= tcx
.lang_items().drop_in_place_fn();
302 for &cnum
in cnums
.iter() {
303 for (exported_symbol
, _
) in tcx
.exported_symbols(cnum
).iter() {
304 let (def_id
, substs
) = match *exported_symbol
{
305 ExportedSymbol
::Generic(def_id
, substs
) => (def_id
, substs
),
306 ExportedSymbol
::DropGlue(ty
) => {
307 if let Some(drop_in_place_fn_def_id
) = drop_in_place_fn_def_id
{
308 (drop_in_place_fn_def_id
, tcx
.intern_substs(&[ty
.into()]))
310 // `drop_in_place` in place does not exist, don't try
315 ExportedSymbol
::NonGeneric(..) | ExportedSymbol
::NoDefId(..) => {
316 // These are no monomorphizations
321 let substs_map
= instances
.entry(def_id
).or_default();
323 match substs_map
.entry(substs
) {
325 // If there are multiple monomorphizations available,
326 // we select one deterministically.
327 let other_cnum
= *e
.get();
328 if cnum_stable_ids
[other_cnum
] > cnum_stable_ids
[cnum
] {
339 tcx
.arena
.alloc(instances
)
342 fn upstream_monomorphizations_for_provider(
345 ) -> Option
<&FxHashMap
<SubstsRef
<'_
>, CrateNum
>> {
346 debug_assert
!(!def_id
.is_local());
347 tcx
.upstream_monomorphizations(LOCAL_CRATE
).get(&def_id
)
350 fn upstream_drop_glue_for_provider
<'tcx
>(
352 substs
: SubstsRef
<'tcx
>,
353 ) -> Option
<CrateNum
> {
354 if let Some(def_id
) = tcx
.lang_items().drop_in_place_fn() {
355 tcx
.upstream_monomorphizations_for(def_id
).and_then(|monos
| monos
.get(&substs
).cloned())
361 fn is_unreachable_local_definition_provider(tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> bool
{
362 if let Some(hir_id
) = tcx
.hir().as_local_hir_id(def_id
) {
363 !tcx
.reachable_set(LOCAL_CRATE
).contains(&hir_id
)
365 bug
!("is_unreachable_local_definition called with non-local DefId: {:?}", def_id
)
369 pub fn provide(providers
: &mut Providers
<'_
>) {
370 providers
.reachable_non_generics
= reachable_non_generics_provider
;
371 providers
.is_reachable_non_generic
= is_reachable_non_generic_provider_local
;
372 providers
.exported_symbols
= exported_symbols_provider_local
;
373 providers
.upstream_monomorphizations
= upstream_monomorphizations_provider
;
374 providers
.is_unreachable_local_definition
= is_unreachable_local_definition_provider
;
375 providers
.upstream_drop_glue_for
= upstream_drop_glue_for_provider
;
378 pub fn provide_extern(providers
: &mut Providers
<'_
>) {
379 providers
.is_reachable_non_generic
= is_reachable_non_generic_provider_extern
;
380 providers
.upstream_monomorphizations_for
= upstream_monomorphizations_for_provider
;
383 fn symbol_export_level(tcx
: TyCtxt
<'_
>, sym_def_id
: DefId
) -> SymbolExportLevel
{
384 // We export anything that's not mangled at the "C" layer as it probably has
385 // to do with ABI concerns. We do not, however, apply such treatment to
386 // special symbols in the standard library for various plumbing between
387 // core/std/allocators/etc. For example symbols used to hook up allocation
388 // are not considered for export
389 let codegen_fn_attrs
= tcx
.codegen_fn_attrs(sym_def_id
);
390 let is_extern
= codegen_fn_attrs
.contains_extern_indicator();
392 codegen_fn_attrs
.flags
.contains(CodegenFnAttrFlags
::RUSTC_STD_INTERNAL_SYMBOL
);
394 if is_extern
&& !std_internal
{
395 let target
= &tcx
.sess
.target
.target
.llvm_target
;
396 // WebAssembly cannot export data symbols, so reduce their export level
397 if target
.contains("emscripten") {
398 if let Some(Node
::Item(&hir
::Item { kind: hir::ItemKind::Static(..), .. }
)) =
399 tcx
.hir().get_if_local(sym_def_id
)
401 return SymbolExportLevel
::Rust
;
407 SymbolExportLevel
::Rust
411 /// This is the symbol name of the given instance instantiated in a specific crate.
412 pub fn symbol_name_for_instance_in_crate
<'tcx
>(
414 symbol
: ExportedSymbol
<'tcx
>,
415 instantiating_crate
: CrateNum
,
417 // If this is something instantiated in the local crate then we might
418 // already have cached the name as a query result.
419 if instantiating_crate
== LOCAL_CRATE
{
420 return symbol
.symbol_name_for_local_instance(tcx
).to_string();
423 // This is something instantiated in an upstream crate, so we have to use
424 // the slower (because uncached) version of computing the symbol name.
426 ExportedSymbol
::NonGeneric(def_id
) => symbol_names
::symbol_name_for_instance_in_crate(
428 Instance
::mono(tcx
, def_id
),
431 ExportedSymbol
::Generic(def_id
, substs
) => symbol_names
::symbol_name_for_instance_in_crate(
433 Instance
::new(def_id
, substs
),
436 ExportedSymbol
::DropGlue(ty
) => symbol_names
::symbol_name_for_instance_in_crate(
438 Instance
::resolve_drop_in_place(tcx
, ty
),
441 ExportedSymbol
::NoDefId(symbol_name
) => symbol_name
.to_string(),