Skip to content

Commit 38eeebd

Browse files
committed
rustc: Refactor MonoItem linkage/visibility calculation
The previous iteration was a large `match` which was quite heavily indented, making it slightly difficult to read and see what was going on. This iteration is a refactoring (no functional change intended) to make it a bit easier on the eyes and a bit easier to modify over time.
1 parent 18925de commit 38eeebd

File tree

1 file changed

+151
-140
lines changed

1 file changed

+151
-140
lines changed

src/librustc_mir/monomorphize/partitioning.rs

+151-140
Original file line numberDiff line numberDiff line change
@@ -300,13 +300,6 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
300300
let is_incremental_build = tcx.sess.opts.incremental.is_some();
301301
let mut internalization_candidates = FxHashSet();
302302

303-
// Determine if monomorphizations instantiated in this crate will be made
304-
// available to downstream crates. This depends on whether we are in
305-
// share-generics mode and whether the current crate can even have
306-
// downstream crates.
307-
let export_generics = tcx.sess.opts.share_generics() &&
308-
tcx.local_crate_exports_generics();
309-
310303
for mono_item in mono_items {
311304
match mono_item.instantiation_mode(tcx) {
312305
InstantiationMode::GloballyShared { .. } => {}
@@ -322,146 +315,38 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
322315
None => fallback_cgu_name(tcx),
323316
};
324317

325-
let make_codegen_unit = || {
326-
CodegenUnit::new(codegen_unit_name.clone())
327-
};
328-
329318
let codegen_unit = codegen_units.entry(codegen_unit_name.clone())
330-
.or_insert_with(make_codegen_unit);
319+
.or_insert_with(|| CodegenUnit::new(codegen_unit_name.clone()));
331320

332321
let mut can_be_internalized = true;
333-
let default_visibility = |id: DefId, is_generic: bool| {
334-
if !tcx.sess.target.target.options.default_hidden_visibility {
335-
return Visibility::Default
336-
}
322+
let (linkage, visibility) = mono_item_linkage_and_visibility(
323+
tcx,
324+
&mono_item,
325+
&mut can_be_internalized,
326+
&|id, is_generic| {
327+
if !tcx.sess.target.target.options.default_hidden_visibility {
328+
return Visibility::Default
329+
}
337330

338-
// Generic functions never have export level C
339-
if is_generic {
340-
return Visibility::Hidden
341-
}
331+
// Generic functions never have export level C
332+
if is_generic {
333+
return Visibility::Hidden
334+
}
342335

343-
// Things with export level C don't get instantiated in downstream
344-
// crates
345-
if !id.is_local() {
346-
return Visibility::Hidden
347-
}
336+
// Things with export level C don't get instantiated in
337+
// downstream crates
338+
if !id.is_local() {
339+
return Visibility::Hidden
340+
}
348341

349-
if let Some(&SymbolExportLevel::C) = tcx.reachable_non_generics(id.krate)
350-
.get(&id) {
351-
Visibility::Default
352-
} else {
353-
Visibility::Hidden
354-
}
355-
};
356-
let (linkage, visibility) = match mono_item.explicit_linkage(tcx) {
357-
Some(explicit_linkage) => (explicit_linkage, Visibility::Default),
358-
None => {
359-
match mono_item {
360-
MonoItem::Fn(ref instance) => {
361-
let visibility = match instance.def {
362-
InstanceDef::Item(def_id) => {
363-
let is_generic = instance.substs
364-
.types()
365-
.next()
366-
.is_some();
367-
368-
// The `start_fn` lang item is actually a
369-
// monomorphized instance of a function in the
370-
// standard library, used for the `main`
371-
// function. We don't want to export it so we
372-
// tag it with `Hidden` visibility but this
373-
// symbol is only referenced from the actual
374-
// `main` symbol which we unfortunately don't
375-
// know anything about during
376-
// partitioning/collection. As a result we
377-
// forcibly keep this symbol out of the
378-
// `internalization_candidates` set.
379-
//
380-
// FIXME: eventually we don't want to always
381-
// force this symbol to have hidden
382-
// visibility, it should indeed be a candidate
383-
// for internalization, but we have to
384-
// understand that it's referenced from the
385-
// `main` symbol we'll generate later.
386-
if tcx.lang_items().start_fn() == Some(def_id) {
387-
can_be_internalized = false;
388-
Visibility::Hidden
389-
} else if def_id.is_local() {
390-
if is_generic {
391-
if export_generics {
392-
if tcx.is_unreachable_local_definition(def_id) {
393-
// This instance cannot be used
394-
// from another crate.
395-
Visibility::Hidden
396-
} else {
397-
// This instance might be useful in
398-
// a downstream crate.
399-
can_be_internalized = false;
400-
default_visibility(def_id, true)
401-
}
402-
} else {
403-
// We are not exporting generics or
404-
// the definition is not reachable
405-
// for downstream crates, we can
406-
// internalize its instantiations.
407-
Visibility::Hidden
408-
}
409-
} else {
410-
// This isn't a generic function.
411-
if tcx.is_reachable_non_generic(def_id) {
412-
can_be_internalized = false;
413-
debug_assert!(!is_generic);
414-
default_visibility(def_id, false)
415-
} else {
416-
Visibility::Hidden
417-
}
418-
}
419-
} else {
420-
// This is an upstream DefId.
421-
if export_generics && is_generic {
422-
// If it is a upstream monomorphization
423-
// and we export generics, we must make
424-
// it available to downstream crates.
425-
can_be_internalized = false;
426-
default_visibility(def_id, true)
427-
} else {
428-
Visibility::Hidden
429-
}
430-
}
431-
}
432-
InstanceDef::FnPtrShim(..) |
433-
InstanceDef::Virtual(..) |
434-
InstanceDef::Intrinsic(..) |
435-
InstanceDef::ClosureOnceShim { .. } |
436-
InstanceDef::DropGlue(..) |
437-
InstanceDef::CloneShim(..) => {
438-
Visibility::Hidden
439-
}
440-
};
441-
(Linkage::External, visibility)
442-
}
443-
MonoItem::Static(def_id) => {
444-
let visibility = if tcx.is_reachable_non_generic(def_id) {
445-
can_be_internalized = false;
446-
default_visibility(def_id, false)
447-
} else {
448-
Visibility::Hidden
449-
};
450-
(Linkage::External, visibility)
451-
}
452-
MonoItem::GlobalAsm(node_id) => {
453-
let def_id = tcx.hir.local_def_id(node_id);
454-
let visibility = if tcx.is_reachable_non_generic(def_id) {
455-
can_be_internalized = false;
456-
default_visibility(def_id, false)
457-
} else {
458-
Visibility::Hidden
459-
};
460-
(Linkage::External, visibility)
461-
}
342+
// C-export level items remain at `Default`, all other internal
343+
// items become `Hidden`
344+
match tcx.reachable_non_generics(id.krate).get(&id) {
345+
Some(SymbolExportLevel::C) => Visibility::Default,
346+
_ => Visibility::Hidden,
462347
}
463-
}
464-
};
348+
},
349+
);
465350
if visibility == Visibility::Hidden && can_be_internalized {
466351
internalization_candidates.insert(mono_item);
467352
}
@@ -487,6 +372,132 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
487372
}
488373
}
489374

