@@ -43,7 +43,9 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
43
43
)
44
44
}
45
45
46
- fn adt_of < ' tcx > ( ty : & hir:: Ty < ' tcx > ) -> Option < ( LocalDefId , DefKind ) > {
46
+ /// Returns the local def id and def kind of the adt,
47
+ /// if the given ty refers to one local adt definition
48
+ fn adt_def_of_ty < ' tcx > ( ty : & hir:: Ty < ' tcx > ) -> Option < ( LocalDefId , DefKind ) > {
47
49
match ty. kind {
48
50
TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) => {
49
51
if let Res :: Def ( def_kind, def_id) = path. res
@@ -54,8 +56,8 @@ fn adt_of<'tcx>(ty: &hir::Ty<'tcx>) -> Option<(LocalDefId, DefKind)> {
54
56
None
55
57
}
56
58
}
57
- TyKind :: Slice ( ty) | TyKind :: Array ( ty, _) => adt_of ( ty) ,
58
- TyKind :: Ptr ( ty) | TyKind :: Ref ( _, ty) => adt_of ( ty. ty ) ,
59
+ TyKind :: Slice ( ty) | TyKind :: Array ( ty, _) => adt_def_of_ty ( ty) ,
60
+ TyKind :: Ptr ( ty) | TyKind :: Ref ( _, ty) => adt_def_of_ty ( ty. ty ) ,
59
61
_ => None ,
60
62
}
61
63
}
@@ -236,6 +238,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
236
238
) {
237
239
let variant = match self . typeck_results ( ) . node_type ( lhs. hir_id ) . kind ( ) {
238
240
ty:: Adt ( adt, _) => {
241
+ // mark the adt live if its variant appears as the pattern
239
242
self . check_def_id ( adt. did ( ) ) ;
240
243
adt. variant_of_res ( res)
241
244
}
@@ -259,6 +262,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
259
262
) {
260
263
let variant = match self . typeck_results ( ) . node_type ( lhs. hir_id ) . kind ( ) {
261
264
ty:: Adt ( adt, _) => {
265
+ // mark the adt live if its variant appears as the pattern
262
266
self . check_def_id ( adt. did ( ) ) ;
263
267
adt. variant_of_res ( res)
264
268
}
@@ -494,25 +498,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
494
498
}
495
499
}
496
500
497
- fn solve_rest_items ( & mut self , mut unsolved_items : Vec < ( hir:: ItemId , LocalDefId ) > ) {
498
- let mut ready;
499
- ( ready, unsolved_items) =
500
- unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
501
- self . item_should_be_checked ( impl_id, local_def_id)
502
- } ) ;
503
-
504
- while !ready. is_empty ( ) {
505
- self . worklist =
506
- ready. into_iter ( ) . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) ) . collect ( ) ;
507
- self . mark_live_symbols ( ) ;
508
-
509
- ( ready, unsolved_items) =
510
- unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
511
- self . item_should_be_checked ( impl_id, local_def_id)
512
- } ) ;
513
- }
514
- }
515
-
501
+ /// Returns an impl or impl item should be checked or not
502
+ /// `impl_id` is the `ItemId` of the impl or the impl item belongs to,
503
+ /// `local_def_id` may point to the impl or the impl item,
504
+ /// both impl and impl item that may pass to this function are of trait,
505
+ /// and added into the unsolved_items during `create_and_seed_worklist`
516
506
fn item_should_be_checked ( & mut self , impl_id : hir:: ItemId , local_def_id : LocalDefId ) -> bool {
517
507
let trait_def_id = match self . tcx . def_kind ( local_def_id) {
518
508
// for assoc impl items of traits, we concern the corresponding trait items are used or not
@@ -529,20 +519,28 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
529
519
_ => None ,
530
520
} ;
531
521
532
- if !trait_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true ) {
522
+ if let Some ( def_id) = trait_def_id
523
+ && !self . live_symbols . contains ( & def_id)
524
+ {
533
525
return false ;
534
526
}
535
527
536
528
// we only check the ty is used or not for ADTs defined locally
537
- let ty_def_id = adt_of ( self . tcx . hir ( ) . item ( impl_id) . expect_impl ( ) . self_ty ) . and_then (
529
+ let ty_def_id = adt_def_of_ty ( self . tcx . hir ( ) . item ( impl_id) . expect_impl ( ) . self_ty ) . and_then (
538
530
|( local_def_id, def_kind) | {
539
531
matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
540
532
. then_some ( local_def_id)
541
533
} ,
542
534
) ;
543
535
544
536
// the impl/impl item is used if the trait/trait item is used and the ty is used
545
- ty_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true )
537
+ if let Some ( def_id) = ty_def_id
538
+ && !self . live_symbols . contains ( & def_id)
539
+ {
540
+ return false ;
541
+ }
542
+
543
+ true
546
544
}
547
545
548
546
fn visit_middle_ty ( & mut self , ty : Ty < ' tcx > ) {
@@ -848,7 +846,7 @@ fn check_item<'tcx>(
848
846
}
849
847
DefKind :: Impl { of_trait } => {
850
848
// get DefIds from another query
851
- let local_def_ids = tcx
849
+ let associated_item_def_ids = tcx
852
850
. associated_item_def_ids ( id. owner_id )
853
851
. iter ( )
854
852
. filter_map ( |def_id| def_id. as_local ( ) ) ;
@@ -862,11 +860,16 @@ fn check_item<'tcx>(
862
860
}
863
861
864
862
// And we access the Map here to get HirId from LocalDefId
865
- for local_def_id in local_def_ids {
863
+ for local_def_id in associated_item_def_ids {
866
864
if let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
867
865
{
868
866
worklist. push ( ( local_def_id, comes_from_allow) ) ;
869
867
} else if of_trait {
868
+ // we only care about assoc items of trait,
869
+ // because they cannot be visited directly
870
+ // so we mark them based on the trait/trait item
871
+ // and self ty are checked first and both live,
872
+ // but inherent assoc items can be visited and marked directly
870
873
unsolved_items. push ( ( id, local_def_id) ) ;
871
874
}
872
875
}
@@ -977,7 +980,7 @@ fn live_symbols_and_ignored_derived_traits(
977
980
tcx : TyCtxt < ' _ > ,
978
981
( ) : ( ) ,
979
982
) -> ( LocalDefIdSet , LocalDefIdMap < Vec < ( DefId , DefId ) > > ) {
980
- let ( worklist, struct_constructors, unsolved_items) = create_and_seed_worklist ( tcx) ;
983
+ let ( worklist, struct_constructors, mut unsolved_items) = create_and_seed_worklist ( tcx) ;
981
984
let mut symbol_visitor = MarkSymbolVisitor {
982
985
worklist,
983
986
tcx,
@@ -990,8 +993,26 @@ fn live_symbols_and_ignored_derived_traits(
990
993
struct_constructors,
991
994
ignored_derived_traits : Default :: default ( ) ,
992
995
} ;
996
+
993
997
symbol_visitor. mark_live_symbols ( ) ;
994
- symbol_visitor. solve_rest_items ( unsolved_items) ;
998
+ let mut rest_items_should_be_checked;
999
+ ( rest_items_should_be_checked, unsolved_items) =
1000
+ unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
1001
+ symbol_visitor. item_should_be_checked ( impl_id, local_def_id)
1002
+ } ) ;
1003
+
1004
+ while !rest_items_should_be_checked. is_empty ( ) {
1005
+ symbol_visitor. worklist = rest_items_should_be_checked
1006
+ . into_iter ( )
1007
+ . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) )
1008
+ . collect ( ) ;
1009
+ symbol_visitor. mark_live_symbols ( ) ;
1010
+
1011
+ ( rest_items_should_be_checked, unsolved_items) =
1012
+ unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
1013
+ symbol_visitor. item_should_be_checked ( impl_id, local_def_id)
1014
+ } ) ;
1015
+ }
995
1016
996
1017
( symbol_visitor. live_symbols , symbol_visitor. ignored_derived_traits )
997
1018
}
@@ -1268,7 +1289,11 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
1268
1289
let def_kind = tcx. def_kind ( item. owner_id ) ;
1269
1290
1270
1291
let mut dead_codes = Vec :: new ( ) ;
1271
- // if we have diagnosed the trait, do not diagnose unused assoc items
1292
+ // only diagnose unused assoc items for inherient impl and used trait
1293
+ // for unused assoc items in impls of trait,
1294
+ // we have diagnosed them in the trait if they are unused,
1295
+ // for unused assoc items in unused trait,
1296
+ // we have diagnosed the unused trait
1272
1297
if matches ! ( def_kind, DefKind :: Impl { of_trait: false } )
1273
1298
|| ( def_kind == DefKind :: Trait && live_symbols. contains ( & item. owner_id . def_id ) )
1274
1299
{
0 commit comments