@@ -99,8 +99,8 @@ fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt<scope>) {
99
99
let mut handled = true ;
100
100
alt ex. node {
101
101
ast:: expr_call ( f, args, _) {
102
- check_call ( * cx, sc, f, args) ;
103
- handled = false ;
102
+ check_call ( cx, sc, f, args, v ) ;
103
+ visit_expr ( cx , f , sc , v ) ;
104
104
}
105
105
ast:: expr_alt ( input, arms, _) { check_alt ( * cx, input, arms, sc, v) ; }
106
106
ast:: expr_for ( decl, seq, blk) {
@@ -163,33 +163,6 @@ fn visit_block(cx: @ctx, b: ast::blk, sc: scope, v: vt<scope>) {
163
163
visit:: visit_expr_opt ( b. node . expr , sc, v) ;
164
164
}
165
165
166
- fn add_bindings_for_let ( cx : ctx , & bs: [ binding ] , loc : @ast:: local ) {
167
- alt loc. node . init {
168
- some ( init) {
169
- if init. op == ast:: init_move {
170
- err ( cx, loc. span , "can not move into a by-reference binding" ) ;
171
- }
172
- let root = expr_root ( cx, init. expr , false ) ;
173
- let root_var = path_def_id ( cx, root. ex ) ;
174
- if is_none ( root_var) {
175
- err ( cx, loc. span , "a reference binding can't be \
176
- rooted in a temporary") ;
177
- }
178
- for proot in pattern_roots ( cx. tcx , root. mutbl , loc. node . pat ) {
179
- let bnd = mk_binding ( cx, proot. id , proot. span , root_var,
180
- unsafe_set ( proot. mutbl ) ) ;
181
- // Don't implicitly copy explicit references
182
- bnd. copied = not_allowed;
183
- bs += [ bnd] ;
184
- }
185
- }
186
- _ {
187
- err( cx, loc. span , "by-reference bindings must be initialized" ) ;
188
- }
189
- }
190
- }
191
-
192
-
193
166
fn cant_copy ( cx : ctx , b : binding ) -> bool {
194
167
alt b. copied {
195
168
not_allowed { ret true; }
@@ -209,47 +182,67 @@ fn cant_copy(cx: ctx, b: binding) -> bool {
209
182
} else { ret true ; }
210
183
}
211
184
212
- fn check_call ( cx : ctx , sc : scope , f : @ast:: expr , args : [ @ast:: expr ] )
213
- -> [ binding ] {
185
+ // FIXME this is a really awful hack
186
+ fn local_id_for_args ( cx : ctx , args : [ @ast:: expr ] ) -> uint {
187
+ for vec:: each( args) { |arg|
188
+ alt arg. node {
189
+ ast: : expr_fn_block( decl, _) | ast:: expr_fn( _, decl, _, _) |
190
+ ast:: expr_loop_body( @{ node : ast:: expr_fn_block( decl, _) , _} ) {
191
+ if decl. inputs . len ( ) > 0 u {
192
+ ret local_id_of_node ( cx, decl. inputs [ 0 ] . id ) ;
193
+ }
194
+ }
195
+ _ { }
196
+ }
197
+ }
198
+ 0xFFFFFFFF u
199
+ }
200
+
201
+ fn check_call ( cx : @ctx , sc : scope , f : @ast:: expr , args : [ @ast:: expr ] ,
202
+ v : vt < scope > ) {
214
203
let fty = ty:: expr_ty ( cx. tcx , f) ;
215
204
let arg_ts = ty:: ty_fn_args ( fty) ;
216
- let mut mut_roots: [ { arg : uint , node : node_id } ] = [ ] ;
205
+ let mut mut_roots: [ { arg : @ast :: expr , node : node_id } ] = [ ] ;
217
206
let mut bindings = [ ] ;
218
- let mut i = 0 u;
219
- for arg_t: ty:: arg in arg_ts {
220
- let arg = args[ i] ;
221
- let root = expr_root ( cx, arg, false ) ;
207
+ let mut blocks = [ ] , loc_id = local_id_for_args ( * cx, args) ;
208
+ vec:: iter2 ( args, arg_ts) { |arg, arg_t|
209
+ let root = expr_root ( * cx, arg, false ) ;
222
210
alt ty:: resolved_mode ( cx. tcx , arg_t. mode ) {
223
211
ast:: by_mutbl_ref {
224
- alt path_def( cx, arg) {
212
+ alt path_def( * cx, arg) {
225
213
some ( def) {
226
214
let dnum = ast_util:: def_id_of_def ( def) . node ;
227
- mut_roots += [ { arg: i , node: dnum} ] ;
215
+ mut_roots += [ { arg: arg , node: dnum} ] ;
228
216
}
229
217
_ { }
230
218
}
231
219
}
232
- ast:: by_ref | ast:: by_val | ast:: by_move | ast:: by_copy { }
220
+ ast:: by_ref | ast:: by_val | ast:: by_move | ast:: by_copy { }
221
+ }
222
+ alt arg. node {
223
+ ast:: expr_fn_block ( _, _) { blocks += [ arg] ; }
224
+ ast:: expr_loop_body ( b) { blocks += [ b] ; }
225
+ _ {
226
+ let root_var = path_def_id ( * cx, root. ex ) ;
227
+ let arg_copied = alt ty:: resolved_mode ( cx. tcx , arg_t. mode ) {
228
+ ast:: by_move | ast:: by_copy { copied }
229
+ ast:: by_mutbl_ref { not_allowed }
230
+ ast:: by_ref | ast:: by_val { not_copied }
231
+ } ;
232
+ visit_expr ( cx, arg, sc, v) ;
233
+ bindings += [ @{ node_id: arg. id ,
234
+ span: arg. span ,
235
+ root_var: root_var,
236
+ local_id: loc_id,
237
+ unsafe_tys: unsafe_set ( root. mutbl ) ,
238
+ mut copied: arg_copied} ] ;
239
+ }
233
240
}
234
- let root_var = path_def_id ( cx, root. ex ) ;
235
- let arg_copied = alt ty:: resolved_mode ( cx. tcx , arg_t. mode ) {
236
- ast:: by_move | ast:: by_copy { copied }
237
- ast:: by_mutbl_ref { not_allowed }
238
- ast:: by_ref | ast:: by_val { not_copied }
239
- } ;
240
- bindings += [ @{ node_id: arg. id ,
241
- span: arg. span ,
242
- root_var: root_var,
243
- local_id: 0 u,
244
- unsafe_tys: unsafe_set ( root. mutbl ) ,
245
- mut copied: arg_copied} ] ;
246
- i += 1 u;
247
241
}
248
- let f_may_close =
249
- alt f. node {
250
- ast:: expr_path ( _) { def_is_local_or_self ( cx. tcx . def_map . get ( f. id ) ) }
251
- _ { true }
252
- } ;
242
+ let f_may_close = alt f. node {
243
+ ast:: expr_path ( _) { def_is_local_or_self ( cx. tcx . def_map . get ( f. id ) ) }
244
+ _ { true }
245
+ } ;
253
246
if f_may_close {
254
247
let mut i = 0 u;
255
248
for b in bindings {
@@ -264,43 +257,44 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
264
257
}
265
258
_ { }
266
259
}
267
- if unsfe && cant_copy ( cx, b) {
268
- err ( cx, f. span , #fmt[ "function may alias with argument \
269
- %u, which is not immutably rooted", i] ) ;
260
+ if unsfe && cant_copy ( * cx, b) {
261
+ err ( * cx, f. span , #fmt[ "function may alias with argument \
262
+ %u, which is not immutably rooted", i] ) ;
270
263
}
271
264
i += 1 u;
272
265
}
273
266
}
274
267
let mut j = 0 u;
275
268
for b in bindings {
276
269
for unsafe_ty in b. unsafe_tys {
277
- let mut i = 0 u;
278
- for arg_t: ty:: arg in arg_ts {
270
+ vec:: iteri ( arg_ts) { |i, arg_t|
279
271
let mut_alias =
280
272
( ast:: by_mutbl_ref == ty:: arg_mode ( cx. tcx , arg_t) ) ;
281
- if i != j &&
282
- ty_can_unsafely_include ( cx, unsafe_ty, arg_t. ty ,
283
- mut_alias) &&
284
- cant_copy ( cx, b) {
285
- err ( cx, args[ i] . span ,
286
- #fmt[ "argument %u may alias with argument %u, \
287
- which is not immutably rooted", i, j] ) ;
273
+ alt args[ i] . node {
274
+ ast:: expr_fn_block ( _, _) | ast:: expr_loop_body ( _) { }
275
+ _ {
276
+ if i != j && ty_can_unsafely_include (
277
+ * cx, unsafe_ty, arg_t. ty , mut_alias) &&
278
+ cant_copy ( * cx, b) {
279
+ err ( * cx, args[ i] . span ,
280
+ #fmt[ "argument %u may alias with argument %u, \
281
+ which is not immutably rooted", i, j] ) ;
282
+ }
283
+ }
288
284
}
289
- i += 1 u;
290
285
}
291
286
}
292
287
j += 1 u;
293
288
}
294
- // Ensure we're not passing a root by mut alias.
295
289
290
+ // Ensure we're not passing a root by mut alias.
296
291
for { node: node, arg: arg} in mut_roots {
297
- let mut i = 0 u;
298
292
for b in bindings {
299
- if i != arg {
293
+ if b . node_id != arg. id {
300
294
alt b. root_var {
301
295
some ( root) {
302
- if node == root && cant_copy ( cx, b) {
303
- err ( cx, args [ arg] . span ,
296
+ if node == root && cant_copy ( * cx, b) {
297
+ err ( * cx, arg. span ,
304
298
"passing a mut reference to a \
305
299
variable that roots another reference") ;
306
300
break ;
@@ -309,10 +303,22 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
309
303
none { }
310
304
}
311
305
}
312
- i += 1 u;
313
306
}
314
307
}
315
- ret bindings;
308
+ // Check the bodies of block arguments against the current scope
309
+ if blocks. len ( ) > 0 u {
310
+ let inner_sc = { bs: bindings + sc. bs , invalid: sc. invalid } ;
311
+ for blk in blocks {
312
+ alt check blk. node {
313
+ ast:: expr_fn_block ( _, body) {
314
+ v. visit_block ( body, inner_sc, v) ;
315
+ }
316
+ }
317
+ }
318
+ for binding in bindings {
319
+ test_scope ( * cx, sc, binding, none) ;
320
+ }
321
+ }
316
322
}
317
323
318
324
fn check_alt ( cx : ctx , input : @ast:: expr , arms : [ ast:: arm ] , sc : scope ,
@@ -397,7 +403,7 @@ fn check_var(cx: ctx, ex: @ast::expr, p: @ast::path, id: ast::node_id,
397
403
}
398
404
}
399
405
} else if b. node_id == my_defnum {
400
- test_scope ( cx, sc, b, p ) ;
406
+ test_scope ( cx, sc, b, some ( p ) ) ;
401
407
}
402
408
}
403
409
}
@@ -444,7 +450,7 @@ fn check_loop(cx: ctx, sc: scope, checker: fn()) {
444
450
* sc. invalid = new_invalid;
445
451
}
446
452
447
- fn test_scope ( cx : ctx , sc : scope , b : binding , p : @ast:: path ) {
453
+ fn test_scope ( cx : ctx , sc : scope , b : binding , p : option < @ast:: path > ) {
448
454
let mut prob = find_invalid ( b. node_id , * sc. invalid ) ;
449
455
alt b. root_var {
450
456
some ( dn) {
@@ -463,8 +469,12 @@ fn test_scope(cx: ctx, sc: scope, b: binding, p: @ast::path) {
463
469
overwritten { "overwriting " + ast_util:: path_name ( i. path ) }
464
470
val_taken { "taking the value of " + ast_util:: path_name ( i. path ) }
465
471
} ;
466
- err ( cx, i. sp , msg + " will invalidate reference " +
467
- ast_util:: path_name ( p) + ", which is still used" ) ;
472
+ let refname = alt p {
473
+ some( pt) { "reference " + ast_util:: path_name ( pt) +
474
+ ", which is still used" }
475
+ none { "an argument" }
476
+ } ;
477
+ err ( cx, i. sp , msg + " will invalidate " + refname) ;
468
478
}
469
479
}
470
480
0 commit comments