@@ -48,7 +48,10 @@ use syntax::visit;
48
48
49
49
pub struct Rcx {
50
50
fcx : @mut FnCtxt ,
51
- errors_reported : uint
51
+ errors_reported : uint ,
52
+
53
+ // id of innermost fn or loop
54
+ repeating_scope : ast:: node_id ,
52
55
}
53
56
54
57
pub type rvt = visit:: vt < @mut Rcx > ;
@@ -78,6 +81,12 @@ impl Rcx {
78
81
self . fcx . ccx . tcx
79
82
}
80
83
84
+ pub fn set_repeating_scope ( & mut self , scope : ast:: node_id ) -> ast:: node_id {
85
+ let old_scope = self . repeating_scope ;
86
+ self . repeating_scope = scope;
87
+ old_scope
88
+ }
89
+
81
90
pub fn resolve_type ( & mut self , unresolved_ty : ty:: t ) -> ty:: t {
82
91
/*!
83
92
* Try to resolve the type for the given node, returning
@@ -134,7 +143,8 @@ impl Rcx {
134
143
}
135
144
136
145
pub fn regionck_expr ( fcx : @mut FnCtxt , e : @ast:: expr ) {
137
- let rcx = @mut Rcx { fcx : fcx, errors_reported : 0 } ;
146
+ let rcx = @mut Rcx { fcx : fcx, errors_reported : 0 ,
147
+ repeating_scope : e. id } ;
138
148
if fcx. err_count_since_creation ( ) == 0 {
139
149
// regionck assumes typeck succeeded
140
150
let v = regionck_visitor ( ) ;
@@ -144,7 +154,8 @@ pub fn regionck_expr(fcx: @mut FnCtxt, e: @ast::expr) {
144
154
}
145
155
146
156
pub fn regionck_fn ( fcx : @mut FnCtxt , blk : & ast:: blk ) {
147
- let rcx = @mut Rcx { fcx : fcx, errors_reported : 0 } ;
157
+ let rcx = @mut Rcx { fcx : fcx, errors_reported : 0 ,
158
+ repeating_scope : blk. node . id } ;
148
159
if fcx. err_count_since_creation ( ) == 0 {
149
160
// regionck assumes typeck succeeded
150
161
let v = regionck_visitor ( ) ;
@@ -231,7 +242,8 @@ fn constrain_bindings_in_pat(pat: @ast::pat, rcx: @mut Rcx) {
231
242
}
232
243
233
244
fn visit_expr ( expr : @ast:: expr , ( rcx, v) : ( @mut Rcx , rvt ) ) {
234
- debug ! ( "regionck::visit_expr(e=?)" ) ;
245
+ debug ! ( "regionck::visit_expr(e=%s, repeating_scope=%?)" ,
246
+ expr. repr( rcx. fcx. tcx( ) ) , rcx. repeating_scope) ;
235
247
236
248
let has_method_map = rcx. fcx . inh . method_map . contains_key ( & expr. id ) ;
237
249
@@ -274,6 +286,9 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) {
274
286
}
275
287
}
276
288
}
289
+ ast:: expr_loop ( ref body, _) => {
290
+ tcx. region_maps . record_cleanup_scope ( body. node . id ) ;
291
+ }
277
292
ast:: expr_while ( cond, ref body) => {
278
293
tcx. region_maps . record_cleanup_scope ( cond. id ) ;
279
294
tcx. region_maps . record_cleanup_scope ( body. node . id ) ;
@@ -313,10 +328,14 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) {
313
328
ast : : expr_call( callee, ref args, _) => {
314
329
constrain_callee( rcx, callee. id, expr, callee) ;
315
330
constrain_call( rcx, callee. id, expr, None , * args, false ) ;
331
+
332
+ visit:: visit_expr( expr, ( rcx, v) ) ;
316
333
}
317
334
318
335
ast:: expr_method_call( callee_id, arg0, _, _, ref args, _) => {
319
336
constrain_call( rcx, callee_id, expr, Some ( arg0) , * args, false ) ;
337
+
338
+ visit:: visit_expr( expr, ( rcx, v) ) ;
320
339
}
321
340
322
341
ast:: expr_index( callee_id, lhs, rhs) |
@@ -327,23 +346,31 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) {
327
346
// implicit "by ref" sort of passing style here. This
328
347
// should be converted to an adjustment!
329
348
constrain_call( rcx, callee_id, expr, Some ( lhs) , [ rhs] , true ) ;
349
+
350
+ visit:: visit_expr( expr, ( rcx, v) ) ;
330
351
}
331
352
332
353
ast:: expr_unary( callee_id, _, lhs) if has_method_map => {
333
354
// As above.
334
355
constrain_call( rcx, callee_id, expr, Some ( lhs) , [ ] , true ) ;
356
+
357
+ visit:: visit_expr( expr, ( rcx, v) ) ;
335
358
}
336
359
337
360
ast:: expr_unary( _, ast:: deref, base) => {
338
361
// For *a, the lifetime of a must enclose the deref
339
362
let base_ty = rcx. resolve_node_type( base. id) ;
340
363
constrain_derefs( rcx, expr, 1 , base_ty) ;
364
+
365
+ visit:: visit_expr( expr, ( rcx, v) ) ;
341
366
}
342
367
343
368
ast:: expr_index( _, vec_expr, _) => {
344
369
// For a[b], the lifetime of a must enclose the deref
345
370
let vec_type = rcx. resolve_expr_type_adjusted( vec_expr) ;
346
371
constrain_index( rcx, expr, vec_type) ;
372
+
373
+ visit:: visit_expr( expr, ( rcx, v) ) ;
347
374
}
348
375
349
376
ast:: expr_cast( source, _) => {
@@ -372,6 +399,8 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) {
372
399
}
373
400
_ => ( )
374
401
}
402
+
403
+ visit:: visit_expr( expr, ( rcx, v) ) ;
375
404
}
376
405
377
406
ast:: expr_addr_of( _, base) => {
@@ -387,29 +416,87 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) {
387
416
let ty0 = rcx. resolve_node_type ( expr. id ) ;
388
417
constrain_regions_in_type ( rcx, ty:: re_scope ( expr. id ) ,
389
418
infer:: AddrOf ( expr. span ) , ty0) ;
419
+ visit:: visit_expr ( expr, ( rcx, v) ) ;
390
420
}
391
421
392
422
ast:: expr_match ( discr, ref arms) => {
393
423
guarantor:: for_match ( rcx, discr, * arms) ;
424
+
425
+ visit:: visit_expr ( expr, ( rcx, v) ) ;
426
+ }
427
+
428
+ ast:: expr_loop_body ( subexpr) => {
429
+ check_expr_fn_block ( rcx, subexpr, v, true ) ;
394
430
}
395
431
396
432
ast:: expr_fn_block ( * ) => {
397
- // The lifetime of a block fn must not outlive the variables
398
- // it closes over
433
+ check_expr_fn_block ( rcx, expr, v, false ) ;
434
+ }
435
+
436
+ ast:: expr_loop ( ref body, _) => {
437
+ let repeating_scope = rcx. set_repeating_scope ( body. node . id ) ;
438
+ visit:: visit_expr ( expr, ( rcx, v) ) ;
439
+ rcx. set_repeating_scope ( repeating_scope) ;
440
+ }
441
+
442
+ ast:: expr_while ( cond, ref body) => {
443
+ let repeating_scope = rcx. set_repeating_scope ( cond. id ) ;
444
+ ( v. visit_expr ) ( cond, ( rcx, v) ) ;
445
+
446
+ rcx. set_repeating_scope ( body. node . id ) ;
447
+ ( v. visit_block ) ( body, ( rcx, v) ) ;
448
+
449
+ rcx. set_repeating_scope ( repeating_scope) ;
450
+ }
451
+
452
+ _ => {
453
+ visit:: visit_expr ( expr, ( rcx, v) ) ;
454
+ }
455
+ }
456
+ }
457
+
458
+ fn check_expr_fn_block( rcx: @mut Rcx ,
459
+ expr: @ast:: expr,
460
+ v: rvt,
461
+ is_loop_body: bool ) {
462
+ let tcx = rcx. fcx . tcx ( ) ;
463
+ match expr. node {
464
+ ast:: expr_fn_block( _, ref body) => {
399
465
let function_type = rcx. resolve_node_type ( expr. id ) ;
400
466
match ty:: get ( function_type) . sty {
401
- ty:: ty_closure( ty:: ClosureTy { sigil : ast:: BorrowedSigil ,
402
- region : region, _} ) => {
403
- constrain_free_variables ( rcx, region, expr) ;
467
+ ty:: ty_closure(
468
+ ty:: ClosureTy {
469
+ sigil : ast:: BorrowedSigil , region : region, _} ) => {
470
+ if get_freevars ( tcx, expr. id ) . is_empty ( ) && !is_loop_body {
471
+ // No free variables means that the environment
472
+ // will be NULL at runtime and hence the closure
473
+ // has static lifetime.
474
+ } else {
475
+ // Otherwise, the closure must not outlive the
476
+ // variables it closes over, nor can it
477
+ // outlive the innermost repeating scope
478
+ // (since otherwise that would require
479
+ // infinite stack).
480
+ constrain_free_variables ( rcx, region, expr) ;
481
+ let repeating_scope = ty:: re_scope ( rcx. repeating_scope ) ;
482
+ rcx. fcx . mk_subr ( true , infer:: InfStackClosure ( expr. span ) ,
483
+ region, repeating_scope) ;
484
+ }
404
485
}
405
486
_ => ( )
406
487
}
488
+
489
+ let repeating_scope = rcx. set_repeating_scope ( body. node . id ) ;
490
+ visit:: visit_expr ( expr, ( rcx, v) ) ;
491
+ rcx. set_repeating_scope ( repeating_scope) ;
407
492
}
408
493
409
- _ => ( )
494
+ _ => {
495
+ tcx. sess . span_bug (
496
+ expr. span ,
497
+ "Expected expr_fn_block" ) ;
498
+ }
410
499
}
411
-
412
- visit:: visit_expr ( expr, ( rcx, v) ) ;
413
500
}
414
501
415
502
fn constrain_callee ( rcx : @mut Rcx ,
0 commit comments