@@ -41,9 +41,11 @@ struct MarkSymbolVisitor<'tcx> {
4141 maybe_typeck_results : Option < & ' tcx ty:: TypeckResults < ' tcx > > ,
4242 live_symbols : FxHashSet < LocalDefId > ,
4343 repr_has_repr_c : bool ,
44+ repr_has_repr_simd : bool ,
4445 in_pat : bool ,
4546 inherited_pub_visibility : bool ,
4647 pub_visibility : bool ,
48+ allow_dead_field : bool ,
4749 ignore_variant_stack : Vec < DefId > ,
4850 // maps from tuple struct constructors to tuple struct items
4951 struct_constructors : FxHashMap < LocalDefId , LocalDefId > ,
@@ -221,6 +223,32 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
221223 }
222224 }
223225
226+ fn handle_tuple_field_pattern_match (
227+ & mut self ,
228+ lhs : & hir:: Pat < ' _ > ,
229+ res : Res ,
230+ pats : & [ hir:: Pat < ' _ > ] ,
231+ dotdot : Option < usize > ,
232+ ) {
233+ let variant = match self . typeck_results ( ) . node_type ( lhs. hir_id ) . kind ( ) {
234+ ty:: Adt ( adt, _) => adt. variant_of_res ( res) ,
235+ _ => span_bug ! ( lhs. span, "non-ADT in tuple struct pattern" ) ,
236+ } ;
237+ let first_n = pats. iter ( ) . enumerate ( ) . take ( dotdot. unwrap_or ( pats. len ( ) ) ) ;
238+ let missing = variant. fields . len ( ) - pats. len ( ) ;
239+ let last_n = pats
240+ . iter ( )
241+ . enumerate ( )
242+ . skip ( dotdot. unwrap_or ( pats. len ( ) ) )
243+ . map ( |( idx, pat) | ( idx + missing, pat) ) ;
244+ for ( idx, pat) in first_n. chain ( last_n) {
245+ if let PatKind :: Wild = pat. kind {
246+ continue ;
247+ }
248+ self . insert_def_id ( variant. fields [ idx] . did ) ;
249+ }
250+ }
251+
224252 fn mark_live_symbols ( & mut self ) {
225253 let mut scanned = FxHashSet :: default ( ) ;
226254 while let Some ( id) = self . worklist . pop ( ) {
@@ -269,19 +297,38 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
269297 }
270298
271299 let had_repr_c = self . repr_has_repr_c ;
300+ let had_repr_simd = self . repr_has_repr_simd ;
272301 let had_inherited_pub_visibility = self . inherited_pub_visibility ;
273302 let had_pub_visibility = self . pub_visibility ;
303+ let had_allow_dead_field = self . allow_dead_field ;
274304 self . repr_has_repr_c = false ;
305+ self . repr_has_repr_simd = false ;
275306 self . inherited_pub_visibility = false ;
276307 self . pub_visibility = false ;
308+ self . allow_dead_field = false ;
277309 match node {
278310 Node :: Item ( item) => {
279311 self . pub_visibility = item. vis . node . is_pub ( ) ;
280312
281- match item. kind {
282- hir:: ItemKind :: Struct ( ..) | hir:: ItemKind :: Union ( ..) => {
313+ match & item. kind {
314+ hir:: ItemKind :: Struct ( vd , ..) | hir:: ItemKind :: Union ( vd , ..) => {
283315 let def = self . tcx . adt_def ( item. def_id ) ;
284316 self . repr_has_repr_c = def. repr . c ( ) ;
317+ self . repr_has_repr_simd = def. repr . simd ( ) ;
318+
319+ // A single non-public field of unit type in a public tuple struct
320+ // can be used to make the tuple struct constructor private. This
321+ // is allowed and shouldn't yield a "field is never read" warning.
322+ if let hir:: VariantData :: Tuple ( [ field_def] , _) = vd {
323+ match field_def. vis . node {
324+ hir:: VisibilityKind :: Public => { }
325+ _ => {
326+ if let hir:: TyKind :: Tup ( [ ] ) = field_def. ty . kind {
327+ self . allow_dead_field = true ;
328+ }
329+ }
330+ }
331+ }
285332
286333 intravisit:: walk_item ( self , & item) ;
287334 }
@@ -307,8 +354,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
307354 }
308355 _ => { }
309356 }
357+ self . allow_dead_field = had_allow_dead_field;
310358 self . pub_visibility = had_pub_visibility;
311359 self . inherited_pub_visibility = had_inherited_pub_visibility;
360+ self . repr_has_repr_simd = had_repr_simd;
312361 self . repr_has_repr_c = had_repr_c;
313362 }
314363
@@ -346,10 +395,15 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
346395 _: rustc_span:: Span ,
347396 ) {
348397 let has_repr_c = self . repr_has_repr_c ;
398+ let has_repr_simd = self . repr_has_repr_simd ;
349399 let inherited_pub_visibility = self . inherited_pub_visibility ;
350400 let pub_visibility = self . pub_visibility ;
401+ let allow_dead_field = self . allow_dead_field ;
351402 let live_fields = def. fields ( ) . iter ( ) . filter ( |f| {
352- has_repr_c || ( pub_visibility && ( inherited_pub_visibility || f. vis . node . is_pub ( ) ) )
403+ has_repr_c
404+ || ( pub_visibility && ( inherited_pub_visibility || f. vis . node . is_pub ( ) ) )
405+ || ( f. is_positional ( ) && has_repr_simd)
406+ || allow_dead_field
353407 } ) ;
354408 let hir = self . tcx . hir ( ) ;
355409 self . live_symbols . extend ( live_fields. map ( |f| hir. local_def_id ( f. hir_id ) ) ) ;
@@ -403,6 +457,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
403457 let res = self . typeck_results ( ) . qpath_res ( qpath, pat. hir_id ) ;
404458 self . handle_res ( res) ;
405459 }
460+ PatKind :: TupleStruct ( ref qpath, ref fields, dotdot) => {
461+ let res = self . typeck_results ( ) . qpath_res ( qpath, pat. hir_id ) ;
462+ self . handle_tuple_field_pattern_match ( pat, res, fields, dotdot) ;
463+ }
406464 _ => ( ) ,
407465 }
408466
@@ -585,9 +643,11 @@ fn find_live<'tcx>(
585643 maybe_typeck_results : None ,
586644 live_symbols : Default :: default ( ) ,
587645 repr_has_repr_c : false ,
646+ repr_has_repr_simd : false ,
588647 in_pat : false ,
589648 inherited_pub_visibility : false ,
590649 pub_visibility : false ,
650+ allow_dead_field : false ,
591651 ignore_variant_stack : vec ! [ ] ,
592652 struct_constructors,
593653 } ;
@@ -618,8 +678,7 @@ impl<'tcx> DeadVisitor<'tcx> {
618678 fn should_warn_about_field ( & mut self , field : & hir:: FieldDef < ' _ > ) -> bool {
619679 let def_id = self . tcx . hir ( ) . local_def_id ( field. hir_id ) ;
620680 let field_type = self . tcx . type_of ( def_id) ;
621- !field. is_positional ( )
622- && !self . symbol_is_live ( def_id)
681+ !self . symbol_is_live ( def_id)
623682 && !field_type. is_phantom_data ( )
624683 && !has_allow_dead_code_or_lang_attr ( self . tcx , field. hir_id )
625684 }
0 commit comments