@@ -10,14 +10,12 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
1010use rustc_hir:: def_id:: { DefId , LocalDefId } ;
1111use rustc_hir:: intravisit:: { self , Visitor } ;
1212use rustc_hir:: { Node , PatKind , TyKind } ;
13- use rustc_middle:: hir:: nested_filter;
1413use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
1514use rustc_middle:: middle:: privacy;
1615use rustc_middle:: ty:: query:: Providers ;
1716use rustc_middle:: ty:: { self , DefIdTree , TyCtxt } ;
1817use rustc_session:: lint;
1918use rustc_span:: symbol:: { sym, Symbol } ;
20- use rustc_span:: Span ;
2119use std:: mem;
2220
2321// Any local node that may call something in its body block should be
@@ -647,41 +645,16 @@ struct DeadVisitor<'tcx> {
647645}
648646
649647impl < ' tcx > DeadVisitor < ' tcx > {
650- fn should_warn_about_item ( & mut self , item : & hir:: Item < ' _ > ) -> bool {
651- let should_warn = matches ! (
652- item. kind,
653- hir:: ItemKind :: Static ( ..)
654- | hir:: ItemKind :: Const ( ..)
655- | hir:: ItemKind :: Fn ( ..)
656- | hir:: ItemKind :: TyAlias ( ..)
657- | hir:: ItemKind :: Enum ( ..)
658- | hir:: ItemKind :: Struct ( ..)
659- | hir:: ItemKind :: Union ( ..)
660- ) ;
661- should_warn && !self . symbol_is_live ( item. def_id )
662- }
663-
664- fn should_warn_about_field ( & mut self , field : & hir:: FieldDef < ' _ > ) -> bool {
665- let def_id = self . tcx . hir ( ) . local_def_id ( field. hir_id ) ;
666- let field_type = self . tcx . type_of ( def_id) ;
667- !field. is_positional ( )
668- && !self . symbol_is_live ( def_id)
669- && !field_type. is_phantom_data ( )
670- && !has_allow_dead_code_or_lang_attr ( self . tcx , field. hir_id )
671- }
672-
673- fn should_warn_about_variant ( & mut self , variant : & hir:: Variant < ' _ > ) -> bool {
674- let def_id = self . tcx . hir ( ) . local_def_id ( variant. id ) ;
675- !self . symbol_is_live ( def_id) && !has_allow_dead_code_or_lang_attr ( self . tcx , variant. id )
676- }
677-
678- fn should_warn_about_foreign_item ( & mut self , fi : & hir:: ForeignItem < ' _ > ) -> bool {
679- !self . symbol_is_live ( fi. def_id ) && !has_allow_dead_code_or_lang_attr ( self . tcx , fi. hir_id ( ) )
680- }
681-
682- // id := HIR id of an item's definition.
683- fn symbol_is_live ( & mut self , def_id : LocalDefId ) -> bool {
684- self . live_symbols . contains ( & def_id)
648+ fn should_warn_about_field ( & mut self , field : & ty:: FieldDef ) -> bool {
649+ if self . live_symbols . contains ( & field. did . expect_local ( ) ) {
650+ return false ;
651+ }
652+ let is_positional = field. name . as_str ( ) . starts_with ( |c : char | c. is_ascii_digit ( ) ) ;
653+ if is_positional {
654+ return false ;
655+ }
656+ let field_type = self . tcx . type_of ( field. did ) ;
657+ !field_type. is_phantom_data ( )
685658 }
686659
687660 fn warn_multiple_dead_codes (
@@ -790,154 +763,102 @@ impl<'tcx> DeadVisitor<'tcx> {
790763 }
791764
792765 fn warn_dead_code ( & mut self , id : LocalDefId , participle : & str ) {
793- if self . tcx . item_name ( id. to_def_id ( ) ) . as_str ( ) . starts_with ( '_' ) {
794- return ;
795- }
796766 self . warn_multiple_dead_codes ( & [ id] , participle, None ) ;
797767 }
798- }
799768
800- impl < ' tcx > Visitor < ' tcx > for DeadVisitor < ' tcx > {
801- type NestedFilter = nested_filter:: All ;
802-
803- /// Walk nested items in place so that we don't report dead-code
804- /// on inner functions when the outer function is already getting
805- /// an error. We could do this also by checking the parents, but
806- /// this is how the code is setup and it seems harmless enough.
807- fn nested_visit_map ( & mut self ) -> Self :: Map {
808- self . tcx . hir ( )
809- }
810-
811- fn visit_item ( & mut self , item : & ' tcx hir:: Item < ' tcx > ) {
812- if self . should_warn_about_item ( item) {
813- // For most items, we want to highlight its identifier
814- let participle = match item. kind {
815- hir:: ItemKind :: Struct ( ..) => "constructed" , // Issue #52325
816- _ => "used" ,
817- } ;
818- self . warn_dead_code ( item. def_id , participle) ;
819- } else {
820- // Only continue if we didn't warn
821- intravisit:: walk_item ( self , item) ;
769+ fn check_definition ( & mut self , def_id : LocalDefId ) {
770+ if self . live_symbols . contains ( & def_id) {
771+ return ;
822772 }
823- }
824-
825- // This visitor should only visit a single module at a time.
826- fn visit_mod ( & mut self , _: & ' tcx hir:: Mod < ' tcx > , _: Span , _: hir:: HirId ) { }
827-
828- fn visit_enum_def (
829- & mut self ,
830- enum_definition : & ' tcx hir:: EnumDef < ' tcx > ,
831- generics : & ' tcx hir:: Generics < ' tcx > ,
832- item_id : hir:: HirId ,
833- _: Span ,
834- ) {
835- intravisit:: walk_enum_def ( self , enum_definition, generics, item_id) ;
836- let dead_variants = enum_definition
837- . variants
838- . iter ( )
839- . filter_map ( |variant| {
840- if self . should_warn_about_variant ( & variant) {
841- Some ( DeadVariant {
842- def_id : self . tcx . hir ( ) . local_def_id ( variant. id ) ,
843- name : variant. ident . name ,
844- level : self . tcx . lint_level_at_node ( lint:: builtin:: DEAD_CODE , variant. id ) . 0 ,
845- } )
846- } else {
847- None
848- }
849- } )
850- . collect ( ) ;
851- self . warn_dead_fields_and_variants ( item_id. expect_owner ( ) , "constructed" , dead_variants)
852- }
853-
854- fn visit_variant (
855- & mut self ,
856- variant : & ' tcx hir:: Variant < ' tcx > ,
857- g : & ' tcx hir:: Generics < ' tcx > ,
858- id : hir:: HirId ,
859- ) {
860- if !self . should_warn_about_variant ( & variant) {
861- intravisit:: walk_variant ( self , variant, g, id) ;
773+ let hir_id = self . tcx . hir ( ) . local_def_id_to_hir_id ( def_id) ;
774+ if has_allow_dead_code_or_lang_attr ( self . tcx , hir_id) {
775+ return ;
862776 }
863- }
864-
865- fn visit_foreign_item ( & mut self , fi : & ' tcx hir:: ForeignItem < ' tcx > ) {
866- if self . should_warn_about_foreign_item ( fi) {
867- self . warn_dead_code ( fi. def_id , "used" ) ;
777+ let Some ( name) = self . tcx . opt_item_name ( def_id. to_def_id ( ) ) else {
778+ return
779+ } ;
780+ if name. as_str ( ) . starts_with ( '_' ) {
781+ return ;
782+ }
783+ match self . tcx . def_kind ( def_id) {
784+ DefKind :: AssocConst
785+ | DefKind :: AssocFn
786+ | DefKind :: Fn
787+ | DefKind :: Static ( _)
788+ | DefKind :: Const
789+ | DefKind :: TyAlias
790+ | DefKind :: Enum
791+ | DefKind :: Union
792+ | DefKind :: ForeignTy => self . warn_dead_code ( def_id, "used" ) ,
793+ DefKind :: Struct => self . warn_dead_code ( def_id, "constructed" ) ,
794+ DefKind :: Variant | DefKind :: Field => bug ! ( "should be handled specially" ) ,
795+ _ => { }
868796 }
869- intravisit:: walk_foreign_item ( self , fi) ;
870797 }
798+ }
871799
872- fn visit_variant_data (
873- & mut self ,
874- def : & ' tcx hir:: VariantData < ' tcx > ,
875- _: Symbol ,
876- _: & hir:: Generics < ' _ > ,
877- id : hir:: HirId ,
878- _: rustc_span:: Span ,
879- ) {
880- intravisit:: walk_struct_def ( self , def) ;
881- let dead_fields = def
882- . fields ( )
883- . iter ( )
884- . filter_map ( |field| {
885- if self . should_warn_about_field ( & field) {
886- Some ( DeadVariant {
887- def_id : self . tcx . hir ( ) . local_def_id ( field. hir_id ) ,
888- name : field. ident . name ,
889- level : self
890- . tcx
891- . lint_level_at_node ( lint:: builtin:: DEAD_CODE , field. hir_id )
892- . 0 ,
893- } )
894- } else {
895- None
896- }
897- } )
898- . collect ( ) ;
899- self . warn_dead_fields_and_variants ( self . tcx . hir ( ) . local_def_id ( id) , "read" , dead_fields)
900- }
800+ fn check_mod_deathness ( tcx : TyCtxt < ' _ > , module : LocalDefId ) {
801+ let ( live_symbols, ignored_derived_traits) = tcx. live_symbols_and_ignored_derived_traits ( ( ) ) ;
802+ let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits } ;
901803
902- fn visit_impl_item ( & mut self , impl_item : & ' tcx hir:: ImplItem < ' tcx > ) {
903- match impl_item. kind {
904- hir:: ImplItemKind :: Const ( _, body_id) => {
905- if !self . symbol_is_live ( impl_item. def_id ) {
906- self . warn_dead_code ( impl_item. def_id , "used" ) ;
907- }
908- self . visit_nested_body ( body_id)
804+ let module_items = tcx. hir_module_items ( module) ;
805+
806+ for item in module_items. items ( ) {
807+ if !live_symbols. contains ( & item. def_id ) {
808+ let parent = tcx. local_parent ( item. def_id ) ;
809+ if parent != module && !live_symbols. contains ( & parent) {
810+ // We already have diagnosed something.
811+ continue ;
909812 }
910- hir:: ImplItemKind :: Fn ( _, body_id) => {
911- if !self . symbol_is_live ( impl_item. def_id ) {
912- self . warn_dead_code ( impl_item. def_id , "used" ) ;
813+ visitor. check_definition ( item. def_id ) ;
814+ continue ;
815+ }
816+
817+ let def_kind = tcx. def_kind ( item. def_id ) ;
818+ if let DefKind :: Struct | DefKind :: Union | DefKind :: Enum = def_kind {
819+ let adt = tcx. adt_def ( item. def_id ) ;
820+ let mut dead_variants = Vec :: new ( ) ;
821+
822+ for variant in adt. variants ( ) {
823+ let def_id = variant. def_id . expect_local ( ) ;
824+ if !live_symbols. contains ( & def_id) {
825+ // Record to group diagnostics.
826+ let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def_id) ;
827+ let level = tcx. lint_level_at_node ( lint:: builtin:: DEAD_CODE , hir_id) . 0 ;
828+ dead_variants. push ( DeadVariant { def_id, name : variant. name , level } ) ;
829+ continue ;
913830 }
914- self . visit_nested_body ( body_id)
831+
832+ let dead_fields = variant
833+ . fields
834+ . iter ( )
835+ . filter_map ( |field| {
836+ let def_id = field. did . expect_local ( ) ;
837+ let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def_id) ;
838+ if visitor. should_warn_about_field ( & field) {
839+ let level = tcx. lint_level_at_node ( lint:: builtin:: DEAD_CODE , hir_id) . 0 ;
840+ Some ( DeadVariant { def_id, name : field. name , level } )
841+ } else {
842+ None
843+ }
844+ } )
845+ . collect ( ) ;
846+ visitor. warn_dead_fields_and_variants ( def_id, "read" , dead_fields)
915847 }
916- hir:: ImplItemKind :: TyAlias ( ..) => { }
848+
849+ visitor. warn_dead_fields_and_variants ( item. def_id , "constructed" , dead_variants) ;
917850 }
918851 }
919852
920- // Overwrite so that we don't warn the trait item itself.
921- fn visit_trait_item ( & mut self , trait_item : & ' tcx hir:: TraitItem < ' tcx > ) {
922- match trait_item. kind {
923- hir:: TraitItemKind :: Const ( _, Some ( body_id) )
924- | hir:: TraitItemKind :: Fn ( _, hir:: TraitFn :: Provided ( body_id) ) => {
925- self . visit_nested_body ( body_id)
926- }
927- hir:: TraitItemKind :: Const ( _, None )
928- | hir:: TraitItemKind :: Fn ( _, hir:: TraitFn :: Required ( _) )
929- | hir:: TraitItemKind :: Type ( ..) => { }
930- }
853+ for impl_item in module_items. impl_items ( ) {
854+ visitor. check_definition ( impl_item. def_id ) ;
931855 }
932- }
933856
934- fn check_mod_deathness ( tcx : TyCtxt < ' _ > , module : LocalDefId ) {
935- let ( live_symbols, ignored_derived_traits) = tcx. live_symbols_and_ignored_derived_traits ( ( ) ) ;
936- let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits } ;
937- let ( module, _, module_id) = tcx. hir ( ) . get_module ( module) ;
938- // Do not use an ItemLikeVisitor since we may want to skip visiting some items
939- // when a surrounding one is warned against or `_`.
940- intravisit:: walk_mod ( & mut visitor, module, module_id) ;
857+ for foreign_item in module_items. foreign_items ( ) {
858+ visitor. check_definition ( foreign_item. def_id ) ;
859+ }
860+
861+ // We do not warn trait items.
941862}
942863
943864pub ( crate ) fn provide ( providers : & mut Providers ) {
0 commit comments