@@ -206,50 +206,64 @@ impl CodeExtent {
206
206
}
207
207
208
208
/// The region maps encode information about region relationships.
209
- ///
210
- /// - `scope_map` maps from a scope id to the enclosing scope id; this is
211
- /// usually corresponding to the lexical nesting, though in the case of
212
- /// closures the parent scope is the innermost conditional expression or repeating
213
- /// block. (Note that the enclosing scope id for the block
214
- /// associated with a closure is the closure itself.)
215
- ///
216
- /// - `var_map` maps from a variable or binding id to the block in which
217
- /// that variable is declared.
218
- ///
219
- /// - `free_region_map` maps from a free region `a` to a list of free
220
- /// regions `bs` such that `a <= b for all b in bs`
221
- /// - the free region map is populated during type check as we check
222
- /// each function. See the function `relate_free_regions` for
223
- /// more information.
224
- ///
225
- /// - `rvalue_scopes` includes entries for those expressions whose cleanup
226
- /// scope is larger than the default. The map goes from the expression
227
- /// id to the cleanup scope id. For rvalues not present in this table,
228
- /// the appropriate cleanup scope is the innermost enclosing statement,
229
- /// conditional expression, or repeating block (see `terminating_scopes`).
230
- ///
231
- /// - `terminating_scopes` is a set containing the ids of each statement,
232
- /// or conditional/repeating expression. These scopes are calling "terminating
233
- /// scopes" because, when attempting to find the scope of a temporary, by
234
- /// default we search up the enclosing scopes until we encounter the
235
- /// terminating scope. A conditional/repeating
236
- /// expression is one which is not guaranteed to execute exactly once
237
- /// upon entering the parent scope. This could be because the expression
238
- /// only executes conditionally, such as the expression `b` in `a && b`,
239
- /// or because the expression may execute many times, such as a loop
240
- /// body. The reason that we distinguish such expressions is that, upon
241
- /// exiting the parent scope, we cannot statically know how many times
242
- /// the expression executed, and thus if the expression creates
243
- /// temporaries we cannot know statically how many such temporaries we
244
- /// would have to cleanup. Therefore we ensure that the temporaries never
245
- /// outlast the conditional/repeating expression, preventing the need
246
- /// for dynamic checks and/or arbitrary amounts of stack space.
247
209
pub struct RegionMaps {
210
+ /// `scope_map` maps from a scope id to the enclosing scope id;
211
+ /// this is usually corresponding to the lexical nesting, though
212
+ /// in the case of closures the parent scope is the innermost
213
+ /// conditional expression or repeating block. (Note that the
214
+ /// enclosing scope id for the block associated with a closure is
215
+ /// the closure itself.)
248
216
scope_map : RefCell < FnvHashMap < CodeExtent , CodeExtent > > ,
217
+
218
+ /// `var_map` maps from a variable or binding id to the block in
219
+ /// which that variable is declared.
249
220
var_map : RefCell < NodeMap < CodeExtent > > ,
221
+
222
+ /// `free_region_map` maps from a free region `a` to a list of
223
+ /// free regions `bs` such that `a <= b for all b in bs`
224
+ ///
225
+ /// NB. the free region map is populated during type check as we
226
+ /// check each function. See the function `relate_free_regions`
227
+ /// for more information.
250
228
free_region_map : RefCell < FnvHashMap < FreeRegion , Vec < FreeRegion > > > ,
229
+
230
+ /// `rvalue_scopes` includes entries for those expressions whose cleanup scope is
231
+ /// larger than the default. The map goes from the expression id
232
+ /// to the cleanup scope id. For rvalues not present in this
233
+ /// table, the appropriate cleanup scope is the innermost
234
+ /// enclosing statement, conditional expression, or repeating
235
+ /// block (see `terminating_scopes`).
251
236
rvalue_scopes : RefCell < NodeMap < CodeExtent > > ,
237
+
238
+ /// `terminating_scopes` is a set containing the ids of each
239
+ /// statement, or conditional/repeating expression. These scopes
240
+ /// are calling "terminating scopes" because, when attempting to
241
+ /// find the scope of a temporary, by default we search up the
242
+ /// enclosing scopes until we encounter the terminating scope. A
243
+ /// conditional/repeating expression is one which is not
244
+ /// guaranteed to execute exactly once upon entering the parent
245
+ /// scope. This could be because the expression only executes
246
+ /// conditionally, such as the expression `b` in `a && b`, or
247
+ /// because the expression may execute many times, such as a loop
248
+ /// body. The reason that we distinguish such expressions is that,
249
+ /// upon exiting the parent scope, we cannot statically know how
250
+ /// many times the expression executed, and thus if the expression
251
+ /// creates temporaries we cannot know statically how many such
252
+ /// temporaries we would have to cleanup. Therefore we ensure that
253
+ /// the temporaries never outlast the conditional/repeating
254
+ /// expression, preventing the need for dynamic checks and/or
255
+ /// arbitrary amounts of stack space.
252
256
terminating_scopes : RefCell < FnvHashSet < CodeExtent > > ,
257
+
258
+ /// Encodes the hierarchy of fn bodies. Every fn body (including
259
+ /// closures) forms its own distinct region hierarchy, rooted in
260
+ /// the block that is the fn body. This map points from the id of
261
+ /// that root block to the id of the root block for the enclosing
262
+ /// fn, if any. Thus the map structures the fn bodies into a
263
+ /// hierarchy based on their lexical mapping. This is used to
264
+ /// handle the relationships between regions in a fn and in a
265
+ /// closure defined by that fn.
266
+ fn_tree : RefCell < NodeMap < ast:: NodeId > > ,
253
267
}
254
268
255
269
/// Carries the node id for the innermost block or match expression,
@@ -320,6 +334,12 @@ impl InnermostEnclosingExpr {
320
334
321
335
#[ derive( Debug , Copy ) ]
322
336
pub struct Context {
337
+ /// the root of the current region tree. This is typically the id
338
+ /// of the innermost fn body. Each fn forms its own disjoint tree
339
+ /// in the region hierarchy. These fn bodies are themselves
340
+ /// arranged into a tree.
341
+ root_id : Option < ast:: NodeId > ,
342
+
323
343
/// the scope that contains any new variables declared
324
344
var_parent : InnermostDeclaringBlock ,
325
345
@@ -381,19 +401,29 @@ impl RegionMaps {
381
401
self . free_region_map . borrow_mut ( ) . insert ( sub, vec ! ( sup) ) ;
382
402
}
383
403
384
- pub fn record_encl_scope ( & self , sub : CodeExtent , sup : CodeExtent ) {
404
+ /// Records that `sub_fn` is defined within `sup_fn`. These ids
405
+ /// should be the id of the block that is the fn body, which is
406
+ /// also the root of the region hierarchy for that fn.
407
+ fn record_fn_parent ( & self , sub_fn : ast:: NodeId , sup_fn : ast:: NodeId ) {
408
+ debug ! ( "record_fn_parent(sub_fn={:?}, sup_fn={:?})" , sub_fn, sup_fn) ;
409
+ assert ! ( sub_fn != sup_fn) ;
410
+ let previous = self . fn_tree . borrow_mut ( ) . insert ( sub_fn, sup_fn) ;
411
+ assert ! ( previous. is_none( ) ) ;
412
+ }
413
+
414
+ fn record_encl_scope ( & self , sub : CodeExtent , sup : CodeExtent ) {
385
415
debug ! ( "record_encl_scope(sub={:?}, sup={:?})" , sub, sup) ;
386
416
assert ! ( sub != sup) ;
387
417
self . scope_map . borrow_mut ( ) . insert ( sub, sup) ;
388
418
}
389
419
390
- pub fn record_var_scope ( & self , var : ast:: NodeId , lifetime : CodeExtent ) {
420
+ fn record_var_scope ( & self , var : ast:: NodeId , lifetime : CodeExtent ) {
391
421
debug ! ( "record_var_scope(sub={:?}, sup={:?})" , var, lifetime) ;
392
422
assert ! ( var != lifetime. node_id( ) ) ;
393
423
self . var_map . borrow_mut ( ) . insert ( var, lifetime) ;
394
424
}
395
425
396
- pub fn record_rvalue_scope ( & self , var : ast:: NodeId , lifetime : CodeExtent ) {
426
+ fn record_rvalue_scope ( & self , var : ast:: NodeId , lifetime : CodeExtent ) {
397
427
debug ! ( "record_rvalue_scope(sub={:?}, sup={:?})" , var, lifetime) ;
398
428
assert ! ( var != lifetime. node_id( ) ) ;
399
429
self . rvalue_scopes . borrow_mut ( ) . insert ( var, lifetime) ;
@@ -402,7 +432,7 @@ impl RegionMaps {
402
432
/// Records that a scope is a TERMINATING SCOPE. Whenever we create automatic temporaries --
403
433
/// e.g. by an expression like `a().f` -- they will be freed within the innermost terminating
404
434
/// scope.
405
- pub fn mark_as_terminating_scope ( & self , scope_id : CodeExtent ) {
435
+ fn mark_as_terminating_scope ( & self , scope_id : CodeExtent ) {
406
436
debug ! ( "record_terminating_scope(scope_id={:?})" , scope_id) ;
407
437
self . terminating_scopes . borrow_mut ( ) . insert ( scope_id) ;
408
438
}
@@ -684,6 +714,7 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) {
684
714
// itself has returned.
685
715
686
716
visitor. cx = Context {
717
+ root_id : prev_cx. root_id ,
687
718
var_parent : InnermostDeclaringBlock :: Block ( blk. id ) ,
688
719
parent : InnermostEnclosingExpr :: Some ( blk. id ) ,
689
720
} ;
@@ -710,6 +741,7 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) {
710
741
record_superlifetime (
711
742
visitor, declaring. to_code_extent ( ) , statement. span ) ;
712
743
visitor. cx = Context {
744
+ root_id : prev_cx. root_id ,
713
745
var_parent : InnermostDeclaringBlock :: Statement ( declaring) ,
714
746
parent : InnermostEnclosingExpr :: Statement ( declaring) ,
715
747
} ;
@@ -1103,6 +1135,7 @@ fn resolve_item(visitor: &mut RegionResolutionVisitor, item: &ast::Item) {
1103
1135
// Items create a new outer block scope as far as we're concerned.
1104
1136
let prev_cx = visitor. cx ;
1105
1137
visitor. cx = Context {
1138
+ root_id : None ,
1106
1139
var_parent : InnermostDeclaringBlock :: None ,
1107
1140
parent : InnermostEnclosingExpr :: None
1108
1141
} ;
@@ -1127,14 +1160,21 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
1127
1160
1128
1161
let body_scope = CodeExtent :: from_node_id ( body. id ) ;
1129
1162
visitor. region_maps . mark_as_terminating_scope ( body_scope) ;
1163
+
1130
1164
let dtor_scope = CodeExtent :: DestructionScope ( body. id ) ;
1131
1165
visitor. region_maps . record_encl_scope ( body_scope, dtor_scope) ;
1166
+
1132
1167
record_superlifetime ( visitor, dtor_scope, body. span ) ;
1133
1168
1169
+ if let Some ( root_id) = visitor. cx . root_id {
1170
+ visitor. region_maps . record_fn_parent ( body. id , root_id) ;
1171
+ }
1172
+
1134
1173
let outer_cx = visitor. cx ;
1135
1174
1136
1175
// The arguments and `self` are parented to the body of the fn.
1137
1176
visitor. cx = Context {
1177
+ root_id : Some ( body. id ) ,
1138
1178
parent : InnermostEnclosingExpr :: Some ( body. id ) ,
1139
1179
var_parent : InnermostDeclaringBlock :: Block ( body. id )
1140
1180
} ;
@@ -1145,11 +1185,11 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
1145
1185
match fk {
1146
1186
visit:: FkItemFn ( ..) | visit:: FkMethod ( ..) => {
1147
1187
visitor. cx = Context {
1188
+ root_id : Some ( body. id ) ,
1148
1189
parent : InnermostEnclosingExpr :: None ,
1149
1190
var_parent : InnermostDeclaringBlock :: None
1150
1191
} ;
1151
1192
visitor. visit_block ( body) ;
1152
- visitor. cx = outer_cx;
1153
1193
}
1154
1194
visit:: FkFnBlock ( ..) => {
1155
1195
// FIXME(#3696) -- at present we are place the closure body
@@ -1159,10 +1199,16 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
1159
1199
// but the correct fix is a bit subtle, and I am also not sure
1160
1200
// that the present approach is unsound -- it may not permit
1161
1201
// any illegal programs. See issue for more details.
1162
- visitor. cx = outer_cx;
1202
+ visitor. cx = Context {
1203
+ root_id : Some ( body. id ) ,
1204
+ ..outer_cx
1205
+ } ;
1163
1206
visitor. visit_block ( body) ;
1164
1207
}
1165
1208
}
1209
+
1210
+ // Restore context we had at the start.
1211
+ visitor. cx = outer_cx;
1166
1212
}
1167
1213
1168
1214
impl < ' a , ' v > Visitor < ' v > for RegionResolutionVisitor < ' a > {
@@ -1203,12 +1249,14 @@ pub fn resolve_crate(sess: &Session, krate: &ast::Crate) -> RegionMaps {
1203
1249
free_region_map : RefCell :: new ( FnvHashMap ( ) ) ,
1204
1250
rvalue_scopes : RefCell :: new ( NodeMap ( ) ) ,
1205
1251
terminating_scopes : RefCell :: new ( FnvHashSet ( ) ) ,
1252
+ fn_tree : RefCell :: new ( NodeMap ( ) ) ,
1206
1253
} ;
1207
1254
{
1208
1255
let mut visitor = RegionResolutionVisitor {
1209
1256
sess : sess,
1210
1257
region_maps : & maps,
1211
1258
cx : Context {
1259
+ root_id : None ,
1212
1260
parent : InnermostEnclosingExpr :: None ,
1213
1261
var_parent : InnermostDeclaringBlock :: None ,
1214
1262
}
@@ -1225,6 +1273,7 @@ pub fn resolve_inlined_item(sess: &Session,
1225
1273
sess : sess,
1226
1274
region_maps : region_maps,
1227
1275
cx : Context {
1276
+ root_id : None ,
1228
1277
parent : InnermostEnclosingExpr :: None ,
1229
1278
var_parent : InnermostDeclaringBlock :: None
1230
1279
}
0 commit comments