@@ -16,7 +16,7 @@ use rustc_hir::{self as hir, Node, PatKind, TyKind};
1616use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
1717use rustc_middle:: middle:: privacy:: Level ;
1818use rustc_middle:: query:: Providers ;
19- use rustc_middle:: ty:: { self , AssocItemContainer , Ty , TyCtxt } ;
19+ use rustc_middle:: ty:: { self , AssocItemContainer , Ty , TyCtxt , TypeSuperVisitable , TypeVisitor } ;
2020use rustc_middle:: { bug, span_bug} ;
2121use rustc_session:: lint;
2222use rustc_session:: lint:: builtin:: DEAD_CODE ;
@@ -113,7 +113,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
113113
114114 fn handle_res ( & mut self , res : Res ) {
115115 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+ ) => {
117120 self . check_def_id ( def_id) ;
118121 }
119122 _ if self . in_pat => { }
@@ -405,6 +408,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
405408 intravisit:: walk_item ( self , item)
406409 }
407410 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+ }
408418 _ => intravisit:: walk_item ( self , item) ,
409419 } ,
410420 Node :: TraitItem ( trait_item) => {
@@ -415,6 +425,20 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
415425 self . check_def_id ( trait_id) ;
416426 }
417427
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+
418442 intravisit:: walk_trait_item ( self , trait_item) ;
419443 }
420444 Node :: ImplItem ( impl_item) => {
@@ -436,6 +460,20 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
436460 _ => { }
437461 }
438462 }
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+
439477 intravisit:: walk_impl_item ( self , impl_item) ;
440478 }
441479 Node :: ForeignItem ( foreign_item) => {
@@ -478,7 +516,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
478516 fn item_should_be_checked ( & mut self , impl_id : hir:: ItemId , local_def_id : LocalDefId ) -> bool {
479517 let trait_def_id = match self . tcx . def_kind ( local_def_id) {
480518 // 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
482520 . tcx
483521 . associated_item ( local_def_id)
484522 . trait_item_def_id
@@ -506,6 +544,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
506544 // the impl/impl item is used if the trait/trait item is used and the ty is used
507545 ty_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true )
508546 }
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+ }
509563}
510564
511565impl < ' tcx > Visitor < ' tcx > for MarkSymbolVisitor < ' tcx > {
@@ -537,6 +591,19 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
537591 intravisit:: walk_struct_def ( self , def) ;
538592 }
539593
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+
540607 fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr < ' tcx > ) {
541608 match expr. kind {
542609 hir:: ExprKind :: Path ( ref qpath @ hir:: QPath :: TypeRelative ( ..) ) => {
@@ -569,6 +636,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
569636 _ => ( ) ,
570637 }
571638
639+ // check the expr_ty if its type is `T::Ty`
640+ self . visit_middle_ty ( self . typeck_results ( ) . expr_ty ( expr) ) ;
641+
572642 intravisit:: walk_expr ( self , expr) ;
573643 }
574644
@@ -590,6 +660,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
590660 self . handle_field_pattern_match ( pat, res, fields) ;
591661 }
592662 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+ }
593666 let res = self . typeck_results ( ) . qpath_res ( qpath, pat. hir_id ) ;
594667 self . handle_res ( res) ;
595668 }
@@ -606,6 +679,24 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
606679
607680 fn visit_path ( & mut self , path : & hir:: Path < ' tcx > , _: hir:: HirId ) {
608681 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+
609700 intravisit:: walk_path ( self , path) ;
610701 }
611702
@@ -638,6 +729,41 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
638729
639730 self . in_pat = in_pat;
640731 }
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+ }
641767}
642768
643769fn has_allow_dead_code_or_lang_attr (
@@ -648,6 +774,7 @@ fn has_allow_dead_code_or_lang_attr(
648774 tcx. has_attr ( def_id, sym:: lang)
649775 // Stable attribute for #[lang = "panic_impl"]
650776 || tcx. has_attr ( def_id, sym:: panic_handler)
777+ || tcx. has_attr ( def_id, sym:: async_fn_kind_upvars)
651778 }
652779
653780 fn has_allow_expect_dead_code ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> bool {
@@ -736,10 +863,7 @@ fn check_item<'tcx>(
736863
737864 // And we access the Map here to get HirId from LocalDefId
738865 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)
743867 {
744868 worklist. push ( ( local_def_id, comes_from_allow) ) ;
745869 } else if of_trait {
@@ -768,10 +892,13 @@ fn check_trait_item(
768892 worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
769893 id : hir:: TraitItemId ,
770894) {
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+ ) {
773900 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 ( ..) )
775902 && let Some ( comes_from_allow) =
776903 has_allow_dead_code_or_lang_attr ( tcx, trait_item. owner_id . def_id )
777904 {
@@ -813,7 +940,7 @@ fn create_and_seed_worklist(
813940 // checks impls and impl-items later
814941 match tcx. def_kind ( id) {
815942 DefKind :: Impl { of_trait } => !of_trait,
816- DefKind :: AssocFn => {
943+ DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: AssocFn => {
817944 // still check public trait items, and impl items not of trait
818945 let assoc_item = tcx. associated_item ( id) ;
819946 !matches ! ( assoc_item. container, AssocItemContainer :: ImplContainer )
@@ -1104,6 +1231,7 @@ impl<'tcx> DeadVisitor<'tcx> {
11041231 }
11051232 match self . tcx . def_kind ( def_id) {
11061233 DefKind :: AssocConst
1234+ | DefKind :: AssocTy
11071235 | DefKind :: AssocFn
11081236 | DefKind :: Fn
11091237 | DefKind :: Static { .. }
0 commit comments