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,42 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
377
377
intravisit:: walk_item ( self , item)
378
378
}
379
379
hir:: ItemKind :: ForeignMod { .. } => { }
380
+ hir:: ItemKind :: Trait ( ..) => {
381
+ // mark dependent traits live
382
+ for impl_def_id in self . tcx . all_impls ( item. owner_id . to_def_id ( ) ) {
383
+ if let Some ( local_def_id) = impl_def_id. as_local ( )
384
+ && let ItemKind :: Impl ( impl_ref) =
385
+ self . tcx . hir ( ) . expect_item ( local_def_id) . kind
386
+ {
387
+ intravisit:: walk_generics ( self , impl_ref. generics ) ;
388
+ }
389
+ }
390
+
391
+ intravisit:: walk_item ( self , item)
392
+ }
380
393
_ => intravisit:: walk_item ( self , item) ,
381
394
} ,
382
395
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
- // ```
396
+ // mark corresponing ImplTerm live
397
+ let def_id = trait_item. owner_id . to_def_id ( ) ;
398
+ if let Some ( trait_def_id) = self . tcx . trait_of_item ( def_id) {
399
+ // for assoc fn without self, mark the trait live
400
+ self . check_def_id ( trait_def_id) ;
401
+
402
+ for impl_def in self . tcx . all_impls ( trait_def_id) {
403
+ if let Some ( impl_def_id) = impl_def. as_local ( )
404
+ && let ItemKind :: Impl ( impl_ref) =
405
+ self . tcx . hir ( ) . expect_item ( impl_def_id) . kind
406
+ {
407
+ self . check_def_id ( impl_def) ;
408
+ for impl_item in impl_ref. items {
409
+ if Some ( def_id) == impl_item. trait_item_def_id {
410
+ self . check_def_id ( impl_item. id . owner_id . to_def_id ( ) ) ;
411
+ }
412
+ }
413
+ }
414
+ }
415
+ }
394
416
intravisit:: walk_trait_item ( self , trait_item) ;
395
417
}
396
418
Node :: ImplItem ( impl_item) => {
@@ -639,23 +661,6 @@ fn check_item<'tcx>(
639
661
}
640
662
}
641
663
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
664
// get DefIds from another query
660
665
let local_def_ids = tcx
661
666
. associated_item_def_ids ( id. owner_id )
@@ -664,9 +669,9 @@ fn check_item<'tcx>(
664
669
665
670
// And we access the Map here to get HirId from LocalDefId
666
671
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.
672
+ if tcx . local_visibility ( id ) == Visibility :: Public
673
+ || of_trait && ! matches ! ( tcx . def_kind ( id ) , DefKind :: AssocFn )
674
+ {
670
675
worklist. push ( ( id, ComesFromAllowExpect :: No ) ) ;
671
676
} else if let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, id) {
672
677
worklist. push ( ( id, comes_from_allow) ) ;
@@ -697,7 +702,7 @@ fn check_trait_item(
697
702
use hir:: TraitItemKind :: { Const , Fn } ;
698
703
if matches ! ( tcx. def_kind( id. owner_id) , DefKind :: AssocConst | DefKind :: AssocFn ) {
699
704
let trait_item = tcx. hir ( ) . trait_item ( id) ;
700
- if matches ! ( trait_item. kind, Const ( _, Some ( _) ) | Fn ( _ , hir :: TraitFn :: Provided ( _ ) ) )
705
+ if matches ! ( trait_item. kind, Const ( _, Some ( _) ) | Fn ( .. ) )
701
706
&& let Some ( comes_from_allow) =
702
707
has_allow_dead_code_or_lang_attr ( tcx, trait_item. owner_id . def_id )
703
708
{
@@ -965,14 +970,8 @@ impl<'tcx> DeadVisitor<'tcx> {
965
970
| DefKind :: TyAlias
966
971
| DefKind :: Enum
967
972
| 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
- }
973
+ | DefKind :: ForeignTy
974
+ | DefKind :: Trait => self . warn_dead_code ( def_id, "used" ) ,
976
975
DefKind :: Struct => self . warn_dead_code ( def_id, "constructed" ) ,
977
976
DefKind :: Variant | DefKind :: Field => bug ! ( "should be handled specially" ) ,
978
977
_ => { }
@@ -1001,24 +1000,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
1001
1000
let mut dead_items = Vec :: new ( ) ;
1002
1001
for item in impl_item. items {
1003
1002
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 {
1003
+ if !visitor. is_live_code ( def_id) {
1022
1004
let name = tcx. item_name ( def_id. to_def_id ( ) ) ;
1023
1005
let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def_id) ;
1024
1006
let level = tcx. lint_level_at_node ( lint:: builtin:: DEAD_CODE , hir_id) . 0 ;
@@ -1093,9 +1075,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
1093
1075
}
1094
1076
1095
1077
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
- }
1078
+ visitor. check_definition ( trait_item. owner_id . def_id ) ;
1099
1079
}
1100
1080
}
1101
1081
0 commit comments