Skip to content

Commit

Permalink
extend doc comment for reachability set computation
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Mar 20, 2024
1 parent b7dcabe commit 216bef2
Showing 1 changed file with 26 additions and 14 deletions.
40 changes: 26 additions & 14 deletions compiler/rustc_passes/src/reachable.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
// Finds items that are externally reachable, to determine which items
// need to have their metadata (and possibly their AST) serialized.
// All items that can be referred to through an exported name are
// reachable, and when a reachable thing is inline or generic, it
// makes all other generics or inline functions that it references
// reachable as well.
//! Finds local items that are externally reachable, to determine which items
//! need to have their metadata (and possibly their AST) serialized.
//!
//! This set is *not* transitively closed, i.e., in general the set only contains definitions that
//! can be reached *directly* via an exported name, not private functions that can only be reached
//! transitively.
//!
//! However, there's a catch: if an item is generic or cross-crate inlinable, then it will have its
//! code generated by some downstream crate. Now if that item calls private monomorphic
//! non-cross-crate-inlinable items, then those can be reached by the code generated by the
//! downstream create! Therefore, when a reachable thing is cross-crate inlinable or generic, it
//! makes all other functions that it references reachable as well.
use hir::def_id::LocalDefIdSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
Expand Down Expand Up @@ -56,10 +62,15 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
hir::ExprKind::Path(ref qpath) => {
Some(self.typeck_results().qpath_res(qpath, expr.hir_id))
}
hir::ExprKind::MethodCall(..) => self
.typeck_results()
.type_dependent_def(expr.hir_id)
.map(|(kind, def_id)| Res::Def(kind, def_id)),
hir::ExprKind::MethodCall(..) => {
// If this is a method call on a generic type, we might not be able to find the
// callee. That's why `reachable_set` also adds all potential callees for such
// calls, i.e. all trait impl items, to the reachable set. So here we only worry
// about the calls we can identify.
self.typeck_results()
.type_dependent_def(expr.hir_id)
.map(|(kind, def_id)| Res::Def(kind, def_id))
}
hir::ExprKind::Closure(&hir::Closure { def_id, .. }) => {
self.reachable_symbols.insert(def_id);
None
Expand Down Expand Up @@ -394,6 +405,7 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
}

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

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

0 comments on commit 216bef2

Please sign in to comment.