@@ -90,48 +90,51 @@ pub fn krate(sess: &Session, krate: &ast::Crate, def_map: &DefMap) -> NamedRegio
90
90
91
91
impl < ' a , ' v > Visitor < ' v > for LifetimeContext < ' a > {
92
92
fn visit_item ( & mut self , item : & ast:: Item ) {
93
- match item. node {
94
- ast:: ItemFn ( ..) => {
95
- // Fn lifetimes get added in visit_fn below:
96
- self . with ( RootScope , |this| visit:: walk_item ( this, item) ) ;
97
- }
98
- ast:: ItemMod ( ..) |
99
- ast:: ItemMac ( ..) |
100
- ast:: ItemForeignMod ( ..) |
101
- ast:: ItemStatic ( ..) |
102
- ast:: ItemConst ( ..) => {
103
- // These sorts of items have no lifetime parameters at all.
104
- self . with ( RootScope , |this| visit:: walk_item ( this, item) ) ;
105
- }
106
- ast:: ItemTy ( _, ref generics) |
107
- ast:: ItemEnum ( _, ref generics) |
108
- ast:: ItemStruct ( _, ref generics) |
109
- ast:: ItemTrait ( _, ref generics, _, _, _) => {
110
- // These kinds of items have only early bound lifetime parameters.
111
- let lifetimes = & generics. lifetimes ;
112
- self . with ( EarlyScope ( subst:: TypeSpace , lifetimes, & ROOT_SCOPE ) , |this| {
113
- this. check_lifetime_defs ( lifetimes) ;
93
+ // Items always introduce a new root scope
94
+ self . with ( RootScope , |_, this| {
95
+ match item. node {
96
+ ast:: ItemFn ( ..) => {
97
+ // Fn lifetimes get added in visit_fn below:
114
98
visit:: walk_item ( this, item) ;
115
- } ) ;
116
- }
117
- ast:: ItemImpl ( _, ref generics, _, _, _) => {
118
- // Impls have both early- and late-bound lifetimes.
119
- self . visit_early_late ( subst:: TypeSpace , generics, |this| {
120
- this. check_lifetime_defs ( & generics. lifetimes ) ;
99
+ }
100
+ ast:: ItemMod ( ..) |
101
+ ast:: ItemMac ( ..) |
102
+ ast:: ItemForeignMod ( ..) |
103
+ ast:: ItemStatic ( ..) |
104
+ ast:: ItemConst ( ..) => {
105
+ // These sorts of items have no lifetime parameters at all.
121
106
visit:: walk_item ( this, item) ;
122
- } )
107
+ }
108
+ ast:: ItemTy ( _, ref generics) |
109
+ ast:: ItemEnum ( _, ref generics) |
110
+ ast:: ItemStruct ( _, ref generics) |
111
+ ast:: ItemTrait ( _, ref generics, _, _, _) => {
112
+ // These kinds of items have only early bound lifetime parameters.
113
+ let lifetimes = & generics. lifetimes ;
114
+ let early_scope = EarlyScope ( subst:: TypeSpace , lifetimes, & ROOT_SCOPE ) ;
115
+ this. with ( early_scope, |old_scope, this| {
116
+ this. check_lifetime_defs ( old_scope, lifetimes) ;
117
+ visit:: walk_item ( this, item) ;
118
+ } ) ;
119
+ }
120
+ ast:: ItemImpl ( _, ref generics, _, _, _) => {
121
+ // Impls have both early- and late-bound lifetimes.
122
+ this. visit_early_late ( subst:: TypeSpace , generics, |this| {
123
+ visit:: walk_item ( this, item) ;
124
+ } )
125
+ }
123
126
}
124
- }
127
+ } ) ;
125
128
}
126
129
127
130
fn visit_fn ( & mut self , fk : visit:: FnKind < ' v > , fd : & ' v ast:: FnDecl ,
128
131
b : & ' v ast:: Block , s : Span , _: ast:: NodeId ) {
129
132
match fk {
130
133
visit:: FkItemFn ( _, generics, _, _) |
131
134
visit:: FkMethod ( _, generics, _) => {
132
- self . visit_early_late (
133
- subst :: FnSpace , generics ,
134
- |this| visit :: walk_fn ( this , fk , fd , b , s ) )
135
+ self . visit_early_late ( subst :: FnSpace , generics , |this| {
136
+ visit :: walk_fn ( this , fk , fd , b , s )
137
+ } )
135
138
}
136
139
visit:: FkFnBlock ( ..) => {
137
140
visit:: walk_fn ( self , fk, fd, b, s)
@@ -145,8 +148,8 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
145
148
// Careful, the bounds on a closure/proc are *not* within its binder.
146
149
visit:: walk_ty_param_bounds_helper ( self , & c. bounds ) ;
147
150
visit:: walk_lifetime_decls_helper ( self , & c. lifetimes ) ;
148
- self . with ( LateScope ( & c. lifetimes , self . scope ) , |this| {
149
- this. check_lifetime_defs ( & c. lifetimes ) ;
151
+ self . with ( LateScope ( & c. lifetimes , self . scope ) , |old_scope , this| {
152
+ this. check_lifetime_defs ( old_scope , & c. lifetimes ) ;
150
153
for argument in c. decl . inputs . iter ( ) {
151
154
this. visit_ty ( & * argument. ty )
152
155
}
@@ -155,10 +158,10 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
155
158
}
156
159
ast:: TyBareFn ( ref c) => {
157
160
visit:: walk_lifetime_decls_helper ( self , & c. lifetimes ) ;
158
- self . with ( LateScope ( & c. lifetimes , self . scope ) , |this| {
161
+ self . with ( LateScope ( & c. lifetimes , self . scope ) , |old_scope , this| {
159
162
// a bare fn has no bounds, so everything
160
163
// contained within is scoped within its binder.
161
- this. check_lifetime_defs ( & c. lifetimes ) ;
164
+ this. check_lifetime_defs ( old_scope , & c. lifetimes ) ;
162
165
visit:: walk_ty ( this, ty) ;
163
166
} ) ;
164
167
}
@@ -167,7 +170,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
167
170
// a trait ref, which introduces a binding scope.
168
171
match self . def_map . borrow ( ) . get ( & id) {
169
172
Some ( & def:: DefTrait ( ..) ) => {
170
- self . with ( LateScope ( & Vec :: new ( ) , self . scope ) , |this| {
173
+ self . with ( LateScope ( & Vec :: new ( ) , self . scope ) , |_ , this| {
171
174
this. visit_path ( path, id) ;
172
175
} ) ;
173
176
}
@@ -190,7 +193,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
190
193
191
194
fn visit_block ( & mut self , b : & ast:: Block ) {
192
195
self . with ( BlockScope ( region:: CodeExtent :: from_node_id ( b. id ) , self . scope ) ,
193
- |this| visit:: walk_block ( this, b) ) ;
196
+ |_ , this| visit:: walk_block ( this, b) ) ;
194
197
}
195
198
196
199
fn visit_lifetime_ref ( & mut self , lifetime_ref : & ast:: Lifetime ) {
@@ -232,8 +235,8 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
232
235
fn visit_poly_trait_ref ( & mut self , trait_ref : & ast:: PolyTraitRef ) {
233
236
debug ! ( "visit_poly_trait_ref trait_ref={}" , trait_ref) ;
234
237
235
- self . with ( LateScope ( & trait_ref. bound_lifetimes , self . scope ) , |this| {
236
- this. check_lifetime_defs ( & trait_ref. bound_lifetimes ) ;
238
+ self . with ( LateScope ( & trait_ref. bound_lifetimes , self . scope ) , |old_scope , this| {
239
+ this. check_lifetime_defs ( old_scope , & trait_ref. bound_lifetimes ) ;
237
240
for lifetime in trait_ref. bound_lifetimes . iter ( ) {
238
241
this. visit_lifetime_def ( lifetime) ;
239
242
}
@@ -248,7 +251,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
248
251
249
252
impl < ' a > LifetimeContext < ' a > {
250
253
fn with < F > ( & mut self , wrap_scope : ScopeChain , f : F ) where
251
- F : FnOnce ( & mut LifetimeContext ) ,
254
+ F : FnOnce ( Scope , & mut LifetimeContext ) ,
252
255
{
253
256
let LifetimeContext { sess, ref mut named_region_map, ..} = * self ;
254
257
let mut this = LifetimeContext {
@@ -258,7 +261,7 @@ impl<'a> LifetimeContext<'a> {
258
261
def_map : self . def_map ,
259
262
} ;
260
263
debug ! ( "entering scope {}" , this. scope) ;
261
- f ( & mut this) ;
264
+ f ( self . scope , & mut this) ;
262
265
debug ! ( "exiting scope {}" , this. scope) ;
263
266
}
264
267
@@ -294,9 +297,9 @@ impl<'a> LifetimeContext<'a> {
294
297
let ( early, late) = generics. lifetimes . clone ( ) . partition (
295
298
|l| referenced_idents. iter ( ) . any ( |& i| i == l. lifetime . name ) ) ;
296
299
297
- self . with ( EarlyScope ( early_space, & early, self . scope ) , move |this| {
298
- this. with ( LateScope ( & late, this. scope ) , move |this| {
299
- this. check_lifetime_defs ( & generics. lifetimes ) ;
300
+ self . with ( EarlyScope ( early_space, & early, self . scope ) , move |old_scope , this| {
301
+ this. with ( LateScope ( & late, this. scope ) , move |_ , this| {
302
+ this. check_lifetime_defs ( old_scope , & generics. lifetimes ) ;
300
303
walk ( this) ;
301
304
} ) ;
302
305
} ) ;
@@ -323,7 +326,8 @@ impl<'a> LifetimeContext<'a> {
323
326
324
327
EarlyScope ( space, lifetimes, s) => {
325
328
match search_lifetimes ( lifetimes, lifetime_ref) {
326
- Some ( ( index, decl_id) ) => {
329
+ Some ( ( index, lifetime_def) ) => {
330
+ let decl_id = lifetime_def. id ;
327
331
let def = DefEarlyBoundRegion ( space, index, decl_id) ;
328
332
self . insert_lifetime ( lifetime_ref, def) ;
329
333
return ;
@@ -336,7 +340,8 @@ impl<'a> LifetimeContext<'a> {
336
340
337
341
LateScope ( lifetimes, s) => {
338
342
match search_lifetimes ( lifetimes, lifetime_ref) {
339
- Some ( ( _index, decl_id) ) => {
343
+ Some ( ( _index, lifetime_def) ) => {
344
+ let decl_id = lifetime_def. id ;
340
345
let debruijn = ty:: DebruijnIndex :: new ( late_depth + 1 ) ;
341
346
let def = DefLateBoundRegion ( debruijn, decl_id) ;
342
347
self . insert_lifetime ( lifetime_ref, def) ;
@@ -388,8 +393,8 @@ impl<'a> LifetimeContext<'a> {
388
393
}
389
394
390
395
match search_result {
391
- Some ( ( _depth, decl_id ) ) => {
392
- let def = DefFreeRegion ( scope_data, decl_id ) ;
396
+ Some ( ( _depth, lifetime ) ) => {
397
+ let def = DefFreeRegion ( scope_data, lifetime . id ) ;
393
398
self . insert_lifetime ( lifetime_ref, def) ;
394
399
}
395
400
@@ -407,7 +412,7 @@ impl<'a> LifetimeContext<'a> {
407
412
token:: get_name( lifetime_ref. name) ) . as_slice ( ) ) ;
408
413
}
409
414
410
- fn check_lifetime_defs ( & mut self , lifetimes : & Vec < ast:: LifetimeDef > ) {
415
+ fn check_lifetime_defs ( & mut self , old_scope : Scope , lifetimes : & Vec < ast:: LifetimeDef > ) {
411
416
for i in range ( 0 , lifetimes. len ( ) ) {
412
417
let lifetime_i = & lifetimes[ i] ;
413
418
@@ -422,6 +427,7 @@ impl<'a> LifetimeContext<'a> {
422
427
}
423
428
}
424
429
430
+ // It is a hard error to shadow a lifetime within the same scope.
425
431
for j in range ( i + 1 , lifetimes. len ( ) ) {
426
432
let lifetime_j = & lifetimes[ j] ;
427
433
@@ -435,12 +441,54 @@ impl<'a> LifetimeContext<'a> {
435
441
}
436
442
}
437
443
444
+ // It is a soft error to shadow a lifetime within a parent scope.
445
+ self . check_lifetime_def_for_shadowing ( old_scope, & lifetime_i. lifetime ) ;
446
+
438
447
for bound in lifetime_i. bounds . iter ( ) {
439
448
self . resolve_lifetime_ref ( bound) ;
440
449
}
441
450
}
442
451
}
443
452
453
+ fn check_lifetime_def_for_shadowing ( & self ,
454
+ mut old_scope : Scope ,
455
+ lifetime : & ast:: Lifetime )
456
+ {
457
+ loop {
458
+ match * old_scope {
459
+ BlockScope ( _, s) => {
460
+ old_scope = s;
461
+ }
462
+
463
+ RootScope => {
464
+ return ;
465
+ }
466
+
467
+ EarlyScope ( _, lifetimes, s) |
468
+ LateScope ( lifetimes, s) => {
469
+ if let Some ( ( _, lifetime_def) ) = search_lifetimes ( lifetimes, lifetime) {
470
+ self . sess . span_warn (
471
+ lifetime. span ,
472
+ format ! ( "lifetime name `{}` shadows another \
473
+ lifetime name that is already in scope",
474
+ token:: get_name( lifetime. name) ) . as_slice ( ) ) ;
475
+ self . sess . span_help (
476
+ lifetime_def. span ,
477
+ format ! ( "shadowed lifetime `{}` declared here" ,
478
+ token:: get_name( lifetime. name) ) . as_slice ( ) ) ;
479
+ self . sess . span_help (
480
+ lifetime. span ,
481
+ "shadowed lifetimes are deprecated \
482
+ and will become a hard error before 1.0") ;
483
+ return ;
484
+ }
485
+
486
+ old_scope = s;
487
+ }
488
+ }
489
+ }
490
+ }
491
+
444
492
fn insert_lifetime ( & mut self ,
445
493
lifetime_ref : & ast:: Lifetime ,
446
494
def : DefRegion ) {
@@ -458,12 +506,12 @@ impl<'a> LifetimeContext<'a> {
458
506
}
459
507
}
460
508
461
- fn search_lifetimes ( lifetimes : & Vec < ast:: LifetimeDef > ,
509
+ fn search_lifetimes < ' a > ( lifetimes : & ' a Vec < ast:: LifetimeDef > ,
462
510
lifetime_ref : & ast:: Lifetime )
463
- -> Option < ( uint , ast:: NodeId ) > {
511
+ -> Option < ( uint , & ' a ast:: Lifetime ) > {
464
512
for ( i, lifetime_decl) in lifetimes. iter ( ) . enumerate ( ) {
465
513
if lifetime_decl. lifetime . name == lifetime_ref. name {
466
- return Some ( ( i, lifetime_decl. lifetime . id ) ) ;
514
+ return Some ( ( i, & lifetime_decl. lifetime ) ) ;
467
515
}
468
516
}
469
517
return None ;
0 commit comments