@@ -17,7 +17,7 @@ use rustc_hir::{self as hir, Node, PatKind, TyKind};
17
17
use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
18
18
use rustc_middle:: middle:: privacy:: Level ;
19
19
use rustc_middle:: query:: Providers ;
20
- use rustc_middle:: ty:: { self , TyCtxt } ;
20
+ use rustc_middle:: ty:: { self , AssocItemContainer , Ty , TyCtxt } ;
21
21
use rustc_middle:: { bug, span_bug} ;
22
22
use rustc_session:: lint;
23
23
use rustc_session:: lint:: builtin:: DEAD_CODE ;
@@ -44,15 +44,18 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
44
44
)
45
45
}
46
46
47
- fn ty_ref_to_pub_struct ( tcx : TyCtxt < ' _ > , ty : & hir:: Ty < ' _ > ) -> bool {
48
- if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) = ty. kind
49
- && let Res :: Def ( def_kind, def_id) = path. res
50
- && def_id. is_local ( )
51
- && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
52
- {
53
- tcx. visibility ( def_id) . is_public ( )
54
- } else {
55
- true
47
+ fn adt_of < ' tcx > ( ty : & hir:: Ty < ' tcx > ) -> Option < ( LocalDefId , DefKind ) > {
48
+ match ty. kind {
49
+ TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) => {
50
+ if let Res :: Def ( def_kind, def_id) = path. res
51
+ && let Some ( local_def_id) = def_id. as_local ( )
52
+ {
53
+ Some ( ( local_def_id, def_kind) )
54
+ } else {
55
+ None
56
+ }
57
+ }
58
+ _ => None ,
56
59
}
57
60
}
58
61
@@ -420,22 +423,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
420
423
intravisit:: walk_item ( self , item)
421
424
}
422
425
hir:: ItemKind :: ForeignMod { .. } => { }
423
- hir:: ItemKind :: Trait ( ..) => {
424
- for impl_def_id in self . tcx . all_impls ( item. owner_id . to_def_id ( ) ) {
425
- if let Some ( local_def_id) = impl_def_id. as_local ( )
426
- && let ItemKind :: Impl ( impl_ref) =
427
- self . tcx . hir ( ) . expect_item ( local_def_id) . kind
428
- {
429
- // skip items
430
- // mark dependent traits live
431
- intravisit:: walk_generics ( self , impl_ref. generics ) ;
432
- // mark dependent parameters live
433
- intravisit:: walk_path ( self , impl_ref. of_trait . unwrap ( ) . path ) ;
434
- }
435
- }
436
-
437
- intravisit:: walk_item ( self , item)
438
- }
439
426
_ => intravisit:: walk_item ( self , item) ,
440
427
} ,
441
428
Node :: TraitItem ( trait_item) => {
@@ -444,30 +431,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
444
431
if let Some ( trait_id) = self . tcx . trait_of_item ( trait_item_id) {
445
432
// mark the trait live
446
433
self . check_def_id ( trait_id) ;
447
-
448
- for impl_id in self . tcx . all_impls ( trait_id) {
449
- if let Some ( local_impl_id) = impl_id. as_local ( )
450
- && let ItemKind :: Impl ( impl_ref) =
451
- self . tcx . hir ( ) . expect_item ( local_impl_id) . kind
452
- {
453
- if !matches ! ( trait_item. kind, hir:: TraitItemKind :: Type ( ..) )
454
- && !ty_ref_to_pub_struct ( self . tcx , impl_ref. self_ty )
455
- {
456
- // skip methods of private ty,
457
- // they would be solved in `solve_rest_impl_items`
458
- continue ;
459
- }
460
-
461
- // mark self_ty live
462
- intravisit:: walk_unambig_ty ( self , impl_ref. self_ty ) ;
463
- if let Some ( & impl_item_id) =
464
- self . tcx . impl_item_implementor_ids ( impl_id) . get ( & trait_item_id)
465
- {
466
- self . check_def_id ( impl_item_id) ;
467
- }
468
- }
469
- }
470
434
}
435
+
471
436
intravisit:: walk_trait_item ( self , trait_item) ;
472
437
}
473
438
Node :: ImplItem ( impl_item) => {
@@ -510,48 +475,55 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
510
475
}
511
476
}
512
477
513
- fn solve_rest_impl_items ( & mut self , mut unsolved_impl_items : Vec < ( hir:: ItemId , LocalDefId ) > ) {
478
+ fn solve_rest_items ( & mut self , mut unsolved_items : Vec < ( hir:: ItemId , LocalDefId ) > ) {
514
479
let mut ready;
515
- ( ready, unsolved_impl_items ) =
516
- unsolved_impl_items . into_iter ( ) . partition ( |& ( impl_id, impl_item_id ) | {
517
- self . impl_item_with_used_self ( impl_id, impl_item_id )
480
+ ( ready, unsolved_items ) =
481
+ unsolved_items . into_iter ( ) . partition ( |& ( impl_id, local_def_id ) | {
482
+ self . item_should_be_checked ( impl_id, local_def_id )
518
483
} ) ;
519
484
520
485
while !ready. is_empty ( ) {
521
486
self . worklist =
522
487
ready. into_iter ( ) . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) ) . collect ( ) ;
523
488
self . mark_live_symbols ( ) ;
524
489
525
- ( ready, unsolved_impl_items ) =
526
- unsolved_impl_items . into_iter ( ) . partition ( |& ( impl_id, impl_item_id ) | {
527
- self . impl_item_with_used_self ( impl_id, impl_item_id )
490
+ ( ready, unsolved_items ) =
491
+ unsolved_items . into_iter ( ) . partition ( |& ( impl_id, local_def_id ) | {
492
+ self . item_should_be_checked ( impl_id, local_def_id )
528
493
} ) ;
529
494
}
530
495
}
531
496
532
- fn impl_item_with_used_self ( & mut self , impl_id : hir:: ItemId , impl_item_id : LocalDefId ) -> bool {
533
- if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) =
534
- self . tcx . hir_item ( impl_id) . expect_impl ( ) . self_ty . kind
535
- && let Res :: Def ( def_kind, def_id) = path. res
536
- && let Some ( local_def_id) = def_id. as_local ( )
537
- && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
538
- {
539
- if self . tcx . visibility ( impl_item_id) . is_public ( ) {
540
- // for the public method, we don't know the trait item is used or not,
541
- // so we mark the method live if the self is used
542
- return self . live_symbols . contains ( & local_def_id) ;
543
- }
497
+ fn item_should_be_checked ( & mut self , impl_id : hir:: ItemId , local_def_id : LocalDefId ) -> bool {
498
+ let trait_def_id = match self . tcx . def_kind ( local_def_id) {
499
+ // for assoc impl items of traits, we concern the corresponding trait items are used or not
500
+ DefKind :: AssocFn => self
501
+ . tcx
502
+ . associated_item ( local_def_id)
503
+ . trait_item_def_id
504
+ . and_then ( |def_id| def_id. as_local ( ) ) ,
505
+ // for impl items, we concern the corresonding traits are used or not
506
+ DefKind :: Impl { of_trait : true } => self
507
+ . tcx
508
+ . impl_trait_ref ( impl_id. owner_id . def_id )
509
+ . and_then ( |trait_ref| trait_ref. skip_binder ( ) . def_id . as_local ( ) ) ,
510
+ _ => None ,
511
+ } ;
544
512
545
- if let Some ( trait_item_id) = self . tcx . associated_item ( impl_item_id) . trait_item_def_id
546
- && let Some ( local_id) = trait_item_id. as_local ( )
547
- {
548
- // for the private method, we can know the trait item is used or not,
549
- // so we mark the method live if the self is used and the trait item is used
550
- return self . live_symbols . contains ( & local_id)
551
- && self . live_symbols . contains ( & local_def_id) ;
552
- }
513
+ if !trait_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true ) {
514
+ return false ;
553
515
}
554
- false
516
+
517
+ // we only check the ty is used or not for ADTs defined locally
518
+ let ty_def_id = adt_of ( self . tcx . hir_item ( impl_id) . expect_impl ( ) . self_ty ) . and_then (
519
+ |( local_def_id, def_kind) | {
520
+ matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
521
+ . then_some ( local_def_id)
522
+ } ,
523
+ ) ;
524
+
525
+ // the impl/impl item is used if the trait/trait item is used and the ty is used
526
+ ty_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true )
555
527
}
556
528
}
557
529
@@ -740,7 +712,7 @@ fn check_item<'tcx>(
740
712
tcx : TyCtxt < ' tcx > ,
741
713
worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
742
714
struct_constructors : & mut LocalDefIdMap < LocalDefId > ,
743
- unsolved_impl_items : & mut Vec < ( hir:: ItemId , LocalDefId ) > ,
715
+ unsolved_items : & mut Vec < ( hir:: ItemId , LocalDefId ) > ,
744
716
id : hir:: ItemId ,
745
717
) {
746
718
let allow_dead_code = has_allow_dead_code_or_lang_attr ( tcx, id. owner_id . def_id ) ;
@@ -772,35 +744,24 @@ fn check_item<'tcx>(
772
744
. iter ( )
773
745
. filter_map ( |def_id| def_id. as_local ( ) ) ;
774
746
775
- let ty_is_pub = ty_ref_to_pub_struct ( tcx, tcx. hir_item ( id) . expect_impl ( ) . self_ty ) ;
747
+ if let Some ( comes_from_allow) =
748
+ has_allow_dead_code_or_lang_attr ( tcx, id. owner_id . def_id )
749
+ {
750
+ worklist. push ( ( id. owner_id . def_id , comes_from_allow) ) ;
751
+ } else if of_trait {
752
+ unsolved_items. push ( ( id, id. owner_id . def_id ) ) ;
753
+ }
776
754
777
755
// And we access the Map here to get HirId from LocalDefId
778
756
for local_def_id in local_def_ids {
779
- // check the function may construct Self
780
- let mut may_construct_self = false ;
781
- if let Some ( fn_sig) =
782
- tcx. hir_fn_sig_by_hir_id ( tcx. local_def_id_to_hir_id ( local_def_id) )
783
- {
784
- may_construct_self =
785
- matches ! ( fn_sig. decl. implicit_self, hir:: ImplicitSelfKind :: None ) ;
786
- }
787
-
788
- // for trait impl blocks,
789
- // mark the method live if the self_ty is public,
790
- // or the method is public and may construct self
791
- if of_trait
792
- && ( !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn )
793
- || tcx. visibility ( local_def_id) . is_public ( )
794
- && ( ty_is_pub || may_construct_self) )
795
- {
757
+ if !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn ) {
796
758
worklist. push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
797
759
} else if let Some ( comes_from_allow) =
798
760
has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
799
761
{
800
762
worklist. push ( ( local_def_id, comes_from_allow) ) ;
801
763
} else if of_trait {
802
- // private method || public method not constructs self
803
- unsolved_impl_items. push ( ( id, local_def_id) ) ;
764
+ unsolved_items. push ( ( id, local_def_id) ) ;
804
765
}
805
766
}
806
767
}
@@ -866,6 +827,18 @@ fn create_and_seed_worklist(
866
827
effective_vis
867
828
. is_public_at_level ( Level :: Reachable )
868
829
. then_some ( id)
830
+ . filter ( |& id|
831
+ // checks impls and impl-items later
832
+ match tcx. def_kind ( id) {
833
+ DefKind :: Impl { of_trait } => !of_trait,
834
+ DefKind :: AssocFn => {
835
+ // still check public trait items, and impl items not of trait
836
+ let assoc_item = tcx. associated_item ( id) ;
837
+ !matches ! ( assoc_item. container, AssocItemContainer :: Impl )
838
+ || assoc_item. trait_item_def_id . is_none ( )
839
+ } ,
840
+ _ => true
841
+ } )
869
842
. map ( |id| ( id, ComesFromAllowExpect :: No ) )
870
843
} )
871
844
// Seed entry point
@@ -895,7 +868,7 @@ fn live_symbols_and_ignored_derived_traits(
895
868
tcx : TyCtxt < ' _ > ,
896
869
( ) : ( ) ,
897
870
) -> ( LocalDefIdSet , LocalDefIdMap < Vec < ( DefId , DefId ) > > ) {
898
- let ( worklist, struct_constructors, unsolved_impl_items ) = create_and_seed_worklist ( tcx) ;
871
+ let ( worklist, struct_constructors, unsolved_items ) = create_and_seed_worklist ( tcx) ;
899
872
let mut symbol_visitor = MarkSymbolVisitor {
900
873
worklist,
901
874
tcx,
@@ -909,7 +882,7 @@ fn live_symbols_and_ignored_derived_traits(
909
882
ignored_derived_traits : Default :: default ( ) ,
910
883
} ;
911
884
symbol_visitor. mark_live_symbols ( ) ;
912
- symbol_visitor. solve_rest_impl_items ( unsolved_impl_items ) ;
885
+ symbol_visitor. solve_rest_items ( unsolved_items ) ;
913
886
914
887
( symbol_visitor. live_symbols , symbol_visitor. ignored_derived_traits )
915
888
}
@@ -1188,19 +1161,11 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
1188
1161
let def_kind = tcx. def_kind ( item. owner_id ) ;
1189
1162
1190
1163
let mut dead_codes = Vec :: new ( ) ;
1191
- // if we have diagnosed the trait, do not diagnose unused methods
1192
- if matches ! ( def_kind, DefKind :: Impl { .. } )
1164
+ // if we have diagnosed the trait, do not diagnose unused assoc items
1165
+ if matches ! ( def_kind, DefKind :: Impl { of_trait : false } )
1193
1166
|| ( def_kind == DefKind :: Trait && live_symbols. contains ( & item. owner_id . def_id ) )
1194
1167
{
1195
1168
for & def_id in tcx. associated_item_def_ids ( item. owner_id . def_id ) {
1196
- // We have diagnosed unused methods in traits
1197
- if matches ! ( def_kind, DefKind :: Impl { of_trait: true } )
1198
- && tcx. def_kind ( def_id) == DefKind :: AssocFn
1199
- || def_kind == DefKind :: Trait && tcx. def_kind ( def_id) != DefKind :: AssocFn
1200
- {
1201
- continue ;
1202
- }
1203
-
1204
1169
if let Some ( local_def_id) = def_id. as_local ( )
1205
1170
&& !visitor. is_live_code ( local_def_id)
1206
1171
{
0 commit comments