@@ -31,6 +31,7 @@ use syntax_pos::Span;
31
31
use errors:: DiagnosticBuilder ;
32
32
use util:: nodemap:: { DefIdMap , FxHashMap , FxHashSet , NodeMap , NodeSet } ;
33
33
use std:: slice;
34
+ use rustc:: lint;
34
35
35
36
use hir;
36
37
use hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
@@ -56,6 +57,13 @@ impl LifetimeDefOrigin {
56
57
}
57
58
}
58
59
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
+
59
67
#[ derive( Clone , Copy , PartialEq , Eq , Hash , RustcEncodable , RustcDecodable , Debug ) ]
60
68
pub enum Region {
61
69
Static ,
@@ -245,6 +253,8 @@ struct LifetimeContext<'a, 'tcx: 'a> {
245
253
246
254
// Cache for cross-crate per-definition object lifetime defaults.
247
255
xcrate_object_lifetime_defaults : DefIdMap < Vec < ObjectLifetimeDefault > > ,
256
+
257
+ lifetime_uses : DefIdMap < LifetimeUseSet < ' tcx > > ,
248
258
}
249
259
250
260
#[ derive( Debug ) ]
@@ -407,6 +417,7 @@ fn krate<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> NamedRegionMap {
407
417
is_in_fn_syntax : false ,
408
418
labels_in_fn : vec ! [ ] ,
409
419
xcrate_object_lifetime_defaults : DefIdMap ( ) ,
420
+ lifetime_uses : DefIdMap ( ) ,
410
421
} ;
411
422
for ( _, item) in & krate. items {
412
423
visitor. visit_item ( item) ;
@@ -443,8 +454,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
443
454
fn visit_item ( & mut self , item : & ' tcx hir:: Item ) {
444
455
match item. node {
445
456
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) ;
448
462
} ) ;
449
463
}
450
464
hir:: ItemExternCrate ( _)
@@ -499,9 +513,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
499
513
fn visit_foreign_item ( & mut self , item : & ' tcx hir:: ForeignItem ) {
500
514
match item. node {
501
515
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
+ } )
505
522
}
506
523
hir:: ForeignItemStatic ( ..) => {
507
524
intravisit:: walk_foreign_item ( self , item) ;
@@ -1190,12 +1207,41 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1190
1207
is_in_fn_syntax : self . is_in_fn_syntax ,
1191
1208
labels_in_fn,
1192
1209
xcrate_object_lifetime_defaults,
1210
+ lifetime_uses : DefIdMap ( ) ,
1193
1211
} ;
1194
1212
debug ! ( "entering scope {:?}" , this. scope) ;
1195
1213
f ( self . scope , & mut this) ;
1196
1214
debug ! ( "exiting scope {:?}" , this. scope) ;
1197
1215
self . labels_in_fn = this. labels_in_fn ;
1198
1216
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
+ }
1199
1245
}
1200
1246
1201
1247
/// 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> {
1287
1333
}
1288
1334
}
1289
1335
1290
- fn resolve_lifetime_ref ( & mut self , lifetime_ref : & hir:: Lifetime ) {
1336
+ fn resolve_lifetime_ref ( & mut self , lifetime_ref : & ' tcx hir:: Lifetime ) {
1291
1337
debug ! ( "resolve_lifetime_ref(lifetime_ref={:?})" , lifetime_ref) ;
1292
-
1293
1338
// Walk up the scope chain, tracking the number of fn scopes
1294
1339
// that we pass through, until we find a lifetime with the
1295
1340
// given name or we run out of scopes.
@@ -1581,8 +1626,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1581
1626
}
1582
1627
1583
1628
// 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 ,
1586
1631
// Everything else (only closures?) doesn't
1587
1632
// actually enjoy elision in return types.
1588
1633
_ => {
@@ -1758,7 +1803,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1758
1803
}
1759
1804
}
1760
1805
1761
- fn resolve_elided_lifetimes ( & mut self , lifetime_refs : & [ hir:: Lifetime ] ) {
1806
+ fn resolve_elided_lifetimes ( & mut self , lifetime_refs : & ' tcx [ hir:: Lifetime ] ) {
1762
1807
if lifetime_refs. is_empty ( ) {
1763
1808
return ;
1764
1809
}
@@ -1913,7 +1958,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1913
1958
}
1914
1959
}
1915
1960
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 ) {
1917
1962
let mut late_depth = 0 ;
1918
1963
let mut scope = self . scope ;
1919
1964
let lifetime = loop {
@@ -1935,7 +1980,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1935
1980
self . insert_lifetime ( lifetime_ref, lifetime. shifted ( late_depth) ) ;
1936
1981
}
1937
1982
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 ] ) {
1939
1984
for i in 0 ..lifetimes. len ( ) {
1940
1985
let lifetime_i = & lifetimes[ i] ;
1941
1986
@@ -2019,7 +2064,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
2019
2064
}
2020
2065
}
2021
2066
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 ) {
2023
2070
for & ( label, label_span) in & self . labels_in_fn {
2024
2071
// FIXME (#24278): non-hygienic comparison
2025
2072
if lifetime. name . name ( ) == label {
@@ -2068,7 +2115,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
2068
2115
}
2069
2116
}
2070
2117
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 ) {
2072
2119
if lifetime_ref. id == ast:: DUMMY_NODE_ID {
2073
2120
span_bug ! (
2074
2121
lifetime_ref. span,
@@ -2084,6 +2131,25 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
2084
2131
self . tcx. sess. codemap( ) . span_to_string( lifetime_ref. span)
2085
2132
) ;
2086
2133
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
+ }
2087
2153
}
2088
2154
}
2089
2155
0 commit comments