@@ -113,13 +113,30 @@ fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc)
113
113
case ( ty:: ty_native_fn ( _, ?args, _) ) { args }
114
114
} ;
115
115
116
- auto i = 0 u;
117
116
let vec[ def_num] roots = [ ] ;
117
+ let vec[ tup( uint, def_num) ] mut_roots = [ ] ;
118
118
let vec[ ty:: t] unsafe_ts = [ ] ;
119
119
let vec[ uint] unsafe_t_offsets = [ ] ;
120
+
121
+ auto i = 0 u;
120
122
for ( ty:: arg arg_t in arg_ts) {
121
123
if ( arg_t. mode != ty:: mo_val) {
122
- auto root = expr_root ( cx, args. ( i) , false ) ;
124
+ auto arg = args. ( i) ;
125
+ auto root = expr_root ( cx, arg, false ) ;
126
+ if ( arg_t. mode == ty:: mo_alias ( true ) ) {
127
+ alt ( path_def_id ( cx, arg) ) {
128
+ case ( some ( ?did) ) {
129
+ vec:: push ( mut_roots, tup ( i, did. _1 ) ) ;
130
+ }
131
+ case ( _) {
132
+ if ( !root. mut_field ) {
133
+ cx. tcx . sess . span_err
134
+ ( arg. span , "passing a temporary value or \
135
+ immutable field by mutable alias") ;
136
+ }
137
+ }
138
+ }
139
+ }
123
140
alt ( path_def_id ( cx, root. ex ) ) {
124
141
case ( some ( ?did) ) { vec:: push ( roots, did. _1 ) ; }
125
142
case ( _) { }
@@ -154,19 +171,31 @@ fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc)
154
171
j += 1 u;
155
172
auto i = 0 u;
156
173
for ( ty:: arg arg_t in arg_ts) {
174
+ auto mut_alias = arg_t. mode == ty:: mo_alias( true ) ;
157
175
if ( i ! = offset &&
158
- // FIXME false should be replace with mutability of alias
159
- ty_can_unsafely_include( cx, unsafe, arg_t. ty, false ) ) {
176
+ ty_can_unsafely_include( cx, unsafe , arg_t. ty, mut_alias) ) {
160
177
cx. tcx. sess. span_err
161
178
( args. ( i) . span, #fmt( "argument %u may alias with \
162
179
argument %u, which is not immutably rooted", i, offset) ) ;
163
180
}
164
181
i += 1 u;
165
182
}
166
183
}
167
- // FIXME when mutable aliases can be distinguished, go over the args again
168
- // and ensure that we're not passing a root variable by mutable alias
169
- // (using roots and the scope root vars).
184
+
185
+ // Ensure we're not passing a root by mutable alias.
186
+ for ( tup( uint, def_num) root in mut_roots) {
187
+ auto mut_alias_to_root = vec:: count( root. _1, roots) > 1 u;
188
+ for ( restrict r in sc. rs) {
189
+ if ( vec:: member( root. _1, r. root_vars) ) {
190
+ mut_alias_to_root = true ;
191
+ }
192
+ }
193
+ if ( mut_alias_to_root) {
194
+ cx. tcx. sess. span_err
195
+ ( args. ( root. _0) . span, "passing a mutable alias to a \
196
+ variable that roots another alias") ;
197
+ }
198
+ }
170
199
171
200
ret rec( root_vars = roots, unsafe_ts = unsafe_ts) ;
172
201
}
@@ -300,25 +329,16 @@ fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src,
300
329
alt ( dest. node ) {
301
330
case ( ast:: expr_path ( ?p, ?ann) ) {
302
331
auto dnum = ast:: def_id_of_def ( cx. dm . get ( ann. id ) ) . _1 ;
303
-
304
- for ( tup( def_num, ast:: mode) arg in sc. args) {
305
- if ( arg. _0 == dnum && arg. _1 == ast:: alias ( false ) ) {
306
- cx. tcx . sess . span_err
307
- ( dest. span , "assigning to immutable alias" ) ;
308
- }
332
+ if ( is_immutable_alias ( sc, dnum) ) {
333
+ cx. tcx . sess . span_err
334
+ ( dest. span , "assigning to immutable alias" ) ;
309
335
}
310
336
311
337
auto var_t = ty:: expr_ty ( * cx. tcx , dest) ;
312
338
for ( restrict r in sc. rs) {
313
339
if ( vec:: member ( dnum, r. root_vars ) ) {
314
340
r. ok = overwritten ( dest. span , p) ;
315
341
}
316
- for ( def_num bnd in r. bindings) {
317
- if ( dnum == bnd) {
318
- cx. tcx . sess . span_err
319
- ( dest. span , "assigning to immutable alias" ) ;
320
- }
321
- }
322
342
}
323
343
check_var ( * cx, dest, p, ann, true , sc) ;
324
344
}
@@ -328,6 +348,16 @@ fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src,
328
348
}
329
349
}
330
350
351
+ fn is_immutable_alias ( & scope sc, def_num dnum) -> bool {
352
+ for ( tup( def_num, ast:: mode) arg in sc. args) {
353
+ if ( arg. _0 == dnum && arg. _1 == ast:: alias ( false ) ) { ret true ; }
354
+ }
355
+ for ( restrict r in sc. rs) {
356
+ if ( vec:: member ( dnum, r. bindings ) ) { ret true ; }
357
+ }
358
+ ret false;
359
+ }
360
+
331
361
fn test_scope ( & ctx cx, & scope sc, & restrict r, & ast:: path p) {
332
362
auto prob = r. ok ;
333
363
for ( uint dep in r. depends_on) {
@@ -364,13 +394,18 @@ fn deps(&scope sc, vec[def_num] roots) -> vec[uint] {
364
394
}
365
395
366
396
fn expr_root ( & ctx cx, @ast:: expr ex, bool autoderef )
367
- -> rec ( @ast:: expr ex, option:: t[ ty:: t ] inner_mut , bool mut_in_box ) {
397
+ -> rec ( @ast:: expr ex,
398
+ option:: t[ ty:: t ] inner_mut ,
399
+ bool mut_in_box ,
400
+ bool mut_field ) {
368
401
let option:: t[ ty:: t] mut = none;
369
402
// This is not currently used but would make it possible to be more
370
403
// liberal -- only stuff in a mutable box needs full type-inclusion
371
404
// checking, things that aren't in a box need only be checked against
372
405
// locally live aliases and their root.
373
406
auto mut_in_box = false ;
407
+ auto mut_fld = false ;
408
+ auto depth = 0 ;
374
409
while ( true ) {
375
410
alt ( { ex. node } ) {
376
411
case ( ast:: expr_field ( ?base, ?ident, _) ) {
@@ -379,15 +414,19 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef)
379
414
alt ( ty:: struct ( * cx. tcx , auto_unbox. t ) ) {
380
415
case ( ty:: ty_tup ( ?fields) ) {
381
416
auto fnm = ty:: field_num ( cx. tcx . sess , ex. span , ident) ;
382
- if ( fields. ( fnm) . mut != ast:: imm && is_none ( mut) ) {
383
- mut = some ( auto_unbox. t ) ;
417
+ if ( fields. ( fnm) . mut != ast:: imm) {
418
+ if ( is_none ( mut) ) { mut = some ( auto_unbox. t ) ; }
419
+ if ( depth == 0 ) { mut_fld = true ; }
384
420
}
385
421
}
386
422
case ( ty:: ty_rec ( ?fields) ) {
387
423
for ( ty:: field fld in fields) {
388
424
if ( str:: eq ( ident, fld. ident ) ) {
389
- if ( fld. mt . mut != ast:: imm && is_none ( mut) ) {
390
- mut = some ( auto_unbox. t ) ;
425
+ if ( fld. mt . mut != ast:: imm) {
426
+ if ( is_none ( mut) ) {
427
+ mut = some ( auto_unbox. t ) ;
428
+ }
429
+ if ( depth == 0 ) { mut_fld = true ; }
391
430
}
392
431
break ;
393
432
}
@@ -406,26 +445,26 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef)
406
445
auto auto_unbox = maybe_auto_unbox ( cx, base_t) ;
407
446
alt ( ty:: struct ( * cx. tcx , auto_unbox. t ) ) {
408
447
case ( ty:: ty_vec ( ?mt) ) {
409
- if ( mt. mut != ast:: imm && is_none ( mut) ) {
410
- mut = some ( auto_unbox. t ) ;
448
+ if ( mt. mut != ast:: imm) {
449
+ if ( is_none ( mut) ) { mut = some ( auto_unbox. t ) ; }
450
+ if ( depth == 0 ) { mut_fld = true ; }
411
451
}
412
452
}
413
453
}
414
454
if ( auto_unbox. done ) {
415
455
if ( !is_none ( mut) ) { mut_in_box = true ; }
416
456
else if ( auto_unbox. mut ) { mut = some ( base_t) ; }
417
457
}
418
- if ( auto_unbox. done && !is_none ( mut) ) {
419
- }
420
458
ex = base;
421
459
}
422
460
case ( ast:: expr_unary ( ?op, ?base, _) ) {
423
461
if ( op == ast:: deref) {
424
462
auto base_t = ty:: expr_ty ( * cx. tcx , base) ;
425
463
alt ( ty:: struct ( * cx. tcx , base_t) ) {
426
464
case ( ty:: ty_box ( ?mt) ) {
427
- if ( mt. mut != ast:: imm && is_none ( mut) ) {
428
- mut = some ( base_t) ;
465
+ if ( mt. mut != ast:: imm) {
466
+ if ( is_none ( mut) ) { mut = some ( base_t) ; }
467
+ if ( depth == 0 ) { mut_fld = true ; }
429
468
}
430
469
if ( !is_none ( mut) ) {
431
470
mut_in_box = true ;
@@ -439,16 +478,23 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef)
439
478
}
440
479
case ( _) { break ; }
441
480
}
481
+ depth += 1 ;
442
482
}
443
483
if ( autoderef) {
444
484
auto ex_t = ty:: expr_ty ( * cx. tcx , ex) ;
445
485
auto auto_unbox = maybe_auto_unbox ( cx, ex_t) ;
446
486
if ( auto_unbox. done ) {
447
487
if ( !is_none ( mut) ) { mut_in_box = true ; }
448
- else if ( auto_unbox. mut ) { mut = some ( ex_t) ; }
488
+ else if ( auto_unbox. mut ) {
489
+ mut = some ( ex_t) ;
490
+ if ( depth == 0 ) { mut_fld = true ; }
491
+ }
449
492
}
450
493
}
451
- ret rec( ex = ex, inner_mut = mut, mut_in_box = mut_in_box) ;
494
+ ret rec( ex = ex,
495
+ inner_mut = mut,
496
+ mut_in_box = mut_in_box,
497
+ mut_field = mut_fld) ;
452
498
}
453
499
454
500
fn maybe_auto_unbox ( & ctx cx, & ty:: t t)
0 commit comments