@@ -18,7 +18,7 @@ use rustc_hir::{Node, PatKind, TyKind};
18
18
use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
19
19
use rustc_middle:: middle:: privacy:: Level ;
20
20
use rustc_middle:: query:: Providers ;
21
- use rustc_middle:: ty:: { self , TyCtxt } ;
21
+ use rustc_middle:: ty:: { self , AssocItemContainer , Ty , TyCtxt } ;
22
22
use rustc_middle:: { bug, span_bug} ;
23
23
use rustc_session:: lint;
24
24
use rustc_session:: lint:: builtin:: DEAD_CODE ;
@@ -45,15 +45,18 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
45
45
)
46
46
}
47
47
48
- fn ty_ref_to_pub_struct ( tcx : TyCtxt < ' _ > , ty : & hir:: Ty < ' _ > ) -> bool {
49
- if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) = ty. kind
50
- && let Res :: Def ( def_kind, def_id) = path. res
51
- && def_id. is_local ( )
52
- && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
53
- {
54
- tcx. visibility ( def_id) . is_public ( )
55
- } else {
56
- true
48
+ fn adt_of < ' tcx > ( ty : & hir:: Ty < ' tcx > ) -> Option < ( LocalDefId , DefKind ) > {
49
+ match ty. kind {
50
+ TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) => {
51
+ if let Res :: Def ( def_kind, def_id) = path. res
52
+ && let Some ( local_def_id) = def_id. as_local ( )
53
+ {
54
+ Some ( ( local_def_id, def_kind) )
55
+ } else {
56
+ None
57
+ }
58
+ }
59
+ _ => None ,
57
60
}
58
61
}
59
62
@@ -421,22 +424,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
421
424
intravisit:: walk_item ( self , item)
422
425
}
423
426
hir:: ItemKind :: ForeignMod { .. } => { }
424
- hir:: ItemKind :: Trait ( ..) => {
425
- for impl_def_id in self . tcx . all_impls ( item. owner_id . to_def_id ( ) ) {
426
- if let Some ( local_def_id) = impl_def_id. as_local ( )
427
- && let ItemKind :: Impl ( impl_ref) =
428
- self . tcx . hir ( ) . expect_item ( local_def_id) . kind
429
- {
430
- // skip items
431
- // mark dependent traits live
432
- intravisit:: walk_generics ( self , impl_ref. generics ) ;
433
- // mark dependent parameters live
434
- intravisit:: walk_path ( self , impl_ref. of_trait . unwrap ( ) . path ) ;
435
- }
436
- }
437
-
438
- intravisit:: walk_item ( self , item)
439
- }
440
427
_ => intravisit:: walk_item ( self , item) ,
441
428
} ,
442
429
Node :: TraitItem ( trait_item) => {
@@ -445,30 +432,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
445
432
if let Some ( trait_id) = self . tcx . trait_of_item ( trait_item_id) {
446
433
// mark the trait live
447
434
self . check_def_id ( trait_id) ;
448
-
449
- for impl_id in self . tcx . all_impls ( trait_id) {
450
- if let Some ( local_impl_id) = impl_id. as_local ( )
451
- && let ItemKind :: Impl ( impl_ref) =
452
- self . tcx . hir ( ) . expect_item ( local_impl_id) . kind
453
- {
454
- if !matches ! ( trait_item. kind, hir:: TraitItemKind :: Type ( ..) )
455
- && !ty_ref_to_pub_struct ( self . tcx , impl_ref. self_ty )
456
- {
457
- // skip methods of private ty,
458
- // they would be solved in `solve_rest_impl_items`
459
- continue ;
460
- }
461
-
462
- // mark self_ty live
463
- intravisit:: walk_ty ( self , impl_ref. self_ty ) ;
464
- if let Some ( & impl_item_id) =
465
- self . tcx . impl_item_implementor_ids ( impl_id) . get ( & trait_item_id)
466
- {
467
- self . check_def_id ( impl_item_id) ;
468
- }
469
- }
470
- }
471
435
}
436
+
472
437
intravisit:: walk_trait_item ( self , trait_item) ;
473
438
}
474
439
Node :: ImplItem ( impl_item) => {
@@ -511,48 +476,55 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
511
476
}
512
477
}
513
478
514
- fn solve_rest_impl_items ( & mut self , mut unsolved_impl_items : Vec < ( hir:: ItemId , LocalDefId ) > ) {
479
+ fn solve_rest_items ( & mut self , mut unsolved_items : Vec < ( hir:: ItemId , LocalDefId ) > ) {
515
480
let mut ready;
516
- ( ready, unsolved_impl_items ) =
517
- unsolved_impl_items . into_iter ( ) . partition ( |& ( impl_id, impl_item_id ) | {
518
- self . impl_item_with_used_self ( impl_id, impl_item_id )
481
+ ( ready, unsolved_items ) =
482
+ unsolved_items . into_iter ( ) . partition ( |& ( impl_id, local_def_id ) | {
483
+ self . item_should_be_checked ( impl_id, local_def_id )
519
484
} ) ;
520
485
521
486
while !ready. is_empty ( ) {
522
487
self . worklist =
523
488
ready. into_iter ( ) . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) ) . collect ( ) ;
524
489
self . mark_live_symbols ( ) ;
525
490
526
- ( ready, unsolved_impl_items ) =
527
- unsolved_impl_items . into_iter ( ) . partition ( |& ( impl_id, impl_item_id ) | {
528
- self . impl_item_with_used_self ( impl_id, impl_item_id )
491
+ ( ready, unsolved_items ) =
492
+ unsolved_items . into_iter ( ) . partition ( |& ( impl_id, local_def_id ) | {
493
+ self . item_should_be_checked ( impl_id, local_def_id )
529
494
} ) ;
530
495
}
531
496
}
532
497
533
- fn impl_item_with_used_self ( & mut self , impl_id : hir:: ItemId , impl_item_id : LocalDefId ) -> bool {
534
- if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) =
535
- self . tcx . hir ( ) . item ( impl_id) . expect_impl ( ) . self_ty . kind
536
- && let Res :: Def ( def_kind, def_id) = path. res
537
- && let Some ( local_def_id) = def_id. as_local ( )
538
- && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
539
- {
540
- if self . tcx . visibility ( impl_item_id) . is_public ( ) {
541
- // for the public method, we don't know the trait item is used or not,
542
- // so we mark the method live if the self is used
543
- return self . live_symbols . contains ( & local_def_id) ;
544
- }
498
+ fn item_should_be_checked ( & mut self , impl_id : hir:: ItemId , local_def_id : LocalDefId ) -> bool {
499
+ let trait_def_id = match self . tcx . def_kind ( local_def_id) {
500
+ // for assoc impl items of traits, we concern the corresponding trait items are used or not
501
+ DefKind :: AssocFn => self
502
+ . tcx
503
+ . associated_item ( local_def_id)
504
+ . trait_item_def_id
505
+ . and_then ( |def_id| def_id. as_local ( ) ) ,
506
+ // for impl items, we concern the corresonding traits are used or not
507
+ DefKind :: Impl { of_trait : true } => self
508
+ . tcx
509
+ . impl_trait_ref ( impl_id. owner_id . def_id )
510
+ . and_then ( |trait_ref| trait_ref. skip_binder ( ) . def_id . as_local ( ) ) ,
511
+ _ => None ,
512
+ } ;
545
513
546
- if let Some ( trait_item_id) = self . tcx . associated_item ( impl_item_id) . trait_item_def_id
547
- && let Some ( local_id) = trait_item_id. as_local ( )
548
- {
549
- // for the private method, we can know the trait item is used or not,
550
- // so we mark the method live if the self is used and the trait item is used
551
- return self . live_symbols . contains ( & local_id)
552
- && self . live_symbols . contains ( & local_def_id) ;
553
- }
514
+ if !trait_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true ) {
515
+ return false ;
554
516
}
555
- false
517
+
518
+ // we only check the ty is used or not for ADTs defined locally
519
+ let ty_def_id = adt_of ( self . tcx . hir ( ) . item ( impl_id) . expect_impl ( ) . self_ty ) . and_then (
520
+ |( local_def_id, def_kind) | {
521
+ matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
522
+ . then_some ( local_def_id)
523
+ } ,
524
+ ) ;
525
+
526
+ // the impl/impl item is used if the trait/trait item is used and the ty is used
527
+ ty_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true )
556
528
}
557
529
}
558
530
@@ -734,7 +706,7 @@ fn check_item<'tcx>(
734
706
tcx : TyCtxt < ' tcx > ,
735
707
worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
736
708
struct_constructors : & mut LocalDefIdMap < LocalDefId > ,
737
- unsolved_impl_items : & mut Vec < ( hir:: ItemId , LocalDefId ) > ,
709
+ unsolved_items : & mut Vec < ( hir:: ItemId , LocalDefId ) > ,
738
710
id : hir:: ItemId ,
739
711
) {
740
712
let allow_dead_code = has_allow_dead_code_or_lang_attr ( tcx, id. owner_id . def_id ) ;
@@ -766,35 +738,24 @@ fn check_item<'tcx>(
766
738
. iter ( )
767
739
. filter_map ( |def_id| def_id. as_local ( ) ) ;
768
740
769
- let ty_is_pub = ty_ref_to_pub_struct ( tcx, tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty ) ;
741
+ if let Some ( comes_from_allow) =
742
+ has_allow_dead_code_or_lang_attr ( tcx, id. owner_id . def_id )
743
+ {
744
+ worklist. push ( ( id. owner_id . def_id , comes_from_allow) ) ;
745
+ } else if of_trait {
746
+ unsolved_items. push ( ( id, id. owner_id . def_id ) ) ;
747
+ }
770
748
771
749
// And we access the Map here to get HirId from LocalDefId
772
750
for local_def_id in local_def_ids {
773
- // check the function may construct Self
774
- let mut may_construct_self = false ;
775
- if let Some ( fn_sig) =
776
- tcx. hir ( ) . fn_sig_by_hir_id ( tcx. local_def_id_to_hir_id ( local_def_id) )
777
- {
778
- may_construct_self =
779
- matches ! ( fn_sig. decl. implicit_self, hir:: ImplicitSelfKind :: None ) ;
780
- }
781
-
782
- // for trait impl blocks,
783
- // mark the method live if the self_ty is public,
784
- // or the method is public and may construct self
785
- if of_trait
786
- && ( !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn )
787
- || tcx. visibility ( local_def_id) . is_public ( )
788
- && ( ty_is_pub || may_construct_self) )
789
- {
751
+ if !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn ) {
790
752
worklist. push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
791
753
} else if let Some ( comes_from_allow) =
792
754
has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
793
755
{
794
756
worklist. push ( ( local_def_id, comes_from_allow) ) ;
795
757
} else if of_trait {
796
- // private method || public method not constructs self
797
- unsolved_impl_items. push ( ( id, local_def_id) ) ;
758
+ unsolved_items. push ( ( id, local_def_id) ) ;
798
759
}
799
760
}
800
761
}
@@ -860,6 +821,18 @@ fn create_and_seed_worklist(
860
821
effective_vis
861
822
. is_public_at_level ( Level :: Reachable )
862
823
. then_some ( id)
824
+ . filter ( |& id|
825
+ // checks impls and impl-items later
826
+ match tcx. def_kind ( id) {
827
+ DefKind :: Impl { of_trait } => !of_trait,
828
+ DefKind :: AssocFn => {
829
+ // still check public trait items, and impl items not of trait
830
+ let assoc_item = tcx. associated_item ( id) ;
831
+ !matches ! ( assoc_item. container, AssocItemContainer :: ImplContainer )
832
+ || assoc_item. trait_item_def_id . is_none ( )
833
+ } ,
834
+ _ => true
835
+ } )
863
836
. map ( |id| ( id, ComesFromAllowExpect :: No ) )
864
837
} )
865
838
// Seed entry point
@@ -889,7 +862,7 @@ fn live_symbols_and_ignored_derived_traits(
889
862
tcx : TyCtxt < ' _ > ,
890
863
( ) : ( ) ,
891
864
) -> ( LocalDefIdSet , LocalDefIdMap < Vec < ( DefId , DefId ) > > ) {
892
- let ( worklist, struct_constructors, unsolved_impl_items ) = create_and_seed_worklist ( tcx) ;
865
+ let ( worklist, struct_constructors, unsolved_items ) = create_and_seed_worklist ( tcx) ;
893
866
let mut symbol_visitor = MarkSymbolVisitor {
894
867
worklist,
895
868
tcx,
@@ -903,7 +876,7 @@ fn live_symbols_and_ignored_derived_traits(
903
876
ignored_derived_traits : Default :: default ( ) ,
904
877
} ;
905
878
symbol_visitor. mark_live_symbols ( ) ;
906
- symbol_visitor. solve_rest_impl_items ( unsolved_impl_items ) ;
879
+ symbol_visitor. solve_rest_items ( unsolved_items ) ;
907
880
908
881
( symbol_visitor. live_symbols , symbol_visitor. ignored_derived_traits )
909
882
}
@@ -1179,19 +1152,11 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
1179
1152
let def_kind = tcx. def_kind ( item. owner_id ) ;
1180
1153
1181
1154
let mut dead_codes = Vec :: new ( ) ;
1182
- // if we have diagnosed the trait, do not diagnose unused methods
1183
- if matches ! ( def_kind, DefKind :: Impl { .. } )
1155
+ // if we have diagnosed the trait, do not diagnose unused assoc items
1156
+ if matches ! ( def_kind, DefKind :: Impl { of_trait : false } )
1184
1157
|| ( def_kind == DefKind :: Trait && live_symbols. contains ( & item. owner_id . def_id ) )
1185
1158
{
1186
1159
for & def_id in tcx. associated_item_def_ids ( item. owner_id . def_id ) {
1187
- // We have diagnosed unused methods in traits
1188
- if matches ! ( def_kind, DefKind :: Impl { of_trait: true } )
1189
- && tcx. def_kind ( def_id) == DefKind :: AssocFn
1190
- || def_kind == DefKind :: Trait && tcx. def_kind ( def_id) != DefKind :: AssocFn
1191
- {
1192
- continue ;
1193
- }
1194
-
1195
1160
if let Some ( local_def_id) = def_id. as_local ( )
1196
1161
&& !visitor. is_live_code ( local_def_id)
1197
1162
{
0 commit comments