375+
fn mono_item_linkage_and_visibility(
376+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
377+
mono_item: &MonoItem<'tcx>,
378+
can_be_internalized: &mut bool,
379+
default: &dyn Fn(DefId, bool) -> Visibility,
380+
) -> (Linkage, Visibility) {
381+
if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) {
382+
return (explicit_linkage, Visibility::Default)
383+
}
384+
let vis = mono_item_visibility(tcx, mono_item, can_be_internalized, default);
385+
(Linkage::External, vis)
386+
}
387+
388+
fn mono_item_visibility(
389+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
390+
mono_item: &MonoItem<'tcx>,
391+
can_be_internalized: &mut bool,
392+
default_visibility: &dyn Fn(DefId, bool) -> Visibility,
393+
) -> Visibility {
394+
let instance = match mono_item {
395+
// This is pretty complicated, go below
396+
MonoItem::Fn(instance) => instance,
397+
398+
// Misc handling for generics and such, but otherwise
399+
MonoItem::Static(def_id) => {
400+
return if tcx.is_reachable_non_generic(*def_id) {
401+
*can_be_internalized = false;
402+
default_visibility(*def_id, false)
403+
} else {
404+
Visibility::Hidden
405+
};
406+
}
407+
MonoItem::GlobalAsm(node_id) => {
408+
let def_id = tcx.hir.local_def_id(*node_id);
409+
return if tcx.is_reachable_non_generic(def_id) {
410+
*can_be_internalized = false;
411+
default_visibility(def_id, false)
412+
} else {
413+
Visibility::Hidden
414+
};
415+
}
416+
};
417+
418+
let def_id = match instance.def {
419+
InstanceDef::Item(def_id) => def_id,
420+
421+
// These are all compiler glue and such, never exported, always hidden.
422+
InstanceDef::FnPtrShim(..) |
423+
InstanceDef::Virtual(..) |
424+
InstanceDef::Intrinsic(..) |
425+
InstanceDef::ClosureOnceShim { .. } |
426+
InstanceDef::DropGlue(..) |
427+
InstanceDef::CloneShim(..) => {
428+
return Visibility::Hidden
429+
}
430+
};
431+
432+
// The `start_fn` lang item is actually a monomorphized instance of a
433+
// function in the standard library, used for the `main` function. We don't
434+
// want to export it so we tag it with `Hidden` visibility but this symbol
435+
// is only referenced from the actual `main` symbol which we unfortunately
436+
// don't know anything about during partitioning/collection. As a result we
437+
// forcibly keep this symbol out of the `internalization_candidates` set.
438+
//
439+
// FIXME: eventually we don't want to always force this symbol to have
440+
// hidden visibility, it should indeed be a candidate for
441+
// internalization, but we have to understand that it's referenced
442+
// from the `main` symbol we'll generate later.
443+
if tcx.lang_items().start_fn() == Some(def_id) {
444+
*can_be_internalized = false;
445+
return Visibility::Hidden
446+
}
447+
448+
// Determine if monomorphizations instantiated in this crate will be made
449+
// available to downstream crates. This depends on whether we are in
450+
// share-generics mode and whether the current crate can even have
451+
// downstream crates.
452+
let export_generics = tcx.sess.opts.share_generics() &&
453+
tcx.local_crate_exports_generics();
454+
455+
let is_generic = instance.substs.types().next().is_some();
456+
457+
// Upstream `DefId` instances get different handling than local ones
458+
if !def_id.is_local() {
459+
return if export_generics && is_generic {
460+
// If it is a upstream monomorphization
461+
// and we export generics, we must make
462+
// it available to downstream crates.
463+
*can_be_internalized = false;
464+
default_visibility(def_id, true)
465+
} else {
466+
Visibility::Hidden
467+
}
468+
}
469+
470+
if is_generic {
471+
if export_generics {
472+
if tcx.is_unreachable_local_definition(def_id) {
473+
// This instance cannot be used
474+
// from another crate.
475+
Visibility::Hidden
476+
} else {
477+
// This instance might be useful in
478+
// a downstream crate.
479+
*can_be_internalized = false;
480+
default_visibility(def_id, true)
481+
}
482+
} else {
483+
// We are not exporting generics or
484+
// the definition is not reachable
485+
// for downstream crates, we can
486+
// internalize its instantiations.
487+
Visibility::Hidden
488+
}
489+
} else {
490+
// This isn't a generic function.
491+
if tcx.is_reachable_non_generic(def_id) {
492+
*can_be_internalized = false;
493+
debug_assert!(!is_generic);
494+
default_visibility(def_id, false)
495+
} else {
496+
Visibility::Hidden
497+
}
498+
}
499+
}
500+
490501
fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<'tcx>,
491502
target_cgu_count: usize,
492503
crate_name: &str) {

0 commit comments

Comments
 (0)