@@ -125,6 +125,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
125
125
hir:: ExprMethodCall ( ..) => {
126
126
let method_call = ty:: MethodCall :: expr ( expr. id ) ;
127
127
let def_id = self . tcx . tables . borrow ( ) . method_map [ & method_call] . def_id ;
128
+
129
+ // Mark the trait item (and, possibly, its default impl) as reachable
130
+ // Or mark inherent impl item as reachable
128
131
if let Some ( node_id) = self . tcx . map . as_local_node_id ( def_id) {
129
132
if self . def_id_represents_local_inlined_item ( def_id) {
130
133
self . worklist . push ( node_id)
@@ -322,57 +325,69 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
322
325
}
323
326
}
324
327
}
328
+ }
325
329
326
- // Step 3: Mark all destructors as reachable.
327
- //
328
- // FIXME #10732: This is a conservative overapproximation, but fixing
329
- // this properly would result in the necessity of computing *type*
330
- // reachability, which might result in a compile time loss.
331
- fn mark_destructors_reachable ( & mut self ) {
332
- let drop_trait = match self . tcx . lang_items . drop_trait ( ) {
333
- Some ( id) => self . tcx . lookup_trait_def ( id) , None => { return }
334
- } ;
335
- drop_trait. for_each_impl ( self . tcx , |drop_impl| {
336
- for destructor in & self . tcx . impl_items . borrow ( ) [ & drop_impl] {
337
- let destructor_did = destructor. def_id ( ) ;
338
- if let Some ( destructor_node_id) = self . tcx . map . as_local_node_id ( destructor_did) {
339
- self . reachable_symbols . insert ( destructor_node_id) ;
330
+ // Some methods from non-exported (completely private) trait impls still have to be
331
+ // reachable if they are called from inlinable code. Generally, it's not known until
332
+ // monomorphization if a specific trait impl item can be reachable or not. So, we
333
+ // conservatively mark all of them as reachable.
334
+ // FIXME: One possible strategy for pruning the reachable set is to avoid marking impl
335
+ // items of non-exported traits (or maybe all local traits?) unless their respective
336
+ // trait items are used from inlinable code through method call syntax or UFCS, or their
337
+ // trait is a lang item.
338
+ struct CollectPrivateImplItemsVisitor < ' a > {
339
+ exported_items : & ' a privacy:: ExportedItems ,
340
+ worklist : & ' a mut Vec < ast:: NodeId > ,
341
+ }
342
+
343
+ impl < ' a , ' v > Visitor < ' v > for CollectPrivateImplItemsVisitor < ' a > {
344
+ fn visit_item ( & mut self , item : & hir:: Item ) {
345
+ // We need only trait impls here, not inherent impls, and only non-exported ones
346
+ if let hir:: ItemImpl ( _, _, _, Some ( _) , _, ref impl_items) = item. node {
347
+ if !self . exported_items . contains ( & item. id ) {
348
+ for impl_item in impl_items {
349
+ self . worklist . push ( impl_item. id ) ;
340
350
}
341
351
}
342
- } )
352
+ }
353
+
354
+ visit:: walk_item ( self , item) ;
343
355
}
344
356
}
345
357
346
358
pub fn find_reachable ( tcx : & ty:: ctxt ,
347
359
exported_items : & privacy:: ExportedItems )
348
360
-> NodeSet {
361
+
349
362
let mut reachable_context = ReachableContext :: new ( tcx) ;
350
363
351
364
// Step 1: Seed the worklist with all nodes which were found to be public as
352
- // a result of the privacy pass along with all local lang items. If
353
- // other crates link to us, they're going to expect to be able to
365
+ // a result of the privacy pass along with all local lang items and impl items.
366
+ // If other crates link to us, they're going to expect to be able to
354
367
// use the lang items, so we need to be sure to mark them as
355
368
// exported.
356
369
for id in exported_items {
357
370
reachable_context. worklist . push ( * id) ;
358
371
}
359
372
for ( _, item) in tcx. lang_items . items ( ) {
360
- match * item {
361
- Some ( did) => {
362
- if let Some ( node_id) = tcx. map . as_local_node_id ( did) {
363
- reachable_context. worklist . push ( node_id) ;
364
- }
373
+ if let Some ( did) = * item {
374
+ if let Some ( node_id) = tcx. map . as_local_node_id ( did) {
375
+ reachable_context. worklist . push ( node_id) ;
365
376
}
366
- _ => { }
367
377
}
368
378
}
379
+ {
380
+ let mut collect_private_impl_items = CollectPrivateImplItemsVisitor {
381
+ exported_items : exported_items,
382
+ worklist : & mut reachable_context. worklist ,
383
+ } ;
384
+
385
+ visit:: walk_crate ( & mut collect_private_impl_items, tcx. map . krate ( ) ) ;
386
+ }
369
387
370
388
// Step 2: Mark all symbols that the symbols on the worklist touch.
371
389
reachable_context. propagate ( ) ;
372
390
373
- // Step 3: Mark all destructors as reachable.
374
- reachable_context. mark_destructors_reachable ( ) ;
375
-
376
391
// Return the set of reachable symbols.
377
392
reachable_context. reachable_symbols
378
393
}
0 commit comments