@@ -25,6 +25,8 @@ use middle::privacy;
2525use ty:: { self , TyCtxt } ;
2626use util:: nodemap:: FxHashSet ;
2727
28+ use rustc_data_structures:: fx:: FxHashMap ;
29+
2830use syntax:: { ast, source_map} ;
2931use syntax:: attr;
3032use syntax_pos;
@@ -55,12 +57,15 @@ struct MarkSymbolVisitor<'a, 'tcx: 'a> {
5557 in_pat : bool ,
5658 inherited_pub_visibility : bool ,
5759 ignore_variant_stack : Vec < DefId > ,
60+ // maps from tuple struct constructors to tuple struct items
61+ struct_constructors : FxHashMap < ast:: NodeId , ast:: NodeId > ,
5862}
5963
6064impl < ' a , ' tcx > MarkSymbolVisitor < ' a , ' tcx > {
6165 fn check_def_id ( & mut self , def_id : DefId ) {
6266 if let Some ( node_id) = self . tcx . hir ( ) . as_local_node_id ( def_id) {
63- if should_explore ( self . tcx , node_id) {
67+ if should_explore ( self . tcx , node_id) ||
68+ self . struct_constructors . contains_key ( & node_id) {
6469 self . worklist . push ( node_id) ;
6570 }
6671 self . live_symbols . insert ( node_id) ;
@@ -137,19 +142,23 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
137142 continue
138143 }
139144
140- if let Some ( ref node) = self . tcx . hir ( ) . find ( id) {
145+ // in the case of tuple struct constructors we want to check the item, not the generated
146+ // tuple struct constructor function
147+ let id = self . struct_constructors . get ( & id) . cloned ( ) . unwrap_or ( id) ;
148+
149+ if let Some ( node) = self . tcx . hir ( ) . find ( id) {
141150 self . live_symbols . insert ( id) ;
142151 self . visit_node ( node) ;
143152 }
144153 }
145154 }
146155
147- fn visit_node ( & mut self , node : & Node < ' tcx > ) {
156+ fn visit_node ( & mut self , node : Node < ' tcx > ) {
148157 let had_repr_c = self . repr_has_repr_c ;
149158 self . repr_has_repr_c = false ;
150159 let had_inherited_pub_visibility = self . inherited_pub_visibility ;
151160 self . inherited_pub_visibility = false ;
152- match * node {
161+ match node {
153162 Node :: Item ( item) => {
154163 match item. node {
155164 hir:: ItemKind :: Struct ( ..) | hir:: ItemKind :: Union ( ..) => {
@@ -337,6 +346,8 @@ struct LifeSeeder<'k, 'tcx: 'k> {
337346 worklist : Vec < ast:: NodeId > ,
338347 krate : & ' k hir:: Crate ,
339348 tcx : TyCtxt < ' k , ' tcx , ' tcx > ,
349+ // see `MarkSymbolVisitor::struct_constructors`
350+ struct_constructors : FxHashMap < ast:: NodeId , ast:: NodeId > ,
340351}
341352
342353impl < ' v , ' k , ' tcx > ItemLikeVisitor < ' v > for LifeSeeder < ' k , ' tcx > {
@@ -379,6 +390,9 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
379390 }
380391 }
381392 }
393+ hir:: ItemKind :: Struct ( ref variant_data, _) => {
394+ self . struct_constructors . insert ( variant_data. id ( ) , item. id ) ;
395+ }
382396 _ => ( )
383397 }
384398 }
@@ -392,11 +406,11 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
392406 }
393407}
394408
395- fn create_and_seed_worklist < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
396- access_levels : & privacy :: AccessLevels ,
397- krate : & hir :: Crate )
398- -> Vec < ast :: NodeId >
399- {
409+ fn create_and_seed_worklist < ' a , ' tcx > (
410+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
411+ access_levels : & privacy :: AccessLevels ,
412+ krate : & hir :: Crate ,
413+ ) -> ( Vec < ast :: NodeId > , FxHashMap < ast :: NodeId , ast :: NodeId > ) {
400414 let worklist = access_levels. map . iter ( ) . filter_map ( |( & id, level) | {
401415 if level >= & privacy:: AccessLevel :: Reachable {
402416 Some ( id)
@@ -413,17 +427,18 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
413427 worklist,
414428 krate,
415429 tcx,
430+ struct_constructors : Default :: default ( ) ,
416431 } ;
417432 krate. visit_all_item_likes ( & mut life_seeder) ;
418433
419- return life_seeder. worklist ;
434+ ( life_seeder. worklist , life_seeder . struct_constructors )
420435}
421436
422437fn find_live < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
423438 access_levels : & privacy:: AccessLevels ,
424439 krate : & hir:: Crate )
425440 -> FxHashSet < ast:: NodeId > {
426- let worklist = create_and_seed_worklist ( tcx, access_levels, krate) ;
441+ let ( worklist, struct_constructors ) = create_and_seed_worklist ( tcx, access_levels, krate) ;
427442 let mut symbol_visitor = MarkSymbolVisitor {
428443 worklist,
429444 tcx,
@@ -433,20 +448,12 @@ fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
433448 in_pat : false ,
434449 inherited_pub_visibility : false ,
435450 ignore_variant_stack : vec ! [ ] ,
451+ struct_constructors,
436452 } ;
437453 symbol_visitor. mark_live_symbols ( ) ;
438454 symbol_visitor. live_symbols
439455}
440456
441- fn get_struct_ctor_id ( item : & hir:: Item ) -> Option < ast:: NodeId > {
442- match item. node {
443- hir:: ItemKind :: Struct ( ref struct_def, _) if !struct_def. is_struct ( ) => {
444- Some ( struct_def. id ( ) )
445- }
446- _ => None
447- }
448- }
449-
450457struct DeadVisitor < ' a , ' tcx : ' a > {
451458 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
452459 live_symbols : FxHashSet < ast:: NodeId > ,
@@ -464,46 +471,35 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
464471 | hir:: ItemKind :: Union ( ..) => true ,
465472 _ => false
466473 } ;
467- let ctor_id = get_struct_ctor_id ( item) ;
468- should_warn && !self . symbol_is_live ( item. id , ctor_id)
474+ should_warn && !self . symbol_is_live ( item. id )
469475 }
470476
471477 fn should_warn_about_field ( & mut self , field : & hir:: StructField ) -> bool {
472478 let field_type = self . tcx . type_of ( self . tcx . hir ( ) . local_def_id ( field. id ) ) ;
473479 !field. is_positional ( )
474- && !self . symbol_is_live ( field. id , None )
480+ && !self . symbol_is_live ( field. id )
475481 && !field_type. is_phantom_data ( )
476482 && !has_allow_dead_code_or_lang_attr ( self . tcx , field. id , & field. attrs )
477483 }
478484
479485 fn should_warn_about_variant ( & mut self , variant : & hir:: VariantKind ) -> bool {
480- !self . symbol_is_live ( variant. data . id ( ) , None )
486+ !self . symbol_is_live ( variant. data . id ( ) )
481487 && !has_allow_dead_code_or_lang_attr ( self . tcx ,
482488 variant. data . id ( ) ,
483489 & variant. attrs )
484490 }
485491
486492 fn should_warn_about_foreign_item ( & mut self , fi : & hir:: ForeignItem ) -> bool {
487- !self . symbol_is_live ( fi. id , None )
493+ !self . symbol_is_live ( fi. id )
488494 && !has_allow_dead_code_or_lang_attr ( self . tcx , fi. id , & fi. attrs )
489495 }
490496
491497 // id := node id of an item's definition.
492- // ctor_id := `Some` if the item is a struct_ctor (tuple struct),
493- // `None` otherwise.
494- // If the item is a struct_ctor, then either its `id` or
495- // `ctor_id` (unwrapped) is in the live_symbols set. More specifically,
496- // DefMap maps the ExprKind::Path of a struct_ctor to the node referred by
497- // `ctor_id`. On the other hand, in a statement like
498- // `type <ident> <generics> = <ty>;` where <ty> refers to a struct_ctor,
499- // DefMap maps <ty> to `id` instead.
500- fn symbol_is_live ( & mut self ,
501- id : ast:: NodeId ,
502- ctor_id : Option < ast:: NodeId > )
503- -> bool {
504- if self . live_symbols . contains ( & id)
505- || ctor_id. map_or ( false , |ctor| self . live_symbols . contains ( & ctor) )
506- {
498+ fn symbol_is_live (
499+ & mut self ,
500+ id : ast:: NodeId ,
501+ ) -> bool {
502+ if self . live_symbols . contains ( & id) {
507503 return true ;
508504 }
509505 // If it's a type whose items are live, then it's live, too.
@@ -611,7 +607,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
611607 fn visit_impl_item ( & mut self , impl_item : & ' tcx hir:: ImplItem ) {
612608 match impl_item. node {
613609 hir:: ImplItemKind :: Const ( _, body_id) => {
614- if !self . symbol_is_live ( impl_item. id , None ) {
610+ if !self . symbol_is_live ( impl_item. id ) {
615611 self . warn_dead_code ( impl_item. id ,
616612 impl_item. span ,
617613 impl_item. ident . name ,
@@ -621,7 +617,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
621617 self . visit_nested_body ( body_id)
622618 }
623619 hir:: ImplItemKind :: Method ( _, body_id) => {
624- if !self . symbol_is_live ( impl_item. id , None ) {
620+ if !self . symbol_is_live ( impl_item. id ) {
625621 let span = self . tcx . sess . source_map ( ) . def_span ( impl_item. span ) ;
626622 self . warn_dead_code ( impl_item. id , span, impl_item. ident . name , "method" , "used" ) ;
627623 }
0 commit comments