]>
Commit | Line | Data |
---|---|---|
3dfed10e XL |
1 | use std::collections::hash_map::Entry; |
2 | ||
3 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; | |
4 | use rustc_hir::def::DefKind; | |
04454e1e | 5 | use rustc_hir::def_id::{DefId, LOCAL_CRATE}; |
1b1a35ee | 6 | use rustc_hir::definitions::DefPathDataName; |
3dfed10e | 7 | use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; |
04454e1e | 8 | use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; |
3dfed10e XL |
9 | use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility}; |
10 | use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; | |
11 | use rustc_middle::ty::print::characteristic_def_id_of_type; | |
353b0b11 | 12 | use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceDef, TyCtxt}; |
3dfed10e XL |
13 | use rustc_span::symbol::Symbol; |
14 | ||
1b1a35ee | 15 | use super::PartitioningCx; |
c295e0f8 XL |
16 | use crate::collector::InliningMap; |
17 | use crate::partitioning::merging; | |
18 | use crate::partitioning::{ | |
3dfed10e XL |
19 | MonoItemPlacement, Partitioner, PostInliningPartitioning, PreInliningPartitioning, |
20 | }; | |
21 | ||
22 | pub struct DefaultPartitioning; | |
23 | ||
24 | impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { | |
25 | fn place_root_mono_items( | |
26 | &mut self, | |
1b1a35ee | 27 | cx: &PartitioningCx<'_, 'tcx>, |
3dfed10e XL |
28 | mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>, |
29 | ) -> PreInliningPartitioning<'tcx> { | |
30 | let mut roots = FxHashSet::default(); | |
31 | let mut codegen_units = FxHashMap::default(); | |
1b1a35ee | 32 | let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); |
3dfed10e XL |
33 | let mut internalization_candidates = FxHashSet::default(); |
34 | ||
35 | // Determine if monomorphizations instantiated in this crate will be made | |
36 | // available to downstream crates. This depends on whether we are in | |
37 | // share-generics mode and whether the current crate can even have | |
38 | // downstream crates. | |
1b1a35ee XL |
39 | let export_generics = |
40 | cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); | |
3dfed10e | 41 | |
1b1a35ee | 42 | let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); |
3dfed10e XL |
43 | let cgu_name_cache = &mut FxHashMap::default(); |
44 | ||
45 | for mono_item in mono_items { | |
1b1a35ee | 46 | match mono_item.instantiation_mode(cx.tcx) { |
3dfed10e XL |
47 | InstantiationMode::GloballyShared { .. } => {} |
48 | InstantiationMode::LocalCopy => continue, | |
49 | } | |
50 | ||
1b1a35ee | 51 | let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); |
3dfed10e XL |
52 | let is_volatile = is_incremental_build && mono_item.is_generic_fn(); |
53 | ||
54 | let codegen_unit_name = match characteristic_def_id { | |
55 | Some(def_id) => compute_codegen_unit_name( | |
1b1a35ee | 56 | cx.tcx, |
3dfed10e XL |
57 | cgu_name_builder, |
58 | def_id, | |
59 | is_volatile, | |
60 | cgu_name_cache, | |
61 | ), | |
62 | None => fallback_cgu_name(cgu_name_builder), | |
63 | }; | |
64 | ||
65 | let codegen_unit = codegen_units | |
66 | .entry(codegen_unit_name) | |
67 | .or_insert_with(|| CodegenUnit::new(codegen_unit_name)); | |
68 | ||
69 | let mut can_be_internalized = true; | |
70 | let (linkage, visibility) = mono_item_linkage_and_visibility( | |
1b1a35ee | 71 | cx.tcx, |
3dfed10e XL |
72 | &mono_item, |
73 | &mut can_be_internalized, | |
74 | export_generics, | |
75 | ); | |
76 | if visibility == Visibility::Hidden && can_be_internalized { | |
77 | internalization_candidates.insert(mono_item); | |
78 | } | |
79 | ||
80 | codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); | |
81 | roots.insert(mono_item); | |
82 | } | |
83 | ||
84 | // Always ensure we have at least one CGU; otherwise, if we have a | |
85 | // crate with just types (for example), we could wind up with no CGU. | |
86 | if codegen_units.is_empty() { | |
87 | let codegen_unit_name = fallback_cgu_name(cgu_name_builder); | |
88 | codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); | |
89 | } | |
90 | ||
91 | PreInliningPartitioning { | |
353b0b11 | 92 | codegen_units: codegen_units.into_values().map(|codegen_unit| codegen_unit).collect(), |
3dfed10e XL |
93 | roots, |
94 | internalization_candidates, | |
95 | } | |
96 | } | |
97 | ||
98 | fn merge_codegen_units( | |
99 | &mut self, | |
1b1a35ee | 100 | cx: &PartitioningCx<'_, 'tcx>, |
3dfed10e | 101 | initial_partitioning: &mut PreInliningPartitioning<'tcx>, |
3dfed10e | 102 | ) { |
1b1a35ee | 103 | merging::merge_codegen_units(cx, initial_partitioning); |
3dfed10e XL |
104 | } |
105 | ||
106 | fn place_inlined_mono_items( | |
107 | &mut self, | |
1b1a35ee | 108 | cx: &PartitioningCx<'_, 'tcx>, |
3dfed10e | 109 | initial_partitioning: PreInliningPartitioning<'tcx>, |
3dfed10e XL |
110 | ) -> PostInliningPartitioning<'tcx> { |
111 | let mut new_partitioning = Vec::new(); | |
112 | let mut mono_item_placements = FxHashMap::default(); | |
113 | ||
114 | let PreInliningPartitioning { | |
115 | codegen_units: initial_cgus, | |
116 | roots, | |
117 | internalization_candidates, | |
118 | } = initial_partitioning; | |
119 | ||
120 | let single_codegen_unit = initial_cgus.len() == 1; | |
121 | ||
122 | for old_codegen_unit in initial_cgus { | |
123 | // Collect all items that need to be available in this codegen unit. | |
124 | let mut reachable = FxHashSet::default(); | |
125 | for root in old_codegen_unit.items().keys() { | |
1b1a35ee | 126 | follow_inlining(*root, cx.inlining_map, &mut reachable); |
3dfed10e XL |
127 | } |
128 | ||
129 | let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); | |
130 | ||
131 | // Add all monomorphizations that are not already there. | |
132 | for mono_item in reachable { | |
133 | if let Some(linkage) = old_codegen_unit.items().get(&mono_item) { | |
134 | // This is a root, just copy it over. | |
135 | new_codegen_unit.items_mut().insert(mono_item, *linkage); | |
136 | } else { | |
137 | if roots.contains(&mono_item) { | |
138 | bug!( | |
139 | "GloballyShared mono-item inlined into other CGU: \ | |
140 | {:?}", | |
141 | mono_item | |
142 | ); | |
143 | } | |
144 | ||
145 | // This is a CGU-private copy. | |
146 | new_codegen_unit | |
147 | .items_mut() | |
148 | .insert(mono_item, (Linkage::Internal, Visibility::Default)); | |
149 | } | |
150 | ||
151 | if !single_codegen_unit { | |
152 | // If there is more than one codegen unit, we need to keep track | |
153 | // in which codegen units each monomorphization is placed. | |
154 | match mono_item_placements.entry(mono_item) { | |
155 | Entry::Occupied(e) => { | |
156 | let placement = e.into_mut(); | |
157 | debug_assert!(match *placement { | |
158 | MonoItemPlacement::SingleCgu { cgu_name } => { | |
159 | cgu_name != new_codegen_unit.name() | |
160 | } | |
161 | MonoItemPlacement::MultipleCgus => true, | |
162 | }); | |
163 | *placement = MonoItemPlacement::MultipleCgus; | |
164 | } | |
165 | Entry::Vacant(e) => { | |
166 | e.insert(MonoItemPlacement::SingleCgu { | |
167 | cgu_name: new_codegen_unit.name(), | |
168 | }); | |
169 | } | |
170 | } | |
171 | } | |
172 | } | |
173 | ||
174 | new_partitioning.push(new_codegen_unit); | |
175 | } | |
176 | ||
177 | return PostInliningPartitioning { | |
178 | codegen_units: new_partitioning, | |
179 | mono_item_placements, | |
180 | internalization_candidates, | |
181 | }; | |
182 | ||
183 | fn follow_inlining<'tcx>( | |
184 | mono_item: MonoItem<'tcx>, | |
185 | inlining_map: &InliningMap<'tcx>, | |
186 | visited: &mut FxHashSet<MonoItem<'tcx>>, | |
187 | ) { | |
188 | if !visited.insert(mono_item) { | |
189 | return; | |
190 | } | |
191 | ||
192 | inlining_map.with_inlining_candidates(mono_item, |target| { | |
193 | follow_inlining(target, inlining_map, visited); | |
194 | }); | |
195 | } | |
196 | } | |
197 | ||
198 | fn internalize_symbols( | |
199 | &mut self, | |
1b1a35ee | 200 | cx: &PartitioningCx<'_, 'tcx>, |
3dfed10e | 201 | partitioning: &mut PostInliningPartitioning<'tcx>, |
3dfed10e XL |
202 | ) { |
203 | if partitioning.codegen_units.len() == 1 { | |
204 | // Fast path for when there is only one codegen unit. In this case we | |
205 | // can internalize all candidates, since there is nowhere else they | |
206 | // could be accessed from. | |
207 | for cgu in &mut partitioning.codegen_units { | |
208 | for candidate in &partitioning.internalization_candidates { | |
209 | cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default)); | |
210 | } | |
211 | } | |
212 | ||
213 | return; | |
214 | } | |
215 | ||
216 | // Build a map from every monomorphization to all the monomorphizations that | |
217 | // reference it. | |
218 | let mut accessor_map: FxHashMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>> = Default::default(); | |
1b1a35ee | 219 | cx.inlining_map.iter_accesses(|accessor, accessees| { |
3dfed10e XL |
220 | for accessee in accessees { |
221 | accessor_map.entry(*accessee).or_default().push(accessor); | |
222 | } | |
223 | }); | |
224 | ||
225 | let mono_item_placements = &partitioning.mono_item_placements; | |
226 | ||
227 | // For each internalization candidates in each codegen unit, check if it is | |
228 | // accessed from outside its defining codegen unit. | |
229 | for cgu in &mut partitioning.codegen_units { | |
230 | let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; | |
231 | ||
232 | for (accessee, linkage_and_visibility) in cgu.items_mut() { | |
233 | if !partitioning.internalization_candidates.contains(accessee) { | |
234 | // This item is no candidate for internalizing, so skip it. | |
235 | continue; | |
236 | } | |
237 | debug_assert_eq!(mono_item_placements[accessee], home_cgu); | |
238 | ||
239 | if let Some(accessors) = accessor_map.get(accessee) { | |
240 | if accessors | |
241 | .iter() | |
242 | .filter_map(|accessor| { | |
243 | // Some accessors might not have been | |
244 | // instantiated. We can safely ignore those. | |
245 | mono_item_placements.get(accessor) | |
246 | }) | |
247 | .any(|placement| *placement != home_cgu) | |
248 | { | |
249 | // Found an accessor from another CGU, so skip to the next | |
250 | // item without marking this one as internal. | |
251 | continue; | |
252 | } | |
253 | } | |
254 | ||
255 | // If we got here, we did not find any accesses from other CGUs, | |
256 | // so it's fine to make this monomorphization internal. | |
257 | *linkage_and_visibility = (Linkage::Internal, Visibility::Default); | |
258 | } | |
259 | } | |
260 | } | |
261 | } | |
262 | ||
263 | fn characteristic_def_id_of_mono_item<'tcx>( | |
264 | tcx: TyCtxt<'tcx>, | |
265 | mono_item: MonoItem<'tcx>, | |
266 | ) -> Option<DefId> { | |
267 | match mono_item { | |
268 | MonoItem::Fn(instance) => { | |
269 | let def_id = match instance.def { | |
270 | ty::InstanceDef::Item(def) => def.did, | |
064997fb | 271 | ty::InstanceDef::VTableShim(..) |
3dfed10e XL |
272 | | ty::InstanceDef::ReifyShim(..) |
273 | | ty::InstanceDef::FnPtrShim(..) | |
274 | | ty::InstanceDef::ClosureOnceShim { .. } | |
275 | | ty::InstanceDef::Intrinsic(..) | |
276 | | ty::InstanceDef::DropGlue(..) | |
277 | | ty::InstanceDef::Virtual(..) | |
353b0b11 FG |
278 | | ty::InstanceDef::CloneShim(..) |
279 | | ty::InstanceDef::ThreadLocalShim(..) | |
280 | | ty::InstanceDef::FnPtrAddrShim(..) => return None, | |
3dfed10e XL |
281 | }; |
282 | ||
283 | // If this is a method, we want to put it into the same module as | |
284 | // its self-type. If the self-type does not provide a characteristic | |
285 | // DefId, we use the location of the impl after all. | |
286 | ||
287 | if tcx.trait_of_item(def_id).is_some() { | |
288 | let self_ty = instance.substs.type_at(0); | |
289 | // This is a default implementation of a trait method. | |
290 | return characteristic_def_id_of_type(self_ty).or(Some(def_id)); | |
291 | } | |
292 | ||
293 | if let Some(impl_def_id) = tcx.impl_of_method(def_id) { | |
294 | if tcx.sess.opts.incremental.is_some() | |
295 | && tcx.trait_id_of_impl(impl_def_id) == tcx.lang_items().drop_trait() | |
296 | { | |
297 | // Put `Drop::drop` into the same cgu as `drop_in_place` | |
298 | // since `drop_in_place` is the only thing that can | |
299 | // call it. | |
300 | return None; | |
301 | } | |
c295e0f8 XL |
302 | |
303 | // When polymorphization is enabled, methods which do not depend on their generic | |
304 | // parameters, but the self-type of their impl block do will fail to normalize. | |
064997fb | 305 | if !tcx.sess.opts.unstable_opts.polymorphize || !instance.needs_subst() { |
c295e0f8 XL |
306 | // This is a method within an impl, find out what the self-type is: |
307 | let impl_self_ty = tcx.subst_and_normalize_erasing_regions( | |
308 | instance.substs, | |
309 | ty::ParamEnv::reveal_all(), | |
9ffffee4 | 310 | tcx.type_of(impl_def_id).skip_binder(), |
c295e0f8 XL |
311 | ); |
312 | if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { | |
313 | return Some(def_id); | |
314 | } | |
3dfed10e XL |
315 | } |
316 | } | |
317 | ||
318 | Some(def_id) | |
319 | } | |
320 | MonoItem::Static(def_id) => Some(def_id), | |
2b03887a | 321 | MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.to_def_id()), |
3dfed10e XL |
322 | } |
323 | } | |
324 | ||
325 | fn compute_codegen_unit_name( | |
326 | tcx: TyCtxt<'_>, | |
327 | name_builder: &mut CodegenUnitNameBuilder<'_>, | |
328 | def_id: DefId, | |
329 | volatile: bool, | |
330 | cache: &mut CguNameCache, | |
331 | ) -> Symbol { | |
332 | // Find the innermost module that is not nested within a function. | |
333 | let mut current_def_id = def_id; | |
334 | let mut cgu_def_id = None; | |
335 | // Walk backwards from the item we want to find the module for. | |
336 | loop { | |
04454e1e | 337 | if current_def_id.is_crate_root() { |
3dfed10e XL |
338 | if cgu_def_id.is_none() { |
339 | // If we have not found a module yet, take the crate root. | |
04454e1e | 340 | cgu_def_id = Some(def_id.krate.as_def_id()); |
3dfed10e XL |
341 | } |
342 | break; | |
343 | } else if tcx.def_kind(current_def_id) == DefKind::Mod { | |
344 | if cgu_def_id.is_none() { | |
345 | cgu_def_id = Some(current_def_id); | |
346 | } | |
347 | } else { | |
348 | // If we encounter something that is not a module, throw away | |
349 | // any module that we've found so far because we now know that | |
350 | // it is nested within something else. | |
351 | cgu_def_id = None; | |
352 | } | |
353 | ||
04454e1e | 354 | current_def_id = tcx.parent(current_def_id); |
3dfed10e XL |
355 | } |
356 | ||
357 | let cgu_def_id = cgu_def_id.unwrap(); | |
358 | ||
359 | *cache.entry((cgu_def_id, volatile)).or_insert_with(|| { | |
360 | let def_path = tcx.def_path(cgu_def_id); | |
361 | ||
1b1a35ee XL |
362 | let components = def_path.data.iter().map(|part| match part.data.name() { |
363 | DefPathDataName::Named(name) => name, | |
364 | DefPathDataName::Anon { .. } => unreachable!(), | |
365 | }); | |
3dfed10e XL |
366 | |
367 | let volatile_suffix = volatile.then_some("volatile"); | |
368 | ||
369 | name_builder.build_cgu_name(def_path.krate, components, volatile_suffix) | |
370 | }) | |
371 | } | |
372 | ||
373 | // Anything we can't find a proper codegen unit for goes into this. | |
374 | fn fallback_cgu_name(name_builder: &mut CodegenUnitNameBuilder<'_>) -> Symbol { | |
375 | name_builder.build_cgu_name(LOCAL_CRATE, &["fallback"], Some("cgu")) | |
376 | } | |
377 | ||
a2a8927a | 378 | fn mono_item_linkage_and_visibility<'tcx>( |
3dfed10e XL |
379 | tcx: TyCtxt<'tcx>, |
380 | mono_item: &MonoItem<'tcx>, | |
381 | can_be_internalized: &mut bool, | |
382 | export_generics: bool, | |
383 | ) -> (Linkage, Visibility) { | |
384 | if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) { | |
385 | return (explicit_linkage, Visibility::Default); | |
386 | } | |
387 | let vis = mono_item_visibility(tcx, mono_item, can_be_internalized, export_generics); | |
388 | (Linkage::External, vis) | |
389 | } | |
390 | ||
391 | type CguNameCache = FxHashMap<(DefId, bool), Symbol>; | |
392 | ||
353b0b11 FG |
393 | fn static_visibility<'tcx>( |
394 | tcx: TyCtxt<'tcx>, | |
395 | can_be_internalized: &mut bool, | |
396 | def_id: DefId, | |
397 | ) -> Visibility { | |
398 | if tcx.is_reachable_non_generic(def_id) { | |
399 | *can_be_internalized = false; | |
400 | default_visibility(tcx, def_id, false) | |
401 | } else { | |
402 | Visibility::Hidden | |
403 | } | |
404 | } | |
405 | ||
a2a8927a | 406 | fn mono_item_visibility<'tcx>( |
3dfed10e XL |
407 | tcx: TyCtxt<'tcx>, |
408 | mono_item: &MonoItem<'tcx>, | |
409 | can_be_internalized: &mut bool, | |
410 | export_generics: bool, | |
411 | ) -> Visibility { | |
412 | let instance = match mono_item { | |
413 | // This is pretty complicated; see below. | |
414 | MonoItem::Fn(instance) => instance, | |
415 | ||
416 | // Misc handling for generics and such, but otherwise: | |
353b0b11 | 417 | MonoItem::Static(def_id) => return static_visibility(tcx, can_be_internalized, *def_id), |
6a06907d | 418 | MonoItem::GlobalAsm(item_id) => { |
353b0b11 | 419 | return static_visibility(tcx, can_be_internalized, item_id.owner_id.to_def_id()); |
3dfed10e XL |
420 | } |
421 | }; | |
422 | ||
423 | let def_id = match instance.def { | |
424 | InstanceDef::Item(def) => def.did, | |
425 | InstanceDef::DropGlue(def_id, Some(_)) => def_id, | |
426 | ||
353b0b11 FG |
427 | // We match the visiblity of statics here |
428 | InstanceDef::ThreadLocalShim(def_id) => { | |
429 | return static_visibility(tcx, can_be_internalized, def_id); | |
430 | } | |
431 | ||
3dfed10e | 432 | // These are all compiler glue and such, never exported, always hidden. |
064997fb | 433 | InstanceDef::VTableShim(..) |
3dfed10e XL |
434 | | InstanceDef::ReifyShim(..) |
435 | | InstanceDef::FnPtrShim(..) | |
436 | | InstanceDef::Virtual(..) | |
437 | | InstanceDef::Intrinsic(..) | |
438 | | InstanceDef::ClosureOnceShim { .. } | |
439 | | InstanceDef::DropGlue(..) | |
353b0b11 FG |
440 | | InstanceDef::CloneShim(..) |
441 | | InstanceDef::FnPtrAddrShim(..) => return Visibility::Hidden, | |
3dfed10e XL |
442 | }; |
443 | ||
444 | // The `start_fn` lang item is actually a monomorphized instance of a | |
445 | // function in the standard library, used for the `main` function. We don't | |
446 | // want to export it so we tag it with `Hidden` visibility but this symbol | |
447 | // is only referenced from the actual `main` symbol which we unfortunately | |
448 | // don't know anything about during partitioning/collection. As a result we | |
449 | // forcibly keep this symbol out of the `internalization_candidates` set. | |
450 | // | |
451 | // FIXME: eventually we don't want to always force this symbol to have | |
452 | // hidden visibility, it should indeed be a candidate for | |
453 | // internalization, but we have to understand that it's referenced | |
454 | // from the `main` symbol we'll generate later. | |
455 | // | |
456 | // This may be fixable with a new `InstanceDef` perhaps? Unsure! | |
457 | if tcx.lang_items().start_fn() == Some(def_id) { | |
458 | *can_be_internalized = false; | |
459 | return Visibility::Hidden; | |
460 | } | |
461 | ||
462 | let is_generic = instance.substs.non_erasable_generics().next().is_some(); | |
463 | ||
464 | // Upstream `DefId` instances get different handling than local ones. | |
3c0e092e | 465 | let Some(def_id) = def_id.as_local() else { |
3dfed10e | 466 | return if export_generics && is_generic { |
94222f64 | 467 | // If it is an upstream monomorphization and we export generics, we must make |
3dfed10e XL |
468 | // it available to downstream crates. |
469 | *can_be_internalized = false; | |
470 | default_visibility(tcx, def_id, true) | |
471 | } else { | |
472 | Visibility::Hidden | |
473 | }; | |
17df50a5 | 474 | }; |
3dfed10e XL |
475 | |
476 | if is_generic { | |
477 | if export_generics { | |
478 | if tcx.is_unreachable_local_definition(def_id) { | |
479 | // This instance cannot be used from another crate. | |
480 | Visibility::Hidden | |
481 | } else { | |
482 | // This instance might be useful in a downstream crate. | |
483 | *can_be_internalized = false; | |
17df50a5 | 484 | default_visibility(tcx, def_id.to_def_id(), true) |
3dfed10e XL |
485 | } |
486 | } else { | |
487 | // We are not exporting generics or the definition is not reachable | |
488 | // for downstream crates, we can internalize its instantiations. | |
489 | Visibility::Hidden | |
490 | } | |
491 | } else { | |
492 | // If this isn't a generic function then we mark this a `Default` if | |
493 | // this is a reachable item, meaning that it's a symbol other crates may | |
494 | // access when they link to us. | |
17df50a5 | 495 | if tcx.is_reachable_non_generic(def_id.to_def_id()) { |
3dfed10e XL |
496 | *can_be_internalized = false; |
497 | debug_assert!(!is_generic); | |
17df50a5 | 498 | return default_visibility(tcx, def_id.to_def_id(), false); |
3dfed10e XL |
499 | } |
500 | ||
501 | // If this isn't reachable then we're gonna tag this with `Hidden` | |
502 | // visibility. In some situations though we'll want to prevent this | |
503 | // symbol from being internalized. | |
504 | // | |
505 | // There's two categories of items here: | |
506 | // | |
507 | // * First is weak lang items. These are basically mechanisms for | |
508 | // libcore to forward-reference symbols defined later in crates like | |
509 | // the standard library or `#[panic_handler]` definitions. The | |
5e7ed085 | 510 | // definition of these weak lang items needs to be referencable by |
3dfed10e XL |
511 | // libcore, so we're no longer a candidate for internalization. |
512 | // Removal of these functions can't be done by LLVM but rather must be | |
513 | // done by the linker as it's a non-local decision. | |
514 | // | |
515 | // * Second is "std internal symbols". Currently this is primarily used | |
516 | // for allocator symbols. Allocators are a little weird in their | |
517 | // implementation, but the idea is that the compiler, at the last | |
518 | // minute, defines an allocator with an injected object file. The | |
519 | // `alloc` crate references these symbols (`__rust_alloc`) and the | |
520 | // definition doesn't get hooked up until a linked crate artifact is | |
521 | // generated. | |
522 | // | |
523 | // The symbols synthesized by the compiler (`__rust_alloc`) are thin | |
524 | // veneers around the actual implementation, some other symbol which | |
525 | // implements the same ABI. These symbols (things like `__rg_alloc`, | |
526 | // `__rdl_alloc`, `__rde_alloc`, etc), are all tagged with "std | |
527 | // internal symbols". | |
528 | // | |
529 | // The std-internal symbols here **should not show up in a dll as an | |
530 | // exported interface**, so they return `false` from | |
531 | // `is_reachable_non_generic` above and we'll give them `Hidden` | |
532 | // visibility below. Like the weak lang items, though, we can't let | |
533 | // LLVM internalize them as this decision is left up to the linker to | |
534 | // omit them, so prevent them from being internalized. | |
535 | let attrs = tcx.codegen_fn_attrs(def_id); | |
536 | if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { | |
537 | *can_be_internalized = false; | |
538 | } | |
539 | ||
540 | Visibility::Hidden | |
541 | } | |
542 | } | |
543 | ||
544 | fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { | |
29967ef6 | 545 | if !tcx.sess.target.default_hidden_visibility { |
3dfed10e XL |
546 | return Visibility::Default; |
547 | } | |
548 | ||
549 | // Generic functions never have export-level C. | |
550 | if is_generic { | |
551 | return Visibility::Hidden; | |
552 | } | |
553 | ||
554 | // Things with export level C don't get instantiated in | |
555 | // downstream crates. | |
556 | if !id.is_local() { | |
557 | return Visibility::Hidden; | |
558 | } | |
559 | ||
560 | // C-export level items remain at `Default`, all other internal | |
561 | // items become `Hidden`. | |
562 | match tcx.reachable_non_generics(id.krate).get(&id) { | |
04454e1e | 563 | Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => Visibility::Default, |
3dfed10e XL |
564 | _ => Visibility::Hidden, |
565 | } | |
566 | } |