@@ -41,9 +41,11 @@ struct MarkSymbolVisitor<'tcx> {
41
41
maybe_typeck_results : Option < & ' tcx ty:: TypeckResults < ' tcx > > ,
42
42
live_symbols : FxHashSet < LocalDefId > ,
43
43
repr_has_repr_c : bool ,
44
+ repr_has_repr_simd : bool ,
44
45
in_pat : bool ,
45
46
inherited_pub_visibility : bool ,
46
47
pub_visibility : bool ,
48
+ allow_dead_field : bool ,
47
49
ignore_variant_stack : Vec < DefId > ,
48
50
// maps from tuple struct constructors to tuple struct items
49
51
struct_constructors : FxHashMap < LocalDefId , LocalDefId > ,
@@ -221,6 +223,32 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
221
223
}
222
224
}
223
225
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
+
224
252
fn mark_live_symbols ( & mut self ) {
225
253
let mut scanned = FxHashSet :: default ( ) ;
226
254
while let Some ( id) = self . worklist . pop ( ) {
@@ -269,19 +297,38 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
269
297
}
270
298
271
299
let had_repr_c = self . repr_has_repr_c ;
300
+ let had_repr_simd = self . repr_has_repr_simd ;
272
301
let had_inherited_pub_visibility = self . inherited_pub_visibility ;
273
302
let had_pub_visibility = self . pub_visibility ;
303
+ let had_allow_dead_field = self . allow_dead_field ;
274
304
self . repr_has_repr_c = false ;
305
+ self . repr_has_repr_simd = false ;
275
306
self . inherited_pub_visibility = false ;
276
307
self . pub_visibility = false ;
308
+ self . allow_dead_field = false ;
277
309
match node {
278
310
Node :: Item ( item) => {
279
311
self . pub_visibility = item. vis . node . is_pub ( ) ;
280
312
281
- match item. kind {
282
- hir:: ItemKind :: Struct ( ..) | hir:: ItemKind :: Union ( ..) => {
313
+ match & item. kind {
314
+ hir:: ItemKind :: Struct ( vd , ..) | hir:: ItemKind :: Union ( vd , ..) => {
283
315
let def = self . tcx . adt_def ( item. def_id ) ;
284
316
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
+ }
285
332
286
333
intravisit:: walk_item ( self , & item) ;
287
334
}
@@ -307,8 +354,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
307
354
}
308
355
_ => { }
309
356
}
357
+ self . allow_dead_field = had_allow_dead_field;
310
358
self . pub_visibility = had_pub_visibility;
311
359
self . inherited_pub_visibility = had_inherited_pub_visibility;
360
+ self . repr_has_repr_simd = had_repr_simd;
312
361
self . repr_has_repr_c = had_repr_c;
313
362
}
314
363
@@ -346,10 +395,15 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
346
395
_: rustc_span:: Span ,
347
396
) {
348
397
let has_repr_c = self . repr_has_repr_c ;
398
+ let has_repr_simd = self . repr_has_repr_simd ;
349
399
let inherited_pub_visibility = self . inherited_pub_visibility ;
350
400
let pub_visibility = self . pub_visibility ;
401
+ let allow_dead_field = self . allow_dead_field ;
351
402
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
353
407
} ) ;
354
408
let hir = self . tcx . hir ( ) ;
355
409
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> {
403
457
let res = self . typeck_results ( ) . qpath_res ( qpath, pat. hir_id ) ;
404
458
self . handle_res ( res) ;
405
459
}
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
+ }
406
464
_ => ( ) ,
407
465
}
408
466
@@ -585,9 +643,11 @@ fn find_live<'tcx>(
585
643
maybe_typeck_results : None ,
586
644
live_symbols : Default :: default ( ) ,
587
645
repr_has_repr_c : false ,
646
+ repr_has_repr_simd : false ,
588
647
in_pat : false ,
589
648
inherited_pub_visibility : false ,
590
649
pub_visibility : false ,
650
+ allow_dead_field : false ,
591
651
ignore_variant_stack : vec ! [ ] ,
592
652
struct_constructors,
593
653
} ;
@@ -618,8 +678,7 @@ impl<'tcx> DeadVisitor<'tcx> {
618
678
fn should_warn_about_field ( & mut self , field : & hir:: FieldDef < ' _ > ) -> bool {
619
679
let def_id = self . tcx . hir ( ) . local_def_id ( field. hir_id ) ;
620
680
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)
623
682
&& !field_type. is_phantom_data ( )
624
683
&& !has_allow_dead_code_or_lang_attr ( self . tcx , field. hir_id )
625
684
}
0 commit comments