44// is dead.
55
66use hir:: def_id:: { LocalDefIdMap , LocalDefIdSet } ;
7+ use hir:: AssocItemKind ;
78use itertools:: Itertools ;
89use rustc_data_structures:: unord:: UnordSet ;
910use rustc_errors:: MultiSpan ;
@@ -379,6 +380,17 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
379380 _ => intravisit:: walk_item ( self , item) ,
380381 } ,
381382 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+ // ```
382394 intravisit:: walk_trait_item ( self , trait_item) ;
383395 }
384396 Node :: ImplItem ( impl_item) => {
@@ -627,7 +639,20 @@ fn check_item<'tcx>(
627639 }
628640 }
629641 DefKind :: Impl { of_trait } => {
630- if 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 ( ) {
631656 worklist. push ( ( id. owner_id . def_id , ComesFromAllowExpect :: No ) ) ;
632657 }
633658
@@ -640,6 +665,8 @@ fn check_item<'tcx>(
640665 // And we access the Map here to get HirId from LocalDefId
641666 for id in local_def_ids {
642667 if of_trait {
668+ // FIXME: not push impl item into worklist by default,
669+ // pushed when corresponding trait items are reachable.
643670 worklist. push ( ( id, ComesFromAllowExpect :: No ) ) ;
644671 } else if let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, id) {
645672 worklist. push ( ( id, comes_from_allow) ) ;
@@ -939,6 +966,13 @@ impl<'tcx> DeadVisitor<'tcx> {
939966 | DefKind :: Enum
940967 | DefKind :: Union
941968 | 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+ }
942976 DefKind :: Struct => self . warn_dead_code ( def_id, "constructed" ) ,
943977 DefKind :: Variant | DefKind :: Field => bug ! ( "should be handled specially" ) ,
944978 _ => { }
@@ -967,7 +1001,24 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
9671001 let mut dead_items = Vec :: new ( ) ;
9681002 for item in impl_item. items {
9691003 let def_id = item. id . owner_id . def_id ;
970- if !visitor. is_live_code ( 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 {
9711022 let name = tcx. item_name ( def_id. to_def_id ( ) ) ;
9721023 let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def_id) ;
9731024 let level = tcx. lint_level_at_node ( lint:: builtin:: DEAD_CODE , hir_id) . 0 ;
@@ -1041,7 +1092,11 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
10411092 visitor. check_definition ( foreign_item. owner_id . def_id ) ;
10421093 }
10431094
1044- // We do not warn trait items.
1095+ 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+ }
1099+ }
10451100}
10461101
10471102pub ( crate ) fn provide ( providers : & mut Providers ) {
0 commit comments