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