@@ -15,7 +15,7 @@ use rustc_hir::{Node, PatKind, TyKind};
15
15
use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
16
16
use rustc_middle:: middle:: privacy:: Level ;
17
17
use rustc_middle:: query:: Providers ;
18
- use rustc_middle:: ty:: { self , AssocItemContainer , TyCtxt } ;
18
+ use rustc_middle:: ty:: { self , AssocItemContainer , Ty , TyCtxt , TypeSuperVisitable , TypeVisitor } ;
19
19
use rustc_middle:: { bug, span_bug} ;
20
20
use rustc_session:: lint;
21
21
use rustc_session:: lint:: builtin:: DEAD_CODE ;
@@ -450,7 +450,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
450
450
intravisit:: walk_item ( self , item)
451
451
}
452
452
hir:: ItemKind :: ForeignMod { .. } => { }
453
- hir:: ItemKind :: Trait ( _ , _ , _ , _ , trait_item_refs ) => {
453
+ hir:: ItemKind :: Trait ( .. ) => {
454
454
for impl_def_id in self . tcx . all_impls ( item. owner_id . to_def_id ( ) ) {
455
455
if let Some ( local_def_id) = impl_def_id. as_local ( )
456
456
&& let ItemKind :: Impl ( impl_ref) =
@@ -463,12 +463,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
463
463
intravisit:: walk_path ( self , impl_ref. of_trait . unwrap ( ) . path ) ;
464
464
}
465
465
}
466
- // mark assoc ty live if the trait is live
467
- for trait_item in trait_item_refs {
468
- if let hir:: AssocItemKind :: Type = trait_item. kind {
469
- self . check_def_id ( trait_item. id . owner_id . to_def_id ( ) ) ;
470
- }
471
- }
466
+ intravisit:: walk_item ( self , item)
467
+ }
468
+ hir:: ItemKind :: Fn ( ..) => {
469
+ // check `T::Ty` in the types of inputs and output
470
+ // the result of type_of maybe different from the fn sig,
471
+ // so we also check the fn sig
472
+ self . visit_middle_fn_sig ( item. owner_id . def_id ) ;
472
473
intravisit:: walk_item ( self , item)
473
474
}
474
475
_ => intravisit:: walk_item ( self , item) ,
@@ -504,6 +505,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
504
505
}
505
506
}
506
507
}
508
+
509
+ match trait_item. kind {
510
+ hir:: TraitItemKind :: Fn ( ..) => {
511
+ // check `T::Ty` in the types of inputs and output
512
+ // the result of type_of maybe different from the fn sig,
513
+ // so we also check the fn sig
514
+ self . visit_middle_fn_sig ( trait_item. owner_id . def_id )
515
+ }
516
+ hir:: TraitItemKind :: Type ( .., Some ( _) ) | hir:: TraitItemKind :: Const ( ..) => {
517
+ // check `type X = T::Ty;` or `const X: T::Ty;`
518
+ self . visit_middle_ty_by_def_id ( trait_item. owner_id . def_id )
519
+ }
520
+ _ => ( ) ,
521
+ }
522
+
507
523
intravisit:: walk_trait_item ( self , trait_item) ;
508
524
}
509
525
Node :: ImplItem ( impl_item) => {
@@ -525,6 +541,20 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
525
541
_ => { }
526
542
}
527
543
}
544
+
545
+ match impl_item. kind {
546
+ hir:: ImplItemKind :: Fn ( ..) => {
547
+ // check `T::Ty` in the types of inputs and output
548
+ // the result of type_of maybe different from the fn sig,
549
+ // so we also check the fn sig
550
+ self . visit_middle_fn_sig ( impl_item. owner_id . def_id )
551
+ }
552
+ hir:: ImplItemKind :: Type ( ..) | hir:: ImplItemKind :: Const ( ..) => {
553
+ // check `type X = T::Ty;` or `const X: T::Ty;`
554
+ self . visit_middle_ty_by_def_id ( impl_item. owner_id . def_id )
555
+ }
556
+ }
557
+
528
558
intravisit:: walk_impl_item ( self , impl_item) ;
529
559
}
530
560
Node :: ForeignItem ( foreign_item) => {
@@ -587,6 +617,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
587
617
false
588
618
}
589
619
}
620
+
621
+ fn visit_middle_ty ( & mut self , ty : Ty < ' tcx > ) {
622
+ <Self as TypeVisitor < TyCtxt < ' tcx > > >:: visit_ty ( self , ty) ;
623
+ }
624
+
625
+ fn visit_middle_ty_by_def_id ( & mut self , def_id : LocalDefId ) {
626
+ self . visit_middle_ty ( self . tcx . type_of ( def_id) . instantiate_identity ( ) ) ;
627
+ }
628
+
629
+ fn visit_middle_fn_sig ( & mut self , def_id : LocalDefId ) {
630
+ let fn_sig = self . tcx . fn_sig ( def_id) . instantiate_identity ( ) ;
631
+ for ty in fn_sig. inputs ( ) . skip_binder ( ) {
632
+ self . visit_middle_ty ( ty. clone ( ) ) ;
633
+ }
634
+ self . visit_middle_ty ( fn_sig. output ( ) . skip_binder ( ) . clone ( ) ) ;
635
+ }
590
636
}
591
637
592
638
impl < ' tcx > Visitor < ' tcx > for MarkSymbolVisitor < ' tcx > {
@@ -618,6 +664,19 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
618
664
intravisit:: walk_struct_def ( self , def) ;
619
665
}
620
666
667
+ fn visit_field_def ( & mut self , s : & ' tcx rustc_hir:: FieldDef < ' tcx > ) {
668
+ // check `field: T::Ty`
669
+ // marks assoc types live whether the field is not used or not
670
+ // there are three situations:
671
+ // 1. the field is used, it's good
672
+ // 2. the field is not used but marked like `#[allow(dead_code)]`,
673
+ // it's annoying to mark the assoc type `#[allow(dead_code)]` again
674
+ // 3. the field is not used, and will be linted
675
+ // the assoc type will be linted after removing the unused field
676
+ self . visit_middle_ty_by_def_id ( s. def_id ) ;
677
+ intravisit:: walk_field_def ( self , s) ;
678
+ }
679
+
621
680
fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr < ' tcx > ) {
622
681
match expr. kind {
623
682
hir:: ExprKind :: Path ( ref qpath @ hir:: QPath :: TypeRelative ( ..) ) => {
@@ -650,6 +709,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
650
709
_ => ( ) ,
651
710
}
652
711
712
+ // check the expr_ty if its type is `T::Ty`
713
+ self . visit_middle_ty ( self . typeck_results ( ) . expr_ty ( expr) ) ;
714
+
653
715
intravisit:: walk_expr ( self , expr) ;
654
716
}
655
717
@@ -690,6 +752,24 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
690
752
691
753
fn visit_path ( & mut self , path : & hir:: Path < ' tcx > , _: hir:: HirId ) {
692
754
self . handle_res ( path. res ) ;
755
+
756
+ if let Res :: Def ( def_kind, def_id) = path. res
757
+ && matches ! (
758
+ def_kind,
759
+ DefKind :: Fn
760
+ | DefKind :: AssocFn
761
+ | DefKind :: AssocTy
762
+ | DefKind :: Struct
763
+ | DefKind :: Union
764
+ | DefKind :: Enum
765
+ )
766
+ {
767
+ let preds = self . tcx . predicates_of ( def_id) . instantiate_identity ( self . tcx ) ;
768
+ for pred in preds. iter ( ) {
769
+ <Self as TypeVisitor < TyCtxt < ' tcx > > >:: visit_predicate ( self , pred. 0 . as_predicate ( ) ) ;
770
+ }
771
+ }
772
+
693
773
intravisit:: walk_path ( self , path) ;
694
774
}
695
775
@@ -722,6 +802,41 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
722
802
723
803
self . in_pat = in_pat;
724
804
}
805
+
806
+ fn visit_poly_trait_ref ( & mut self , t : & ' tcx hir:: PolyTraitRef < ' tcx > ) {
807
+ // mark the assoc type/const appears in poly-trait-ref live
808
+ if let Some ( pathsegment) = t. trait_ref . path . segments . last ( )
809
+ && let Some ( args) = pathsegment. args
810
+ {
811
+ for constraint in args. constraints {
812
+ if let Some ( item) = self
813
+ . tcx
814
+ . associated_items ( pathsegment. res . def_id ( ) )
815
+ . filter_by_name_unhygienic ( constraint. ident . name )
816
+ . find ( |i| {
817
+ matches ! ( i. kind, ty:: AssocKind :: Const | ty:: AssocKind :: Type )
818
+ && i. ident ( self . tcx ) . normalize_to_macros_2_0 ( ) == constraint. ident
819
+ } )
820
+ && let Some ( local_def_id) = item. def_id . as_local ( )
821
+ {
822
+ self . worklist . push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
823
+ }
824
+ }
825
+ }
826
+ intravisit:: walk_poly_trait_ref ( self , t) ;
827
+ }
828
+ }
829
+
830
+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for MarkSymbolVisitor < ' tcx > {
831
+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) {
832
+ match ty. kind ( ) {
833
+ ty:: Alias ( _, alias) => {
834
+ self . check_def_id ( alias. def_id ) ;
835
+ }
836
+ _ => ( ) ,
837
+ }
838
+ ty. super_visit_with ( self ) ;
839
+ }
725
840
}
726
841
727
842
fn has_allow_dead_code_or_lang_attr (
0 commit comments