@@ -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 ( _)
@@ -498,9 +512,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
498
512
fn visit_foreign_item ( & mut self , item : & ' tcx hir:: ForeignItem ) {
499
513
match item. node {
500
514
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
+ } )
504
521
}
505
522
hir:: ForeignItemStatic ( ..) => {
506
523
intravisit:: walk_foreign_item ( self , item) ;
@@ -1142,12 +1159,41 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1142
1159
is_in_fn_syntax : self . is_in_fn_syntax ,
1143
1160
labels_in_fn,
1144
1161
xcrate_object_lifetime_defaults,
1162
+ lifetime_uses : DefIdMap ( ) ,
1145
1163
} ;
1146
1164
debug ! ( "entering scope {:?}" , this. scope) ;
1147
1165
f ( self . scope , & mut this) ;
1148
1166
debug ! ( "exiting scope {:?}" , this. scope) ;
1149
1167
self . labels_in_fn = this. labels_in_fn ;
1150
1168
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
+ }
1151
1197
}
1152
1198
1153
1199
/// 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> {
1239
1285
}
1240
1286
}
1241
1287
1242
- fn resolve_lifetime_ref ( & mut self , lifetime_ref : & hir:: Lifetime ) {
1288
+ fn resolve_lifetime_ref ( & mut self , lifetime_ref : & ' tcx hir:: Lifetime ) {
1243
1289
debug ! ( "resolve_lifetime_ref(lifetime_ref={:?})" , lifetime_ref) ;
1244
-
1245
1290
// Walk up the scope chain, tracking the number of fn scopes
1246
1291
// that we pass through, until we find a lifetime with the
1247
1292
// given name or we run out of scopes.
@@ -1533,8 +1578,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1533
1578
}
1534
1579
1535
1580
// 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 ,
1538
1583
// Everything else (only closures?) doesn't
1539
1584
// actually enjoy elision in return types.
1540
1585
_ => {
@@ -1710,7 +1755,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1710
1755
}
1711
1756
}
1712
1757
1713
- fn resolve_elided_lifetimes ( & mut self , lifetime_refs : & [ hir:: Lifetime ] ) {
1758
+ fn resolve_elided_lifetimes ( & mut self , lifetime_refs : & ' tcx [ hir:: Lifetime ] ) {
1714
1759
if lifetime_refs. is_empty ( ) {
1715
1760
return ;
1716
1761
}
@@ -1865,7 +1910,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1865
1910
}
1866
1911
}
1867
1912
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 ) {
1869
1914
let mut late_depth = 0 ;
1870
1915
let mut scope = self . scope ;
1871
1916
let lifetime = loop {
@@ -1887,7 +1932,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1887
1932
self . insert_lifetime ( lifetime_ref, lifetime. shifted ( late_depth) ) ;
1888
1933
}
1889
1934
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 ] ) {
1891
1936
for i in 0 ..lifetimes. len ( ) {
1892
1937
let lifetime_i = & lifetimes[ i] ;
1893
1938
@@ -1971,7 +2016,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1971
2016
}
1972
2017
}
1973
2018
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 ) {
1975
2022
for & ( label, label_span) in & self . labels_in_fn {
1976
2023
// FIXME (#24278): non-hygienic comparison
1977
2024
if lifetime. name . name ( ) == label {
@@ -2020,7 +2067,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
2020
2067
}
2021
2068
}
2022
2069
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 ) {
2024
2071
if lifetime_ref. id == ast:: DUMMY_NODE_ID {
2025
2072
span_bug ! (
2026
2073
lifetime_ref. span,
@@ -2036,6 +2083,25 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
2036
2083
self . tcx. sess. codemap( ) . span_to_string( lifetime_ref. span)
2037
2084
) ;
2038
2085
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
+ }
2039
2105
}
2040
2106
}
2041
2107
0 commit comments