@@ -17,7 +17,7 @@ use rustc_hir::{Node, PatKind, TyKind};
1717use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
1818use rustc_middle:: middle:: privacy:: Level ;
1919use rustc_middle:: query:: Providers ;
20- use rustc_middle:: ty:: { self , TyCtxt } ;
20+ use rustc_middle:: ty:: { self , AssocItemContainer , Ty , TyCtxt } ;
2121use rustc_middle:: { bug, span_bug} ;
2222use rustc_session:: lint;
2323use rustc_session:: lint:: builtin:: DEAD_CODE ;
@@ -44,15 +44,18 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
4444 )
4545}
4646
47- fn ty_ref_to_pub_struct ( tcx : TyCtxt < ' _ > , ty : & hir:: Ty < ' _ > ) -> bool {
48- if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) = ty. kind
49- && let Res :: Def ( def_kind, def_id) = path. res
50- && def_id. is_local ( )
51- && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
52- {
53- tcx. visibility ( def_id) . is_public ( )
54- } else {
55- true
47+ fn adt_of < ' tcx > ( ty : & hir:: Ty < ' tcx > ) -> Option < ( LocalDefId , DefKind ) > {
48+ match ty. kind {
49+ TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) => {
50+ if let Res :: Def ( def_kind, def_id) = path. res
51+ && let Some ( local_def_id) = def_id. as_local ( )
52+ {
53+ Some ( ( local_def_id, def_kind) )
54+ } else {
55+ None
56+ }
57+ }
58+ _ => None ,
5659 }
5760}
5861
@@ -420,22 +423,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
420423 intravisit:: walk_item ( self , item)
421424 }
422425 hir:: ItemKind :: ForeignMod { .. } => { }
423- hir:: ItemKind :: Trait ( ..) => {
424- for impl_def_id in self . tcx . all_impls ( item. owner_id . to_def_id ( ) ) {
425- if let Some ( local_def_id) = impl_def_id. as_local ( )
426- && let ItemKind :: Impl ( impl_ref) =
427- self . tcx . hir ( ) . expect_item ( local_def_id) . kind
428- {
429- // skip items
430- // mark dependent traits live
431- intravisit:: walk_generics ( self , impl_ref. generics ) ;
432- // mark dependent parameters live
433- intravisit:: walk_path ( self , impl_ref. of_trait . unwrap ( ) . path ) ;
434- }
435- }
436-
437- intravisit:: walk_item ( self , item)
438- }
439426 _ => intravisit:: walk_item ( self , item) ,
440427 } ,
441428 Node :: TraitItem ( trait_item) => {
@@ -444,30 +431,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
444431 if let Some ( trait_id) = self . tcx . trait_of_item ( trait_item_id) {
445432 // mark the trait live
446433 self . check_def_id ( trait_id) ;
447-
448- for impl_id in self . tcx . all_impls ( trait_id) {
449- if let Some ( local_impl_id) = impl_id. as_local ( )
450- && let ItemKind :: Impl ( impl_ref) =
451- self . tcx . hir ( ) . expect_item ( local_impl_id) . kind
452- {
453- if !matches ! ( trait_item. kind, hir:: TraitItemKind :: Type ( ..) )
454- && !ty_ref_to_pub_struct ( self . tcx , impl_ref. self_ty )
455- {
456- // skip methods of private ty,
457- // they would be solved in `solve_rest_impl_items`
458- continue ;
459- }
460-
461- // mark self_ty live
462- intravisit:: walk_ty ( self , impl_ref. self_ty ) ;
463- if let Some ( & impl_item_id) =
464- self . tcx . impl_item_implementor_ids ( impl_id) . get ( & trait_item_id)
465- {
466- self . check_def_id ( impl_item_id) ;
467- }
468- }
469- }
470434 }
435+
471436 intravisit:: walk_trait_item ( self , trait_item) ;
472437 }
473438 Node :: ImplItem ( impl_item) => {
@@ -509,48 +474,55 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
509474 }
510475 }
511476
512- fn solve_rest_impl_items ( & mut self , mut unsolved_impl_items : Vec < ( hir:: ItemId , LocalDefId ) > ) {
477+ fn solve_rest_items ( & mut self , mut unsolved_items : Vec < ( hir:: ItemId , LocalDefId ) > ) {
513478 let mut ready;
514- ( ready, unsolved_impl_items ) =
515- unsolved_impl_items . into_iter ( ) . partition ( |& ( impl_id, impl_item_id ) | {
516- self . impl_item_with_used_self ( impl_id, impl_item_id )
479+ ( ready, unsolved_items ) =
480+ unsolved_items . into_iter ( ) . partition ( |& ( impl_id, local_def_id ) | {
481+ self . item_should_be_checked ( impl_id, local_def_id )
517482 } ) ;
518483
519484 while !ready. is_empty ( ) {
520485 self . worklist =
521486 ready. into_iter ( ) . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) ) . collect ( ) ;
522487 self . mark_live_symbols ( ) ;
523488
524- ( ready, unsolved_impl_items ) =
525- unsolved_impl_items . into_iter ( ) . partition ( |& ( impl_id, impl_item_id ) | {
526- self . impl_item_with_used_self ( impl_id, impl_item_id )
489+ ( ready, unsolved_items ) =
490+ unsolved_items . into_iter ( ) . partition ( |& ( impl_id, local_def_id ) | {
491+ self . item_should_be_checked ( impl_id, local_def_id )
527492 } ) ;
528493 }
529494 }
530495
531- fn impl_item_with_used_self ( & mut self , impl_id : hir:: ItemId , impl_item_id : LocalDefId ) -> bool {
532- if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) =
533- self . tcx . hir ( ) . item ( impl_id) . expect_impl ( ) . self_ty . kind
534- && let Res :: Def ( def_kind, def_id) = path. res
535- && let Some ( local_def_id) = def_id. as_local ( )
536- && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
537- {
538- if self . tcx . visibility ( impl_item_id) . is_public ( ) {
539- // for the public method, we don't know the trait item is used or not,
540- // so we mark the method live if the self is used
541- return self . live_symbols . contains ( & local_def_id) ;
542- }
496+ fn item_should_be_checked ( & mut self , impl_id : hir:: ItemId , local_def_id : LocalDefId ) -> bool {
497+ let trait_def_id = match self . tcx . def_kind ( local_def_id) {
498+ // for assoc impl items of traits, we concern the corresponding trait items are used or not
499+ DefKind :: AssocFn => self
500+ . tcx
501+ . associated_item ( local_def_id)
502+ . trait_item_def_id
503+ . and_then ( |def_id| def_id. as_local ( ) ) ,
504+ // for impl items, we concern the corresonding traits are used or not
505+ DefKind :: Impl { of_trait : true } => self
506+ . tcx
507+ . impl_trait_ref ( impl_id. owner_id . def_id )
508+ . and_then ( |trait_ref| trait_ref. skip_binder ( ) . def_id . as_local ( ) ) ,
509+ _ => None ,
510+ } ;
543511
544- if let Some ( trait_item_id) = self . tcx . associated_item ( impl_item_id) . trait_item_def_id
545- && let Some ( local_id) = trait_item_id. as_local ( )
546- {
547- // for the private method, we can know the trait item is used or not,
548- // so we mark the method live if the self is used and the trait item is used
549- return self . live_symbols . contains ( & local_id)
550- && self . live_symbols . contains ( & local_def_id) ;
551- }
512+ if !trait_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true ) {
513+ return false ;
552514 }
553- false
515+
516+ // we only check the ty is used or not for ADTs defined locally
517+ let ty_def_id = adt_of ( self . tcx . hir ( ) . item ( impl_id) . expect_impl ( ) . self_ty ) . and_then (
518+ |( local_def_id, def_kind) | {
519+ matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
520+ . then_some ( local_def_id)
521+ } ,
522+ ) ;
523+
524+ // the impl/impl item is used if the trait/trait item is used and the ty is used
525+ ty_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true )
554526 }
555527}
556528
@@ -740,7 +712,7 @@ fn check_item<'tcx>(
740712 tcx : TyCtxt < ' tcx > ,
741713 worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
742714 struct_constructors : & mut LocalDefIdMap < LocalDefId > ,
743- unsolved_impl_items : & mut Vec < ( hir:: ItemId , LocalDefId ) > ,
715+ unsolved_items : & mut Vec < ( hir:: ItemId , LocalDefId ) > ,
744716 id : hir:: ItemId ,
745717) {
746718 let allow_dead_code = has_allow_dead_code_or_lang_attr ( tcx, id. owner_id . def_id ) ;
@@ -772,35 +744,24 @@ fn check_item<'tcx>(
772744 . iter ( )
773745 . filter_map ( |def_id| def_id. as_local ( ) ) ;
774746
775- let ty_is_pub = ty_ref_to_pub_struct ( tcx, tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty ) ;
747+ if let Some ( comes_from_allow) =
748+ has_allow_dead_code_or_lang_attr ( tcx, id. owner_id . def_id )
749+ {
750+ worklist. push ( ( id. owner_id . def_id , comes_from_allow) ) ;
751+ } else if of_trait {
752+ unsolved_items. push ( ( id, id. owner_id . def_id ) ) ;
753+ }
776754
777755 // And we access the Map here to get HirId from LocalDefId
778756 for local_def_id in local_def_ids {
779- // check the function may construct Self
780- let mut may_construct_self = false ;
781- if let Some ( fn_sig) =
782- tcx. hir ( ) . fn_sig_by_hir_id ( tcx. local_def_id_to_hir_id ( local_def_id) )
783- {
784- may_construct_self =
785- matches ! ( fn_sig. decl. implicit_self, hir:: ImplicitSelfKind :: None ) ;
786- }
787-
788- // for trait impl blocks,
789- // mark the method live if the self_ty is public,
790- // or the method is public and may construct self
791- if of_trait
792- && ( !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn )
793- || tcx. visibility ( local_def_id) . is_public ( )
794- && ( ty_is_pub || may_construct_self) )
795- {
757+ if !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn ) {
796758 worklist. push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
797759 } else if let Some ( comes_from_allow) =
798760 has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
799761 {
800762 worklist. push ( ( local_def_id, comes_from_allow) ) ;
801763 } else if of_trait {
802- // private method || public method not constructs self
803- unsolved_impl_items. push ( ( id, local_def_id) ) ;
764+ unsolved_items. push ( ( id, local_def_id) ) ;
804765 }
805766 }
806767 }
@@ -866,6 +827,18 @@ fn create_and_seed_worklist(
866827 effective_vis
867828 . is_public_at_level ( Level :: Reachable )
868829 . then_some ( id)
830+ . filter ( |& id|
831+ // checks impls and impl-items later
832+ match tcx. def_kind ( id) {
833+ DefKind :: Impl { of_trait } => !of_trait,
834+ DefKind :: AssocFn => {
835+ // still check public trait items, and impl items not of trait
836+ let assoc_item = tcx. associated_item ( id) ;
837+ !matches ! ( assoc_item. container, AssocItemContainer :: ImplContainer )
838+ || assoc_item. trait_item_def_id . is_none ( )
839+ } ,
840+ _ => true
841+ } )
869842 . map ( |id| ( id, ComesFromAllowExpect :: No ) )
870843 } )
871844 // Seed entry point
@@ -895,7 +868,7 @@ fn live_symbols_and_ignored_derived_traits(
895868 tcx : TyCtxt < ' _ > ,
896869 ( ) : ( ) ,
897870) -> ( LocalDefIdSet , LocalDefIdMap < Vec < ( DefId , DefId ) > > ) {
898- let ( worklist, struct_constructors, unsolved_impl_items ) = create_and_seed_worklist ( tcx) ;
871+ let ( worklist, struct_constructors, unsolved_items ) = create_and_seed_worklist ( tcx) ;
899872 let mut symbol_visitor = MarkSymbolVisitor {
900873 worklist,
901874 tcx,
@@ -909,7 +882,7 @@ fn live_symbols_and_ignored_derived_traits(
909882 ignored_derived_traits : Default :: default ( ) ,
910883 } ;
911884 symbol_visitor. mark_live_symbols ( ) ;
912- symbol_visitor. solve_rest_impl_items ( unsolved_impl_items ) ;
885+ symbol_visitor. solve_rest_items ( unsolved_items ) ;
913886
914887 ( symbol_visitor. live_symbols , symbol_visitor. ignored_derived_traits )
915888}
@@ -1185,19 +1158,11 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
11851158 let def_kind = tcx. def_kind ( item. owner_id ) ;
11861159
11871160 let mut dead_codes = Vec :: new ( ) ;
1188- // if we have diagnosed the trait, do not diagnose unused methods
1189- if matches ! ( def_kind, DefKind :: Impl { .. } )
1161+ // if we have diagnosed the trait, do not diagnose unused assoc items
1162+ if matches ! ( def_kind, DefKind :: Impl { of_trait : false } )
11901163 || ( def_kind == DefKind :: Trait && live_symbols. contains ( & item. owner_id . def_id ) )
11911164 {
11921165 for & def_id in tcx. associated_item_def_ids ( item. owner_id . def_id ) {
1193- // We have diagnosed unused methods in traits
1194- if matches ! ( def_kind, DefKind :: Impl { of_trait: true } )
1195- && tcx. def_kind ( def_id) == DefKind :: AssocFn
1196- || def_kind == DefKind :: Trait && tcx. def_kind ( def_id) != DefKind :: AssocFn
1197- {
1198- continue ;
1199- }
1200-
12011166 if let Some ( local_def_id) = def_id. as_local ( )
12021167 && !visitor. is_live_code ( local_def_id)
12031168 {
0 commit comments