1 use std
::collections
::hash_map
::Entry
::*;
3 use rustc_ast
::expand
::allocator
::ALLOCATOR_METHODS
;
4 use rustc_data_structures
::fingerprint
::Fingerprint
;
5 use rustc_data_structures
::fx
::FxHashMap
;
7 use rustc_hir
::def_id
::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}
;
9 use rustc_index
::vec
::IndexVec
;
10 use rustc_middle
::middle
::codegen_fn_attrs
::CodegenFnAttrFlags
;
11 use rustc_middle
::middle
::exported_symbols
::{
12 metadata_symbol_name
, ExportedSymbol
, SymbolExportLevel
,
14 use rustc_middle
::ty
::query
::{ExternProviders, Providers}
;
15 use rustc_middle
::ty
::subst
::{GenericArgKind, SubstsRef}
;
16 use rustc_middle
::ty
::Instance
;
17 use rustc_middle
::ty
::{SymbolName, TyCtxt}
;
18 use rustc_session
::config
::CrateType
;
19 use rustc_target
::spec
::SanitizerSet
;
21 pub fn threshold(tcx
: TyCtxt
<'_
>) -> SymbolExportLevel
{
22 crates_export_threshold(&tcx
.sess
.crate_types())
25 fn crate_export_threshold(crate_type
: CrateType
) -> SymbolExportLevel
{
27 CrateType
::Executable
| CrateType
::Staticlib
| CrateType
::ProcMacro
| CrateType
::Cdylib
=> {
30 CrateType
::Rlib
| CrateType
::Dylib
=> SymbolExportLevel
::Rust
,
34 pub fn crates_export_threshold(crate_types
: &[CrateType
]) -> SymbolExportLevel
{
37 .any(|&crate_type
| crate_export_threshold(crate_type
) == SymbolExportLevel
::Rust
)
39 SymbolExportLevel
::Rust
45 fn reachable_non_generics_provider(tcx
: TyCtxt
<'_
>, cnum
: CrateNum
) -> DefIdMap
<SymbolExportLevel
> {
46 assert_eq
!(cnum
, LOCAL_CRATE
);
48 if !tcx
.sess
.opts
.output_types
.should_codegen() {
49 return Default
::default();
52 // Check to see if this crate is a "special runtime crate". These
53 // crates, implementation details of the standard library, typically
54 // have a bunch of `pub extern` and `#[no_mangle]` functions as the
55 // ABI between them. We don't want their symbols to have a `C`
56 // export level, however, as they're just implementation details.
57 // Down below we'll hardwire all of the symbols to the `Rust` export
59 let special_runtime_crate
=
60 tcx
.is_panic_runtime(LOCAL_CRATE
) || tcx
.is_compiler_builtins(LOCAL_CRATE
);
62 let mut reachable_non_generics
: DefIdMap
<_
> = tcx
65 .filter_map(|&def_id
| {
66 // We want to ignore some FFI functions that are not exposed from
67 // this crate. Reachable FFI functions can be lumped into two
70 // 1. Those that are included statically via a static library
71 // 2. Those included otherwise (e.g., dynamically or via a framework)
73 // Although our LLVM module is not literally emitting code for the
74 // statically included symbols, it's an export of our library which
75 // needs to be passed on to the linker and encoded in the metadata.
77 // As a result, if this id is an FFI item (foreign item) then we only
78 // let it through if it's included statically.
79 match tcx
.hir().get_by_def_id(def_id
) {
80 Node
::ForeignItem(..) => {
81 tcx
.is_statically_included_foreign_item(def_id
).then_some(def_id
)
84 // Only consider nodes that actually have exported symbols.
85 Node
::Item(&hir
::Item
{
86 kind
: hir
::ItemKind
::Static(..) | hir
::ItemKind
::Fn(..),
89 | Node
::ImplItem(&hir
::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }
) => {
90 let generics
= tcx
.generics_of(def_id
);
91 if !generics
.requires_monomorphization(tcx
)
92 // Functions marked with #[inline] are codegened with "internal"
93 // linkage and are not exported unless marked with an extern
95 && (!Instance
::mono(tcx
, def_id
.to_def_id()).def
.generates_cgu_internal_copy(tcx
)
96 || tcx
.codegen_fn_attrs(def_id
.to_def_id()).contains_extern_indicator())
108 let export_level
= if special_runtime_crate
{
109 let name
= tcx
.symbol_name(Instance
::mono(tcx
, def_id
.to_def_id())).name
;
110 // We can probably do better here by just ensuring that
111 // it has hidden visibility rather than public
112 // visibility, as this is primarily here to ensure it's
113 // not stripped during LTO.
115 // In general though we won't link right if these
116 // symbols are stripped, and LTO currently strips them.
118 "rust_eh_personality"
119 | "rust_eh_register_frames"
120 | "rust_eh_unregister_frames" =>
121 SymbolExportLevel
::C
,
122 _
=> SymbolExportLevel
::Rust
,
125 symbol_export_level(tcx
, def_id
.to_def_id())
128 "EXPORTED SYMBOL (local): {} ({:?})",
129 tcx
.symbol_name(Instance
::mono(tcx
, def_id
.to_def_id())),
132 (def_id
.to_def_id(), export_level
)
136 if let Some(id
) = tcx
.proc_macro_decls_static(()) {
137 reachable_non_generics
.insert(id
.to_def_id(), SymbolExportLevel
::C
);
140 reachable_non_generics
143 fn is_reachable_non_generic_provider_local(tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> bool
{
144 let export_threshold
= threshold(tcx
);
146 if let Some(&level
) = tcx
.reachable_non_generics(def_id
.krate
).get(&def_id
) {
147 level
.is_below_threshold(export_threshold
)
153 fn is_reachable_non_generic_provider_extern(tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> bool
{
154 tcx
.reachable_non_generics(def_id
.krate
).contains_key(&def_id
)
157 fn exported_symbols_provider_local
<'tcx
>(
160 ) -> &'tcx
[(ExportedSymbol
<'tcx
>, SymbolExportLevel
)] {
161 assert_eq
!(cnum
, LOCAL_CRATE
);
163 if !tcx
.sess
.opts
.output_types
.should_codegen() {
167 let mut symbols
: Vec
<_
> = tcx
168 .reachable_non_generics(LOCAL_CRATE
)
170 .map(|(&def_id
, &level
)| (ExportedSymbol
::NonGeneric(def_id
), level
))
173 if tcx
.entry_fn(()).is_some() {
174 let exported_symbol
= ExportedSymbol
::NoDefId(SymbolName
::new(tcx
, "main"));
176 symbols
.push((exported_symbol
, SymbolExportLevel
::C
));
179 if tcx
.allocator_kind(()).is_some() {
180 for method
in ALLOCATOR_METHODS
{
181 let symbol_name
= format
!("__rust_{}", method
.name
);
182 let exported_symbol
= ExportedSymbol
::NoDefId(SymbolName
::new(tcx
, &symbol_name
));
184 symbols
.push((exported_symbol
, SymbolExportLevel
::Rust
));
188 if tcx
.sess
.instrument_coverage() || tcx
.sess
.opts
.cg
.profile_generate
.enabled() {
189 // These are weak symbols that point to the profile version and the
190 // profile name, which need to be treated as exported so LTO doesn't nix
192 const PROFILER_WEAK_SYMBOLS
: [&str; 2] =
193 ["__llvm_profile_raw_version", "__llvm_profile_filename"];
195 symbols
.extend(PROFILER_WEAK_SYMBOLS
.iter().map(|sym
| {
196 let exported_symbol
= ExportedSymbol
::NoDefId(SymbolName
::new(tcx
, sym
));
197 (exported_symbol
, SymbolExportLevel
::C
)
201 if tcx
.sess
.opts
.debugging_opts
.sanitizer
.contains(SanitizerSet
::MEMORY
) {
202 // Similar to profiling, preserve weak msan symbol during LTO.
203 const MSAN_WEAK_SYMBOLS
: [&str; 2] = ["__msan_track_origins", "__msan_keep_going"];
205 symbols
.extend(MSAN_WEAK_SYMBOLS
.iter().map(|sym
| {
206 let exported_symbol
= ExportedSymbol
::NoDefId(SymbolName
::new(tcx
, sym
));
207 (exported_symbol
, SymbolExportLevel
::C
)
211 if tcx
.sess
.crate_types().contains(&CrateType
::Dylib
) {
212 let symbol_name
= metadata_symbol_name(tcx
);
213 let exported_symbol
= ExportedSymbol
::NoDefId(SymbolName
::new(tcx
, &symbol_name
));
215 symbols
.push((exported_symbol
, SymbolExportLevel
::Rust
));
218 if tcx
.sess
.opts
.share_generics() && tcx
.local_crate_exports_generics() {
219 use rustc_middle
::mir
::mono
::{Linkage, MonoItem, Visibility}
;
220 use rustc_middle
::ty
::InstanceDef
;
222 // Normally, we require that shared monomorphizations are not hidden,
223 // because if we want to re-use a monomorphization from a Rust dylib, it
224 // needs to be exported.
225 // However, on platforms that don't allow for Rust dylibs, having
226 // external linkage is enough for monomorphization to be linked to.
227 let need_visibility
= tcx
.sess
.target
.dynamic_linking
&& !tcx
.sess
.target
.only_cdylib
;
229 let (_
, cgus
) = tcx
.collect_and_partition_mono_items(());
231 for (mono_item
, &(linkage
, visibility
)) in cgus
.iter().flat_map(|cgu
| cgu
.items().iter()) {
232 if linkage
!= Linkage
::External
{
233 // We can only re-use things with external linkage, otherwise
234 // we'll get a linker error
238 if need_visibility
&& visibility
== Visibility
::Hidden
{
239 // If we potentially share things from Rust dylibs, they must
245 MonoItem
::Fn(Instance { def: InstanceDef::Item(def), substs }
) => {
246 if substs
.non_erasable_generics().next().is_some() {
247 let symbol
= ExportedSymbol
::Generic(def
.did
, substs
);
248 symbols
.push((symbol
, SymbolExportLevel
::Rust
));
251 MonoItem
::Fn(Instance { def: InstanceDef::DropGlue(_, Some(ty)), substs }
) => {
252 // A little sanity-check
254 substs
.non_erasable_generics().next(),
255 Some(GenericArgKind
::Type(ty
))
257 symbols
.push((ExportedSymbol
::DropGlue(ty
), SymbolExportLevel
::Rust
));
260 // Any other symbols don't qualify for sharing
266 // Sort so we get a stable incr. comp. hash.
267 symbols
.sort_by_cached_key(|s
| s
.0.symbol_name_for_local_instance(tcx
));
269 tcx
.arena
.alloc_from_iter(symbols
)
272 fn upstream_monomorphizations_provider(
275 ) -> DefIdMap
<FxHashMap
<SubstsRef
<'_
>, CrateNum
>> {
276 let cnums
= tcx
.crates(());
278 let mut instances
: DefIdMap
<FxHashMap
<_
, _
>> = Default
::default();
280 let cnum_stable_ids
: IndexVec
<CrateNum
, Fingerprint
> = {
281 let mut cnum_stable_ids
= IndexVec
::from_elem_n(Fingerprint
::ZERO
, cnums
.len() + 1);
283 for &cnum
in cnums
.iter() {
284 cnum_stable_ids
[cnum
] =
285 tcx
.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX }
).0;
291 let drop_in_place_fn_def_id
= tcx
.lang_items().drop_in_place_fn();
293 for &cnum
in cnums
.iter() {
294 for (exported_symbol
, _
) in tcx
.exported_symbols(cnum
).iter() {
295 let (def_id
, substs
) = match *exported_symbol
{
296 ExportedSymbol
::Generic(def_id
, substs
) => (def_id
, substs
),
297 ExportedSymbol
::DropGlue(ty
) => {
298 if let Some(drop_in_place_fn_def_id
) = drop_in_place_fn_def_id
{
299 (drop_in_place_fn_def_id
, tcx
.intern_substs(&[ty
.into()]))
301 // `drop_in_place` in place does not exist, don't try
306 ExportedSymbol
::NonGeneric(..) | ExportedSymbol
::NoDefId(..) => {
307 // These are no monomorphizations
312 let substs_map
= instances
.entry(def_id
).or_default();
314 match substs_map
.entry(substs
) {
316 // If there are multiple monomorphizations available,
317 // we select one deterministically.
318 let other_cnum
= *e
.get();
319 if cnum_stable_ids
[other_cnum
] > cnum_stable_ids
[cnum
] {
333 fn upstream_monomorphizations_for_provider(
336 ) -> Option
<&FxHashMap
<SubstsRef
<'_
>, CrateNum
>> {
337 debug_assert
!(!def_id
.is_local());
338 tcx
.upstream_monomorphizations(()).get(&def_id
)
341 fn upstream_drop_glue_for_provider
<'tcx
>(
343 substs
: SubstsRef
<'tcx
>,
344 ) -> Option
<CrateNum
> {
345 if let Some(def_id
) = tcx
.lang_items().drop_in_place_fn() {
346 tcx
.upstream_monomorphizations_for(def_id
).and_then(|monos
| monos
.get(&substs
).cloned())
352 fn is_unreachable_local_definition_provider(tcx
: TyCtxt
<'_
>, def_id
: LocalDefId
) -> bool
{
353 !tcx
.reachable_set(()).contains(&def_id
)
356 pub fn provide(providers
: &mut Providers
) {
357 providers
.reachable_non_generics
= reachable_non_generics_provider
;
358 providers
.is_reachable_non_generic
= is_reachable_non_generic_provider_local
;
359 providers
.exported_symbols
= exported_symbols_provider_local
;
360 providers
.upstream_monomorphizations
= upstream_monomorphizations_provider
;
361 providers
.is_unreachable_local_definition
= is_unreachable_local_definition_provider
;
362 providers
.upstream_drop_glue_for
= upstream_drop_glue_for_provider
;
363 providers
.wasm_import_module_map
= wasm_import_module_map
;
366 pub fn provide_extern(providers
: &mut ExternProviders
) {
367 providers
.is_reachable_non_generic
= is_reachable_non_generic_provider_extern
;
368 providers
.upstream_monomorphizations_for
= upstream_monomorphizations_for_provider
;
371 fn symbol_export_level(tcx
: TyCtxt
<'_
>, sym_def_id
: DefId
) -> SymbolExportLevel
{
372 // We export anything that's not mangled at the "C" layer as it probably has
373 // to do with ABI concerns. We do not, however, apply such treatment to
374 // special symbols in the standard library for various plumbing between
375 // core/std/allocators/etc. For example symbols used to hook up allocation
376 // are not considered for export
377 let codegen_fn_attrs
= tcx
.codegen_fn_attrs(sym_def_id
);
378 let is_extern
= codegen_fn_attrs
.contains_extern_indicator();
380 codegen_fn_attrs
.flags
.contains(CodegenFnAttrFlags
::RUSTC_STD_INTERNAL_SYMBOL
);
382 if is_extern
&& !std_internal
{
383 let target
= &tcx
.sess
.target
.llvm_target
;
384 // WebAssembly cannot export data symbols, so reduce their export level
385 if target
.contains("emscripten") {
386 if let Some(Node
::Item(&hir
::Item { kind: hir::ItemKind::Static(..), .. }
)) =
387 tcx
.hir().get_if_local(sym_def_id
)
389 return SymbolExportLevel
::Rust
;
395 SymbolExportLevel
::Rust
399 /// This is the symbol name of the given instance instantiated in a specific crate.
400 pub fn symbol_name_for_instance_in_crate
<'tcx
>(
402 symbol
: ExportedSymbol
<'tcx
>,
403 instantiating_crate
: CrateNum
,
405 // If this is something instantiated in the local crate then we might
406 // already have cached the name as a query result.
407 if instantiating_crate
== LOCAL_CRATE
{
408 return symbol
.symbol_name_for_local_instance(tcx
).to_string();
411 // This is something instantiated in an upstream crate, so we have to use
412 // the slower (because uncached) version of computing the symbol name.
414 ExportedSymbol
::NonGeneric(def_id
) => {
415 rustc_symbol_mangling
::symbol_name_for_instance_in_crate(
417 Instance
::mono(tcx
, def_id
),
421 ExportedSymbol
::Generic(def_id
, substs
) => {
422 rustc_symbol_mangling
::symbol_name_for_instance_in_crate(
424 Instance
::new(def_id
, substs
),
428 ExportedSymbol
::DropGlue(ty
) => rustc_symbol_mangling
::symbol_name_for_instance_in_crate(
430 Instance
::resolve_drop_in_place(tcx
, ty
),
433 ExportedSymbol
::NoDefId(symbol_name
) => symbol_name
.to_string(),
437 fn wasm_import_module_map(tcx
: TyCtxt
<'_
>, cnum
: CrateNum
) -> FxHashMap
<DefId
, String
> {
438 // Build up a map from DefId to a `NativeLib` structure, where
439 // `NativeLib` internally contains information about
440 // `#[link(wasm_import_module = "...")]` for example.
441 let native_libs
= tcx
.native_libraries(cnum
);
443 let def_id_to_native_lib
= native_libs
445 .filter_map(|lib
| lib
.foreign_module
.map(|id
| (id
, lib
)))
446 .collect
::<FxHashMap
<_
, _
>>();
448 let mut ret
= FxHashMap
::default();
449 for (def_id
, lib
) in tcx
.foreign_modules(cnum
).iter() {
450 let module
= def_id_to_native_lib
.get(&def_id
).and_then(|s
| s
.wasm_import_module
);
451 let module
= match module
{
455 ret
.extend(lib
.foreign_items
.iter().map(|id
| {
456 assert_eq
!(id
.krate
, cnum
);
457 (*id
, module
.to_string())