@@ -8,6 +8,7 @@ use std::mem;
88use hir:: ItemKind ;
99use hir:: def_id:: { LocalDefIdMap , LocalDefIdSet } ;
1010use rustc_abi:: FieldIdx ;
11+ use rustc_data_structures:: fx:: FxIndexSet ;
1112use rustc_data_structures:: unord:: UnordSet ;
1213use rustc_errors:: MultiSpan ;
1314use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
@@ -44,15 +45,20 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
4445 )
4546}
4647
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
48+ /// Returns the local def id and def kind of the adt,
49+ /// if the given ty refers to one local adt definition
50+ fn adt_def_of_ty < ' tcx > ( ty : & hir:: Ty < ' tcx > ) -> Option < ( LocalDefId , DefKind ) > {
51+ match ty. kind {
52+ TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) => {
53+ if let Res :: Def ( def_kind, def_id) = path. res
54+ && let Some ( local_def_id) = def_id. as_local ( )
55+ {
56+ Some ( ( local_def_id, def_kind) )
57+ } else {
58+ None
59+ }
60+ }
61+ _ => None ,
5662 }
5763}
5864
@@ -78,7 +84,7 @@ struct MarkSymbolVisitor<'tcx> {
7884 // maps from ADTs to ignored derived traits (e.g. Debug and Clone)
7985 // and the span of their respective impl (i.e., part of the derive
8086 // macro)
81- ignored_derived_traits : LocalDefIdMap < Vec < ( DefId , DefId ) > > ,
87+ ignored_derived_traits : LocalDefIdMap < FxIndexSet < ( DefId , DefId ) > > ,
8288}
8389
8490impl < ' tcx > MarkSymbolVisitor < ' tcx > {
@@ -388,7 +394,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
388394 self . ignored_derived_traits
389395 . entry ( adt_def_id)
390396 . or_default ( )
391- . push ( ( trait_of, impl_of) ) ;
397+ . insert ( ( trait_of, impl_of) ) ;
392398 }
393399 return true ;
394400 }
@@ -420,51 +426,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
420426 intravisit:: walk_item ( self , item)
421427 }
422428 hir:: ItemKind :: ForeignMod { .. } => { }
423- hir:: ItemKind :: Trait ( ..) => {
424- for & impl_def_id in self . tcx . local_trait_impls ( item. owner_id . def_id ) {
425- if let ItemKind :: Impl ( impl_ref) = self . tcx . hir_expect_item ( impl_def_id) . kind
426- {
427- // skip items
428- // mark dependent traits live
429- intravisit:: walk_generics ( self , impl_ref. generics ) ;
430- // mark dependent parameters live
431- intravisit:: walk_path ( self , impl_ref. of_trait . unwrap ( ) . path ) ;
429+ hir:: ItemKind :: Trait ( _, _, _, _, _, trait_item_refs) => {
430+ // mark assoc ty live if the trait is live
431+ for trait_item in trait_item_refs {
432+ if matches ! ( trait_item. kind, hir:: AssocItemKind :: Type ) {
433+ self . check_def_id ( trait_item. id . owner_id . to_def_id ( ) ) ;
432434 }
433435 }
434-
435436 intravisit:: walk_item ( self , item)
436437 }
437438 _ => intravisit:: walk_item ( self , item) ,
438439 } ,
439440 Node :: TraitItem ( trait_item) => {
440- // mark corresponding ImplTerm live
441+ // mark the trait live
441442 let trait_item_id = trait_item. owner_id . to_def_id ( ) ;
442443 if let Some ( trait_id) = self . tcx . trait_of_item ( trait_item_id) {
443- // mark the trait live
444444 self . check_def_id ( trait_id) ;
445-
446- for impl_id in self . tcx . all_impls ( trait_id) {
447- if let Some ( local_impl_id) = impl_id. as_local ( )
448- && let ItemKind :: Impl ( impl_ref) =
449- self . tcx . hir_expect_item ( local_impl_id) . kind
450- {
451- if !matches ! ( trait_item. kind, hir:: TraitItemKind :: Type ( ..) )
452- && !ty_ref_to_pub_struct ( self . tcx , impl_ref. self_ty )
453- {
454- // skip methods of private ty,
455- // they would be solved in `solve_rest_impl_items`
456- continue ;
457- }
458-
459- // mark self_ty live
460- intravisit:: walk_unambig_ty ( self , impl_ref. self_ty ) ;
461- if let Some ( & impl_item_id) =
462- self . tcx . impl_item_implementor_ids ( impl_id) . get ( & trait_item_id)
463- {
464- self . check_def_id ( impl_item_id) ;
465- }
466- }
467- }
468445 }
469446 intravisit:: walk_trait_item ( self , trait_item) ;
470447 }
@@ -508,48 +485,57 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
508485 }
509486 }
510487
511- fn solve_rest_impl_items ( & mut self , mut unsolved_impl_items : Vec < ( hir:: ItemId , LocalDefId ) > ) {
512- let mut ready;
513- ( ready, unsolved_impl_items) =
514- unsolved_impl_items. into_iter ( ) . partition ( |& ( impl_id, impl_item_id) | {
515- self . impl_item_with_used_self ( impl_id, impl_item_id)
516- } ) ;
517-
518- while !ready. is_empty ( ) {
519- self . worklist =
520- ready. into_iter ( ) . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) ) . collect ( ) ;
521- self . mark_live_symbols ( ) ;
522-
523- ( ready, unsolved_impl_items) =
524- unsolved_impl_items. into_iter ( ) . partition ( |& ( impl_id, impl_item_id) | {
525- self . impl_item_with_used_self ( impl_id, impl_item_id)
526- } ) ;
488+ /// Returns an impl or impl item should be checked or not
489+ /// `impl_id` is the `ItemId` of the impl or the impl item belongs to,
490+ /// `local_def_id` may point to the impl or the impl item,
491+ /// both impl and impl item that may pass to this function are of trait,
492+ /// and added into the unsolved_items during `create_and_seed_worklist`
493+ fn item_should_be_checked ( & mut self , impl_id : hir:: ItemId , local_def_id : LocalDefId ) -> bool {
494+ if self . should_ignore_item ( local_def_id. to_def_id ( ) ) {
495+ return false ;
527496 }
528- }
529497
530- fn impl_item_with_used_self ( & mut self , impl_id : hir:: ItemId , impl_item_id : LocalDefId ) -> bool {
531- if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) =
532- self . tcx . hir_item ( impl_id) . expect_impl ( ) . self_ty . kind
533- && let Res :: Def ( def_kind, def_id) = path. res
534- && let Some ( local_def_id) = def_id. as_local ( )
535- && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
536- {
537- if self . tcx . visibility ( impl_item_id) . is_public ( ) {
538- // for the public method, we don't know the trait item is used or not,
539- // so we mark the method live if the self is used
540- return self . live_symbols . contains ( & local_def_id) ;
498+ let trait_def_id = match self . tcx . def_kind ( local_def_id) {
499+ // assoc impl items of traits are live if the corresponding trait items are live
500+ DefKind :: AssocFn => self . tcx . associated_item ( local_def_id) . trait_item_def_id ,
501+ // impl items are live if the corresponding traits are live
502+ DefKind :: Impl { of_trait : true } => self
503+ . tcx
504+ . impl_trait_ref ( impl_id. owner_id . def_id )
505+ . and_then ( |trait_ref| Some ( trait_ref. skip_binder ( ) . def_id ) ) ,
506+ _ => None ,
507+ } ;
508+
509+ if let Some ( trait_def_id) = trait_def_id {
510+ if let Some ( trait_def_id) = trait_def_id. as_local ( )
511+ && !self . live_symbols . contains ( & trait_def_id)
512+ {
513+ return false ;
541514 }
542515
543- if let Some ( trait_item_id) = self . tcx . associated_item ( impl_item_id) . trait_item_def_id
544- && let Some ( local_id) = trait_item_id. as_local ( )
516+ // FIXME: legacy logic to check the fn may construct self,
517+ // this can be removed after supporting marking adt appears
518+ // in patterns as live, then we can check private impls of
519+ // public traits directly
520+ if let Some ( fn_sig) =
521+ self . tcx . hir_fn_sig_by_hir_id ( self . tcx . local_def_id_to_hir_id ( local_def_id) )
522+ && matches ! ( fn_sig. decl. implicit_self, hir:: ImplicitSelfKind :: None )
523+ && self . tcx . visibility ( trait_def_id) . is_public ( )
545524 {
546- // for the private method, we can know the trait item is used or not,
547- // so we mark the method live if the self is used and the trait item is used
548- return self . live_symbols . contains ( & local_id)
549- && self . live_symbols . contains ( & local_def_id) ;
525+ return true ;
550526 }
551527 }
552- false
528+
529+ // the impl/impl item is used if the trait/trait item is used and the ty is used
530+ if let Some ( ( local_def_id, def_kind) ) =
531+ adt_def_of_ty ( self . tcx . hir_item ( impl_id) . expect_impl ( ) . self_ty )
532+ && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
533+ && !self . live_symbols . contains ( & local_def_id)
534+ {
535+ return false ;
536+ }
537+
538+ true
553539 }
554540}
555541
@@ -738,7 +724,7 @@ fn check_item<'tcx>(
738724 tcx : TyCtxt < ' tcx > ,
739725 worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
740726 struct_constructors : & mut LocalDefIdMap < LocalDefId > ,
741- unsolved_impl_items : & mut Vec < ( hir:: ItemId , LocalDefId ) > ,
727+ unsolved_items : & mut Vec < ( hir:: ItemId , LocalDefId ) > ,
742728 id : hir:: ItemId ,
743729) {
744730 let allow_dead_code = has_allow_dead_code_or_lang_attr ( tcx, id. owner_id . def_id ) ;
@@ -765,40 +751,36 @@ fn check_item<'tcx>(
765751 }
766752 DefKind :: Impl { of_trait } => {
767753 // get DefIds from another query
768- let local_def_ids = tcx
754+ let associated_item_def_ids = tcx
769755 . associated_item_def_ids ( id. owner_id )
770756 . iter ( )
771757 . filter_map ( |def_id| def_id. as_local ( ) ) ;
772758
773- let ty_is_pub = ty_ref_to_pub_struct ( tcx, tcx. hir_item ( id) . expect_impl ( ) . self_ty ) ;
759+ if let Some ( comes_from_allow) =
760+ has_allow_dead_code_or_lang_attr ( tcx, id. owner_id . def_id )
761+ {
762+ worklist. push ( ( id. owner_id . def_id , comes_from_allow) ) ;
763+ } else if of_trait {
764+ unsolved_items. push ( ( id, id. owner_id . def_id ) ) ;
765+ }
774766
775767 // And we access the Map here to get HirId from LocalDefId
776- for local_def_id in local_def_ids {
777- // check the function may construct Self
778- let mut may_construct_self = false ;
779- if let Some ( fn_sig) =
780- tcx. hir_fn_sig_by_hir_id ( tcx. local_def_id_to_hir_id ( local_def_id) )
781- {
782- may_construct_self =
783- matches ! ( fn_sig. decl. implicit_self, hir:: ImplicitSelfKind :: None ) ;
784- }
785-
786- // for trait impl blocks,
787- // mark the method live if the self_ty is public,
788- // or the method is public and may construct self
789- if of_trait
790- && ( !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn )
791- || tcx. visibility ( local_def_id) . is_public ( )
792- && ( ty_is_pub || may_construct_self) )
793- {
768+ for local_def_id in associated_item_def_ids {
769+ // FIXME: this condition can be removed
770+ // if we support dead check for assoc consts and tys
771+ if of_trait && !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn ) {
794772 worklist. push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
795773 } else if let Some ( comes_from_allow) =
796774 has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
797775 {
798776 worklist. push ( ( local_def_id, comes_from_allow) ) ;
799777 } else if of_trait {
800- // private method || public method not constructs self
801- unsolved_impl_items. push ( ( id, local_def_id) ) ;
778+ // we only care about assoc items of trait,
779+ // because they cannot be visited directly
780+ // so we mark them based on the trait/trait item
781+ // and self ty are checked first and both live,
782+ // but inherent assoc items can be visited and marked directly
783+ unsolved_items. push ( ( id, local_def_id) ) ;
802784 }
803785 }
804786 }
@@ -892,8 +874,8 @@ fn create_and_seed_worklist(
892874fn live_symbols_and_ignored_derived_traits (
893875 tcx : TyCtxt < ' _ > ,
894876 ( ) : ( ) ,
895- ) -> ( LocalDefIdSet , LocalDefIdMap < Vec < ( DefId , DefId ) > > ) {
896- let ( worklist, struct_constructors, unsolved_impl_items ) = create_and_seed_worklist ( tcx) ;
877+ ) -> ( LocalDefIdSet , LocalDefIdMap < FxIndexSet < ( DefId , DefId ) > > ) {
878+ let ( worklist, struct_constructors, mut unsolved_items ) = create_and_seed_worklist ( tcx) ;
897879 let mut symbol_visitor = MarkSymbolVisitor {
898880 worklist,
899881 tcx,
@@ -907,7 +889,24 @@ fn live_symbols_and_ignored_derived_traits(
907889 ignored_derived_traits : Default :: default ( ) ,
908890 } ;
909891 symbol_visitor. mark_live_symbols ( ) ;
910- symbol_visitor. solve_rest_impl_items ( unsolved_impl_items) ;
892+ let mut rest_items_should_be_checked;
893+ ( rest_items_should_be_checked, unsolved_items) =
894+ unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
895+ symbol_visitor. item_should_be_checked ( impl_id, local_def_id)
896+ } ) ;
897+
898+ while !rest_items_should_be_checked. is_empty ( ) {
899+ symbol_visitor. worklist = rest_items_should_be_checked
900+ . into_iter ( )
901+ . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) )
902+ . collect ( ) ;
903+ symbol_visitor. mark_live_symbols ( ) ;
904+
905+ ( rest_items_should_be_checked, unsolved_items) =
906+ unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
907+ symbol_visitor. item_should_be_checked ( impl_id, local_def_id)
908+ } ) ;
909+ }
911910
912911 ( symbol_visitor. live_symbols , symbol_visitor. ignored_derived_traits )
913912}
@@ -921,7 +920,7 @@ struct DeadItem {
921920struct DeadVisitor < ' tcx > {
922921 tcx : TyCtxt < ' tcx > ,
923922 live_symbols : & ' tcx LocalDefIdSet ,
924- ignored_derived_traits : & ' tcx LocalDefIdMap < Vec < ( DefId , DefId ) > > ,
923+ ignored_derived_traits : & ' tcx LocalDefIdMap < FxIndexSet < ( DefId , DefId ) > > ,
925924}
926925
927926enum ShouldWarnAboutField {
@@ -1188,19 +1187,14 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
11881187 let def_kind = tcx. def_kind ( item. owner_id ) ;
11891188
11901189 let mut dead_codes = Vec :: new ( ) ;
1191- // if we have diagnosed the trait, do not diagnose unused methods
1192- if matches ! ( def_kind, DefKind :: Impl { .. } )
1190+ // only diagnose unused assoc items for inherient impl and used trait
1191+ // for unused assoc items in impls of trait, we have diagnosed them in
1192+ // the trait if they are unused, for unused assoc items in unused trait,
1193+ // we have diagnosed the unused trait
1194+ if matches ! ( def_kind, DefKind :: Impl { of_trait: false } )
11931195 || ( def_kind == DefKind :: Trait && live_symbols. contains ( & item. owner_id . def_id ) )
11941196 {
11951197 for & def_id in tcx. associated_item_def_ids ( item. owner_id . def_id ) {
1196- // We have diagnosed unused methods in traits
1197- if matches ! ( def_kind, DefKind :: Impl { of_trait: true } )
1198- && tcx. def_kind ( def_id) == DefKind :: AssocFn
1199- || def_kind == DefKind :: Trait && tcx. def_kind ( def_id) != DefKind :: AssocFn
1200- {
1201- continue ;
1202- }
1203-
12041198 if let Some ( local_def_id) = def_id. as_local ( )
12051199 && !visitor. is_live_code ( local_def_id)
12061200 {
0 commit comments