@@ -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
@@ -722,6 +784,41 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
722
784
723
785
self . in_pat = in_pat;
724
786
}
787
+
788
+ fn visit_poly_trait_ref ( & mut self , t : & ' tcx hir:: PolyTraitRef < ' tcx > ) {
789
+ // mark the assoc type/const appears in poly-trait-ref live
790
+ if let Some ( pathsegment) = t. trait_ref . path . segments . last ( )
791
+ && let Some ( args) = pathsegment. args
792
+ {
793
+ for constraint in args. constraints {
794
+ if let Some ( item) = self
795
+ . tcx
796
+ . associated_items ( pathsegment. res . def_id ( ) )
797
+ . filter_by_name_unhygienic ( constraint. ident . name )
798
+ . find ( |i| {
799
+ matches ! ( i. kind, ty:: AssocKind :: Const | ty:: AssocKind :: Type )
800
+ && i. ident ( self . tcx ) . normalize_to_macros_2_0 ( ) == constraint. ident
801
+ } )
802
+ && let Some ( local_def_id) = item. def_id . as_local ( )
803
+ {
804
+ self . worklist . push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
805
+ }
806
+ }
807
+ }
808
+ intravisit:: walk_poly_trait_ref ( self , t) ;
809
+ }
810
+ }
811
+
812
+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for MarkSymbolVisitor < ' tcx > {
813
+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) {
814
+ match ty. kind ( ) {
815
+ ty:: Alias ( _, alias) => {
816
+ self . check_def_id ( alias. def_id ) ;
817
+ }
818
+ _ => ( ) ,
819
+ }
820
+ ty. super_visit_with ( self ) ;
821
+ }
725
822
}
726
823
727
824
fn has_allow_dead_code_or_lang_attr (
0 commit comments