4
4
// is dead.
5
5
6
6
use hir:: def_id:: { LocalDefIdMap , LocalDefIdSet } ;
7
- use hir:: AssocItemKind ;
7
+ use hir:: ItemKind ;
8
8
use itertools:: Itertools ;
9
9
use rustc_data_structures:: unord:: UnordSet ;
10
10
use rustc_errors:: MultiSpan ;
@@ -16,7 +16,7 @@ use rustc_hir::{Node, PatKind, TyKind};
16
16
use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
17
17
use rustc_middle:: middle:: privacy:: Level ;
18
18
use rustc_middle:: query:: Providers ;
19
- use rustc_middle:: ty:: { self , TyCtxt } ;
19
+ use rustc_middle:: ty:: { self , TyCtxt , Visibility } ;
20
20
use rustc_session:: lint;
21
21
use rustc_span:: symbol:: { sym, Symbol } ;
22
22
use rustc_target:: abi:: FieldIdx ;
@@ -377,20 +377,46 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
377
377
intravisit:: walk_item ( self , item)
378
378
}
379
379
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
+ }
380
396
_ => intravisit:: walk_item ( self , item) ,
381
397
} ,
382
398
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
+ }
394
420
intravisit:: walk_trait_item ( self , trait_item) ;
395
421
}
396
422
Node :: ImplItem ( impl_item) => {
@@ -639,23 +665,6 @@ fn check_item<'tcx>(
639
665
}
640
666
}
641
667
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
-
659
668
// get DefIds from another query
660
669
let local_def_ids = tcx
661
670
. associated_item_def_ids ( id. owner_id )
@@ -664,9 +673,10 @@ fn check_item<'tcx>(
664
673
665
674
// And we access the Map here to get HirId from LocalDefId
666
675
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
+ {
670
680
worklist. push ( ( id, ComesFromAllowExpect :: No ) ) ;
671
681
} else if let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, id) {
672
682
worklist. push ( ( id, comes_from_allow) ) ;
@@ -697,7 +707,7 @@ fn check_trait_item(
697
707
use hir:: TraitItemKind :: { Const , Fn } ;
698
708
if matches ! ( tcx. def_kind( id. owner_id) , DefKind :: AssocConst | DefKind :: AssocFn ) {
699
709
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 ( .. ) )
701
711
&& let Some ( comes_from_allow) =
702
712
has_allow_dead_code_or_lang_attr ( tcx, trait_item. owner_id . def_id )
703
713
{
@@ -965,14 +975,8 @@ impl<'tcx> DeadVisitor<'tcx> {
965
975
| DefKind :: TyAlias
966
976
| DefKind :: Enum
967
977
| 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" ) ,
976
980
DefKind :: Struct => self . warn_dead_code ( def_id, "constructed" ) ,
977
981
DefKind :: Variant | DefKind :: Field => bug ! ( "should be handled specially" ) ,
978
982
_ => { }
@@ -1001,24 +1005,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
1001
1005
let mut dead_items = Vec :: new ( ) ;
1002
1006
for item in impl_item. items {
1003
1007
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) {
1022
1009
let name = tcx. item_name ( def_id. to_def_id ( ) ) ;
1023
1010
let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def_id) ;
1024
1011
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) {
1093
1080
}
1094
1081
1095
1082
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 ) ;
1099
1084
}
1100
1085
}
1101
1086
0 commit comments