@@ -17,7 +17,7 @@ use rustc_hir::{self as 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 , AssocItemContainer , Ty , TyCtxt } ;
20+ use rustc_middle:: ty:: { self , AssocItemContainer , TyCtxt } ;
2121use rustc_middle:: { bug, span_bug} ;
2222use rustc_session:: lint;
2323use rustc_session:: lint:: builtin:: DEAD_CODE ;
@@ -44,7 +44,9 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
4444 )
4545}
4646
47- fn adt_of < ' tcx > ( ty : & hir:: Ty < ' tcx > ) -> Option < ( LocalDefId , DefKind ) > {
47+ /// Returns the local def id and def kind of the adt,
48+ /// if the given ty refers to one local adt definition
49+ fn adt_def_of_ty < ' tcx > ( ty : & hir:: Ty < ' tcx > ) -> Option < ( LocalDefId , DefKind ) > {
4850 match ty. kind {
4951 TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) => {
5052 if let Res :: Def ( def_kind, def_id) = path. res
@@ -55,8 +57,8 @@ fn adt_of<'tcx>(ty: &hir::Ty<'tcx>) -> Option<(LocalDefId, DefKind)> {
5557 None
5658 }
5759 }
58- TyKind :: Slice ( ty) | TyKind :: Array ( ty, _) => adt_of ( ty) ,
59- TyKind :: Ptr ( ty) | TyKind :: Ref ( _, ty) => adt_of ( ty. ty ) ,
60+ TyKind :: Slice ( ty) | TyKind :: Array ( ty, _) => adt_def_of_ty ( ty) ,
61+ TyKind :: Ptr ( ty) | TyKind :: Ref ( _, ty) => adt_def_of_ty ( ty. ty ) ,
6062 _ => None ,
6163 }
6264}
@@ -114,7 +116,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
114116
115117 fn handle_res ( & mut self , res : Res ) {
116118 match res {
117- Res :: Def ( DefKind :: Const | DefKind :: AssocConst | DefKind :: TyAlias , def_id) => {
119+ Res :: Def (
120+ DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: Const | DefKind :: TyAlias ,
121+ def_id,
122+ ) => {
118123 self . check_def_id ( def_id) ;
119124 }
120125 _ if self . in_pat => { }
@@ -234,6 +239,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
234239 ) {
235240 let variant = match self . typeck_results ( ) . node_type ( lhs. hir_id ) . kind ( ) {
236241 ty:: Adt ( adt, _) => {
242+ // mark the adt live if its variant appears as the pattern
243+ // considering cases when we have `let T(x) = foo()` and `fn foo<T>() -> T;`
244+ // we will lose the liveness info of `T` cause we cannot mark it live when visiting `foo`
245+ // related issue: https://github.com/rust-lang/rust/issues/120770
237246 self . check_def_id ( adt. did ( ) ) ;
238247 adt. variant_of_res ( res)
239248 }
@@ -257,6 +266,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
257266 ) {
258267 let variant = match self . typeck_results ( ) . node_type ( lhs. hir_id ) . kind ( ) {
259268 ty:: Adt ( adt, _) => {
269+ // mark the adt live if its variant appears as the pattern
270+ // considering cases when we have `let T(x) = foo()` and `fn foo<T>() -> T;`
271+ // we will lose the liveness info of `T` cause we cannot mark it live when visiting `foo`
272+ // related issue: https://github.com/rust-lang/rust/issues/120770
260273 self . check_def_id ( adt. did ( ) ) ;
261274 adt. variant_of_res ( res)
262275 }
@@ -406,13 +419,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
406419 intravisit:: walk_item ( self , item)
407420 }
408421 hir:: ItemKind :: ForeignMod { .. } => { }
422+ hir:: ItemKind :: Trait ( _, _, _, _, _, trait_item_refs) => {
423+ // mark assoc ty live if the trait is live
424+ for trait_item in trait_item_refs {
425+ if matches ! ( trait_item. kind, hir:: AssocItemKind :: Type ) {
426+ self . check_def_id ( trait_item. id . owner_id . to_def_id ( ) ) ;
427+ }
428+ }
429+ intravisit:: walk_item ( self , item)
430+ }
409431 _ => intravisit:: walk_item ( self , item) ,
410432 } ,
411433 Node :: TraitItem ( trait_item) => {
412- // mark corresponding ImplTerm live
434+ // mark the trait live
413435 let trait_item_id = trait_item. owner_id . to_def_id ( ) ;
414436 if let Some ( trait_id) = self . tcx . trait_of_item ( trait_item_id) {
415- // mark the trait live
416437 self . check_def_id ( trait_id) ;
417438 }
418439
@@ -437,6 +458,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
437458 _ => { }
438459 }
439460 }
461+
440462 intravisit:: walk_impl_item ( self , impl_item) ;
441463 }
442464 Node :: ForeignItem ( foreign_item) => {
@@ -458,55 +480,44 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
458480 }
459481 }
460482
461- fn solve_rest_items ( & mut self , mut unsolved_items : Vec < ( hir:: ItemId , LocalDefId ) > ) {
462- let mut ready;
463- ( ready, unsolved_items) =
464- unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
465- self . item_should_be_checked ( impl_id, local_def_id)
466- } ) ;
467-
468- while !ready. is_empty ( ) {
469- self . worklist =
470- ready. into_iter ( ) . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) ) . collect ( ) ;
471- self . mark_live_symbols ( ) ;
472-
473- ( ready, unsolved_items) =
474- unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
475- self . item_should_be_checked ( impl_id, local_def_id)
476- } ) ;
477- }
478- }
479-
483+ /// Returns an impl or impl item should be checked or not
484+ /// `impl_id` is the `ItemId` of the impl or the impl item belongs to,
485+ /// `local_def_id` may point to the impl or the impl item,
486+ /// both impl and impl item that may pass to this function are of trait,
487+ /// and added into the unsolved_items during `create_and_seed_worklist`
480488 fn item_should_be_checked ( & mut self , impl_id : hir:: ItemId , local_def_id : LocalDefId ) -> bool {
481489 let trait_def_id = match self . tcx . def_kind ( local_def_id) {
482- // for assoc impl items of traits, we concern the corresponding trait items are used or not
483- DefKind :: AssocFn => self
490+ // assoc impl items of traits are live if the corresponding trait items are live
491+ DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: AssocFn => self
484492 . tcx
485493 . associated_item ( local_def_id)
486494 . trait_item_def_id
487495 . and_then ( |def_id| def_id. as_local ( ) ) ,
488- // for impl items, we concern the corresonding traits are used or not
496+ // impl items are live if the corresponding traits are live
489497 DefKind :: Impl { of_trait : true } => self
490498 . tcx
491499 . impl_trait_ref ( impl_id. owner_id . def_id )
492500 . and_then ( |trait_ref| trait_ref. skip_binder ( ) . def_id . as_local ( ) ) ,
493501 _ => None ,
494502 } ;
495503
496- if !trait_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true ) {
504+ if let Some ( def_id) = trait_def_id
505+ && !self . live_symbols . contains ( & def_id)
506+ {
497507 return false ;
498508 }
499509
500510 // we only check the ty is used or not for ADTs defined locally
501- let ty_def_id = adt_of ( self . tcx . hir_item ( impl_id) . expect_impl ( ) . self_ty ) . and_then (
502- |( local_def_id, def_kind) | {
503- matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
504- . then_some ( local_def_id)
505- } ,
506- ) ;
507-
508511 // the impl/impl item is used if the trait/trait item is used and the ty is used
509- ty_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true )
512+ if let Some ( ( local_def_id, def_kind) ) =
513+ adt_def_of_ty ( self . tcx . hir_item ( impl_id) . expect_impl ( ) . self_ty )
514+ && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
515+ && !self . live_symbols . contains ( & local_def_id)
516+ {
517+ return false ;
518+ }
519+
520+ true
510521 }
511522}
512523
@@ -643,6 +654,29 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
643654
644655 self . in_pat = in_pat;
645656 }
657+
658+ fn visit_poly_trait_ref ( & mut self , t : & ' tcx hir:: PolyTraitRef < ' tcx > ) {
659+ // mark the assoc const appears in poly-trait-ref live
660+ if let Some ( pathsegment) = t. trait_ref . path . segments . last ( )
661+ && let Some ( args) = pathsegment. args
662+ {
663+ for constraint in args. constraints {
664+ if let Some ( item) = self
665+ . tcx
666+ . associated_items ( pathsegment. res . def_id ( ) )
667+ . filter_by_name_unhygienic ( constraint. ident . name )
668+ . find ( |i| {
669+ matches ! ( i. kind, ty:: AssocKind :: Const )
670+ && i. ident ( self . tcx ) . normalize_to_macros_2_0 ( ) == constraint. ident
671+ } )
672+ && let Some ( local_def_id) = item. def_id . as_local ( )
673+ {
674+ self . worklist . push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
675+ }
676+ }
677+ }
678+ intravisit:: walk_poly_trait_ref ( self , t) ;
679+ }
646680}
647681
648682fn has_allow_dead_code_or_lang_attr (
@@ -726,7 +760,7 @@ fn check_item<'tcx>(
726760 }
727761 DefKind :: Impl { of_trait } => {
728762 // get DefIds from another query
729- let local_def_ids = tcx
763+ let associated_item_def_ids = tcx
730764 . associated_item_def_ids ( id. owner_id )
731765 . iter ( )
732766 . filter_map ( |def_id| def_id. as_local ( ) ) ;
@@ -740,14 +774,16 @@ fn check_item<'tcx>(
740774 }
741775
742776 // And we access the Map here to get HirId from LocalDefId
743- for local_def_id in local_def_ids {
744- if !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn ) {
745- worklist. push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
746- } else if let Some ( comes_from_allow) =
747- has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
777+ for local_def_id in associated_item_def_ids {
778+ if let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
748779 {
749780 worklist. push ( ( local_def_id, comes_from_allow) ) ;
750781 } else if of_trait {
782+ // we only care about assoc items of trait,
783+ // because they cannot be visited directly
784+ // so we mark them based on the trait/trait item
785+ // and self ty are checked first and both live,
786+ // but inherent assoc items can be visited and marked directly
751787 unsolved_items. push ( ( id, local_def_id) ) ;
752788 }
753789 }
@@ -773,10 +809,13 @@ fn check_trait_item(
773809 worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
774810 id : hir:: TraitItemId ,
775811) {
776- use hir:: TraitItemKind :: { Const , Fn } ;
777- if matches ! ( tcx. def_kind( id. owner_id) , DefKind :: AssocConst | DefKind :: AssocFn ) {
812+ use hir:: TraitItemKind :: { Const , Fn , Type } ;
813+ if matches ! (
814+ tcx. def_kind( id. owner_id) ,
815+ DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: AssocFn
816+ ) {
778817 let trait_item = tcx. hir_trait_item ( id) ;
779- if matches ! ( trait_item. kind, Const ( _, Some ( _) ) | Fn ( ..) )
818+ if matches ! ( trait_item. kind, Const ( _, Some ( _) ) | Type ( .. ) | Fn ( ..) )
780819 && let Some ( comes_from_allow) =
781820 has_allow_dead_code_or_lang_attr ( tcx, trait_item. owner_id . def_id )
782821 {
@@ -818,7 +857,7 @@ fn create_and_seed_worklist(
818857 // checks impls and impl-items later
819858 match tcx. def_kind ( id) {
820859 DefKind :: Impl { of_trait } => !of_trait,
821- DefKind :: AssocFn => {
860+ DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: AssocFn => {
822861 // still check public trait items, and impl items not of trait
823862 let assoc_item = tcx. associated_item ( id) ;
824863 !matches ! ( assoc_item. container, AssocItemContainer :: Impl )
@@ -855,7 +894,7 @@ fn live_symbols_and_ignored_derived_traits(
855894 tcx : TyCtxt < ' _ > ,
856895 ( ) : ( ) ,
857896) -> ( LocalDefIdSet , LocalDefIdMap < Vec < ( DefId , DefId ) > > ) {
858- let ( worklist, struct_constructors, unsolved_items) = create_and_seed_worklist ( tcx) ;
897+ let ( worklist, struct_constructors, mut unsolved_items) = create_and_seed_worklist ( tcx) ;
859898 let mut symbol_visitor = MarkSymbolVisitor {
860899 worklist,
861900 tcx,
@@ -868,8 +907,26 @@ fn live_symbols_and_ignored_derived_traits(
868907 struct_constructors,
869908 ignored_derived_traits : Default :: default ( ) ,
870909 } ;
910+
871911 symbol_visitor. mark_live_symbols ( ) ;
872- symbol_visitor. solve_rest_items ( unsolved_items) ;
912+ let mut rest_items_should_be_checked;
913+ ( rest_items_should_be_checked, unsolved_items) =
914+ unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
915+ symbol_visitor. item_should_be_checked ( impl_id, local_def_id)
916+ } ) ;
917+
918+ while !rest_items_should_be_checked. is_empty ( ) {
919+ symbol_visitor. worklist = rest_items_should_be_checked
920+ . into_iter ( )
921+ . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) )
922+ . collect ( ) ;
923+ symbol_visitor. mark_live_symbols ( ) ;
924+
925+ ( rest_items_should_be_checked, unsolved_items) =
926+ unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
927+ symbol_visitor. item_should_be_checked ( impl_id, local_def_id)
928+ } ) ;
929+ }
873930
874931 ( symbol_visitor. live_symbols , symbol_visitor. ignored_derived_traits )
875932}
@@ -1112,6 +1169,7 @@ impl<'tcx> DeadVisitor<'tcx> {
11121169 }
11131170 match self . tcx . def_kind ( def_id) {
11141171 DefKind :: AssocConst
1172+ | DefKind :: AssocTy
11151173 | DefKind :: AssocFn
11161174 | DefKind :: Fn
11171175 | DefKind :: Static { .. }
@@ -1148,7 +1206,11 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
11481206 let def_kind = tcx. def_kind ( item. owner_id ) ;
11491207
11501208 let mut dead_codes = Vec :: new ( ) ;
1151- // if we have diagnosed the trait, do not diagnose unused assoc items
1209+ // only diagnose unused assoc items for inherient impl and used trait
1210+ // for unused assoc items in impls of trait,
1211+ // we have diagnosed them in the trait if they are unused,
1212+ // for unused assoc items in unused trait,
1213+ // we have diagnosed the unused trait
11521214 if matches ! ( def_kind, DefKind :: Impl { of_trait: false } )
11531215 || ( def_kind == DefKind :: Trait && live_symbols. contains ( & item. owner_id . def_id ) )
11541216 {
0 commit comments