@@ -17,7 +17,7 @@ use rustc_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 , TyCtxt } ;
20
+ use rustc_middle:: ty:: { self , AssocItemContainer , Ty , TyCtxt , TypeSuperVisitable , TypeVisitor } ;
21
21
use rustc_middle:: { bug, span_bug} ;
22
22
use rustc_session:: lint;
23
23
use rustc_session:: lint:: builtin:: DEAD_CODE ;
@@ -465,7 +465,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
465
465
intravisit:: walk_item ( self , item)
466
466
}
467
467
hir:: ItemKind :: ForeignMod { .. } => { }
468
- hir:: ItemKind :: Trait ( _ , _ , _ , _ , trait_item_refs ) => {
468
+ hir:: ItemKind :: Trait ( .. ) => {
469
469
for impl_def_id in self . tcx . all_impls ( item. owner_id . to_def_id ( ) ) {
470
470
if let Some ( local_def_id) = impl_def_id. as_local ( )
471
471
&& let ItemKind :: Impl ( impl_ref) =
@@ -478,12 +478,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
478
478
intravisit:: walk_path ( self , impl_ref. of_trait . unwrap ( ) . path ) ;
479
479
}
480
480
}
481
- // mark assoc ty live if the trait is live
482
- for trait_item in trait_item_refs {
483
- if let hir:: AssocItemKind :: Type = trait_item. kind {
484
- self . check_def_id ( trait_item. id . owner_id . to_def_id ( ) ) ;
485
- }
486
- }
481
+ intravisit:: walk_item ( self , item)
482
+ }
483
+ hir:: ItemKind :: Fn ( ..) => {
484
+ // check `T::Ty` in the types of inputs and output
485
+ // the result of type_of maybe different from the fn sig,
486
+ // so we also check the fn sig
487
+ self . visit_middle_fn_sig ( item. owner_id . def_id ) ;
487
488
intravisit:: walk_item ( self , item)
488
489
}
489
490
_ => intravisit:: walk_item ( self , item) ,
@@ -519,6 +520,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
519
520
}
520
521
}
521
522
}
523
+
524
+ match trait_item. kind {
525
+ hir:: TraitItemKind :: Fn ( ..) => {
526
+ // check `T::Ty` in the types of inputs and output
527
+ // the result of type_of maybe different from the fn sig,
528
+ // so we also check the fn sig
529
+ self . visit_middle_fn_sig ( trait_item. owner_id . def_id )
530
+ }
531
+ hir:: TraitItemKind :: Type ( .., Some ( _) ) | hir:: TraitItemKind :: Const ( ..) => {
532
+ // check `type X = T::Ty;` or `const X: T::Ty;`
533
+ self . visit_middle_ty_by_def_id ( trait_item. owner_id . def_id )
534
+ }
535
+ _ => ( ) ,
536
+ }
537
+
522
538
intravisit:: walk_trait_item ( self , trait_item) ;
523
539
}
524
540
Node :: ImplItem ( impl_item) => {
@@ -540,6 +556,20 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
540
556
_ => { }
541
557
}
542
558
}
559
+
560
+ match impl_item. kind {
561
+ hir:: ImplItemKind :: Fn ( ..) => {
562
+ // check `T::Ty` in the types of inputs and output
563
+ // the result of type_of maybe different from the fn sig,
564
+ // so we also check the fn sig
565
+ self . visit_middle_fn_sig ( impl_item. owner_id . def_id )
566
+ }
567
+ hir:: ImplItemKind :: Type ( ..) | hir:: ImplItemKind :: Const ( ..) => {
568
+ // check `type X = T::Ty;` or `const X: T::Ty;`
569
+ self . visit_middle_ty_by_def_id ( impl_item. owner_id . def_id )
570
+ }
571
+ }
572
+
543
573
intravisit:: walk_impl_item ( self , impl_item) ;
544
574
}
545
575
Node :: ForeignItem ( foreign_item) => {
@@ -600,6 +630,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
600
630
false
601
631
}
602
632
}
633
+
634
+ fn visit_middle_ty ( & mut self , ty : Ty < ' tcx > ) {
635
+ <Self as TypeVisitor < TyCtxt < ' tcx > > >:: visit_ty ( self , ty) ;
636
+ }
637
+
638
+ fn visit_middle_ty_by_def_id ( & mut self , def_id : LocalDefId ) {
639
+ self . visit_middle_ty ( self . tcx . type_of ( def_id) . instantiate_identity ( ) ) ;
640
+ }
641
+
642
+ fn visit_middle_fn_sig ( & mut self , def_id : LocalDefId ) {
643
+ let fn_sig = self . tcx . fn_sig ( def_id) . instantiate_identity ( ) ;
644
+ for ty in fn_sig. inputs ( ) . skip_binder ( ) {
645
+ self . visit_middle_ty ( ty. clone ( ) ) ;
646
+ }
647
+ self . visit_middle_ty ( fn_sig. output ( ) . skip_binder ( ) . clone ( ) ) ;
648
+ }
603
649
}
604
650
605
651
impl < ' tcx > Visitor < ' tcx > for MarkSymbolVisitor < ' tcx > {
@@ -631,6 +677,19 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
631
677
intravisit:: walk_struct_def ( self , def) ;
632
678
}
633
679
680
+ fn visit_field_def ( & mut self , s : & ' tcx rustc_hir:: FieldDef < ' tcx > ) {
681
+ // check `field: T::Ty`
682
+ // marks assoc types live whether the field is not used or not
683
+ // there are three situations:
684
+ // 1. the field is used, it's good
685
+ // 2. the field is not used but marked like `#[allow(dead_code)]`,
686
+ // it's annoying to mark the assoc type `#[allow(dead_code)]` again
687
+ // 3. the field is not used, and will be linted
688
+ // the assoc type will be linted after removing the unused field
689
+ self . visit_middle_ty_by_def_id ( s. def_id ) ;
690
+ intravisit:: walk_field_def ( self , s) ;
691
+ }
692
+
634
693
fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr < ' tcx > ) {
635
694
match expr. kind {
636
695
hir:: ExprKind :: Path ( ref qpath @ hir:: QPath :: TypeRelative ( ..) ) => {
@@ -663,6 +722,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
663
722
_ => ( ) ,
664
723
}
665
724
725
+ // check the expr_ty if its type is `T::Ty`
726
+ self . visit_middle_ty ( self . typeck_results ( ) . expr_ty ( expr) ) ;
727
+
666
728
intravisit:: walk_expr ( self , expr) ;
667
729
}
668
730
@@ -703,6 +765,24 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
703
765
704
766
fn visit_path ( & mut self , path : & hir:: Path < ' tcx > , _: hir:: HirId ) {
705
767
self . handle_res ( path. res ) ;
768
+
769
+ if let Res :: Def ( def_kind, def_id) = path. res
770
+ && matches ! (
771
+ def_kind,
772
+ DefKind :: Fn
773
+ | DefKind :: AssocFn
774
+ | DefKind :: AssocTy
775
+ | DefKind :: Struct
776
+ | DefKind :: Union
777
+ | DefKind :: Enum
778
+ )
779
+ {
780
+ let preds = self . tcx . predicates_of ( def_id) . instantiate_identity ( self . tcx ) ;
781
+ for pred in preds. iter ( ) {
782
+ <Self as TypeVisitor < TyCtxt < ' tcx > > >:: visit_predicate ( self , pred. 0 . as_predicate ( ) ) ;
783
+ }
784
+ }
785
+
706
786
intravisit:: walk_path ( self , path) ;
707
787
}
708
788
@@ -735,6 +815,41 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
735
815
736
816
self . in_pat = in_pat;
737
817
}
818
+
819
+ fn visit_poly_trait_ref ( & mut self , t : & ' tcx hir:: PolyTraitRef < ' tcx > ) {
820
+ // mark the assoc type/const appears in poly-trait-ref live
821
+ if let Some ( pathsegment) = t. trait_ref . path . segments . last ( )
822
+ && let Some ( args) = pathsegment. args
823
+ {
824
+ for constraint in args. constraints {
825
+ if let Some ( item) = self
826
+ . tcx
827
+ . associated_items ( pathsegment. res . def_id ( ) )
828
+ . filter_by_name_unhygienic ( constraint. ident . name )
829
+ . find ( |i| {
830
+ matches ! ( i. kind, ty:: AssocKind :: Const | ty:: AssocKind :: Type )
831
+ && i. ident ( self . tcx ) . normalize_to_macros_2_0 ( ) == constraint. ident
832
+ } )
833
+ && let Some ( local_def_id) = item. def_id . as_local ( )
834
+ {
835
+ self . worklist . push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
836
+ }
837
+ }
838
+ }
839
+ intravisit:: walk_poly_trait_ref ( self , t) ;
840
+ }
841
+ }
842
+
843
+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for MarkSymbolVisitor < ' tcx > {
844
+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) {
845
+ match ty. kind ( ) {
846
+ ty:: Alias ( _, alias) => {
847
+ self . check_def_id ( alias. def_id ) ;
848
+ }
849
+ _ => ( ) ,
850
+ }
851
+ ty. super_visit_with ( self ) ;
852
+ }
738
853
}
739
854
740
855
fn has_allow_dead_code_or_lang_attr (
0 commit comments