Skip to content

Commit 42f39b5

Browse files
committed
extend doc comment for reachability set computation
1 parent b7dcabe commit 42f39b5

File tree

1 file changed

+30
-14
lines changed

1 file changed

+30
-14
lines changed

compiler/rustc_passes/src/reachable.rs

+30-14
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
// Finds items that are externally reachable, to determine which items
2-
// need to have their metadata (and possibly their AST) serialized.
3-
// All items that can be referred to through an exported name are
4-
// reachable, and when a reachable thing is inline or generic, it
5-
// makes all other generics or inline functions that it references
6-
// reachable as well.
1+
//! Finds local items that are externally reachable, to determine which items
2+
//! need to have their metadata (and possibly their AST) serialized.
3+
//!
4+
//! An item is "externally reachable" if it is relevant for other crates. This obviously includes
5+
//! all public items. However, when a reachable function `f` of this crate has its code generated as
6+
//! part of another crate's compilation, that other crate must be able to access everything needed
7+
//! to compile `f` -- in particular, every function called by `f`! Therefore, when a reachable thing
8+
//! is cross-crate inlinable or generic, it makes all other functions that it references reachable
9+
//! as well. Similarly, `const fn` may be evaluated by other crates, so everything they call is also
10+
//! "externally reachable". This is how private items can become "externally reachable".
711
812
use hir::def_id::LocalDefIdSet;
913
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -21,6 +25,9 @@ use rustc_privacy::DefIdVisitor;
2125
use rustc_session::config::CrateType;
2226
use rustc_target::spec::abi::Abi;
2327

28+
/// Determines whether this function may be codegen'd or evaluated as part of another crate's
29+
/// compilation. In that case, things that show up in its body are relevant for other crates as
30+
/// well.
2431
fn item_might_be_inlined(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
2532
tcx.generics_of(def_id).requires_monomorphization(tcx)
2633
|| tcx.cross_crate_inlinable(def_id)
@@ -54,12 +61,20 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
5461
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
5562
let res = match expr.kind {
5663
hir::ExprKind::Path(ref qpath) => {
64+
// This covers fn ptr casts but also "non-method" calls.
5765
Some(self.typeck_results().qpath_res(qpath, expr.hir_id))
5866
}
59-
hir::ExprKind::MethodCall(..) => self
60-
.typeck_results()
61-
.type_dependent_def(expr.hir_id)
62-
.map(|(kind, def_id)| Res::Def(kind, def_id)),
67+
hir::ExprKind::MethodCall(..) => {
68+
// Method calls don't involve a full "path", so we need to determine the callee
69+
// based on the receiver type.
70+
// If this is a method call on a generic type, we might not be able to find the
71+
// callee. That's why `reachable_set` also adds all potential callees for such
72+
// calls, i.e. all trait impl items, to the reachable set. So here we only worry
73+
// about the calls we can identify.
74+
self.typeck_results()
75+
.type_dependent_def(expr.hir_id)
76+
.map(|(kind, def_id)| Res::Def(kind, def_id))
77+
}
6378
hir::ExprKind::Closure(&hir::Closure { def_id, .. }) => {
6479
self.reachable_symbols.insert(def_id);
6580
None
@@ -394,6 +409,7 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
394409
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
395410
}
396411

412+
/// See module-level doc comment above.
397413
fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet {
398414
let effective_visibilities = &tcx.effective_visibilities(());
399415

@@ -427,10 +443,10 @@ fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet {
427443
}
428444
}
429445
{
430-
// Some methods from non-exported (completely private) trait impls still have to be
431-
// reachable if they are called from inlinable code. Generally, it's not known until
432-
// monomorphization if a specific trait impl item can be reachable or not. So, we
433-
// conservatively mark all of them as reachable.
446+
// As explained above, we have to mark all functions called from reachable
447+
// `item_might_be_inlined` items as reachable. The issue is, when those functions are
448+
// generic and call a trait method, we have no idea where that call goes! So, we
449+
// conservatively mark all trait impl items as reachable.
434450
// FIXME: One possible strategy for pruning the reachable set is to avoid marking impl
435451
// items of non-exported traits (or maybe all local traits?) unless their respective
436452
// trait items are used from inlinable code through method call syntax or UFCS, or their

0 commit comments

Comments
 (0)