44
55use  itertools:: Itertools ; 
66use  rustc_data_structures:: fx:: { FxHashMap ,  FxHashSet } ; 
7- use  rustc_errors:: { pluralize,  MultiSpan } ; 
7+ use  rustc_errors:: { pluralize,  Applicability ,   MultiSpan } ; 
88use  rustc_hir as  hir; 
99use  rustc_hir:: def:: { CtorOf ,  DefKind ,  Res } ; 
1010use  rustc_hir:: def_id:: { DefId ,  LocalDefId } ; 
@@ -42,6 +42,7 @@ struct MarkSymbolVisitor<'tcx> {
4242    maybe_typeck_results :  Option < & ' tcx  ty:: TypeckResults < ' tcx > > , 
4343    live_symbols :  FxHashSet < LocalDefId > , 
4444    repr_has_repr_c :  bool , 
45+     repr_has_repr_simd :  bool , 
4546    in_pat :  bool , 
4647    ignore_variant_stack :  Vec < DefId > , 
4748    // maps from tuple struct constructors to tuple struct items 
@@ -220,6 +221,32 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
220221        } 
221222    } 
222223
224+     fn  handle_tuple_field_pattern_match ( 
225+         & mut  self , 
226+         lhs :  & hir:: Pat < ' _ > , 
227+         res :  Res , 
228+         pats :  & [ hir:: Pat < ' _ > ] , 
229+         dotdot :  Option < usize > , 
230+     )  { 
231+         let  variant = match  self . typeck_results ( ) . node_type ( lhs. hir_id ) . kind ( )  { 
232+             ty:: Adt ( adt,  _)  => adt. variant_of_res ( res) , 
233+             _ => span_bug ! ( lhs. span,  "non-ADT in tuple struct pattern" ) , 
234+         } ; 
235+         let  first_n = pats. iter ( ) . enumerate ( ) . take ( dotdot. unwrap_or ( pats. len ( ) ) ) ; 
236+         let  missing = variant. fields . len ( )  - pats. len ( ) ; 
237+         let  last_n = pats
238+             . iter ( ) 
239+             . enumerate ( ) 
240+             . skip ( dotdot. unwrap_or ( pats. len ( ) ) ) 
241+             . map ( |( idx,  pat) | ( idx + missing,  pat) ) ; 
242+         for  ( idx,  pat)  in  first_n. chain ( last_n)  { 
243+             if  let  PatKind :: Wild  = pat. kind  { 
244+                 continue ; 
245+             } 
246+             self . insert_def_id ( variant. fields [ idx] . did ) ; 
247+         } 
248+     } 
249+ 
223250    fn  mark_live_symbols ( & mut  self )  { 
224251        let  mut  scanned = FxHashSet :: default ( ) ; 
225252        while  let  Some ( id)  = self . worklist . pop ( )  { 
@@ -274,12 +301,15 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
274301        } 
275302
276303        let  had_repr_c = self . repr_has_repr_c ; 
304+         let  had_repr_simd = self . repr_has_repr_simd ; 
277305        self . repr_has_repr_c  = false ; 
306+         self . repr_has_repr_simd  = false ; 
278307        match  node { 
279308            Node :: Item ( item)  => match  item. kind  { 
280309                hir:: ItemKind :: Struct ( ..)  | hir:: ItemKind :: Union ( ..)  => { 
281310                    let  def = self . tcx . adt_def ( item. def_id ) ; 
282311                    self . repr_has_repr_c  = def. repr ( ) . c ( ) ; 
312+                     self . repr_has_repr_simd  = def. repr ( ) . simd ( ) ; 
283313
284314                    intravisit:: walk_item ( self ,  & item) 
285315                } 
@@ -315,6 +345,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
315345            } 
316346            _ => { } 
317347        } 
348+         self . repr_has_repr_simd  = had_repr_simd; 
318349        self . repr_has_repr_c  = had_repr_c; 
319350    } 
320351
@@ -347,9 +378,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
347378    )  { 
348379        let  tcx = self . tcx ; 
349380        let  has_repr_c = self . repr_has_repr_c ; 
381+         let  has_repr_simd = self . repr_has_repr_simd ; 
350382        let  live_fields = def. fields ( ) . iter ( ) . filter_map ( |f| { 
351383            let  def_id = tcx. hir ( ) . local_def_id ( f. hir_id ) ; 
352-             if  has_repr_c { 
384+             if  has_repr_c ||  ( f . is_positional ( )  && has_repr_simd )   { 
353385                return  Some ( def_id) ; 
354386            } 
355387            if  !tcx. visibility ( f. hir_id . owner ) . is_public ( )  { 
@@ -408,6 +440,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
408440                let  res = self . typeck_results ( ) . qpath_res ( qpath,  pat. hir_id ) ; 
409441                self . handle_res ( res) ; 
410442            } 
443+             PatKind :: TupleStruct ( ref  qpath,  ref  fields,  dotdot)  => { 
444+                 let  res = self . typeck_results ( ) . qpath_res ( qpath,  pat. hir_id ) ; 
445+                 self . handle_tuple_field_pattern_match ( pat,  res,  fields,  dotdot) ; 
446+             } 
411447            _ => ( ) , 
412448        } 
413449
@@ -440,7 +476,11 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
440476    } 
441477} 
442478
443- fn  has_allow_dead_code_or_lang_attr ( tcx :  TyCtxt < ' _ > ,  id :  hir:: HirId )  -> bool  { 
479+ fn  has_allow_dead_code_or_lang_attr_helper ( 
480+     tcx :  TyCtxt < ' _ > , 
481+     id :  hir:: HirId , 
482+     lint :  & ' static  lint:: Lint , 
483+ )  -> bool  { 
444484    let  attrs = tcx. hir ( ) . attrs ( id) ; 
445485    if  tcx. sess . contains_name ( attrs,  sym:: lang)  { 
446486        return  true ; 
@@ -470,7 +510,11 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
470510        } 
471511    } 
472512
473-     tcx. lint_level_at_node ( lint:: builtin:: DEAD_CODE ,  id) . 0  == lint:: Allow 
513+     tcx. lint_level_at_node ( lint,  id) . 0  == lint:: Allow 
514+ } 
515+ 
516+ fn  has_allow_dead_code_or_lang_attr ( tcx :  TyCtxt < ' _ > ,  id :  hir:: HirId )  -> bool  { 
517+     has_allow_dead_code_or_lang_attr_helper ( tcx,  id,  lint:: builtin:: DEAD_CODE ) 
474518} 
475519
476520// These check_* functions seeds items that 
@@ -623,6 +667,7 @@ fn live_symbols_and_ignored_derived_traits<'tcx>(
623667        maybe_typeck_results :  None , 
624668        live_symbols :  Default :: default ( ) , 
625669        repr_has_repr_c :  false , 
670+         repr_has_repr_simd :  false , 
626671        in_pat :  false , 
627672        ignore_variant_stack :  vec ! [ ] , 
628673        struct_constructors, 
@@ -644,32 +689,46 @@ struct DeadVisitor<'tcx> {
644689    ignored_derived_traits :  & ' tcx  FxHashMap < LocalDefId ,  Vec < ( DefId ,  DefId ) > > , 
645690} 
646691
692+ enum  ShouldWarnAboutField  { 
693+     Yes ( bool ) ,  // positional? 
694+     No , 
695+ } 
696+ 
647697impl < ' tcx >  DeadVisitor < ' tcx >  { 
648-     fn  should_warn_about_field ( & mut  self ,  field :  & ty:: FieldDef )  -> bool  { 
698+     fn  should_warn_about_field ( & mut  self ,  field :  & ty:: FieldDef )  -> ShouldWarnAboutField  { 
649699        if  self . live_symbols . contains ( & field. did . expect_local ( ) )  { 
650-             return  false ; 
700+             return  ShouldWarnAboutField :: No ; 
701+         } 
702+         let  field_type = self . tcx . type_of ( field. did ) ; 
703+         if  field_type. is_phantom_data ( )  { 
704+             return  ShouldWarnAboutField :: No ; 
651705        } 
652706        let  is_positional = field. name . as_str ( ) . starts_with ( |c :  char | c. is_ascii_digit ( ) ) ; 
653-         if  is_positional { 
654-             return  false ; 
707+         if  is_positional
708+             && self 
709+                 . tcx 
710+                 . layout_of ( self . tcx . param_env ( field. did ) . and ( field_type) ) 
711+                 . map_or ( true ,  |layout| layout. is_zst ( ) ) 
712+         { 
713+             return  ShouldWarnAboutField :: No ; 
655714        } 
656-         let  field_type = self . tcx . type_of ( field. did ) ; 
657-         !field_type. is_phantom_data ( ) 
715+         ShouldWarnAboutField :: Yes ( is_positional) 
658716    } 
659717
660718    fn  warn_multiple_dead_codes ( 
661719        & self , 
662720        dead_codes :  & [ LocalDefId ] , 
663721        participle :  & str , 
664722        parent_item :  Option < LocalDefId > , 
723+         is_positional :  bool , 
665724    )  { 
666725        if  let  Some ( & first_id)  = dead_codes. first ( )  { 
667726            let  tcx = self . tcx ; 
668727            let  names:  Vec < _ >  = dead_codes
669728                . iter ( ) 
670729                . map ( |& def_id| tcx. item_name ( def_id. to_def_id ( ) ) . to_string ( ) ) 
671730                . collect ( ) ; 
672-             let  spans = dead_codes
731+             let  spans:   Vec < _ >  = dead_codes
673732                . iter ( ) 
674733                . map ( |& def_id| match  tcx. def_ident_span ( def_id)  { 
675734                    Some ( s)  => s. with_ctxt ( tcx. def_span ( def_id) . ctxt ( ) ) , 
@@ -678,9 +737,13 @@ impl<'tcx> DeadVisitor<'tcx> {
678737                . collect ( ) ; 
679738
680739            tcx. struct_span_lint_hir ( 
681-                 lint:: builtin:: DEAD_CODE , 
740+                 if  is_positional { 
741+                     lint:: builtin:: UNUSED_TUPLE_STRUCT_FIELDS 
742+                 }  else  { 
743+                     lint:: builtin:: DEAD_CODE 
744+                 } , 
682745                tcx. hir ( ) . local_def_id_to_hir_id ( first_id) , 
683-                 MultiSpan :: from_spans ( spans) , 
746+                 MultiSpan :: from_spans ( spans. clone ( ) ) , 
684747                |lint| { 
685748                    let  descr = tcx. def_kind ( first_id) . descr ( first_id. to_def_id ( ) ) ; 
686749                    let  span_len = dead_codes. len ( ) ; 
@@ -702,6 +765,21 @@ impl<'tcx> DeadVisitor<'tcx> {
702765                        are = pluralize!( "is" ,  span_len) , 
703766                    ) ) ; 
704767
768+                     if  is_positional { 
769+                         err. multipart_suggestion ( 
770+                             & format ! ( 
771+                                 "consider changing the field{s} to be of unit type to \  
772+                                        suppress this warning while preserving the field \ 
773+                                        numbering, or remove the field{s}", 
774+                                 s = pluralize!( span_len) 
775+                             ) , 
776+                             spans. iter ( ) . map ( |sp| ( * sp,  "()" . to_string ( ) ) ) . collect ( ) , 
777+                             // "HasPlaceholders" because applying this fix by itself isn't 
778+                             // enough: All constructor calls have to be adjusted as well 
779+                             Applicability :: HasPlaceholders , 
780+                         ) ; 
781+                     } 
782+ 
705783                    if  let  Some ( parent_item)  = parent_item { 
706784                        let  parent_descr = tcx. def_kind ( parent_item) . descr ( parent_item. to_def_id ( ) ) ; 
707785                        err. span_label ( 
@@ -743,6 +821,7 @@ impl<'tcx> DeadVisitor<'tcx> {
743821        def_id :  LocalDefId , 
744822        participle :  & str , 
745823        dead_codes :  Vec < DeadVariant > , 
824+         is_positional :  bool , 
746825    )  { 
747826        let  mut  dead_codes = dead_codes
748827            . iter ( ) 
@@ -758,12 +837,13 @@ impl<'tcx> DeadVisitor<'tcx> {
758837                & group. map ( |v| v. def_id ) . collect :: < Vec < _ > > ( ) , 
759838                participle, 
760839                Some ( def_id) , 
840+                 is_positional, 
761841            ) ; 
762842        } 
763843    } 
764844
765845    fn  warn_dead_code ( & mut  self ,  id :  LocalDefId ,  participle :  & str )  { 
766-         self . warn_multiple_dead_codes ( & [ id] ,  participle,  None ) ; 
846+         self . warn_multiple_dead_codes ( & [ id] ,  participle,  None ,   false ) ; 
767847    } 
768848
769849    fn  check_definition ( & mut  self ,  def_id :  LocalDefId )  { 
@@ -829,24 +909,37 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
829909                    continue ; 
830910                } 
831911
912+                 let  mut  is_positional = false ; 
832913                let  dead_fields = variant
833914                    . fields 
834915                    . iter ( ) 
835916                    . filter_map ( |field| { 
836917                        let  def_id = field. did . expect_local ( ) ; 
837918                        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 ; 
919+                         if  let  ShouldWarnAboutField :: Yes ( is_pos)  =
920+                             visitor. should_warn_about_field ( & field) 
921+                         { 
922+                             let  level = tcx
923+                                 . lint_level_at_node ( 
924+                                     if  is_pos { 
925+                                         is_positional = true ; 
926+                                         lint:: builtin:: UNUSED_TUPLE_STRUCT_FIELDS 
927+                                     }  else  { 
928+                                         lint:: builtin:: DEAD_CODE 
929+                                     } , 
930+                                     hir_id, 
931+                                 ) 
932+                                 . 0 ; 
840933                            Some ( DeadVariant  {  def_id,  name :  field. name ,  level } ) 
841934                        }  else  { 
842935                            None 
843936                        } 
844937                    } ) 
845938                    . collect ( ) ; 
846-                 visitor. warn_dead_fields_and_variants ( def_id,  "read" ,  dead_fields) 
939+                 visitor. warn_dead_fields_and_variants ( def_id,  "read" ,  dead_fields,  is_positional ) 
847940            } 
848941
849-             visitor. warn_dead_fields_and_variants ( item. def_id ,  "constructed" ,  dead_variants) ; 
942+             visitor. warn_dead_fields_and_variants ( item. def_id ,  "constructed" ,  dead_variants,   false ) ; 
850943        } 
851944    } 
852945
0 commit comments