@@ -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 ( _)
@@ -499,9 +513,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
499513 fn visit_foreign_item ( & mut self , item : & ' tcx hir:: ForeignItem ) {
500514 match item. node {
501515 hir:: ForeignItemFn ( ref decl, _, ref generics) => {
502- self . visit_early_late ( None , decl, generics, |this| {
503- intravisit:: walk_foreign_item ( this, item) ;
504- } )
516+ self . visit_early_late ( None ,
517+ decl,
518+ generics,
519+ |this| {
520+ intravisit:: walk_foreign_item ( this, item) ;
521+ } )
505522 }
506523 hir:: ForeignItemStatic ( ..) => {
507524 intravisit:: walk_foreign_item ( self , item) ;
@@ -1190,12 +1207,41 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
11901207 is_in_fn_syntax : self . is_in_fn_syntax ,
11911208 labels_in_fn,
11921209 xcrate_object_lifetime_defaults,
1210+ lifetime_uses : DefIdMap ( ) ,
11931211 } ;
11941212 debug ! ( "entering scope {:?}" , this. scope) ;
11951213 f ( self . scope , & mut this) ;
11961214 debug ! ( "exiting scope {:?}" , this. scope) ;
11971215 self . labels_in_fn = this. labels_in_fn ;
11981216 self . xcrate_object_lifetime_defaults = this. xcrate_object_lifetime_defaults ;
1217+
1218+ for ( def_id, lifetimeuseset) in & this. lifetime_uses {
1219+ match lifetimeuseset {
1220+ & LifetimeUseSet :: One ( _) => {
1221+ let node_id = this. tcx . hir . as_local_node_id ( * def_id) . unwrap ( ) ;
1222+ debug ! ( "node id first={:?}" , node_id) ;
1223+ if let hir:: map:: NodeLifetime ( hir_lifetime) = this. tcx . hir . get ( node_id) {
1224+ let span = hir_lifetime. span ;
1225+ let id = hir_lifetime. id ;
1226+ debug ! ( "id ={:?} span = {:?} hir_lifetime = {:?}" ,
1227+ node_id,
1228+ span,
1229+ hir_lifetime) ;
1230+
1231+ this. tcx
1232+ . struct_span_lint_node ( lint:: builtin:: SINGLE_USE_LIFETIME ,
1233+ id,
1234+ span,
1235+ & format ! ( "lifetime name `{}` only used once" ,
1236+ hir_lifetime. name. name( ) ) )
1237+ . emit ( ) ;
1238+ }
1239+ }
1240+ _ => {
1241+ debug ! ( "Not one use lifetime" ) ;
1242+ }
1243+ }
1244+ }
11991245 }
12001246
12011247 /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
@@ -1287,9 +1333,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
12871333 }
12881334 }
12891335
1290- fn resolve_lifetime_ref ( & mut self , lifetime_ref : & hir:: Lifetime ) {
1336+ fn resolve_lifetime_ref ( & mut self , lifetime_ref : & ' tcx hir:: Lifetime ) {
12911337 debug ! ( "resolve_lifetime_ref(lifetime_ref={:?})" , lifetime_ref) ;
1292-
12931338 // Walk up the scope chain, tracking the number of fn scopes
12941339 // that we pass through, until we find a lifetime with the
12951340 // given name or we run out of scopes.
@@ -1581,8 +1626,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
15811626 }
15821627
15831628 // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
1584- hir:: map:: NodeForeignItem ( _) | hir:: map:: NodeTy ( _) | hir:: map:: NodeTraitRef ( _) => None ,
1585-
1629+ hir:: map:: NodeForeignItem ( _) | hir:: map:: NodeTy ( _) | hir:: map:: NodeTraitRef ( _) =>
1630+ None ,
15861631 // Everything else (only closures?) doesn't
15871632 // actually enjoy elision in return types.
15881633 _ => {
@@ -1758,7 +1803,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
17581803 }
17591804 }
17601805
1761- fn resolve_elided_lifetimes ( & mut self , lifetime_refs : & [ hir:: Lifetime ] ) {
1806+ fn resolve_elided_lifetimes ( & mut self , lifetime_refs : & ' tcx [ hir:: Lifetime ] ) {
17621807 if lifetime_refs. is_empty ( ) {
17631808 return ;
17641809 }
@@ -1913,7 +1958,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
19131958 }
19141959 }
19151960
1916- fn resolve_object_lifetime_default ( & mut self , lifetime_ref : & hir:: Lifetime ) {
1961+ fn resolve_object_lifetime_default ( & mut self , lifetime_ref : & ' tcx hir:: Lifetime ) {
19171962 let mut late_depth = 0 ;
19181963 let mut scope = self . scope ;
19191964 let lifetime = loop {
@@ -1935,7 +1980,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
19351980 self . insert_lifetime ( lifetime_ref, lifetime. shifted ( late_depth) ) ;
19361981 }
19371982
1938- fn check_lifetime_defs ( & mut self , old_scope : ScopeRef , lifetimes : & [ hir:: LifetimeDef ] ) {
1983+ fn check_lifetime_defs ( & mut self , old_scope : ScopeRef , lifetimes : & ' tcx [ hir:: LifetimeDef ] ) {
19391984 for i in 0 ..lifetimes. len ( ) {
19401985 let lifetime_i = & lifetimes[ i] ;
19411986
@@ -2019,7 +2064,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
20192064 }
20202065 }
20212066
2022- fn check_lifetime_def_for_shadowing ( & self , mut old_scope : ScopeRef , lifetime : & hir:: Lifetime ) {
2067+ fn check_lifetime_def_for_shadowing ( & self ,
2068+ mut old_scope : ScopeRef ,
2069+ lifetime : & ' tcx hir:: Lifetime ) {
20232070 for & ( label, label_span) in & self . labels_in_fn {
20242071 // FIXME (#24278): non-hygienic comparison
20252072 if lifetime. name . name ( ) == label {
@@ -2068,7 +2115,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
20682115 }
20692116 }
20702117
2071- fn insert_lifetime ( & mut self , lifetime_ref : & hir:: Lifetime , def : Region ) {
2118+ fn insert_lifetime ( & mut self , lifetime_ref : & ' tcx hir:: Lifetime , def : Region ) {
20722119 if lifetime_ref. id == ast:: DUMMY_NODE_ID {
20732120 span_bug ! (
20742121 lifetime_ref. span,
@@ -2084,6 +2131,25 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
20842131 self . tcx. sess. codemap( ) . span_to_string( lifetime_ref. span)
20852132 ) ;
20862133 self . map . defs . insert ( lifetime_ref. id , def) ;
2134+
2135+ match def {
2136+ Region :: LateBoundAnon ( ..) |
2137+ Region :: Static => {
2138+ // These are anonymous lifetimes or lifetimes that are not declared.
2139+ }
2140+
2141+ Region :: Free ( _, def_id) |
2142+ Region :: LateBound ( _, def_id, _) |
2143+ Region :: EarlyBound ( _, def_id, _) => {
2144+ // A lifetime declared by the user.
2145+ if !self . lifetime_uses . contains_key ( & def_id) {
2146+ self . lifetime_uses
2147+ . insert ( def_id, LifetimeUseSet :: One ( lifetime_ref) ) ;
2148+ } else {
2149+ self . lifetime_uses . insert ( def_id, LifetimeUseSet :: Many ) ;
2150+ }
2151+ }
2152+ }
20872153 }
20882154}
20892155
0 commit comments