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".
7
11
8
12
use hir:: def_id:: LocalDefIdSet ;
9
13
use rustc_data_structures:: stack:: ensure_sufficient_stack;
@@ -21,6 +25,9 @@ use rustc_privacy::DefIdVisitor;
21
25
use rustc_session:: config:: CrateType ;
22
26
use rustc_target:: spec:: abi:: Abi ;
23
27
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.
24
31
fn item_might_be_inlined ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> bool {
25
32
tcx. generics_of ( def_id) . requires_monomorphization ( tcx)
26
33
|| tcx. cross_crate_inlinable ( def_id)
@@ -54,12 +61,20 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
54
61
fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr < ' tcx > ) {
55
62
let res = match expr. kind {
56
63
hir:: ExprKind :: Path ( ref qpath) => {
64
+ // This covers fn ptr casts but also "non-method" calls.
57
65
Some ( self . typeck_results ( ) . qpath_res ( qpath, expr. hir_id ) )
58
66
}
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
+ }
63
78
hir:: ExprKind :: Closure ( & hir:: Closure { def_id, .. } ) => {
64
79
self . reachable_symbols . insert ( def_id) ;
65
80
None
@@ -394,6 +409,7 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
394
409
|| codegen_attrs. flags . contains ( CodegenFnAttrFlags :: USED_LINKER )
395
410
}
396
411
412
+ /// See module-level doc comment above.
397
413
fn reachable_set ( tcx : TyCtxt < ' _ > , ( ) : ( ) ) -> LocalDefIdSet {
398
414
let effective_visibilities = & tcx. effective_visibilities ( ( ) ) ;
399
415
@@ -427,10 +443,10 @@ fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet {
427
443
}
428
444
}
429
445
{
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.
434
450
// FIXME: One possible strategy for pruning the reachable set is to avoid marking impl
435
451
// items of non-exported traits (or maybe all local traits?) unless their respective
436
452
// trait items are used from inlinable code through method call syntax or UFCS, or their
0 commit comments