1use std::collections::hash_map::Entry::*;
2
3use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE};
4use rustc_data_structures::unord::UnordMap;
5use rustc_hir::def::DefKind;
6use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId};
7use rustc_middle::bug;
8use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
9use rustc_middle::middle::exported_symbols::{
10 ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, metadata_symbol_name,
11};
12use rustc_middle::query::LocalCrate;
13use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolName, TyCtxt};
14use rustc_middle::util::Providers;
15use rustc_session::config::{CrateType, OomStrategy};
16use rustc_target::spec::{SanitizerSet, TlsModel};
17use tracing::debug;
18
19use crate::base::allocator_kind_for_codegen;
20
21fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
22 crates_export_threshold(tcx.crate_types())
23}
24
25fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel {
26 match crate_type {
27 CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Cdylib => {
28 SymbolExportLevel::C
29 }
30 CrateType::Rlib | CrateType::Dylib => SymbolExportLevel::Rust,
31 }
32}
33
34pub fn crates_export_threshold(crate_types: &[CrateType]) -> SymbolExportLevel {
35 if crate_types
36 .iter()
37 .any(|&crate_type| crate_export_threshold(crate_type) == SymbolExportLevel::Rust)
38 {
39 SymbolExportLevel::Rust
40 } else {
41 SymbolExportLevel::C
42 }
43}
44
45fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<SymbolExportInfo> {
46 if !tcx.sess.opts.output_types.should_codegen() {
47 return Default::default();
48 }
49
50 let special_runtime_crate =
58 tcx.is_panic_runtime(LOCAL_CRATE) || tcx.is_compiler_builtins(LOCAL_CRATE);
59
60 let mut reachable_non_generics: DefIdMap<_> = tcx
61 .reachable_set(())
62 .items()
63 .filter_map(|&def_id| {
64 if let Some(parent_id) = tcx.opt_local_parent(def_id)
78 && let DefKind::ForeignMod = tcx.def_kind(parent_id)
79 {
80 let library = tcx.native_library(def_id)?;
81 return library.kind.is_statically_included().then_some(def_id);
82 }
83
84 match tcx.def_kind(def_id) {
86 DefKind::Fn | DefKind::Static { .. } => {}
87 DefKind::AssocFn if tcx.impl_of_method(def_id.to_def_id()).is_some() => {}
88 _ => return None,
89 };
90
91 let generics = tcx.generics_of(def_id);
92 if generics.requires_monomorphization(tcx) {
93 return None;
94 }
95
96 if !Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx)
100 || tcx.codegen_fn_attrs(def_id.to_def_id()).contains_extern_indicator()
101 {
102 Some(def_id)
103 } else {
104 None
105 }
106 })
107 .map(|def_id| {
108 let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name;
110 let used = name == "rust_eh_personality";
111
112 let export_level = if special_runtime_crate {
113 SymbolExportLevel::Rust
114 } else {
115 symbol_export_level(tcx, def_id.to_def_id())
116 };
117 let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id());
118 debug!(
119 "EXPORTED SYMBOL (local): {} ({:?})",
120 tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())),
121 export_level
122 );
123 let info = SymbolExportInfo {
124 level: export_level,
125 kind: if tcx.is_static(def_id.to_def_id()) {
126 if codegen_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
127 SymbolExportKind::Tls
128 } else {
129 SymbolExportKind::Data
130 }
131 } else {
132 SymbolExportKind::Text
133 },
134 used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
135 || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
136 || used,
137 };
138 (def_id.to_def_id(), info)
139 })
140 .into();
141
142 if let Some(id) = tcx.proc_macro_decls_static(()) {
143 reachable_non_generics.insert(
144 id.to_def_id(),
145 SymbolExportInfo {
146 level: SymbolExportLevel::C,
147 kind: SymbolExportKind::Data,
148 used: false,
149 },
150 );
151 }
152
153 reachable_non_generics
154}
155
156fn is_reachable_non_generic_provider_local(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
157 let export_threshold = threshold(tcx);
158
159 if let Some(&info) = tcx.reachable_non_generics(LOCAL_CRATE).get(&def_id.to_def_id()) {
160 info.level.is_below_threshold(export_threshold)
161 } else {
162 false
163 }
164}
165
166fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
167 tcx.reachable_non_generics(def_id.krate).contains_key(&def_id)
168}
169
170fn exported_symbols_provider_local(
171 tcx: TyCtxt<'_>,
172 _: LocalCrate,
173) -> &[(ExportedSymbol<'_>, SymbolExportInfo)] {
174 if !tcx.sess.opts.output_types.should_codegen() {
175 return &[];
176 }
177
178 let sorted = tcx.with_stable_hashing_context(|hcx| {
181 tcx.reachable_non_generics(LOCAL_CRATE).to_sorted(&hcx, true)
182 });
183
184 let mut symbols: Vec<_> =
185 sorted.iter().map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)).collect();
186
187 if !tcx.sess.target.dll_tls_export {
189 symbols.extend(sorted.iter().filter_map(|(&def_id, &info)| {
190 tcx.needs_thread_local_shim(def_id).then(|| {
191 (
192 ExportedSymbol::ThreadLocalShim(def_id),
193 SymbolExportInfo {
194 level: info.level,
195 kind: SymbolExportKind::Text,
196 used: info.used,
197 },
198 )
199 })
200 }))
201 }
202
203 if tcx.entry_fn(()).is_some() {
204 let exported_symbol =
205 ExportedSymbol::NoDefId(SymbolName::new(tcx, tcx.sess.target.entry_name.as_ref()));
206
207 symbols.push((
208 exported_symbol,
209 SymbolExportInfo {
210 level: SymbolExportLevel::C,
211 kind: SymbolExportKind::Text,
212 used: false,
213 },
214 ));
215 }
216
217 if allocator_kind_for_codegen(tcx).is_some() {
219 for symbol_name in ALLOCATOR_METHODS
220 .iter()
221 .map(|method| format!("__rust_{}", method.name))
222 .chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()])
223 {
224 let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
225
226 symbols.push((
227 exported_symbol,
228 SymbolExportInfo {
229 level: SymbolExportLevel::Rust,
230 kind: SymbolExportKind::Text,
231 used: false,
232 },
233 ));
234 }
235
236 let exported_symbol =
237 ExportedSymbol::NoDefId(SymbolName::new(tcx, NO_ALLOC_SHIM_IS_UNSTABLE));
238 symbols.push((
239 exported_symbol,
240 SymbolExportInfo {
241 level: SymbolExportLevel::Rust,
242 kind: SymbolExportKind::Data,
243 used: false,
244 },
245 ))
246 }
247
248 if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() {
249 const PROFILER_WEAK_SYMBOLS: [&str; 2] =
253 ["__llvm_profile_raw_version", "__llvm_profile_filename"];
254
255 symbols.extend(PROFILER_WEAK_SYMBOLS.iter().map(|sym| {
256 let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym));
257 (
258 exported_symbol,
259 SymbolExportInfo {
260 level: SymbolExportLevel::C,
261 kind: SymbolExportKind::Data,
262 used: false,
263 },
264 )
265 }));
266 }
267
268 if tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) {
269 let mut msan_weak_symbols = Vec::new();
270
271 if tcx.sess.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY) {
273 msan_weak_symbols.push("__msan_keep_going");
274 }
275
276 if tcx.sess.opts.unstable_opts.sanitizer_memory_track_origins != 0 {
277 msan_weak_symbols.push("__msan_track_origins");
278 }
279
280 symbols.extend(msan_weak_symbols.into_iter().map(|sym| {
281 let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym));
282 (
283 exported_symbol,
284 SymbolExportInfo {
285 level: SymbolExportLevel::C,
286 kind: SymbolExportKind::Data,
287 used: false,
288 },
289 )
290 }));
291 }
292
293 if tcx.crate_types().contains(&CrateType::Dylib)
294 || tcx.crate_types().contains(&CrateType::ProcMacro)
295 {
296 let symbol_name = metadata_symbol_name(tcx);
297 let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
298
299 symbols.push((
300 exported_symbol,
301 SymbolExportInfo {
302 level: SymbolExportLevel::C,
303 kind: SymbolExportKind::Data,
304 used: true,
305 },
306 ));
307 }
308
309 if tcx.local_crate_exports_generics() {
310 use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility};
311 use rustc_middle::ty::InstanceKind;
312
313 let need_visibility = tcx.sess.target.dynamic_linking && !tcx.sess.target.only_cdylib;
319
320 let cgus = tcx.collect_and_partition_mono_items(()).codegen_units;
321
322 #[allow(rustc::potential_query_instability)]
324 for (mono_item, data) in cgus.iter().flat_map(|cgu| cgu.items().iter()) {
325 if data.linkage != Linkage::External {
326 continue;
329 }
330
331 if need_visibility && data.visibility == Visibility::Hidden {
332 continue;
335 }
336
337 if !tcx.sess.opts.share_generics() {
338 if tcx.codegen_fn_attrs(mono_item.def_id()).inline
339 == rustc_attr_parsing::InlineAttr::Never
340 {
341 } else {
344 continue;
345 }
346 }
347
348 match *mono_item {
349 MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => {
350 if args.non_erasable_generics().next().is_some() {
351 let symbol = ExportedSymbol::Generic(def, args);
352 symbols.push((
353 symbol,
354 SymbolExportInfo {
355 level: SymbolExportLevel::Rust,
356 kind: SymbolExportKind::Text,
357 used: false,
358 },
359 ));
360 }
361 }
362 MonoItem::Fn(Instance { def: InstanceKind::DropGlue(_, Some(ty)), args }) => {
363 assert_eq!(args.non_erasable_generics().next(), Some(GenericArgKind::Type(ty)));
365 symbols.push((
366 ExportedSymbol::DropGlue(ty),
367 SymbolExportInfo {
368 level: SymbolExportLevel::Rust,
369 kind: SymbolExportKind::Text,
370 used: false,
371 },
372 ));
373 }
374 MonoItem::Fn(Instance {
375 def: InstanceKind::AsyncDropGlueCtorShim(_, Some(ty)),
376 args,
377 }) => {
378 assert_eq!(args.non_erasable_generics().next(), Some(GenericArgKind::Type(ty)));
380 symbols.push((
381 ExportedSymbol::AsyncDropGlueCtorShim(ty),
382 SymbolExportInfo {
383 level: SymbolExportLevel::Rust,
384 kind: SymbolExportKind::Text,
385 used: false,
386 },
387 ));
388 }
389 _ => {
390 }
392 }
393 }
394 }
395
396 symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx));
398
399 tcx.arena.alloc_from_iter(symbols)
400}
401
402fn upstream_monomorphizations_provider(
403 tcx: TyCtxt<'_>,
404 (): (),
405) -> DefIdMap<UnordMap<GenericArgsRef<'_>, CrateNum>> {
406 let cnums = tcx.crates(());
407
408 let mut instances: DefIdMap<UnordMap<_, _>> = Default::default();
409
410 let drop_in_place_fn_def_id = tcx.lang_items().drop_in_place_fn();
411 let async_drop_in_place_fn_def_id = tcx.lang_items().async_drop_in_place_fn();
412
413 for &cnum in cnums.iter() {
414 for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() {
415 let (def_id, args) = match *exported_symbol {
416 ExportedSymbol::Generic(def_id, args) => (def_id, args),
417 ExportedSymbol::DropGlue(ty) => {
418 if let Some(drop_in_place_fn_def_id) = drop_in_place_fn_def_id {
419 (drop_in_place_fn_def_id, tcx.mk_args(&[ty.into()]))
420 } else {
421 continue;
424 }
425 }
426 ExportedSymbol::AsyncDropGlueCtorShim(ty) => {
427 if let Some(async_drop_in_place_fn_def_id) = async_drop_in_place_fn_def_id {
428 (async_drop_in_place_fn_def_id, tcx.mk_args(&[ty.into()]))
429 } else {
430 continue;
433 }
434 }
435 ExportedSymbol::NonGeneric(..)
436 | ExportedSymbol::ThreadLocalShim(..)
437 | ExportedSymbol::NoDefId(..) => {
438 continue;
440 }
441 };
442
443 let args_map = instances.entry(def_id).or_default();
444
445 match args_map.entry(args) {
446 Occupied(mut e) => {
447 let other_cnum = *e.get();
450 if tcx.stable_crate_id(other_cnum) > tcx.stable_crate_id(cnum) {
451 e.insert(cnum);
452 }
453 }
454 Vacant(e) => {
455 e.insert(cnum);
456 }
457 }
458 }
459 }
460
461 instances
462}
463
464fn upstream_monomorphizations_for_provider(
465 tcx: TyCtxt<'_>,
466 def_id: DefId,
467) -> Option<&UnordMap<GenericArgsRef<'_>, CrateNum>> {
468 assert!(!def_id.is_local());
469 tcx.upstream_monomorphizations(()).get(&def_id)
470}
471
472fn upstream_drop_glue_for_provider<'tcx>(
473 tcx: TyCtxt<'tcx>,
474 args: GenericArgsRef<'tcx>,
475) -> Option<CrateNum> {
476 let def_id = tcx.lang_items().drop_in_place_fn()?;
477 tcx.upstream_monomorphizations_for(def_id)?.get(&args).cloned()
478}
479
480fn upstream_async_drop_glue_for_provider<'tcx>(
481 tcx: TyCtxt<'tcx>,
482 args: GenericArgsRef<'tcx>,
483) -> Option<CrateNum> {
484 let def_id = tcx.lang_items().async_drop_in_place_fn()?;
485 tcx.upstream_monomorphizations_for(def_id)?.get(&args).cloned()
486}
487
488fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
489 !tcx.reachable_set(()).contains(&def_id)
490}
491
492pub(crate) fn provide(providers: &mut Providers) {
493 providers.reachable_non_generics = reachable_non_generics_provider;
494 providers.is_reachable_non_generic = is_reachable_non_generic_provider_local;
495 providers.exported_symbols = exported_symbols_provider_local;
496 providers.upstream_monomorphizations = upstream_monomorphizations_provider;
497 providers.is_unreachable_local_definition = is_unreachable_local_definition_provider;
498 providers.upstream_drop_glue_for = upstream_drop_glue_for_provider;
499 providers.upstream_async_drop_glue_for = upstream_async_drop_glue_for_provider;
500 providers.wasm_import_module_map = wasm_import_module_map;
501 providers.extern_queries.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
502 providers.extern_queries.upstream_monomorphizations_for =
503 upstream_monomorphizations_for_provider;
504}
505
506fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel {
507 let codegen_fn_attrs = tcx.codegen_fn_attrs(sym_def_id);
513 let is_extern = codegen_fn_attrs.contains_extern_indicator();
514 let std_internal =
515 codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
516
517 if is_extern && !std_internal {
518 let target = &tcx.sess.target.llvm_target;
519 if target.contains("emscripten") {
521 if let DefKind::Static { .. } = tcx.def_kind(sym_def_id) {
522 return SymbolExportLevel::Rust;
523 }
524 }
525
526 SymbolExportLevel::C
527 } else {
528 SymbolExportLevel::Rust
529 }
530}
531
532pub(crate) fn symbol_name_for_instance_in_crate<'tcx>(
534 tcx: TyCtxt<'tcx>,
535 symbol: ExportedSymbol<'tcx>,
536 instantiating_crate: CrateNum,
537) -> String {
538 if instantiating_crate == LOCAL_CRATE {
541 return symbol.symbol_name_for_local_instance(tcx).to_string();
542 }
543
544 match symbol {
547 ExportedSymbol::NonGeneric(def_id) => {
548 rustc_symbol_mangling::symbol_name_for_instance_in_crate(
549 tcx,
550 Instance::mono(tcx, def_id),
551 instantiating_crate,
552 )
553 }
554 ExportedSymbol::Generic(def_id, args) => {
555 rustc_symbol_mangling::symbol_name_for_instance_in_crate(
556 tcx,
557 Instance::new(def_id, args),
558 instantiating_crate,
559 )
560 }
561 ExportedSymbol::ThreadLocalShim(def_id) => {
562 rustc_symbol_mangling::symbol_name_for_instance_in_crate(
563 tcx,
564 ty::Instance {
565 def: ty::InstanceKind::ThreadLocalShim(def_id),
566 args: ty::GenericArgs::empty(),
567 },
568 instantiating_crate,
569 )
570 }
571 ExportedSymbol::DropGlue(ty) => rustc_symbol_mangling::symbol_name_for_instance_in_crate(
572 tcx,
573 Instance::resolve_drop_in_place(tcx, ty),
574 instantiating_crate,
575 ),
576 ExportedSymbol::AsyncDropGlueCtorShim(ty) => {
577 rustc_symbol_mangling::symbol_name_for_instance_in_crate(
578 tcx,
579 Instance::resolve_async_drop_in_place(tcx, ty),
580 instantiating_crate,
581 )
582 }
583 ExportedSymbol::NoDefId(symbol_name) => symbol_name.to_string(),
584 }
585}
586
587pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>(
591 tcx: TyCtxt<'tcx>,
592 symbol: ExportedSymbol<'tcx>,
593 instantiating_crate: CrateNum,
594) -> String {
595 use rustc_target::callconv::Conv;
596
597 let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
598
599 if let Some(name) = maybe_emutls_symbol_name(tcx, symbol, &undecorated) {
602 return name;
603 }
604
605 let target = &tcx.sess.target;
606 if !target.is_like_windows {
607 return undecorated;
610 }
611
612 let prefix = match &target.arch[..] {
613 "x86" => Some('_'),
614 "x86_64" => None,
615 "arm64ec" => Some('#'),
616 _ => return undecorated,
618 };
619
620 let instance = match symbol {
621 ExportedSymbol::NonGeneric(def_id) | ExportedSymbol::Generic(def_id, _)
622 if tcx.is_static(def_id) =>
623 {
624 None
625 }
626 ExportedSymbol::NonGeneric(def_id) => Some(Instance::mono(tcx, def_id)),
627 ExportedSymbol::Generic(def_id, args) => Some(Instance::new(def_id, args)),
628 ExportedSymbol::DropGlue(..) => None,
631 ExportedSymbol::AsyncDropGlueCtorShim(..) => None,
634 ExportedSymbol::NoDefId(..) => None,
636 ExportedSymbol::ThreadLocalShim(..) => None,
638 };
639
640 let (conv, args) = instance
641 .map(|i| {
642 tcx.fn_abi_of_instance(
643 ty::TypingEnv::fully_monomorphized().as_query_input((i, ty::List::empty())),
644 )
645 .unwrap_or_else(|_| bug!("fn_abi_of_instance({i:?}) failed"))
646 })
647 .map(|fnabi| (fnabi.conv, &fnabi.args[..]))
648 .unwrap_or((Conv::Rust, &[]));
649
650 let (prefix, suffix) = match conv {
653 Conv::X86Fastcall => ("@", "@"),
654 Conv::X86Stdcall => ("_", "@"),
655 Conv::X86VectorCall => ("", "@@"),
656 _ => {
657 if let Some(prefix) = prefix {
658 undecorated.insert(0, prefix);
659 }
660 return undecorated;
661 }
662 };
663
664 let args_in_bytes: u64 = args
665 .iter()
666 .map(|abi| abi.layout.size.bytes().next_multiple_of(target.pointer_width as u64 / 8))
667 .sum();
668 format!("{prefix}{undecorated}{suffix}{args_in_bytes}")
669}
670
671pub(crate) fn exporting_symbol_name_for_instance_in_crate<'tcx>(
672 tcx: TyCtxt<'tcx>,
673 symbol: ExportedSymbol<'tcx>,
674 cnum: CrateNum,
675) -> String {
676 let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, cnum);
677 maybe_emutls_symbol_name(tcx, symbol, &undecorated).unwrap_or(undecorated)
678}
679
680fn maybe_emutls_symbol_name<'tcx>(
681 tcx: TyCtxt<'tcx>,
682 symbol: ExportedSymbol<'tcx>,
683 undecorated: &str,
684) -> Option<String> {
685 if matches!(tcx.sess.tls_model(), TlsModel::Emulated)
686 && let ExportedSymbol::NonGeneric(def_id) = symbol
687 && tcx.is_thread_local_static(def_id)
688 {
689 Some(format!("__emutls_v.{undecorated}"))
692 } else {
693 None
694 }
695}
696
697fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<String> {
698 let native_libs = tcx.native_libraries(cnum);
702
703 let def_id_to_native_lib = native_libs
704 .iter()
705 .filter_map(|lib| lib.foreign_module.map(|id| (id, lib)))
706 .collect::<DefIdMap<_>>();
707
708 let mut ret = DefIdMap::default();
709 for (def_id, lib) in tcx.foreign_modules(cnum).iter() {
710 let module = def_id_to_native_lib.get(def_id).and_then(|s| s.wasm_import_module());
711 let Some(module) = module else { continue };
712 ret.extend(lib.foreign_items.iter().map(|id| {
713 assert_eq!(id.krate, cnum);
714 (*id, module.to_string())
715 }));
716 }
717
718 ret
719}