1- // This implements the dead-code warning pass. It follows middle::reachable
2- // closely. The idea is that all reachable symbols are live, codes called
3- // from live codes are live, and everything else is dead.
1+ // This implements the dead-code warning pass.
2+ // All reachable symbols are live, code called from live code is live, code with certain lint
3+ // expectations such as `#[expect(unused)]` and `#[expect(dead_code)]` is live, and everything else
4+ // is dead.
45
56use hir:: def_id:: { LocalDefIdMap , LocalDefIdSet } ;
67use itertools:: Itertools ;
@@ -747,7 +748,7 @@ fn live_symbols_and_ignored_derived_traits(
747748 ( symbol_visitor. live_symbols , symbol_visitor. ignored_derived_traits )
748749}
749750
750- struct DeadVariant {
751+ struct DeadItem {
751752 def_id : LocalDefId ,
752753 name : Symbol ,
753754 level : lint:: Level ,
@@ -785,7 +786,13 @@ impl<'tcx> DeadVisitor<'tcx> {
785786 ShouldWarnAboutField :: Yes ( is_positional)
786787 }
787788
788- fn warn_multiple_dead_codes (
789+ // # Panics
790+ // All `dead_codes` must have the same lint level, otherwise we will intentionally ICE.
791+ // This is because we emit a multi-spanned lint using the lint level of the `dead_codes`'s
792+ // first local def id.
793+ // Prefer calling `Self.warn_dead_code` or `Self.warn_dead_code_grouped_by_lint_level`
794+ // since those methods group by lint level before calling this method.
795+ fn lint_at_single_level (
789796 & self ,
790797 dead_codes : & [ LocalDefId ] ,
791798 participle : & str ,
@@ -796,6 +803,15 @@ impl<'tcx> DeadVisitor<'tcx> {
796803 return ;
797804 } ;
798805 let tcx = self . tcx ;
806+
807+ let first_hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( first_id) ;
808+ let first_lint_level = tcx. lint_level_at_node ( lint:: builtin:: DEAD_CODE , first_hir_id) . 0 ;
809+ assert ! ( dead_codes. iter( ) . skip( 1 ) . all( |id| {
810+ let hir_id = tcx. hir( ) . local_def_id_to_hir_id( * id) ;
811+ let level = tcx. lint_level_at_node( lint:: builtin:: DEAD_CODE , hir_id) . 0 ;
812+ level == first_lint_level
813+ } ) ) ;
814+
799815 let names: Vec < _ > =
800816 dead_codes. iter ( ) . map ( |& def_id| tcx. item_name ( def_id. to_def_id ( ) ) ) . collect ( ) ;
801817 let spans: Vec < _ > = dead_codes
@@ -876,31 +892,26 @@ impl<'tcx> DeadVisitor<'tcx> {
876892 }
877893 } ;
878894
879- self . tcx . emit_spanned_lint (
880- lint,
881- tcx. hir ( ) . local_def_id_to_hir_id ( first_id) ,
882- MultiSpan :: from_spans ( spans) ,
883- diag,
884- ) ;
895+ self . tcx . emit_spanned_lint ( lint, first_hir_id, MultiSpan :: from_spans ( spans) , diag) ;
885896 }
886897
887- fn warn_dead_fields_and_variants (
898+ fn warn_multiple (
888899 & self ,
889900 def_id : LocalDefId ,
890901 participle : & str ,
891- dead_codes : Vec < DeadVariant > ,
902+ dead_codes : Vec < DeadItem > ,
892903 is_positional : bool ,
893904 ) {
894905 let mut dead_codes = dead_codes
895906 . iter ( )
896907 . filter ( |v| !v. name . as_str ( ) . starts_with ( '_' ) )
897- . collect :: < Vec < & DeadVariant > > ( ) ;
908+ . collect :: < Vec < & DeadItem > > ( ) ;
898909 if dead_codes. is_empty ( ) {
899910 return ;
900911 }
901912 dead_codes. sort_by_key ( |v| v. level ) ;
902913 for ( _, group) in & dead_codes. into_iter ( ) . group_by ( |v| v. level ) {
903- self . warn_multiple_dead_codes (
914+ self . lint_at_single_level (
904915 & group. map ( |v| v. def_id ) . collect :: < Vec < _ > > ( ) ,
905916 participle,
906917 Some ( def_id) ,
@@ -910,7 +921,7 @@ impl<'tcx> DeadVisitor<'tcx> {
910921 }
911922
912923 fn warn_dead_code ( & mut self , id : LocalDefId , participle : & str ) {
913- self . warn_multiple_dead_codes ( & [ id] , participle, None , false ) ;
924+ self . lint_at_single_level ( & [ id] , participle, None , false ) ;
914925 }
915926
916927 fn check_definition ( & mut self , def_id : LocalDefId ) {
@@ -954,17 +965,16 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
954965 if let hir:: ItemKind :: Impl ( impl_item) = tcx. hir ( ) . item ( item) . kind {
955966 let mut dead_items = Vec :: new ( ) ;
956967 for item in impl_item. items {
957- let did = item. id . owner_id . def_id ;
958- if !visitor. is_live_code ( did) {
959- dead_items. push ( did)
968+ let def_id = item. id . owner_id . def_id ;
969+ if !visitor. is_live_code ( def_id) {
970+ let name = tcx. item_name ( def_id. to_def_id ( ) ) ;
971+ let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def_id) ;
972+ let level = tcx. lint_level_at_node ( lint:: builtin:: DEAD_CODE , hir_id) . 0 ;
973+
974+ dead_items. push ( DeadItem { def_id, name, level } )
960975 }
961976 }
962- visitor. warn_multiple_dead_codes (
963- & dead_items,
964- "used" ,
965- Some ( item. owner_id . def_id ) ,
966- false ,
967- ) ;
977+ visitor. warn_multiple ( item. owner_id . def_id , "used" , dead_items, false ) ;
968978 }
969979
970980 if !live_symbols. contains ( & item. owner_id . def_id ) {
@@ -988,7 +998,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
988998 // Record to group diagnostics.
989999 let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def_id) ;
9901000 let level = tcx. lint_level_at_node ( lint:: builtin:: DEAD_CODE , hir_id) . 0 ;
991- dead_variants. push ( DeadVariant { def_id, name : variant. name , level } ) ;
1001+ dead_variants. push ( DeadItem { def_id, name : variant. name , level } ) ;
9921002 continue ;
9931003 }
9941004
@@ -1013,21 +1023,16 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
10131023 hir_id,
10141024 )
10151025 . 0 ;
1016- Some ( DeadVariant { def_id, name : field. name , level } )
1026+ Some ( DeadItem { def_id, name : field. name , level } )
10171027 } else {
10181028 None
10191029 }
10201030 } )
10211031 . collect ( ) ;
1022- visitor. warn_dead_fields_and_variants ( def_id, "read" , dead_fields, is_positional)
1032+ visitor. warn_multiple ( def_id, "read" , dead_fields, is_positional) ;
10231033 }
10241034
1025- visitor. warn_dead_fields_and_variants (
1026- item. owner_id . def_id ,
1027- "constructed" ,
1028- dead_variants,
1029- false ,
1030- ) ;
1035+ visitor. warn_multiple ( item. owner_id . def_id , "constructed" , dead_variants, false ) ;
10311036 }
10321037 }
10331038
0 commit comments