@@ -124,6 +124,32 @@ impl<'a> MarkSymbolVisitor<'a> {
124
124
}
125
125
}
126
126
127
+ fn handle_field_access ( & mut self , lhs : & ast:: Expr , name : & ast:: Ident ) {
128
+ match ty:: get ( ty:: expr_ty_adjusted ( self . tcx , lhs) ) . sty {
129
+ ty:: ty_struct( id, _) => {
130
+ let fields = ty:: lookup_struct_fields ( self . tcx , id) ;
131
+ let field_id = fields. iter ( )
132
+ . find ( |field| field. name == name. name ) . unwrap ( ) . id ;
133
+ self . live_symbols . insert ( field_id. node ) ;
134
+ } ,
135
+ _ => ( )
136
+ }
137
+ }
138
+
139
+ fn handle_field_pattern_match ( & mut self , lhs : & ast:: Pat , pats : & [ ast:: FieldPat ] ) {
140
+ match self . tcx . def_map . borrow ( ) . get ( & lhs. id ) {
141
+ & def:: DefStruct ( id) | & def:: DefVariant ( _, id, _) => {
142
+ let fields = ty:: lookup_struct_fields ( self . tcx , id) ;
143
+ for pat in pats. iter ( ) {
144
+ let field_id = fields. iter ( )
145
+ . find ( |field| field. name == pat. ident . name ) . unwrap ( ) . id ;
146
+ self . live_symbols . insert ( field_id. node ) ;
147
+ }
148
+ }
149
+ _ => ( )
150
+ }
151
+ }
152
+
127
153
fn mark_live_symbols ( & mut self ) {
128
154
let mut scanned = HashSet :: new ( ) ;
129
155
while self . worklist . len ( ) > 0 {
@@ -147,10 +173,22 @@ impl<'a> MarkSymbolVisitor<'a> {
147
173
match * node {
148
174
ast_map:: NodeItem ( item) => {
149
175
match item. node {
176
+ ast:: ItemStruct ( struct_def, _) => {
177
+ let has_extern_repr = item. attrs . iter ( ) . fold ( attr:: ReprAny , |acc, attr| {
178
+ attr:: find_repr_attr ( self . tcx . sess . diagnostic ( ) , attr, acc)
179
+ } ) == attr:: ReprExtern ;
180
+ let live_fields = struct_def. fields . iter ( ) . filter ( |f| {
181
+ has_extern_repr || match f. node . kind {
182
+ ast:: NamedField ( _, ast:: Public ) => true ,
183
+ _ => false
184
+ }
185
+ } ) ;
186
+ self . live_symbols . extend ( live_fields. map ( |f| f. node . id ) ) ;
187
+ visit:: walk_item ( self , item, ( ) ) ;
188
+ }
150
189
ast:: ItemFn ( ..)
151
190
| ast:: ItemTy ( ..)
152
191
| ast:: ItemEnum ( ..)
153
- | ast:: ItemStruct ( ..)
154
192
| ast:: ItemStatic ( ..) => {
155
193
visit:: walk_item ( self , item, ( ) ) ;
156
194
}
@@ -178,18 +216,32 @@ impl<'a> Visitor<()> for MarkSymbolVisitor<'a> {
178
216
ast:: ExprMethodCall ( ..) => {
179
217
self . lookup_and_handle_method ( expr. id , expr. span ) ;
180
218
}
219
+ ast:: ExprField ( ref lhs, ref ident, _) => {
220
+ self . handle_field_access ( * lhs, ident) ;
221
+ }
181
222
_ => ( )
182
223
}
183
224
184
225
visit:: walk_expr ( self , expr, ( ) )
185
226
}
186
227
228
+ fn visit_pat ( & mut self , pat : & ast:: Pat , _: ( ) ) {
229
+ match pat. node {
230
+ ast:: PatStruct ( _, ref fields, _) => {
231
+ self . handle_field_pattern_match ( pat, fields. as_slice ( ) ) ;
232
+ }
233
+ _ => ( )
234
+ }
235
+
236
+ visit:: walk_pat ( self , pat, ( ) )
237
+ }
238
+
187
239
fn visit_path ( & mut self , path : & ast:: Path , id : ast:: NodeId , _: ( ) ) {
188
240
self . lookup_and_handle_definition ( & id) ;
189
241
visit:: walk_path ( self , path, ( ) ) ;
190
242
}
191
243
192
- fn visit_item ( & mut self , _item : & ast:: Item , _: ( ) ) {
244
+ fn visit_item ( & mut self , _ : & ast:: Item , _: ( ) ) {
193
245
// Do not recurse into items. These items will be added to the
194
246
// worklist and recursed into manually if necessary.
195
247
}
@@ -317,6 +369,23 @@ struct DeadVisitor<'a> {
317
369
}
318
370
319
371
impl < ' a > DeadVisitor < ' a > {
372
+ fn should_warn_about_field ( & mut self , node : & ast:: StructField_ ) -> bool {
373
+ let ( is_named, has_leading_underscore) = match node. ident ( ) {
374
+ Some ( ref ident) => ( true , token:: get_ident ( * ident) . get ( ) [ 0 ] == ( '_' as u8 ) ) ,
375
+ _ => ( false , false )
376
+ } ;
377
+ let field_type = ty:: node_id_to_type ( self . tcx , node. id ) ;
378
+ let is_marker_field = match ty:: ty_to_def_id ( field_type) {
379
+ Some ( def_id) => self . tcx . lang_items . items ( ) . any ( |( _, item) | * item == Some ( def_id) ) ,
380
+ _ => false
381
+ } ;
382
+ is_named
383
+ && !self . symbol_is_live ( node. id , None )
384
+ && !has_leading_underscore
385
+ && !is_marker_field
386
+ && !has_allow_dead_code_or_lang_attr ( node. attrs . as_slice ( ) )
387
+ }
388
+
320
389
// id := node id of an item's definition.
321
390
// ctor_id := `Some` if the item is a struct_ctor (tuple struct),
322
391
// `None` otherwise.
@@ -399,6 +468,14 @@ impl<'a> Visitor<()> for DeadVisitor<'a> {
399
468
visit:: walk_block ( self , block, ( ) ) ;
400
469
}
401
470
471
+ fn visit_struct_field ( & mut self , field : & ast:: StructField , _: ( ) ) {
472
+ if self . should_warn_about_field ( & field. node ) {
473
+ self . warn_dead_code ( field. node . id , field. span , field. node . ident ( ) . unwrap ( ) ) ;
474
+ }
475
+
476
+ visit:: walk_struct_field ( self , field, ( ) ) ;
477
+ }
478
+
402
479
// Overwrite so that we don't warn the trait method itself.
403
480
fn visit_trait_method ( & mut self , trait_method : & ast:: TraitMethod , _: ( ) ) {
404
481
match * trait_method {
0 commit comments