@@ -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 , AssocItemContainer , Ty , TyCtxt } ;
20
+ use rustc_middle:: ty:: { self , AssocItemContainer , 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,7 +44,9 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
44
44
)
45
45
}
46
46
47
- fn adt_of < ' tcx > ( ty : & hir:: Ty < ' tcx > ) -> Option < ( LocalDefId , DefKind ) > {
47
+ /// Returns the local def id and def kind of the adt,
48
+ /// if the given ty refers to one local adt definition
49
+ fn adt_def_of_ty < ' tcx > ( ty : & hir:: Ty < ' tcx > ) -> Option < ( LocalDefId , DefKind ) > {
48
50
match ty. kind {
49
51
TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) => {
50
52
if let Res :: Def ( def_kind, def_id) = path. res
@@ -55,8 +57,8 @@ fn adt_of<'tcx>(ty: &hir::Ty<'tcx>) -> Option<(LocalDefId, DefKind)> {
55
57
None
56
58
}
57
59
}
58
- TyKind :: Slice ( ty) | TyKind :: Array ( ty, _) => adt_of ( ty) ,
59
- TyKind :: Ptr ( ty) | TyKind :: Ref ( _, ty) => adt_of ( ty. ty ) ,
60
+ TyKind :: Slice ( ty) | TyKind :: Array ( ty, _) => adt_def_of_ty ( ty) ,
61
+ TyKind :: Ptr ( ty) | TyKind :: Ref ( _, ty) => adt_def_of_ty ( ty. ty ) ,
60
62
_ => None ,
61
63
}
62
64
}
@@ -114,7 +116,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
114
116
115
117
fn handle_res ( & mut self , res : Res ) {
116
118
match res {
117
- Res :: Def ( DefKind :: Const | DefKind :: AssocConst | DefKind :: TyAlias , def_id) => {
119
+ Res :: Def (
120
+ DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: Const | DefKind :: TyAlias ,
121
+ def_id,
122
+ ) => {
118
123
self . check_def_id ( def_id) ;
119
124
}
120
125
_ if self . in_pat => { }
@@ -234,6 +239,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
234
239
) {
235
240
let variant = match self . typeck_results ( ) . node_type ( lhs. hir_id ) . kind ( ) {
236
241
ty:: Adt ( adt, _) => {
242
+ // mark the adt live if its variant appears as the pattern
243
+ // considering cases when we have `let T(x) = foo()` and `fn foo<T>() -> T;`
244
+ // we will lose the liveness info of `T` cause we cannot mark it live when visiting `foo`
245
+ // related issue: https://github.com/rust-lang/rust/issues/120770
237
246
self . check_def_id ( adt. did ( ) ) ;
238
247
adt. variant_of_res ( res)
239
248
}
@@ -257,6 +266,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
257
266
) {
258
267
let variant = match self . typeck_results ( ) . node_type ( lhs. hir_id ) . kind ( ) {
259
268
ty:: Adt ( adt, _) => {
269
+ // mark the adt live if its variant appears as the pattern
270
+ // considering cases when we have `let T(x) = foo()` and `fn foo<T>() -> T;`
271
+ // we will lose the liveness info of `T` cause we cannot mark it live when visiting `foo`
272
+ // related issue: https://github.com/rust-lang/rust/issues/120770
260
273
self . check_def_id ( adt. did ( ) ) ;
261
274
adt. variant_of_res ( res)
262
275
}
@@ -406,13 +419,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
406
419
intravisit:: walk_item ( self , item)
407
420
}
408
421
hir:: ItemKind :: ForeignMod { .. } => { }
422
+ hir:: ItemKind :: Trait ( _, _, _, _, trait_item_refs) => {
423
+ // mark assoc ty live if the trait is live
424
+ for trait_item in trait_item_refs {
425
+ if matches ! ( trait_item. kind, hir:: AssocItemKind :: Type ) {
426
+ self . check_def_id ( trait_item. id . owner_id . to_def_id ( ) ) ;
427
+ }
428
+ }
429
+ intravisit:: walk_item ( self , item)
430
+ }
409
431
_ => intravisit:: walk_item ( self , item) ,
410
432
} ,
411
433
Node :: TraitItem ( trait_item) => {
412
- // mark corresponding ImplTerm live
434
+ // mark the trait live
413
435
let trait_item_id = trait_item. owner_id . to_def_id ( ) ;
414
436
if let Some ( trait_id) = self . tcx . trait_of_item ( trait_item_id) {
415
- // mark the trait live
416
437
self . check_def_id ( trait_id) ;
417
438
}
418
439
@@ -437,6 +458,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
437
458
_ => { }
438
459
}
439
460
}
461
+
440
462
intravisit:: walk_impl_item ( self , impl_item) ;
441
463
}
442
464
Node :: ForeignItem ( foreign_item) => {
@@ -458,55 +480,44 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
458
480
}
459
481
}
460
482
461
- fn solve_rest_items ( & mut self , mut unsolved_items : Vec < ( hir:: ItemId , LocalDefId ) > ) {
462
- let mut ready;
463
- ( ready, unsolved_items) =
464
- unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
465
- self . item_should_be_checked ( impl_id, local_def_id)
466
- } ) ;
467
-
468
- while !ready. is_empty ( ) {
469
- self . worklist =
470
- ready. into_iter ( ) . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) ) . collect ( ) ;
471
- self . mark_live_symbols ( ) ;
472
-
473
- ( ready, unsolved_items) =
474
- unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
475
- self . item_should_be_checked ( impl_id, local_def_id)
476
- } ) ;
477
- }
478
- }
479
-
483
+ /// Returns an impl or impl item should be checked or not
484
+ /// `impl_id` is the `ItemId` of the impl or the impl item belongs to,
485
+ /// `local_def_id` may point to the impl or the impl item,
486
+ /// both impl and impl item that may pass to this function are of trait,
487
+ /// and added into the unsolved_items during `create_and_seed_worklist`
480
488
fn item_should_be_checked ( & mut self , impl_id : hir:: ItemId , local_def_id : LocalDefId ) -> bool {
481
489
let trait_def_id = match self . tcx . def_kind ( local_def_id) {
482
- // for assoc impl items of traits, we concern the corresponding trait items are used or not
483
- DefKind :: AssocFn => self
490
+ // assoc impl items of traits are live if the corresponding trait items are live
491
+ DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: AssocFn => self
484
492
. tcx
485
493
. associated_item ( local_def_id)
486
494
. trait_item_def_id
487
495
. and_then ( |def_id| def_id. as_local ( ) ) ,
488
- // for impl items, we concern the corresonding traits are used or not
496
+ // impl items are live if the corresponding traits are live
489
497
DefKind :: Impl { of_trait : true } => self
490
498
. tcx
491
499
. impl_trait_ref ( impl_id. owner_id . def_id )
492
500
. and_then ( |trait_ref| trait_ref. skip_binder ( ) . def_id . as_local ( ) ) ,
493
501
_ => None ,
494
502
} ;
495
503
496
- if !trait_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true ) {
504
+ if let Some ( def_id) = trait_def_id
505
+ && !self . live_symbols . contains ( & def_id)
506
+ {
497
507
return false ;
498
508
}
499
509
500
510
// we only check the ty is used or not for ADTs defined locally
501
- let ty_def_id = adt_of ( self . tcx . hir ( ) . item ( impl_id) . expect_impl ( ) . self_ty ) . and_then (
502
- |( local_def_id, def_kind) | {
503
- matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
504
- . then_some ( local_def_id)
505
- } ,
506
- ) ;
507
-
508
511
// the impl/impl item is used if the trait/trait item is used and the ty is used
509
- ty_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true )
512
+ if let Some ( ( local_def_id, def_kind) ) =
513
+ adt_def_of_ty ( self . tcx . hir ( ) . item ( impl_id) . expect_impl ( ) . self_ty )
514
+ && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
515
+ && !self . live_symbols . contains ( & local_def_id)
516
+ {
517
+ return false ;
518
+ }
519
+
520
+ true
510
521
}
511
522
}
512
523
@@ -632,6 +643,29 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
632
643
633
644
self . in_pat = in_pat;
634
645
}
646
+
647
+ fn visit_poly_trait_ref ( & mut self , t : & ' tcx hir:: PolyTraitRef < ' tcx > ) {
648
+ // mark the assoc const appears in poly-trait-ref live
649
+ if let Some ( pathsegment) = t. trait_ref . path . segments . last ( )
650
+ && let Some ( args) = pathsegment. args
651
+ {
652
+ for constraint in args. constraints {
653
+ if let Some ( item) = self
654
+ . tcx
655
+ . associated_items ( pathsegment. res . def_id ( ) )
656
+ . filter_by_name_unhygienic ( constraint. ident . name )
657
+ . find ( |i| {
658
+ matches ! ( i. kind, ty:: AssocKind :: Const )
659
+ && i. ident ( self . tcx ) . normalize_to_macros_2_0 ( ) == constraint. ident
660
+ } )
661
+ && let Some ( local_def_id) = item. def_id . as_local ( )
662
+ {
663
+ self . worklist . push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
664
+ }
665
+ }
666
+ }
667
+ intravisit:: walk_poly_trait_ref ( self , t) ;
668
+ }
635
669
}
636
670
637
671
fn has_allow_dead_code_or_lang_attr (
@@ -715,7 +749,7 @@ fn check_item<'tcx>(
715
749
}
716
750
DefKind :: Impl { of_trait } => {
717
751
// get DefIds from another query
718
- let local_def_ids = tcx
752
+ let associated_item_def_ids = tcx
719
753
. associated_item_def_ids ( id. owner_id )
720
754
. iter ( )
721
755
. filter_map ( |def_id| def_id. as_local ( ) ) ;
@@ -729,14 +763,16 @@ fn check_item<'tcx>(
729
763
}
730
764
731
765
// And we access the Map here to get HirId from LocalDefId
732
- for local_def_id in local_def_ids {
733
- if !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn ) {
734
- worklist. push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
735
- } else if let Some ( comes_from_allow) =
736
- has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
766
+ for local_def_id in associated_item_def_ids {
767
+ if let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
737
768
{
738
769
worklist. push ( ( local_def_id, comes_from_allow) ) ;
739
770
} else if of_trait {
771
+ // we only care about assoc items of trait,
772
+ // because they cannot be visited directly
773
+ // so we mark them based on the trait/trait item
774
+ // and self ty are checked first and both live,
775
+ // but inherent assoc items can be visited and marked directly
740
776
unsolved_items. push ( ( id, local_def_id) ) ;
741
777
}
742
778
}
@@ -762,10 +798,13 @@ fn check_trait_item(
762
798
worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
763
799
id : hir:: TraitItemId ,
764
800
) {
765
- use hir:: TraitItemKind :: { Const , Fn } ;
766
- if matches ! ( tcx. def_kind( id. owner_id) , DefKind :: AssocConst | DefKind :: AssocFn ) {
801
+ use hir:: TraitItemKind :: { Const , Fn , Type } ;
802
+ if matches ! (
803
+ tcx. def_kind( id. owner_id) ,
804
+ DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: AssocFn
805
+ ) {
767
806
let trait_item = tcx. hir ( ) . trait_item ( id) ;
768
- if matches ! ( trait_item. kind, Const ( _, Some ( _) ) | Fn ( ..) )
807
+ if matches ! ( trait_item. kind, Const ( _, Some ( _) ) | Type ( .. ) | Fn ( ..) )
769
808
&& let Some ( comes_from_allow) =
770
809
has_allow_dead_code_or_lang_attr ( tcx, trait_item. owner_id . def_id )
771
810
{
@@ -807,7 +846,7 @@ fn create_and_seed_worklist(
807
846
// checks impls and impl-items later
808
847
match tcx. def_kind ( id) {
809
848
DefKind :: Impl { of_trait } => !of_trait,
810
- DefKind :: AssocFn => {
849
+ DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: AssocFn => {
811
850
// still check public trait items, and impl items not of trait
812
851
let assoc_item = tcx. associated_item ( id) ;
813
852
!matches ! ( assoc_item. container, AssocItemContainer :: ImplContainer )
@@ -844,7 +883,7 @@ fn live_symbols_and_ignored_derived_traits(
844
883
tcx : TyCtxt < ' _ > ,
845
884
( ) : ( ) ,
846
885
) -> ( LocalDefIdSet , LocalDefIdMap < Vec < ( DefId , DefId ) > > ) {
847
- let ( worklist, struct_constructors, unsolved_items) = create_and_seed_worklist ( tcx) ;
886
+ let ( worklist, struct_constructors, mut unsolved_items) = create_and_seed_worklist ( tcx) ;
848
887
let mut symbol_visitor = MarkSymbolVisitor {
849
888
worklist,
850
889
tcx,
@@ -857,8 +896,26 @@ fn live_symbols_and_ignored_derived_traits(
857
896
struct_constructors,
858
897
ignored_derived_traits : Default :: default ( ) ,
859
898
} ;
899
+
860
900
symbol_visitor. mark_live_symbols ( ) ;
861
- symbol_visitor. solve_rest_items ( unsolved_items) ;
901
+ let mut rest_items_should_be_checked;
902
+ ( rest_items_should_be_checked, unsolved_items) =
903
+ unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
904
+ symbol_visitor. item_should_be_checked ( impl_id, local_def_id)
905
+ } ) ;
906
+
907
+ while !rest_items_should_be_checked. is_empty ( ) {
908
+ symbol_visitor. worklist = rest_items_should_be_checked
909
+ . into_iter ( )
910
+ . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) )
911
+ . collect ( ) ;
912
+ symbol_visitor. mark_live_symbols ( ) ;
913
+
914
+ ( rest_items_should_be_checked, unsolved_items) =
915
+ unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
916
+ symbol_visitor. item_should_be_checked ( impl_id, local_def_id)
917
+ } ) ;
918
+ }
862
919
863
920
( symbol_visitor. live_symbols , symbol_visitor. ignored_derived_traits )
864
921
}
@@ -1098,6 +1155,7 @@ impl<'tcx> DeadVisitor<'tcx> {
1098
1155
}
1099
1156
match self . tcx . def_kind ( def_id) {
1100
1157
DefKind :: AssocConst
1158
+ | DefKind :: AssocTy
1101
1159
| DefKind :: AssocFn
1102
1160
| DefKind :: Fn
1103
1161
| DefKind :: Static { .. }
@@ -1134,7 +1192,11 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
1134
1192
let def_kind = tcx. def_kind ( item. owner_id ) ;
1135
1193
1136
1194
let mut dead_codes = Vec :: new ( ) ;
1137
- // if we have diagnosed the trait, do not diagnose unused assoc items
1195
+ // only diagnose unused assoc items for inherient impl and used trait
1196
+ // for unused assoc items in impls of trait,
1197
+ // we have diagnosed them in the trait if they are unused,
1198
+ // for unused assoc items in unused trait,
1199
+ // we have diagnosed the unused trait
1138
1200
if matches ! ( def_kind, DefKind :: Impl { of_trait: false } )
1139
1201
|| ( def_kind == DefKind :: Trait && live_symbols. contains ( & item. owner_id . def_id ) )
1140
1202
{
0 commit comments