@@ -22,7 +22,7 @@ type binding = @{node_id: node_id,
22
22
unsafe_tys: [ ty:: t] ,
23
23
mutable ok: valid,
24
24
mutable copied: copied} ;
25
- type scope = [ binding ] ; // {bs: [binding], ret_style: ast::ret_style}
25
+ type scope = { bs : [ binding ] , ret_style : ast:: ret_style } ;
26
26
27
27
fn mk_binding ( cx : ctx , id : node_id , span : span , root_var : option:: t < node_id > ,
28
28
unsafe : [ ty:: t ] ) -> binding {
@@ -47,25 +47,32 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> copy_map {
47
47
local_map: std:: map:: new_int_hash ( ) ,
48
48
mutable next_local: 0 u,
49
49
copy_map: std:: map:: new_int_hash ( ) } ;
50
- let v = @{ visit_fn: visit_fn,
50
+ let v = @{ visit_fn: bind visit_fn ( cx , _ , _ , _ , _ , _ , _ , _ ) ,
51
51
visit_expr: bind visit_expr ( cx, _, _, _) ,
52
52
visit_decl: bind visit_decl ( cx, _, _, _)
53
53
with * visit:: default_visitor :: < scope > ( ) } ;
54
- visit:: visit_crate ( * crate , [ ] , visit:: mk_vt ( v) ) ;
54
+ visit:: visit_crate ( * crate , { bs: [ ] , ret_style: ast:: return_val} ,
55
+ visit:: mk_vt ( v) ) ;
55
56
tcx. sess . abort_if_errors ( ) ;
56
57
ret cx. copy_map ;
57
58
}
58
59
59
- fn visit_fn ( f : ast:: _fn , _tp : [ ast:: ty_param ] , _sp : span , _name : fn_ident ,
60
- _id : ast:: node_id , sc : scope , v : vt < scope > ) {
60
+ fn visit_fn ( cx : @ ctx , f : ast:: _fn , _tp : [ ast:: ty_param ] , _sp : span ,
61
+ _name : fn_ident , _id : ast:: node_id , sc : scope , v : vt < scope > ) {
61
62
visit:: visit_fn_decl ( f. decl , sc, v) ;
62
- let scope = alt f. proto {
63
+ let bs = alt f. proto {
63
64
// Blocks need to obey any restrictions from the enclosing scope.
64
- ast:: proto_block. | ast:: proto_closure. { sc }
65
+ ast:: proto_block. | ast:: proto_closure. { sc . bs }
65
66
// Non capturing functions start out fresh.
66
67
_ { [ ] }
67
68
} ;
68
- v. visit_block ( f. body , scope, v) ;
69
+ if f. decl . cf == ast:: return_ref && !is_none ( f. body . node . expr ) {
70
+ // FIXME this will be easier to lift once have DPS
71
+ cx. tcx . sess . span_err ( option:: get ( f. body . node . expr ) . span ,
72
+ "reference-returning functions may not " +
73
+ "return implicitly" ) ;
74
+ }
75
+ v. visit_block ( f. body , { bs: bs, ret_style: f. decl . cf } , v) ;
69
76
}
70
77
71
78
fn visit_expr ( cx : @ctx , ex : @ast:: expr , sc : scope , v : vt < scope > ) {
@@ -111,7 +118,9 @@ fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt<scope>) {
111
118
check_assign ( cx, dest, src, sc, v) ;
112
119
}
113
120
ast:: expr_ret ( oexpr) {
114
-
121
+ if sc. ret_style == ast:: return_ref && !is_none ( oexpr) {
122
+ check_ret_ref ( * cx, option:: get ( oexpr) ) ;
123
+ }
115
124
handled = false ;
116
125
}
117
126
_ { handled = false ; }
@@ -256,12 +265,33 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr]) -> [binding] {
256
265
ret bindings;
257
266
}
258
267
268
+ fn check_ret_ref ( cx : ctx , expr : @ast:: expr ) {
269
+ let root = expr_root ( cx. tcx , expr, false ) ;
270
+ let bad = none;
271
+ alt path_def( cx, root. ex ) {
272
+ none. { bad = some ( "temporary" ) ; }
273
+ some ( ast:: def_arg ( _, mode) ) {
274
+ if mode == ast:: by_move { bad = some ( "move-mode parameter" ) ; }
275
+ if mut_field ( root. ds ) { bad = some ( "mutable field" ) ; }
276
+ }
277
+ // FIXME allow references to constants and static items?
278
+ _ { bad = some ( "non-argument value" ) ; }
279
+ }
280
+ alt bad {
281
+ some( name) {
282
+ cx. tcx . sess . span_err ( expr. span , "can not return a reference " +
283
+ "to a " + name) ;
284
+ }
285
+ _ { }
286
+ }
287
+ }
288
+
259
289
fn check_alt ( cx : ctx , input : @ast:: expr , arms : [ ast:: arm ] , sc : scope ,
260
290
v : vt < scope > ) {
261
291
v. visit_expr ( input, sc, v) ;
262
292
let root = expr_root ( cx. tcx , input, true ) ;
263
293
for a: ast:: arm in arms {
264
- let new_sc = sc;
294
+ let new_bs = sc. bs ;
265
295
let root_var = path_def_id ( cx, root. ex ) ;
266
296
let pat_id_map = ast_util:: pat_id_map ( a. pats [ 0 ] ) ;
267
297
type info = { id : node_id , mutable unsafe: [ ty:: t ] , span : span } ;
@@ -283,11 +313,11 @@ fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope,
283
313
}
284
314
}
285
315
for info in binding_info {
286
- new_sc += [ mk_binding ( cx, info. id , info. span , root_var,
287
- info. unsafe ) ] ;
316
+ new_bs += [ mk_binding ( cx, info. id , info. span , root_var,
317
+ copy info. unsafe ) ] ;
288
318
}
289
319
register_locals ( cx, a. pats [ 0 ] ) ;
290
- visit:: visit_arm ( a, new_sc , v) ;
320
+ visit:: visit_arm ( a, { bs : new_bs with sc } , v) ;
291
321
}
292
322
}
293
323
@@ -296,13 +326,13 @@ fn check_for_each(cx: ctx, local: @ast::local, call: @ast::expr,
296
326
v. visit_expr ( call, sc, v) ;
297
327
alt call. node {
298
328
ast:: expr_call ( f, args) {
299
- let new_sc = sc + check_call ( cx, f, args) ;
329
+ let new_bs = sc. bs + check_call ( cx, f, args) ;
300
330
for proot in * pattern_roots ( cx. tcx , [ ] , local. node . pat ) {
301
- new_sc += [ mk_binding ( cx, proot. id , proot. span , none,
331
+ new_bs += [ mk_binding ( cx, proot. id , proot. span , none,
302
332
inner_mut ( proot. ds ) ) ] ;
303
333
}
304
334
register_locals ( cx, local. node . pat ) ;
305
- visit:: visit_block ( blk, new_sc , v) ;
335
+ visit:: visit_block ( blk, { bs : new_bs with sc } , v) ;
306
336
}
307
337
}
308
338
}
@@ -324,13 +354,13 @@ fn check_for(cx: ctx, local: @ast::local, seq: @ast::expr, blk: ast::blk,
324
354
_ { }
325
355
}
326
356
let root_var = path_def_id ( cx, root. ex ) ;
327
- let new_sc = sc;
357
+ let new_bs = sc. bs ;
328
358
for proot in * pattern_roots ( cx. tcx , ext_ds, local. node . pat ) {
329
- new_sc += [ mk_binding ( cx, proot. id , proot. span , root_var,
359
+ new_bs += [ mk_binding ( cx, proot. id , proot. span , root_var,
330
360
inner_mut ( proot. ds ) ) ] ;
331
361
}
332
362
register_locals ( cx, local. node . pat ) ;
333
- visit:: visit_block ( blk, new_sc , v) ;
363
+ visit:: visit_block ( blk, { bs : new_bs with sc } , v) ;
334
364
}
335
365
336
366
fn check_var ( cx : ctx , ex : @ast:: expr , p : ast:: path , id : ast:: node_id ,
@@ -341,7 +371,7 @@ fn check_var(cx: ctx, ex: @ast::expr, p: ast::path, id: ast::node_id,
341
371
let my_local_id =
342
372
alt cx. local_map . find ( my_defnum) { some ( local ( id) ) { id } _ { 0 u } } ;
343
373
let var_t = ty:: expr_ty ( cx. tcx , ex) ;
344
- for b in sc {
374
+ for b in sc. bs {
345
375
// excludes variables introduced since the alias was made
346
376
if my_local_id < b. local_id {
347
377
for ty in b. unsafe_tys {
@@ -360,7 +390,7 @@ fn check_lval(cx: @ctx, dest: @ast::expr, sc: scope, v: vt<scope>) {
360
390
ast:: expr_path ( p) {
361
391
let def = cx. tcx . def_map . get ( dest. id ) ;
362
392
let dnum = ast_util:: def_id_of_def ( def) . node ;
363
- for b in sc {
393
+ for b in sc. bs {
364
394
if b. root_var == some ( dnum) { b. ok = overwritten ( dest. span , p) ; }
365
395
}
366
396
}
@@ -378,7 +408,7 @@ fn test_scope(cx: ctx, sc: scope, b: binding, p: ast::path) {
378
408
let prob = b. ok ;
379
409
alt b. root_var {
380
410
some ( dn) {
381
- for other in sc {
411
+ for other in sc. bs {
382
412
if other. node_id == dn {
383
413
prob = other. ok ;
384
414
if prob != valid { break ; }
@@ -461,11 +491,6 @@ fn ty_can_unsafely_include(cx: ctx, needle: ty::t, haystack: ty::t, mut: bool)
461
491
ret true ;
462
492
}
463
493
ty:: ty_obj ( _) { ret true ; }
464
-
465
-
466
-
467
-
468
-
469
494
// A type param may include everything, but can only be
470
495
// treated as opaque downstream, and is thus safe unless we
471
496
// saw mutable fields, in which case the whole thing can be
0 commit comments