@@ -125,6 +125,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
125125 hir:: ExprMethodCall ( ..) => {
126126 let method_call = ty:: MethodCall :: expr ( expr. id ) ;
127127 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
128131 if let Some ( node_id) = self . tcx . map . as_local_node_id ( def_id) {
129132 if self . def_id_represents_local_inlined_item ( def_id) {
130133 self . worklist . push ( node_id)
@@ -322,57 +325,69 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
322325 }
323326 }
324327 }
328+ }
325329
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 ) ;
340350 }
341351 }
342- } )
352+ }
353+
354+ visit:: walk_item ( self , item) ;
343355 }
344356}
345357
346358pub fn find_reachable ( tcx : & ty:: ctxt ,
347359 exported_items : & privacy:: ExportedItems )
348360 -> NodeSet {
361+
349362 let mut reachable_context = ReachableContext :: new ( tcx) ;
350363
351364 // 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
354367 // use the lang items, so we need to be sure to mark them as
355368 // exported.
356369 for id in exported_items {
357370 reachable_context. worklist . push ( * id) ;
358371 }
359372 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) ;
365376 }
366- _ => { }
367377 }
368378 }
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+ }
369387
370388 // Step 2: Mark all symbols that the symbols on the worklist touch.
371389 reachable_context. propagate ( ) ;
372390
373- // Step 3: Mark all destructors as reachable.
374- reachable_context. mark_destructors_reachable ( ) ;
375-
376391 // Return the set of reachable symbols.
377392 reachable_context. reachable_symbols
378393}
0 commit comments