@@ -16,7 +16,7 @@ use rustc_hir::{self as hir, Node, PatKind, TyKind};
16
16
use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
17
17
use rustc_middle:: middle:: privacy:: Level ;
18
18
use rustc_middle:: query:: Providers ;
19
- use rustc_middle:: ty:: { self , AssocItemContainer , Ty , TyCtxt } ;
19
+ use rustc_middle:: ty:: { self , AssocItemContainer , Ty , TyCtxt , TypeSuperVisitable , TypeVisitor } ;
20
20
use rustc_middle:: { bug, span_bug} ;
21
21
use rustc_session:: lint;
22
22
use rustc_session:: lint:: builtin:: DEAD_CODE ;
@@ -113,7 +113,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
113
113
114
114
fn handle_res ( & mut self , res : Res ) {
115
115
match res {
116
- Res :: Def ( DefKind :: Const | DefKind :: AssocConst | DefKind :: TyAlias , def_id) => {
116
+ Res :: Def (
117
+ DefKind :: Const | DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: TyAlias ,
118
+ def_id,
119
+ ) => {
117
120
self . check_def_id ( def_id) ;
118
121
}
119
122
_ if self . in_pat => { }
@@ -405,6 +408,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
405
408
intravisit:: walk_item ( self , item)
406
409
}
407
410
hir:: ItemKind :: ForeignMod { .. } => { }
411
+ hir:: ItemKind :: Fn ( ..) => {
412
+ // check `T::Ty` in the types of inputs and output
413
+ // the result of type_of maybe different from the fn sig,
414
+ // so we also check the fn sig
415
+ self . visit_middle_fn_sig ( item. owner_id . def_id ) ;
416
+ intravisit:: walk_item ( self , item)
417
+ }
408
418
_ => intravisit:: walk_item ( self , item) ,
409
419
} ,
410
420
Node :: TraitItem ( trait_item) => {
@@ -415,6 +425,20 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
415
425
self . check_def_id ( trait_id) ;
416
426
}
417
427
428
+ match trait_item. kind {
429
+ hir:: TraitItemKind :: Fn ( ..) => {
430
+ // check `T::Ty` in the types of inputs and output
431
+ // the result of type_of maybe different from the fn sig,
432
+ // so we also check the fn sig
433
+ self . visit_middle_fn_sig ( trait_item. owner_id . def_id )
434
+ }
435
+ hir:: TraitItemKind :: Type ( .., Some ( _) ) | hir:: TraitItemKind :: Const ( ..) => {
436
+ // check `type X = T::Ty;` or `const X: T::Ty;`
437
+ self . visit_middle_ty_by_def_id ( trait_item. owner_id . def_id )
438
+ }
439
+ _ => ( ) ,
440
+ }
441
+
418
442
intravisit:: walk_trait_item ( self , trait_item) ;
419
443
}
420
444
Node :: ImplItem ( impl_item) => {
@@ -436,6 +460,20 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
436
460
_ => { }
437
461
}
438
462
}
463
+
464
+ match impl_item. kind {
465
+ hir:: ImplItemKind :: Fn ( ..) => {
466
+ // check `T::Ty` in the types of inputs and output
467
+ // the result of type_of maybe different from the fn sig,
468
+ // so we also check the fn sig
469
+ self . visit_middle_fn_sig ( impl_item. owner_id . def_id )
470
+ }
471
+ hir:: ImplItemKind :: Type ( ..) | hir:: ImplItemKind :: Const ( ..) => {
472
+ // check `type X = T::Ty;` or `const X: T::Ty;`
473
+ self . visit_middle_ty_by_def_id ( impl_item. owner_id . def_id )
474
+ }
475
+ }
476
+
439
477
intravisit:: walk_impl_item ( self , impl_item) ;
440
478
}
441
479
Node :: ForeignItem ( foreign_item) => {
@@ -478,7 +516,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
478
516
fn item_should_be_checked ( & mut self , impl_id : hir:: ItemId , local_def_id : LocalDefId ) -> bool {
479
517
let trait_def_id = match self . tcx . def_kind ( local_def_id) {
480
518
// for assoc impl items of traits, we concern the corresponding trait items are used or not
481
- DefKind :: AssocFn => self
519
+ DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: AssocFn => self
482
520
. tcx
483
521
. associated_item ( local_def_id)
484
522
. trait_item_def_id
@@ -506,6 +544,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
506
544
// the impl/impl item is used if the trait/trait item is used and the ty is used
507
545
ty_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true )
508
546
}
547
+
548
+ fn visit_middle_ty ( & mut self , ty : Ty < ' tcx > ) {
549
+ <Self as TypeVisitor < TyCtxt < ' tcx > > >:: visit_ty ( self , ty) ;
550
+ }
551
+
552
+ fn visit_middle_ty_by_def_id ( & mut self , def_id : LocalDefId ) {
553
+ self . visit_middle_ty ( self . tcx . type_of ( def_id) . instantiate_identity ( ) ) ;
554
+ }
555
+
556
+ fn visit_middle_fn_sig ( & mut self , def_id : LocalDefId ) {
557
+ let fn_sig = self . tcx . fn_sig ( def_id) . instantiate_identity ( ) ;
558
+ for ty in fn_sig. inputs ( ) . skip_binder ( ) {
559
+ self . visit_middle_ty ( ty. clone ( ) ) ;
560
+ }
561
+ self . visit_middle_ty ( fn_sig. output ( ) . skip_binder ( ) . clone ( ) ) ;
562
+ }
509
563
}
510
564
511
565
impl < ' tcx > Visitor < ' tcx > for MarkSymbolVisitor < ' tcx > {
@@ -537,6 +591,19 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
537
591
intravisit:: walk_struct_def ( self , def) ;
538
592
}
539
593
594
+ fn visit_field_def ( & mut self , s : & ' tcx rustc_hir:: FieldDef < ' tcx > ) {
595
+ // check `field: T::Ty`
596
+ // marks assoc types live whether the field is not used or not
597
+ // there are three situations:
598
+ // 1. the field is used, it's good
599
+ // 2. the field is not used but marked like `#[allow(dead_code)]`,
600
+ // it's annoying to mark the assoc type `#[allow(dead_code)]` again
601
+ // 3. the field is not used, and will be linted
602
+ // the assoc type will be linted after removing the unused field
603
+ self . visit_middle_ty_by_def_id ( s. def_id ) ;
604
+ intravisit:: walk_field_def ( self , s) ;
605
+ }
606
+
540
607
fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr < ' tcx > ) {
541
608
match expr. kind {
542
609
hir:: ExprKind :: Path ( ref qpath @ hir:: QPath :: TypeRelative ( ..) ) => {
@@ -569,6 +636,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
569
636
_ => ( ) ,
570
637
}
571
638
639
+ // check the expr_ty if its type is `T::Ty`
640
+ self . visit_middle_ty ( self . typeck_results ( ) . expr_ty ( expr) ) ;
641
+
572
642
intravisit:: walk_expr ( self , expr) ;
573
643
}
574
644
@@ -590,6 +660,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
590
660
self . handle_field_pattern_match ( pat, res, fields) ;
591
661
}
592
662
PatKind :: Path ( ref qpath) => {
663
+ if let ty:: Adt ( adt, _) = self . typeck_results ( ) . node_type ( pat. hir_id ) . kind ( ) {
664
+ self . check_def_id ( adt. did ( ) ) ;
665
+ }
593
666
let res = self . typeck_results ( ) . qpath_res ( qpath, pat. hir_id ) ;
594
667
self . handle_res ( res) ;
595
668
}
@@ -606,6 +679,24 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
606
679
607
680
fn visit_path ( & mut self , path : & hir:: Path < ' tcx > , _: hir:: HirId ) {
608
681
self . handle_res ( path. res ) ;
682
+
683
+ if let Res :: Def ( def_kind, def_id) = path. res
684
+ && matches ! (
685
+ def_kind,
686
+ DefKind :: Fn
687
+ | DefKind :: AssocFn
688
+ | DefKind :: AssocTy
689
+ | DefKind :: Struct
690
+ | DefKind :: Union
691
+ | DefKind :: Enum
692
+ )
693
+ {
694
+ let preds = self . tcx . predicates_of ( def_id) . instantiate_identity ( self . tcx ) ;
695
+ for pred in preds. iter ( ) {
696
+ <Self as TypeVisitor < TyCtxt < ' tcx > > >:: visit_predicate ( self , pred. 0 . as_predicate ( ) ) ;
697
+ }
698
+ }
699
+
609
700
intravisit:: walk_path ( self , path) ;
610
701
}
611
702
@@ -638,6 +729,41 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
638
729
639
730
self . in_pat = in_pat;
640
731
}
732
+
733
+ fn visit_poly_trait_ref ( & mut self , t : & ' tcx hir:: PolyTraitRef < ' tcx > ) {
734
+ // mark the assoc type/const appears in poly-trait-ref live
735
+ if let Some ( pathsegment) = t. trait_ref . path . segments . last ( )
736
+ && let Some ( args) = pathsegment. args
737
+ {
738
+ for constraint in args. constraints {
739
+ if let Some ( item) = self
740
+ . tcx
741
+ . associated_items ( pathsegment. res . def_id ( ) )
742
+ . filter_by_name_unhygienic ( constraint. ident . name )
743
+ . find ( |i| {
744
+ matches ! ( i. kind, ty:: AssocKind :: Const | ty:: AssocKind :: Type )
745
+ && i. ident ( self . tcx ) . normalize_to_macros_2_0 ( ) == constraint. ident
746
+ } )
747
+ && let Some ( local_def_id) = item. def_id . as_local ( )
748
+ {
749
+ self . worklist . push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
750
+ }
751
+ }
752
+ }
753
+ intravisit:: walk_poly_trait_ref ( self , t) ;
754
+ }
755
+ }
756
+
757
+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for MarkSymbolVisitor < ' tcx > {
758
+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) {
759
+ match ty. kind ( ) {
760
+ ty:: Alias ( _, alias) => {
761
+ self . check_def_id ( alias. def_id ) ;
762
+ }
763
+ _ => ( ) ,
764
+ }
765
+ ty. super_visit_with ( self ) ;
766
+ }
641
767
}
642
768
643
769
fn has_allow_dead_code_or_lang_attr (
@@ -648,6 +774,7 @@ fn has_allow_dead_code_or_lang_attr(
648
774
tcx. has_attr ( def_id, sym:: lang)
649
775
// Stable attribute for #[lang = "panic_impl"]
650
776
|| tcx. has_attr ( def_id, sym:: panic_handler)
777
+ || tcx. has_attr ( def_id, sym:: async_fn_kind_upvars)
651
778
}
652
779
653
780
fn has_allow_expect_dead_code ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> bool {
@@ -736,10 +863,7 @@ fn check_item<'tcx>(
736
863
737
864
// And we access the Map here to get HirId from LocalDefId
738
865
for local_def_id in local_def_ids {
739
- if !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn ) {
740
- worklist. push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
741
- } else if let Some ( comes_from_allow) =
742
- has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
866
+ if let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
743
867
{
744
868
worklist. push ( ( local_def_id, comes_from_allow) ) ;
745
869
} else if of_trait {
@@ -768,10 +892,13 @@ fn check_trait_item(
768
892
worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
769
893
id : hir:: TraitItemId ,
770
894
) {
771
- use hir:: TraitItemKind :: { Const , Fn } ;
772
- if matches ! ( tcx. def_kind( id. owner_id) , DefKind :: AssocConst | DefKind :: AssocFn ) {
895
+ use hir:: TraitItemKind :: { Const , Fn , Type } ;
896
+ if matches ! (
897
+ tcx. def_kind( id. owner_id) ,
898
+ DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: AssocFn
899
+ ) {
773
900
let trait_item = tcx. hir ( ) . trait_item ( id) ;
774
- if matches ! ( trait_item. kind, Const ( _, Some ( _) ) | Fn ( ..) )
901
+ if matches ! ( trait_item. kind, Const ( _, Some ( _) ) | Type ( .. ) | Fn ( ..) )
775
902
&& let Some ( comes_from_allow) =
776
903
has_allow_dead_code_or_lang_attr ( tcx, trait_item. owner_id . def_id )
777
904
{
@@ -813,7 +940,7 @@ fn create_and_seed_worklist(
813
940
// checks impls and impl-items later
814
941
match tcx. def_kind ( id) {
815
942
DefKind :: Impl { of_trait } => !of_trait,
816
- DefKind :: AssocFn => {
943
+ DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: AssocFn => {
817
944
// still check public trait items, and impl items not of trait
818
945
let assoc_item = tcx. associated_item ( id) ;
819
946
!matches ! ( assoc_item. container, AssocItemContainer :: ImplContainer )
@@ -1104,6 +1231,7 @@ impl<'tcx> DeadVisitor<'tcx> {
1104
1231
}
1105
1232
match self . tcx . def_kind ( def_id) {
1106
1233
DefKind :: AssocConst
1234
+ | DefKind :: AssocTy
1107
1235
| DefKind :: AssocFn
1108
1236
| DefKind :: Fn
1109
1237
| DefKind :: Static { .. }
0 commit comments