33// from live codes are live, and everything else is dead.
44
55use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
6+ use rustc_errors:: pluralize;
67use rustc_hir as hir;
78use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
89use rustc_hir:: def_id:: { DefId , LocalDefId } ;
@@ -47,6 +48,8 @@ struct MarkSymbolVisitor<'tcx> {
4748 ignore_variant_stack : Vec < DefId > ,
4849 // maps from tuple struct constructors to tuple struct items
4950 struct_constructors : FxHashMap < LocalDefId , LocalDefId > ,
51+ // maps from ADTs to ignored derived traits (e.g. Debug and Clone)
52+ ignored_derived_traits : FxHashMap < DefId , Vec < DefId > > ,
5053}
5154
5255impl < ' tcx > MarkSymbolVisitor < ' tcx > {
@@ -242,14 +245,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
242245 /// Automatically generated items marked with `rustc_trivial_field_reads`
243246 /// will be ignored for the purposes of dead code analysis (see PR #85200
244247 /// for discussion).
245- fn should_ignore_item ( & self , def_id : DefId ) -> bool {
248+ fn should_ignore_item ( & mut self , def_id : DefId ) -> bool {
246249 if let Some ( impl_of) = self . tcx . impl_of_method ( def_id) {
247250 if !self . tcx . has_attr ( impl_of, sym:: automatically_derived) {
248251 return false ;
249252 }
250253
251254 if let Some ( trait_of) = self . tcx . trait_id_of_impl ( impl_of) {
252255 if self . tcx . has_attr ( trait_of, sym:: rustc_trivial_field_reads) {
256+ let trait_ref = self . tcx . impl_trait_ref ( impl_of) . unwrap ( ) ;
257+ if let ty:: Adt ( adt_def, _) = trait_ref. self_ty ( ) . kind ( ) {
258+ if let Some ( v) = self . ignored_derived_traits . get_mut ( & adt_def. did ) {
259+ v. push ( trait_of) ;
260+ } else {
261+ self . ignored_derived_traits . insert ( adt_def. did , vec ! [ trait_of] ) ;
262+ }
263+ }
253264 return true ;
254265 }
255266 }
@@ -577,7 +588,7 @@ fn create_and_seed_worklist<'tcx>(
577588fn find_live < ' tcx > (
578589 tcx : TyCtxt < ' tcx > ,
579590 access_levels : & privacy:: AccessLevels ,
580- ) -> FxHashSet < LocalDefId > {
591+ ) -> ( FxHashSet < LocalDefId > , FxHashMap < DefId , Vec < DefId > > ) {
581592 let ( worklist, struct_constructors) = create_and_seed_worklist ( tcx, access_levels) ;
582593 let mut symbol_visitor = MarkSymbolVisitor {
583594 worklist,
@@ -590,14 +601,16 @@ fn find_live<'tcx>(
590601 pub_visibility : false ,
591602 ignore_variant_stack : vec ! [ ] ,
592603 struct_constructors,
604+ ignored_derived_traits : FxHashMap :: default ( ) ,
593605 } ;
594606 symbol_visitor. mark_live_symbols ( ) ;
595- symbol_visitor. live_symbols
607+ ( symbol_visitor. live_symbols , symbol_visitor . ignored_derived_traits )
596608}
597609
598610struct DeadVisitor < ' tcx > {
599611 tcx : TyCtxt < ' tcx > ,
600612 live_symbols : FxHashSet < LocalDefId > ,
613+ ignored_derived_traits : FxHashMap < DefId , Vec < DefId > > ,
601614}
602615
603616impl < ' tcx > DeadVisitor < ' tcx > {
@@ -666,7 +679,34 @@ impl<'tcx> DeadVisitor<'tcx> {
666679 self . tcx . struct_span_lint_hir ( lint:: builtin:: DEAD_CODE , id, span, |lint| {
667680 let def_id = self . tcx . hir ( ) . local_def_id ( id) ;
668681 let descr = self . tcx . def_kind ( def_id) . descr ( def_id. to_def_id ( ) ) ;
669- lint. build ( & format ! ( "{} is never {}: `{}`" , descr, participle, name) ) . emit ( )
682+ let mut err = lint. build ( & format ! ( "{} is never {}: `{}`" , descr, participle, name) ) ;
683+ let hir = self . tcx . hir ( ) ;
684+ if let Some ( encl_scope) = hir. get_enclosing_scope ( id) {
685+ if let Some ( encl_def_id) = hir. opt_local_def_id ( encl_scope) {
686+ if let Some ( ign_traits) = self . ignored_derived_traits . get ( & encl_def_id. to_def_id ( ) ) {
687+ let traits_str = ign_traits
688+ . iter ( )
689+ . map ( |t| format ! ( "`{}`" , self . tcx. item_name( * t) ) ) . collect :: < Vec < _ > > ( )
690+ . join ( " and " ) ;
691+ let plural_s = pluralize ! ( ign_traits. len( ) ) ;
692+ let article = if ign_traits. len ( ) > 1 { "" } else { "a " } ;
693+ let is_are = if ign_traits. len ( ) > 1 { "these are" } else { "this is" } ;
694+ let msg = format ! ( "`{}` has {}derived impl{} for the trait{} {}, but {} ignored during dead code analysis" ,
695+ self . tcx. item_name( encl_def_id. to_def_id( ) ) ,
696+ article,
697+ plural_s,
698+ plural_s,
699+ traits_str,
700+ is_are) ;
701+ if let Some ( span) = self . tcx . def_ident_span ( encl_def_id) {
702+ err. span_note ( span, & msg) ;
703+ } else {
704+ err. note ( & msg) ;
705+ }
706+ }
707+ }
708+ }
709+ err. emit ( ) ;
670710 } ) ;
671711 }
672712 }
@@ -796,7 +836,7 @@ impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> {
796836
797837pub fn check_crate ( tcx : TyCtxt < ' _ > ) {
798838 let access_levels = & tcx. privacy_access_levels ( ( ) ) ;
799- let live_symbols = find_live ( tcx, access_levels) ;
800- let mut visitor = DeadVisitor { tcx, live_symbols } ;
839+ let ( live_symbols, ignored_derived_traits ) = find_live ( tcx, access_levels) ;
840+ let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits } ;
801841 tcx. hir ( ) . walk_toplevel_module ( & mut visitor) ;
802842}
0 commit comments