44// is dead.
55
66use hir:: def_id:: { LocalDefIdMap , LocalDefIdSet } ;
7- use hir:: AssocItemKind ;
7+ use hir:: ItemKind ;
88use itertools:: Itertools ;
99use rustc_data_structures:: unord:: UnordSet ;
1010use rustc_errors:: MultiSpan ;
@@ -16,7 +16,7 @@ use rustc_hir::{Node, PatKind, TyKind};
1616use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
1717use rustc_middle:: middle:: privacy:: Level ;
1818use rustc_middle:: query:: Providers ;
19- use rustc_middle:: ty:: { self , TyCtxt } ;
19+ use rustc_middle:: ty:: { self , TyCtxt , Visibility } ;
2020use rustc_session:: lint;
2121use rustc_span:: symbol:: { sym, Symbol } ;
2222use rustc_target:: abi:: FieldIdx ;
@@ -377,20 +377,46 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
377377 intravisit:: walk_item ( self , item)
378378 }
379379 hir:: ItemKind :: ForeignMod { .. } => { }
380+ hir:: ItemKind :: Trait ( ..) => {
381+ for impl_def_id in self . tcx . all_impls ( item. owner_id . to_def_id ( ) ) {
382+ if let Some ( local_def_id) = impl_def_id. as_local ( )
383+ && let ItemKind :: Impl ( impl_ref) =
384+ self . tcx . hir ( ) . expect_item ( local_def_id) . kind
385+ {
386+ // skip items
387+ // mark dependent traits live
388+ intravisit:: walk_generics ( self , impl_ref. generics ) ;
389+ // mark dependent parameters live
390+ intravisit:: walk_path ( self , impl_ref. of_trait . unwrap ( ) . path ) ;
391+ }
392+ }
393+
394+ intravisit:: walk_item ( self , item)
395+ }
380396 _ => intravisit:: walk_item ( self , item) ,
381397 } ,
382398 Node :: TraitItem ( trait_item) => {
383- // FIXME: could we get all impl terms for the trait item?
384- // then we can add them into worklist when the trait item is live,
385- // so that we won't lose any lost chain in the impl terms.
386- // this also allows us to lint such code:
387- // ```rust
388- // struct UnusedStruct; //~ WARN
389- // trait UnusedTrait { //~ WARN
390- // fn foo() {}
391- // }
392- // impl UnusedTrait for UnusedStruct { fn foo() {} }
393- // ```
399+ // mark corresponing ImplTerm live
400+ let def_id = trait_item. owner_id . to_def_id ( ) ;
401+ if let Some ( trait_def_id) = self . tcx . trait_of_item ( def_id) {
402+ // mark the trait live
403+ self . check_def_id ( trait_def_id) ;
404+
405+ for impl_def in self . tcx . all_impls ( trait_def_id) {
406+ if let Some ( impl_def_id) = impl_def. as_local ( )
407+ && let ItemKind :: Impl ( impl_ref) =
408+ self . tcx . hir ( ) . expect_item ( impl_def_id) . kind
409+ {
410+ // mark self_ty live
411+ intravisit:: walk_ty ( self , impl_ref. self_ty ) ;
412+ for impl_item in impl_ref. items {
413+ if Some ( def_id) == impl_item. trait_item_def_id {
414+ self . check_def_id ( impl_item. id . owner_id . to_def_id ( ) ) ;
415+ }
416+ }
417+ }
418+ }
419+ }
394420 intravisit:: walk_trait_item ( self , trait_item) ;
395421 }
396422 Node :: ImplItem ( impl_item) => {
@@ -639,23 +665,6 @@ fn check_item<'tcx>(
639665 }
640666 }
641667 DefKind :: Impl { of_trait } => {
642- // lints unused struct and traits after 2024, e.g.,
643- // ```rust
644- // #[derive(Debug)]
645- // struct Unused; //~ WARN
646- //
647- // trait Foo {} //~ WARN
648- // impl Foo for () {}
649- // ```
650- // but we still cannot lint unused traits whose impl blocks have methods:
651- // ```rust
652- // trait Foo { fn foo(); }
653- // impl Foo for () { fn foo() {} }
654- // ```
655- if of_trait && !tcx. hir ( ) . item ( id) . span . source_callsite ( ) . at_least_rust_2024 ( ) {
656- worklist. push ( ( id. owner_id . def_id , ComesFromAllowExpect :: No ) ) ;
657- }
658-
659668 // get DefIds from another query
660669 let local_def_ids = tcx
661670 . associated_item_def_ids ( id. owner_id )
@@ -664,9 +673,10 @@ fn check_item<'tcx>(
664673
665674 // And we access the Map here to get HirId from LocalDefId
666675 for id in local_def_ids {
667- if of_trait {
668- // FIXME: not push impl item into worklist by default,
669- // pushed when corresponding trait items are reachable.
676+ if of_trait
677+ && ( !matches ! ( tcx. def_kind( id) , DefKind :: AssocFn )
678+ || tcx. local_visibility ( id) == Visibility :: Public )
679+ {
670680 worklist. push ( ( id, ComesFromAllowExpect :: No ) ) ;
671681 } else if let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, id) {
672682 worklist. push ( ( id, comes_from_allow) ) ;
@@ -697,7 +707,7 @@ fn check_trait_item(
697707 use hir:: TraitItemKind :: { Const , Fn } ;
698708 if matches ! ( tcx. def_kind( id. owner_id) , DefKind :: AssocConst | DefKind :: AssocFn ) {
699709 let trait_item = tcx. hir ( ) . trait_item ( id) ;
700- if matches ! ( trait_item. kind, Const ( _, Some ( _) ) | Fn ( _ , hir :: TraitFn :: Provided ( _ ) ) )
710+ if matches ! ( trait_item. kind, Const ( _, Some ( _) ) | Fn ( .. ) )
701711 && let Some ( comes_from_allow) =
702712 has_allow_dead_code_or_lang_attr ( tcx, trait_item. owner_id . def_id )
703713 {
@@ -965,14 +975,8 @@ impl<'tcx> DeadVisitor<'tcx> {
965975 | DefKind :: TyAlias
966976 | DefKind :: Enum
967977 | DefKind :: Union
968- | DefKind :: ForeignTy => self . warn_dead_code ( def_id, "used" ) ,
969- DefKind :: Trait => {
970- if let Some ( Node :: Item ( item) ) = self . tcx . hir ( ) . find_by_def_id ( def_id)
971- && item. span . at_least_rust_2024 ( )
972- {
973- self . warn_dead_code ( def_id, "used" )
974- }
975- }
978+ | DefKind :: ForeignTy
979+ | DefKind :: Trait => self . warn_dead_code ( def_id, "used" ) ,
976980 DefKind :: Struct => self . warn_dead_code ( def_id, "constructed" ) ,
977981 DefKind :: Variant | DefKind :: Field => bug ! ( "should be handled specially" ) ,
978982 _ => { }
@@ -1001,24 +1005,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
10011005 let mut dead_items = Vec :: new ( ) ;
10021006 for item in impl_item. items {
10031007 let def_id = item. id . owner_id . def_id ;
1004- let is_dead_code = if !visitor. is_live_code ( def_id) {
1005- true
1006- } else if item. span . edition ( ) . at_least_rust_2024 ( ) // temporary
1007- && let AssocItemKind :: Fn { .. } = item. kind
1008- && let Some ( local_def_id) = item. trait_item_def_id . and_then ( DefId :: as_local)
1009- && !visitor. is_live_code ( local_def_id)
1010- && has_allow_dead_code_or_lang_attr ( tcx, local_def_id) . is_none ( )
1011- {
1012- // lint methods in impl if we are sure the corresponding methods in trait are dead,
1013- // but the chain of dead code within the methods in impl would be lost.
1014-
1015- // FIXME: the better way is to mark trait items and corresponding impl items active,
1016- // then the rests are dead, which requires the above FIXME at line 383
1017- true
1018- } else {
1019- false
1020- } ;
1021- if is_dead_code {
1008+ if !visitor. is_live_code ( def_id) {
10221009 let name = tcx. item_name ( def_id. to_def_id ( ) ) ;
10231010 let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def_id) ;
10241011 let level = tcx. lint_level_at_node ( lint:: builtin:: DEAD_CODE , hir_id) . 0 ;
@@ -1093,9 +1080,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
10931080 }
10941081
10951082 for trait_item in module_items. trait_items ( ) {
1096- if tcx. hir ( ) . trait_item ( trait_item) . span . at_least_rust_2024 ( ) {
1097- visitor. check_definition ( trait_item. owner_id . def_id ) ;
1098- }
1083+ visitor. check_definition ( trait_item. owner_id . def_id ) ;
10991084 }
11001085}
11011086
0 commit comments