@@ -8,12 +8,13 @@ use std::mem;
8
8
use hir:: ItemKind ;
9
9
use hir:: def_id:: { LocalDefIdMap , LocalDefIdSet } ;
10
10
use rustc_abi:: FieldIdx ;
11
+ use rustc_data_structures:: fx:: FxIndexSet ;
11
12
use rustc_data_structures:: unord:: UnordSet ;
12
13
use rustc_errors:: MultiSpan ;
13
14
use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
14
15
use rustc_hir:: def_id:: { DefId , LocalDefId , LocalModDefId } ;
15
16
use rustc_hir:: intravisit:: { self , Visitor } ;
16
- use rustc_hir:: { self as hir, Node , PatKind , TyKind } ;
17
+ use rustc_hir:: { self as hir, Node , PatKind , QPath , TyKind } ;
17
18
use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
18
19
use rustc_middle:: middle:: privacy:: Level ;
19
20
use rustc_middle:: query:: Providers ;
@@ -44,15 +45,20 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
44
45
)
45
46
}
46
47
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
48
+ /// Returns the local def id of the ADT if the given ty refers to a local one.
49
+ fn local_adt_def_of_ty < ' tcx > ( ty : & hir:: Ty < ' tcx > ) -> Option < LocalDefId > {
50
+ match ty. kind {
51
+ TyKind :: Path ( QPath :: Resolved ( _, path) ) => {
52
+ if let Res :: Def ( def_kind, def_id) = path. res
53
+ && let Some ( local_def_id) = def_id. as_local ( )
54
+ && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
55
+ {
56
+ Some ( local_def_id)
57
+ } else {
58
+ None
59
+ }
60
+ }
61
+ _ => None ,
56
62
}
57
63
}
58
64
@@ -78,7 +84,7 @@ struct MarkSymbolVisitor<'tcx> {
78
84
// maps from ADTs to ignored derived traits (e.g. Debug and Clone)
79
85
// and the span of their respective impl (i.e., part of the derive
80
86
// macro)
81
- ignored_derived_traits : LocalDefIdMap < Vec < ( DefId , DefId ) > > ,
87
+ ignored_derived_traits : LocalDefIdMap < FxIndexSet < ( DefId , DefId ) > > ,
82
88
}
83
89
84
90
impl < ' tcx > MarkSymbolVisitor < ' tcx > {
@@ -360,7 +366,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
360
366
&& let Some ( fn_sig) =
361
367
self . tcx . hir_fn_sig_by_hir_id ( self . tcx . local_def_id_to_hir_id ( local_def_id) )
362
368
&& matches ! ( fn_sig. decl. implicit_self, hir:: ImplicitSelfKind :: None )
363
- && let TyKind :: Path ( hir :: QPath :: Resolved ( _, path) ) =
369
+ && let TyKind :: Path ( QPath :: Resolved ( _, path) ) =
364
370
self . tcx . hir_expect_item ( local_impl_of) . expect_impl ( ) . self_ty . kind
365
371
&& let Res :: Def ( def_kind, did) = path. res
366
372
{
@@ -388,7 +394,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
388
394
self . ignored_derived_traits
389
395
. entry ( adt_def_id)
390
396
. or_default ( )
391
- . push ( ( trait_of, impl_of) ) ;
397
+ . insert ( ( trait_of, impl_of) ) ;
392
398
}
393
399
return true ;
394
400
}
@@ -420,51 +426,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
420
426
intravisit:: walk_item ( self , item)
421
427
}
422
428
hir:: ItemKind :: ForeignMod { .. } => { }
423
- hir:: ItemKind :: Trait ( ..) => {
424
- for & impl_def_id in self . tcx . local_trait_impls ( item. owner_id . def_id ) {
425
- if let ItemKind :: Impl ( impl_ref) = self . tcx . hir_expect_item ( impl_def_id) . kind
426
- {
427
- // skip items
428
- // mark dependent traits live
429
- intravisit:: walk_generics ( self , impl_ref. generics ) ;
430
- // mark dependent parameters live
431
- intravisit:: walk_path ( self , impl_ref. of_trait . unwrap ( ) . path ) ;
429
+ hir:: ItemKind :: Trait ( .., trait_item_refs) => {
430
+ // mark assoc ty live if the trait is live
431
+ for trait_item in trait_item_refs {
432
+ if matches ! ( trait_item. kind, hir:: AssocItemKind :: Type ) {
433
+ self . check_def_id ( trait_item. id . owner_id . to_def_id ( ) ) ;
432
434
}
433
435
}
434
-
435
436
intravisit:: walk_item ( self , item)
436
437
}
437
438
_ => intravisit:: walk_item ( self , item) ,
438
439
} ,
439
440
Node :: TraitItem ( trait_item) => {
440
- // mark corresponding ImplTerm live
441
+ // mark the trait live
441
442
let trait_item_id = trait_item. owner_id . to_def_id ( ) ;
442
443
if let Some ( trait_id) = self . tcx . trait_of_item ( trait_item_id) {
443
- // mark the trait live
444
444
self . check_def_id ( trait_id) ;
445
-
446
- for impl_id in self . tcx . all_impls ( trait_id) {
447
- if let Some ( local_impl_id) = impl_id. as_local ( )
448
- && let ItemKind :: Impl ( impl_ref) =
449
- self . tcx . hir_expect_item ( local_impl_id) . kind
450
- {
451
- if !matches ! ( trait_item. kind, hir:: TraitItemKind :: Type ( ..) )
452
- && !ty_ref_to_pub_struct ( self . tcx , impl_ref. self_ty )
453
- {
454
- // skip methods of private ty,
455
- // they would be solved in `solve_rest_impl_items`
456
- continue ;
457
- }
458
-
459
- // mark self_ty live
460
- intravisit:: walk_unambig_ty ( self , impl_ref. self_ty ) ;
461
- if let Some ( & impl_item_id) =
462
- self . tcx . impl_item_implementor_ids ( impl_id) . get ( & trait_item_id)
463
- {
464
- self . check_def_id ( impl_item_id) ;
465
- }
466
- }
467
- }
468
445
}
469
446
intravisit:: walk_trait_item ( self , trait_item) ;
470
447
}
@@ -508,48 +485,58 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
508
485
}
509
486
}
510
487
511
- fn solve_rest_impl_items ( & mut self , mut unsolved_impl_items : Vec < ( hir:: ItemId , LocalDefId ) > ) {
512
- let mut ready;
513
- ( ready, unsolved_impl_items) =
514
- unsolved_impl_items. into_iter ( ) . partition ( |& ( impl_id, impl_item_id) | {
515
- self . impl_item_with_used_self ( impl_id, impl_item_id)
516
- } ) ;
517
-
518
- while !ready. is_empty ( ) {
519
- self . worklist =
520
- ready. into_iter ( ) . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) ) . collect ( ) ;
521
- self . mark_live_symbols ( ) ;
522
-
523
- ( ready, unsolved_impl_items) =
524
- unsolved_impl_items. into_iter ( ) . partition ( |& ( impl_id, impl_item_id) | {
525
- self . impl_item_with_used_self ( impl_id, impl_item_id)
526
- } ) ;
488
+ /// Returns whether `local_def_id` is potentially alive or not.
489
+ /// `local_def_id` points to an impl or an impl item,
490
+ /// both impl and impl item that may be passed to this function are of a trait,
491
+ /// and added into the unsolved_items during `create_and_seed_worklist`
492
+ fn check_impl_or_impl_item_live (
493
+ & mut self ,
494
+ impl_id : hir:: ItemId ,
495
+ local_def_id : LocalDefId ,
496
+ ) -> bool {
497
+ if self . should_ignore_item ( local_def_id. to_def_id ( ) ) {
498
+ return false ;
527
499
}
528
- }
529
500
530
- fn impl_item_with_used_self ( & mut self , impl_id : hir:: ItemId , impl_item_id : LocalDefId ) -> bool {
531
- if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) =
532
- self . tcx . hir_item ( impl_id) . expect_impl ( ) . self_ty . kind
533
- && let Res :: Def ( def_kind, def_id) = path. res
534
- && let Some ( local_def_id) = def_id. as_local ( )
535
- && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
536
- {
537
- if self . tcx . visibility ( impl_item_id) . is_public ( ) {
538
- // for the public method, we don't know the trait item is used or not,
539
- // so we mark the method live if the self is used
540
- return self . live_symbols . contains ( & local_def_id) ;
501
+ let trait_def_id = match self . tcx . def_kind ( local_def_id) {
502
+ // assoc impl items of traits are live if the corresponding trait items are live
503
+ DefKind :: AssocFn => self . tcx . associated_item ( local_def_id) . trait_item_def_id ,
504
+ // impl items are live if the corresponding traits are live
505
+ DefKind :: Impl { of_trait : true } => self
506
+ . tcx
507
+ . impl_trait_ref ( impl_id. owner_id . def_id )
508
+ . and_then ( |trait_ref| Some ( trait_ref. skip_binder ( ) . def_id ) ) ,
509
+ _ => None ,
510
+ } ;
511
+
512
+ if let Some ( trait_def_id) = trait_def_id {
513
+ if let Some ( trait_def_id) = trait_def_id. as_local ( )
514
+ && !self . live_symbols . contains ( & trait_def_id)
515
+ {
516
+ return false ;
541
517
}
542
518
543
- if let Some ( trait_item_id) = self . tcx . associated_item ( impl_item_id) . trait_item_def_id
544
- && let Some ( local_id) = trait_item_id. as_local ( )
519
+ // FIXME: legacy logic to check whether the function may construct `Self`,
520
+ // this can be removed after supporting marking ADTs appearing in patterns
521
+ // as live, then we can check private impls of public traits directly
522
+ if let Some ( fn_sig) =
523
+ self . tcx . hir_fn_sig_by_hir_id ( self . tcx . local_def_id_to_hir_id ( local_def_id) )
524
+ && matches ! ( fn_sig. decl. implicit_self, hir:: ImplicitSelfKind :: None )
525
+ && self . tcx . visibility ( trait_def_id) . is_public ( )
545
526
{
546
- // for the private method, we can know the trait item is used or not,
547
- // so we mark the method live if the self is used and the trait item is used
548
- return self . live_symbols . contains ( & local_id)
549
- && self . live_symbols . contains ( & local_def_id) ;
527
+ return true ;
550
528
}
551
529
}
552
- false
530
+
531
+ // The impl or impl item is used if the corresponding trait or trait item is used and the ty is used.
532
+ if let Some ( local_def_id) =
533
+ local_adt_def_of_ty ( self . tcx . hir_item ( impl_id) . expect_impl ( ) . self_ty )
534
+ && !self . live_symbols . contains ( & local_def_id)
535
+ {
536
+ return false ;
537
+ }
538
+
539
+ true
553
540
}
554
541
}
555
542
@@ -584,7 +571,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
584
571
585
572
fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr < ' tcx > ) {
586
573
match expr. kind {
587
- hir:: ExprKind :: Path ( ref qpath @ hir :: QPath :: TypeRelative ( ..) ) => {
574
+ hir:: ExprKind :: Path ( ref qpath @ QPath :: TypeRelative ( ..) ) => {
588
575
let res = self . typeck_results ( ) . qpath_res ( qpath, expr. hir_id ) ;
589
576
self . handle_res ( res) ;
590
577
}
@@ -738,7 +725,7 @@ fn check_item<'tcx>(
738
725
tcx : TyCtxt < ' tcx > ,
739
726
worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
740
727
struct_constructors : & mut LocalDefIdMap < LocalDefId > ,
741
- unsolved_impl_items : & mut Vec < ( hir:: ItemId , LocalDefId ) > ,
728
+ unsolved_items : & mut Vec < ( hir:: ItemId , LocalDefId ) > ,
742
729
id : hir:: ItemId ,
743
730
) {
744
731
let allow_dead_code = has_allow_dead_code_or_lang_attr ( tcx, id. owner_id . def_id ) ;
@@ -764,41 +751,33 @@ fn check_item<'tcx>(
764
751
}
765
752
}
766
753
DefKind :: Impl { of_trait } => {
767
- // get DefIds from another query
768
- let local_def_ids = tcx
769
- . associated_item_def_ids ( id. owner_id )
770
- . iter ( )
771
- . filter_map ( |def_id| def_id. as_local ( ) ) ;
772
-
773
- let ty_is_pub = ty_ref_to_pub_struct ( tcx, tcx. hir_item ( id) . expect_impl ( ) . self_ty ) ;
774
-
775
- // And we access the Map here to get HirId from LocalDefId
776
- for local_def_id in local_def_ids {
777
- // check the function may construct Self
778
- let mut may_construct_self = false ;
779
- if let Some ( fn_sig) =
780
- tcx. hir_fn_sig_by_hir_id ( tcx. local_def_id_to_hir_id ( local_def_id) )
781
- {
782
- may_construct_self =
783
- matches ! ( fn_sig. decl. implicit_self, hir:: ImplicitSelfKind :: None ) ;
784
- }
754
+ if let Some ( comes_from_allow) =
755
+ has_allow_dead_code_or_lang_attr ( tcx, id. owner_id . def_id )
756
+ {
757
+ worklist. push ( ( id. owner_id . def_id , comes_from_allow) ) ;
758
+ } else if of_trait {
759
+ unsolved_items. push ( ( id, id. owner_id . def_id ) ) ;
760
+ }
785
761
786
- // for trait impl blocks,
787
- // mark the method live if the self_ty is public,
788
- // or the method is public and may construct self
789
- if of_trait
790
- && ( !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn )
791
- || tcx. visibility ( local_def_id) . is_public ( )
792
- && ( ty_is_pub || may_construct_self) )
793
- {
794
- worklist. push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
795
- } else if let Some ( comes_from_allow) =
796
- has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
762
+ for def_id in tcx. associated_item_def_ids ( id. owner_id ) {
763
+ let local_def_id = def_id. expect_local ( ) ;
764
+
765
+ if let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
797
766
{
798
767
worklist. push ( ( local_def_id, comes_from_allow) ) ;
799
768
} else if of_trait {
800
- // private method || public method not constructs self
801
- unsolved_impl_items. push ( ( id, local_def_id) ) ;
769
+ // FIXME: This condition can be removed
770
+ // if we support dead check for assoc consts and tys.
771
+ if !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn ) {
772
+ worklist. push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
773
+ } else {
774
+ // We only care about associated items of traits,
775
+ // because they cannot be visited directly,
776
+ // so we later mark them as live if their corresponding traits
777
+ // or trait items and self types are both live,
778
+ // but inherent associated items can be visited and marked directly.
779
+ unsolved_items. push ( ( id, local_def_id) ) ;
780
+ }
802
781
}
803
782
}
804
783
}
@@ -892,8 +871,8 @@ fn create_and_seed_worklist(
892
871
fn live_symbols_and_ignored_derived_traits (
893
872
tcx : TyCtxt < ' _ > ,
894
873
( ) : ( ) ,
895
- ) -> ( LocalDefIdSet , LocalDefIdMap < Vec < ( DefId , DefId ) > > ) {
896
- let ( worklist, struct_constructors, unsolved_impl_items ) = create_and_seed_worklist ( tcx) ;
874
+ ) -> ( LocalDefIdSet , LocalDefIdMap < FxIndexSet < ( DefId , DefId ) > > ) {
875
+ let ( worklist, struct_constructors, mut unsolved_items ) = create_and_seed_worklist ( tcx) ;
897
876
let mut symbol_visitor = MarkSymbolVisitor {
898
877
worklist,
899
878
tcx,
@@ -907,7 +886,22 @@ fn live_symbols_and_ignored_derived_traits(
907
886
ignored_derived_traits : Default :: default ( ) ,
908
887
} ;
909
888
symbol_visitor. mark_live_symbols ( ) ;
910
- symbol_visitor. solve_rest_impl_items ( unsolved_impl_items) ;
889
+ let mut items_to_check;
890
+ ( items_to_check, unsolved_items) =
891
+ unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
892
+ symbol_visitor. check_impl_or_impl_item_live ( impl_id, local_def_id)
893
+ } ) ;
894
+
895
+ while !items_to_check. is_empty ( ) {
896
+ symbol_visitor. worklist =
897
+ items_to_check. into_iter ( ) . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) ) . collect ( ) ;
898
+ symbol_visitor. mark_live_symbols ( ) ;
899
+
900
+ ( items_to_check, unsolved_items) =
901
+ unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
902
+ symbol_visitor. check_impl_or_impl_item_live ( impl_id, local_def_id)
903
+ } ) ;
904
+ }
911
905
912
906
( symbol_visitor. live_symbols , symbol_visitor. ignored_derived_traits )
913
907
}
@@ -921,7 +915,7 @@ struct DeadItem {
921
915
struct DeadVisitor < ' tcx > {
922
916
tcx : TyCtxt < ' tcx > ,
923
917
live_symbols : & ' tcx LocalDefIdSet ,
924
- ignored_derived_traits : & ' tcx LocalDefIdMap < Vec < ( DefId , DefId ) > > ,
918
+ ignored_derived_traits : & ' tcx LocalDefIdMap < FxIndexSet < ( DefId , DefId ) > > ,
925
919
}
926
920
927
921
enum ShouldWarnAboutField {
@@ -1188,19 +1182,15 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
1188
1182
let def_kind = tcx. def_kind ( item. owner_id ) ;
1189
1183
1190
1184
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 { .. } )
1185
+ // Only diagnose unused assoc items in inherient impl and used trait,
1186
+ // for unused assoc items in impls of trait,
1187
+ // we have diagnosed them in the trait if they are unused,
1188
+ // for unused assoc items in unused trait,
1189
+ // we have diagnosed the unused trait.
1190
+ if matches ! ( def_kind, DefKind :: Impl { of_trait: false } )
1193
1191
|| ( def_kind == DefKind :: Trait && live_symbols. contains ( & item. owner_id . def_id ) )
1194
1192
{
1195
1193
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
1194
if let Some ( local_def_id) = def_id. as_local ( )
1205
1195
&& !visitor. is_live_code ( local_def_id)
1206
1196
{
0 commit comments