@@ -124,6 +124,32 @@ impl<'a> MarkSymbolVisitor<'a> {
124124 }
125125 }
126126
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+
127153 fn mark_live_symbols ( & mut self ) {
128154 let mut scanned = HashSet :: new ( ) ;
129155 while self . worklist . len ( ) > 0 {
@@ -147,10 +173,22 @@ impl<'a> MarkSymbolVisitor<'a> {
147173 match * node {
148174 ast_map:: NodeItem ( item) => {
149175 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+ }
150189 ast:: ItemFn ( ..)
151190 | ast:: ItemTy ( ..)
152191 | ast:: ItemEnum ( ..)
153- | ast:: ItemStruct ( ..)
154192 | ast:: ItemStatic ( ..) => {
155193 visit:: walk_item ( self , item, ( ) ) ;
156194 }
@@ -178,18 +216,32 @@ impl<'a> Visitor<()> for MarkSymbolVisitor<'a> {
178216 ast:: ExprMethodCall ( ..) => {
179217 self . lookup_and_handle_method ( expr. id , expr. span ) ;
180218 }
219+ ast:: ExprField ( ref lhs, ref ident, _) => {
220+ self . handle_field_access ( * lhs, ident) ;
221+ }
181222 _ => ( )
182223 }
183224
184225 visit:: walk_expr ( self , expr, ( ) )
185226 }
186227
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+
187239 fn visit_path ( & mut self , path : & ast:: Path , id : ast:: NodeId , _: ( ) ) {
188240 self . lookup_and_handle_definition ( & id) ;
189241 visit:: walk_path ( self , path, ( ) ) ;
190242 }
191243
192- fn visit_item ( & mut self , _item : & ast:: Item , _: ( ) ) {
244+ fn visit_item ( & mut self , _ : & ast:: Item , _: ( ) ) {
193245 // Do not recurse into items. These items will be added to the
194246 // worklist and recursed into manually if necessary.
195247 }
@@ -317,6 +369,23 @@ struct DeadVisitor<'a> {
317369}
318370
319371impl < ' 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+
320389 // id := node id of an item's definition.
321390 // ctor_id := `Some` if the item is a struct_ctor (tuple struct),
322391 // `None` otherwise.
@@ -399,6 +468,14 @@ impl<'a> Visitor<()> for DeadVisitor<'a> {
399468 visit:: walk_block ( self , block, ( ) ) ;
400469 }
401470
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+
402479 // Overwrite so that we don't warn the trait method itself.
403480 fn visit_trait_method ( & mut self , trait_method : & ast:: TraitMethod , _: ( ) ) {
404481 match * trait_method {
0 commit comments