@@ -31,6 +31,7 @@ use syntax_pos::Span;
3131use errors:: DiagnosticBuilder ;
3232use util:: nodemap:: { DefIdMap , FxHashMap , FxHashSet , NodeMap , NodeSet } ;
3333use std:: slice;
34+ use rustc:: lint;
3435
3536use hir;
3637use hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
@@ -56,6 +57,13 @@ impl LifetimeDefOrigin {
5657 }
5758}
5859
60+ // This counts the no of times a lifetime is used
61+ #[ derive( Clone , Copy , Debug ) ]
62+ pub enum LifetimeUseSet < ' tcx > {
63+ One ( & ' tcx hir:: Lifetime ) ,
64+ Many ,
65+ }
66+
5967#[ derive( Clone , Copy , PartialEq , Eq , Hash , RustcEncodable , RustcDecodable , Debug ) ]
6068pub enum Region {
6169 Static ,
@@ -245,6 +253,8 @@ struct LifetimeContext<'a, 'tcx: 'a> {
245253
246254 // Cache for cross-crate per-definition object lifetime defaults.
247255 xcrate_object_lifetime_defaults : DefIdMap < Vec < ObjectLifetimeDefault > > ,
256+
257+ lifetime_uses : DefIdMap < LifetimeUseSet < ' tcx > > ,
248258}
249259
250260#[ derive( Debug ) ]
@@ -407,6 +417,7 @@ fn krate<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> NamedRegionMap {
407417 is_in_fn_syntax : false ,
408418 labels_in_fn : vec ! [ ] ,
409419 xcrate_object_lifetime_defaults : DefIdMap ( ) ,
420+ lifetime_uses : DefIdMap ( ) ,
410421 } ;
411422 for ( _, item) in & krate. items {
412423 visitor. visit_item ( item) ;
@@ -443,8 +454,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
443454 fn visit_item ( & mut self , item : & ' tcx hir:: Item ) {
444455 match item. node {
445456 hir:: ItemFn ( ref decl, _, _, _, ref generics, _) => {
446- self . visit_early_late ( None , decl, generics, |this| {
447- intravisit:: walk_item ( this, item) ;
457+ self . visit_early_late ( None ,
458+ decl,
459+ generics,
460+ |this| {
461+ intravisit:: walk_item ( this, item) ;
448462 } ) ;
449463 }
450464 hir:: ItemExternCrate ( _)
@@ -498,9 +512,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
498512 fn visit_foreign_item ( & mut self , item : & ' tcx hir:: ForeignItem ) {
499513 match item. node {
500514 hir:: ForeignItemFn ( ref decl, _, ref generics) => {
501- self . visit_early_late ( None , decl, generics, |this| {
502- intravisit:: walk_foreign_item ( this, item) ;
503- } )
515+ self . visit_early_late ( None ,
516+ decl,
517+ generics,
518+ |this| {
519+ intravisit:: walk_foreign_item ( this, item) ;
520+ } )
504521 }
505522 hir:: ForeignItemStatic ( ..) => {
506523 intravisit:: walk_foreign_item ( self , item) ;
@@ -1142,12 +1159,41 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
11421159 is_in_fn_syntax : self . is_in_fn_syntax ,
11431160 labels_in_fn,
11441161 xcrate_object_lifetime_defaults,
1162+ lifetime_uses : DefIdMap ( ) ,
11451163 } ;
11461164 debug ! ( "entering scope {:?}" , this. scope) ;
11471165 f ( self . scope , & mut this) ;
11481166 debug ! ( "exiting scope {:?}" , this. scope) ;
11491167 self . labels_in_fn = this. labels_in_fn ;
11501168 self . xcrate_object_lifetime_defaults = this. xcrate_object_lifetime_defaults ;
1169+
1170+ for ( def_id, lifetimeuseset) in & this. lifetime_uses {
1171+ match lifetimeuseset {
1172+ & LifetimeUseSet :: One ( _) => {
1173+ let node_id = this. tcx . hir . as_local_node_id ( * def_id) . unwrap ( ) ;
1174+ debug ! ( "node id first={:?}" , node_id) ;
1175+ if let hir:: map:: NodeLifetime ( hir_lifetime) = this. tcx . hir . get ( node_id) {
1176+ let span = hir_lifetime. span ;
1177+ let id = hir_lifetime. id ;
1178+ debug ! ( "id ={:?} span = {:?} hir_lifetime = {:?}" ,
1179+ node_id,
1180+ span,
1181+ hir_lifetime) ;
1182+
1183+ this. tcx
1184+ . struct_span_lint_node ( lint:: builtin:: SINGLE_USE_LIFETIME ,
1185+ id,
1186+ span,
1187+ & format ! ( "lifetime name `{}` only used once" ,
1188+ hir_lifetime. name. name( ) ) )
1189+ . emit ( ) ;
1190+ }
1191+ }
1192+ _ => {
1193+ debug ! ( "Not one use lifetime" ) ;
1194+ }
1195+ }
1196+ }
11511197 }
11521198
11531199 /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
@@ -1239,9 +1285,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
12391285 }
12401286 }
12411287
1242- fn resolve_lifetime_ref ( & mut self , lifetime_ref : & hir:: Lifetime ) {
1288+ fn resolve_lifetime_ref ( & mut self , lifetime_ref : & ' tcx hir:: Lifetime ) {
12431289 debug ! ( "resolve_lifetime_ref(lifetime_ref={:?})" , lifetime_ref) ;
1244-
12451290 // Walk up the scope chain, tracking the number of fn scopes
12461291 // that we pass through, until we find a lifetime with the
12471292 // given name or we run out of scopes.
@@ -1533,8 +1578,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
15331578 }
15341579
15351580 // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
1536- hir:: map:: NodeForeignItem ( _) | hir:: map:: NodeTy ( _) | hir:: map:: NodeTraitRef ( _) => None ,
1537-
1581+ hir:: map:: NodeForeignItem ( _) | hir:: map:: NodeTy ( _) | hir:: map:: NodeTraitRef ( _) =>
1582+ None ,
15381583 // Everything else (only closures?) doesn't
15391584 // actually enjoy elision in return types.
15401585 _ => {
@@ -1710,7 +1755,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
17101755 }
17111756 }
17121757
1713- fn resolve_elided_lifetimes ( & mut self , lifetime_refs : & [ hir:: Lifetime ] ) {
1758+ fn resolve_elided_lifetimes ( & mut self , lifetime_refs : & ' tcx [ hir:: Lifetime ] ) {
17141759 if lifetime_refs. is_empty ( ) {
17151760 return ;
17161761 }
@@ -1865,7 +1910,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
18651910 }
18661911 }
18671912
1868- fn resolve_object_lifetime_default ( & mut self , lifetime_ref : & hir:: Lifetime ) {
1913+ fn resolve_object_lifetime_default ( & mut self , lifetime_ref : & ' tcx hir:: Lifetime ) {
18691914 let mut late_depth = 0 ;
18701915 let mut scope = self . scope ;
18711916 let lifetime = loop {
@@ -1887,7 +1932,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
18871932 self . insert_lifetime ( lifetime_ref, lifetime. shifted ( late_depth) ) ;
18881933 }
18891934
1890- fn check_lifetime_defs ( & mut self , old_scope : ScopeRef , lifetimes : & [ hir:: LifetimeDef ] ) {
1935+ fn check_lifetime_defs ( & mut self , old_scope : ScopeRef , lifetimes : & ' tcx [ hir:: LifetimeDef ] ) {
18911936 for i in 0 ..lifetimes. len ( ) {
18921937 let lifetime_i = & lifetimes[ i] ;
18931938
@@ -1971,7 +2016,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
19712016 }
19722017 }
19732018
1974- fn check_lifetime_def_for_shadowing ( & self , mut old_scope : ScopeRef , lifetime : & hir:: Lifetime ) {
2019+ fn check_lifetime_def_for_shadowing ( & self ,
2020+ mut old_scope : ScopeRef ,
2021+ lifetime : & ' tcx hir:: Lifetime ) {
19752022 for & ( label, label_span) in & self . labels_in_fn {
19762023 // FIXME (#24278): non-hygienic comparison
19772024 if lifetime. name . name ( ) == label {
@@ -2020,7 +2067,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
20202067 }
20212068 }
20222069
2023- fn insert_lifetime ( & mut self , lifetime_ref : & hir:: Lifetime , def : Region ) {
2070+ fn insert_lifetime ( & mut self , lifetime_ref : & ' tcx hir:: Lifetime , def : Region ) {
20242071 if lifetime_ref. id == ast:: DUMMY_NODE_ID {
20252072 span_bug ! (
20262073 lifetime_ref. span,
@@ -2036,6 +2083,25 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
20362083 self . tcx. sess. codemap( ) . span_to_string( lifetime_ref. span)
20372084 ) ;
20382085 self . map . defs . insert ( lifetime_ref. id , def) ;
2086+
2087+ match def {
2088+ Region :: LateBoundAnon ( ..) |
2089+ Region :: Static => {
2090+ // These are anonymous lifetimes or lifetimes that are not declared.
2091+ }
2092+
2093+ Region :: Free ( _, def_id) |
2094+ Region :: LateBound ( _, def_id, _) |
2095+ Region :: EarlyBound ( _, def_id, _) => {
2096+ // A lifetime declared by the user.
2097+ if !self . lifetime_uses . contains_key ( & def_id) {
2098+ self . lifetime_uses
2099+ . insert ( def_id, LifetimeUseSet :: One ( lifetime_ref) ) ;
2100+ } else {
2101+ self . lifetime_uses . insert ( def_id, LifetimeUseSet :: Many ) ;
2102+ }
2103+ }
2104+ }
20392105 }
20402106}
20412107
0 commit comments