@@ -17,7 +17,7 @@ use rustc_hir::{self as hir, Node, PatKind, QPath};
1717use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
1818use rustc_middle:: middle:: privacy:: Level ;
1919use rustc_middle:: query:: Providers ;
20- use rustc_middle:: ty:: { self , AssocTag , TyCtxt } ;
20+ use rustc_middle:: ty:: { self , AssocTag , Ty , TyCtxt , TypeSuperVisitable , TypeVisitor } ;
2121use rustc_middle:: { bug, span_bug} ;
2222use rustc_session:: lint:: builtin:: DEAD_CODE ;
2323use rustc_session:: lint:: { self , LintExpectationId } ;
@@ -110,6 +110,56 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
110110 }
111111 }
112112
113+ fn check_assoc_ty ( & mut self , def_id : LocalDefId ) {
114+ let def_kind = self . tcx . def_kind ( def_id) ;
115+
116+ match def_kind {
117+ // Check `T::Ty` used in types of inputs and output
118+ DefKind :: Fn | DefKind :: AssocFn => {
119+ let fn_sig = self . tcx . fn_sig ( def_id) . instantiate_identity ( ) ;
120+ for ty in fn_sig. inputs ( ) . skip_binder ( ) {
121+ self . visit_middle_ty ( ty. clone ( ) ) ;
122+ }
123+ self . visit_middle_ty ( fn_sig. output ( ) . skip_binder ( ) . clone ( ) ) ;
124+ }
125+ // Check `T::Ty` used in assoc type
126+ DefKind :: AssocTy => {
127+ if matches ! ( self . tcx. def_kind( self . tcx. local_parent( def_id) ) , DefKind :: Impl { .. } )
128+ || matches ! (
129+ self . tcx. hir_expect_trait_item( def_id) . kind,
130+ hir:: TraitItemKind :: Type ( _, Some ( _) )
131+ )
132+ {
133+ self . visit_middle_ty ( self . tcx . type_of ( def_id) . instantiate_identity ( ) ) ;
134+ }
135+ }
136+ // Check `T::Ty` used in assoc const's type
137+ DefKind :: AssocConst => {
138+ self . visit_middle_ty ( self . tcx . type_of ( def_id) . instantiate_identity ( ) ) ;
139+ }
140+ _ => ( ) ,
141+ }
142+
143+ if matches ! (
144+ def_kind,
145+ DefKind :: Struct
146+ | DefKind :: Union
147+ | DefKind :: Enum
148+ | DefKind :: Fn
149+ | DefKind :: Const
150+ | DefKind :: Trait
151+ | DefKind :: Impl { .. }
152+ | DefKind :: AssocFn
153+ | DefKind :: AssocTy
154+ | DefKind :: AssocConst
155+ ) {
156+ let preds = self . tcx . predicates_of ( def_id) . instantiate_identity ( self . tcx ) ;
157+ for pred in preds. iter ( ) {
158+ <Self as TypeVisitor < TyCtxt < ' tcx > > >:: visit_predicate ( self , pred. 0 . as_predicate ( ) ) ;
159+ }
160+ }
161+ }
162+
113163 fn insert_def_id ( & mut self , def_id : DefId ) {
114164 if let Some ( def_id) = def_id. as_local ( ) {
115165 debug_assert ! ( !should_explore( self . tcx, def_id) ) ;
@@ -119,12 +169,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
119169
120170 fn handle_res ( & mut self , res : Res ) {
121171 match res {
122- Res :: Def (
123- DefKind :: Const | DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: TyAlias ,
124- def_id,
125- ) => {
126- self . check_def_id ( def_id) ;
127- }
128172 Res :: PrimTy ( ..) | Res :: SelfCtor ( ..) | Res :: Local ( ..) => { }
129173 Res :: Def ( DefKind :: Ctor ( CtorOf :: Variant , ..) , ctor_def_id) => {
130174 // Using a variant in patterns should not make the variant live,
@@ -376,6 +420,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
376420 continue ;
377421 }
378422
423+ self . check_assoc_ty ( id) ;
379424 self . visit_node ( self . tcx . hir_node_by_def_id ( id) ) ?;
380425 }
381426
@@ -429,15 +474,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
429474 intravisit:: walk_item ( self , item)
430475 }
431476 hir:: ItemKind :: ForeignMod { .. } => ControlFlow :: Continue ( ( ) ) ,
432- hir:: ItemKind :: Trait ( .., trait_item_refs) => {
433- // mark assoc ty live if the trait is live
434- for trait_item in trait_item_refs {
435- if matches ! ( self . tcx. def_kind( trait_item. owner_id) , DefKind :: AssocTy ) {
436- self . check_def_id ( trait_item. owner_id . to_def_id ( ) ) ;
437- }
438- }
439- intravisit:: walk_item ( self , item)
440- }
441477 _ => intravisit:: walk_item ( self , item) ,
442478 } ,
443479 Node :: TraitItem ( trait_item) => {
@@ -523,6 +559,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
523559
524560 true
525561 }
562+
563+ fn visit_middle_ty ( & mut self , ty : Ty < ' tcx > ) {
564+ <Self as TypeVisitor < TyCtxt < ' tcx > > >:: visit_ty ( self , ty) ;
565+ }
526566}
527567
528568impl < ' tcx > Visitor < ' tcx > for MarkSymbolVisitor < ' tcx > {
@@ -600,6 +640,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
600640 _ => ( ) ,
601641 }
602642
643+ // Check `T::Ty` used in the type of `expr`
644+ self . visit_middle_ty ( self . typeck_results ( ) . expr_ty ( expr) ) ;
645+
603646 intravisit:: walk_expr ( self , expr)
604647 }
605648
@@ -687,16 +730,16 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
687730 && let Some ( segment) = t. path . segments . last ( )
688731 && let Some ( args) = segment. args
689732 {
733+ // Mark assoc items used if they are constrained in the trait ref
690734 for constraint in args. constraints {
691735 if let Some ( local_def_id) = self
692736 . tcx
693737 . associated_items ( trait_def_id)
694- . find_by_ident_and_kind (
695- self . tcx ,
696- constraint. ident ,
697- AssocTag :: Const ,
698- trait_def_id,
699- )
738+ . filter_by_name_unhygienic ( constraint. ident . name )
739+ . filter ( |item| matches ! ( item. as_tag( ) , AssocTag :: Const | AssocTag :: Type ) )
740+ . find ( |item| {
741+ self . tcx . hygienic_eq ( constraint. ident , item. ident ( self . tcx ) , trait_def_id)
742+ } )
700743 . and_then ( |item| item. def_id . as_local ( ) )
701744 {
702745 self . worklist . push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
@@ -706,6 +749,30 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
706749
707750 intravisit:: walk_trait_ref ( self , t)
708751 }
752+
753+ fn visit_field_def ( & mut self , field_def : & ' tcx hir:: FieldDef < ' tcx > ) -> Self :: Result {
754+ // Check `T::Ty` used in field's type, marks assoc types live whether the field is used or not
755+ // Consider that there would be three situations:
756+ // 1. `field` is used, it's good
757+ // 2. `field` is not used but marked like `#[allow(dead_code)]`,
758+ // it's annoying to mark the assoc type `#[allow(dead_code)]` again
759+ // 3. `field` is not used and will be linted,
760+ // the assoc type will be linted after removing the unused field
761+ self . visit_middle_ty ( self . tcx . type_of ( field_def. def_id ) . instantiate_identity ( ) ) ;
762+ intravisit:: walk_field_def ( self , field_def)
763+ }
764+ }
765+
766+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for MarkSymbolVisitor < ' tcx > {
767+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) {
768+ match ty. kind ( ) {
769+ ty:: Alias ( _, alias) => {
770+ self . check_def_id ( alias. def_id ) ;
771+ }
772+ _ => ( ) ,
773+ }
774+ ty. super_visit_with ( self ) ;
775+ }
709776}
710777
711778fn has_allow_dead_code_or_lang_attr (
0 commit comments