Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
55a2fd18
R
Rust
项目概览
int
/
Rust
大约 1 年 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
55a2fd18
编写于
12月 19, 2011
作者:
N
Niko Matsakis
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
implement capture clauses (move, in particular) and integrate
them into type state and so forth
上级
41ae1460
变更
14
隐藏空白更改
内联
并排
Showing
14 changed file
with
305 addition
and
53 deletion
+305
-53
src/comp/middle/capture.rs
src/comp/middle/capture.rs
+132
-0
src/comp/middle/trans.rs
src/comp/middle/trans.rs
+9
-4
src/comp/middle/trans_closure.rs
src/comp/middle/trans_closure.rs
+96
-46
src/comp/middle/tstate/pre_post_conditions.rs
src/comp/middle/tstate/pre_post_conditions.rs
+7
-0
src/comp/middle/typeck.rs
src/comp/middle/typeck.rs
+4
-3
src/comp/rustc.rc
src/comp/rustc.rc
+1
-0
src/comp/syntax/ast.rs
src/comp/syntax/ast.rs
+4
-0
src/test/compile-fail/cap-clause-both-copy-and-move.rs
src/test/compile-fail/cap-clause-both-copy-and-move.rs
+5
-0
src/test/compile-fail/cap-clause-double-copy.rs
src/test/compile-fail/cap-clause-double-copy.rs
+5
-0
src/test/compile-fail/cap-clause-double-move.rs
src/test/compile-fail/cap-clause-double-move.rs
+5
-0
src/test/compile-fail/cap-clause-move-upvar.rs
src/test/compile-fail/cap-clause-move-upvar.rs
+8
-0
src/test/compile-fail/cap-clause-use-after-move.rs
src/test/compile-fail/cap-clause-use-after-move.rs
+7
-0
src/test/run-pass/cap-clause-move.rs
src/test/run-pass/cap-clause-move.rs
+17
-0
src/test/run-pass/cap-clause-not-used.rs
src/test/run-pass/cap-clause-not-used.rs
+5
-0
未找到文件。
src/comp/middle/capture.rs
0 → 100644
浏览文件 @
55a2fd18
import
syntax
::{
ast
,
ast_util
};
import
std
::
map
;
export
capture_mode
;
export
capture_var
;
export
capture_map
;
export
check_capture_clause
;
export
compute_capture_vars
;
export
cap_copy
;
export
cap_move
;
export
cap_drop
;
export
cap_ref
;
tag
capture_mode
{
cap_copy
;
//< Copy the value into the closure.
cap_move
;
//< Move the value into the closure.
cap_drop
;
//< Drop value after creating closure.
cap_ref
;
//< Reference directly from parent stack frame (block fn).
}
type
capture_var
=
{
def
:
ast
::
def
,
//< The variable being accessed free.
mode
:
capture_mode
//< How is the variable being accessed.
};
type
capture_map
=
map
::
hashmap
<
ast
::
def_id
,
capture_var
>
;
// checks the capture clause for a fn_expr() and issues warnings or
// errors for any irregularities which we identify.
fn
check_capture_clause
(
tcx
:
ty
::
ctxt
,
fn_expr_id
:
ast
::
node_id
,
fn_proto
:
ast
::
proto
,
cap_clause
:
ast
::
capture_clause
)
{
let
freevars
=
freevars
::
get_freevars
(
tcx
,
fn_expr_id
);
let
seen_defs
=
map
::
new_int_hash
();
let
check_capture_item
=
lambda
(
&&
cap_item
:
@
ast
::
capture_item
)
{
let
cap_def
=
tcx
.def_map
.get
(
cap_item
.id
);
if
!
vec
::
any
(
*
freevars
,
{|
fv
|
fv
.def
==
cap_def
})
{
tcx
.sess
.span_warn
(
cap_item
.span
,
#
fmt
(
"Captured variable '%s' not used in closure"
,
cap_item
.name
));
}
let
cap_def_id
=
ast_util
::
def_id_of_def
(
cap_def
)
.node
;
if
!
seen_defs
.insert
(
cap_def_id
,
())
{
tcx
.sess
.span_err
(
cap_item
.span
,
#
fmt
(
"Variable '%s' captured more than once"
,
cap_item
.name
));
}
};
let
check_not_upvar
=
lambda
(
&&
cap_item
:
@
ast
::
capture_item
)
{
alt
tcx
.def_map
.get
(
cap_item
.id
)
{
ast
::
def_upvar
(
_
,
_
,
_
)
{
tcx
.sess
.span_err
(
cap_item
.span
,
#
fmt
(
"Upvars (like '%s') cannot be moved into a closure"
,
cap_item
.name
));
}
_
{}
}
};
let
check_block_captures
=
lambda
(
v
:
[
@
ast
::
capture_item
])
{
if
check
vec
::
is_not_empty
(
v
)
{
let
cap_item0
=
vec
::
head
(
v
);
tcx
.sess
.span_err
(
cap_item0
.span
,
"Cannot capture values explicitly with a block closure"
);
}
};
alt
fn_proto
{
ast
::
proto_block
.
{
check_block_captures
(
cap_clause
.copies
);
check_block_captures
(
cap_clause
.moves
);
}
ast
::
proto_bare
.
|
ast
::
proto_shared
(
_
)
|
ast
::
proto_send
.
{
vec
::
iter
(
cap_clause
.copies
,
check_capture_item
);
vec
::
iter
(
cap_clause
.moves
,
check_capture_item
);
vec
::
iter
(
cap_clause
.moves
,
check_not_upvar
);
}
}
}
fn
compute_capture_vars
(
tcx
:
ty
::
ctxt
,
fn_expr_id
:
ast
::
node_id
,
fn_proto
:
ast
::
proto
,
cap_clause
:
ast
::
capture_clause
)
->
[
capture_var
]
{
let
freevars
=
freevars
::
get_freevars
(
tcx
,
fn_expr_id
);
let
cap_map
=
map
::
new_int_hash
();
vec
::
iter
(
cap_clause
.copies
)
{
|
cap_item
|
let
cap_def
=
tcx
.def_map
.get
(
cap_item
.id
);
let
cap_def_id
=
ast_util
::
def_id_of_def
(
cap_def
)
.node
;
if
vec
::
any
(
*
freevars
,
{|
fv
|
fv
.def
==
cap_def
})
{
cap_map
.insert
(
cap_def_id
,
{
def
:
cap_def
,
mode
:
cap_copy
});
}
}
vec
::
iter
(
cap_clause
.moves
)
{
|
cap_item
|
let
cap_def
=
tcx
.def_map
.get
(
cap_item
.id
);
let
cap_def_id
=
ast_util
::
def_id_of_def
(
cap_def
)
.node
;
if
vec
::
any
(
*
freevars
,
{|
fv
|
fv
.def
==
cap_def
})
{
cap_map
.insert
(
cap_def_id
,
{
def
:
cap_def
,
mode
:
cap_move
});
}
else
{
cap_map
.insert
(
cap_def_id
,
{
def
:
cap_def
,
mode
:
cap_drop
});
}
}
let
implicit_mode
=
alt
fn_proto
{
ast
::
proto_block
.
{
cap_ref
}
ast
::
proto_bare
.
|
ast
::
proto_shared
(
_
)
|
ast
::
proto_send
.
{
cap_copy
}
};
vec
::
iter
(
*
freevars
)
{
|
fvar
|
let
fvar_def_id
=
ast_util
::
def_id_of_def
(
fvar
.def
)
.node
;
alt
cap_map
.find
(
fvar_def_id
)
{
option
::
some
(
_
)
{
/* was explicitly named, do nothing */
}
option
::
none
.
{
cap_map
.insert
(
fvar_def_id
,
{
def
:
fvar
.def
,
mode
:
implicit_mode
});
}
}
}
let
result
=
[];
cap_map
.values
{
|
cap_var
|
result
+=
[
cap_var
];
}
ret
result
;
}
src/comp/middle/trans.rs
浏览文件 @
55a2fd18
...
...
@@ -2566,7 +2566,11 @@ fn trans_do_while(cx: @block_ctxt, body: ast::blk, cond: @ast::expr) ->
static_tis
:
[
option
::
t
<@
tydesc_info
>
],
tydescs
:
[
ValueRef
]};
tag
lval_kind
{
temporary
;
owned
;
owned_imm
;
}
tag
lval_kind
{
temporary
;
//< Temporary value passed by value if of immediate type
owned
;
//< Non-temporary value passed by pointer
owned_imm
;
//< Non-temporary value passed by value
}
type
local_var_result
=
{
val
:
ValueRef
,
kind
:
lval_kind
};
type
lval_result
=
{
bcx
:
@
block_ctxt
,
val
:
ValueRef
,
kind
:
lval_kind
};
tag
callee_env
{
obj_env
(
ValueRef
);
null_env
;
is_closure
;
}
...
...
@@ -3550,12 +3554,13 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
assert
op
!=
ast
::
deref
;
// lvals are handled above
ret
trans_unary
(
bcx
,
op
,
x
,
e
.id
,
dest
);
}
// NDM captures
ast
::
expr_fn
(
f
,
cap_clause
)
{
ret
trans_closure
::
trans_expr_fn
(
bcx
,
f
,
e
.span
,
e
.id
,
dest
);
ret
trans_closure
::
trans_expr_fn
(
bcx
,
f
,
e
.span
,
e
.id
,
*
cap_clause
,
dest
);
}
ast
::
expr_bind
(
f
,
args
)
{
ret
trans_closure
::
trans_bind
(
bcx
,
f
,
args
,
e
.id
,
dest
);
ret
trans_closure
::
trans_bind
(
bcx
,
f
,
args
,
e
.id
,
dest
);
}
ast
::
expr_copy
(
a
)
{
if
!
expr_is_lval
(
bcx
,
a
)
{
...
...
src/comp/middle/trans_closure.rs
浏览文件 @
55a2fd18
...
...
@@ -43,8 +43,10 @@
// };
// };
//
// NB: this is defined in the code in T_closure_ptr and
// closure_ty_to_tuple_ty (below).
// NB: this struct is defined in the code in trans_common::T_closure()
// and mk_closure_ty() below. The former defines the LLVM version and
// the latter the Rust equivalent. It occurs to me that these could
// perhaps be unified, but currently they are not.
//
// Note that the closure carries a type descriptor that describes
// itself. Trippy. This is needed because the precise types of the
...
...
@@ -64,8 +66,17 @@
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tag
environment_value
{
// Evaluate expr and store result in env (used for bind).
env_expr
(
@
ast
::
expr
);
env_direct
(
ValueRef
,
ty
::
t
,
bool
);
// Copy the value from this llvm ValueRef into the environment.
env_copy
(
ValueRef
,
ty
::
t
,
lval_kind
);
// Move the value from this llvm ValueRef into the environment.
env_move
(
ValueRef
,
ty
::
t
,
lval_kind
);
// Access by reference (used for blocks).
env_ref
(
ValueRef
,
ty
::
t
,
lval_kind
);
}
// Given a closure ty, emits a corresponding tuple ty
...
...
@@ -143,8 +154,10 @@ fn maybe_clone_tydesc(bcx: @block_ctxt,
let
bound_tys
=
[];
for
bv
in
bound_values
{
bound_tys
+=
[
alt
bv
{
env_direct
(
_
,
t
,
_
)
{
t
}
env_expr
(
e
)
{
ty
::
expr_ty
(
tcx
,
e
)
}
env_copy
(
_
,
t
,
_
)
{
t
}
env_move
(
_
,
t
,
_
)
{
t
}
env_ref
(
_
,
t
,
_
)
{
t
}
env_expr
(
e
)
{
ty
::
expr_ty
(
tcx
,
e
)
}
}];
}
let
bound_data_ty
=
ty
::
mk_tup
(
tcx
,
bound_tys
);
...
...
@@ -239,17 +252,29 @@ fn maybe_clone_tydesc(bcx: @block_ctxt,
add_clean_temp_mem
(
bcx
,
bound
.val
,
bound_tys
[
i
]);
temp_cleanups
+=
[
bound
.val
];
}
env_direct
(
val
,
ty
,
is_mem
)
{
alt
ck
{
ty
::
closure_shared
.
|
ty
::
closure_send
.
{
let
val1
=
is_mem
?
load_if_immediate
(
bcx
,
val
,
ty
)
:
val
;
bcx
=
trans
::
copy_val
(
bcx
,
INIT
,
bound
.val
,
val1
,
ty
);
}
ty
::
closure_block
.
{
let
addr
=
is_mem
?
val
:
do_spill_noroot
(
bcx
,
val
);
Store
(
bcx
,
addr
,
bound
.val
);
}
}
env_copy
(
val
,
ty
,
owned
.
)
{
let
val1
=
load_if_immediate
(
bcx
,
val
,
ty
);
bcx
=
trans
::
copy_val
(
bcx
,
INIT
,
bound
.val
,
val1
,
ty
);
}
env_copy
(
val
,
ty
,
owned_imm
.
)
{
bcx
=
trans
::
copy_val
(
bcx
,
INIT
,
bound
.val
,
val
,
ty
);
}
env_copy
(
_
,
_
,
temporary
.
)
{
fail
"Cannot capture temporary upvar"
;
}
env_move
(
val
,
ty
,
kind
)
{
let
src
=
{
bcx
:
bcx
,
val
:
val
,
kind
:
kind
};
bcx
=
move_val
(
bcx
,
INIT
,
bound
.val
,
src
,
ty
);
}
env_ref
(
val
,
ty
,
owned
.
)
{
Store
(
bcx
,
val
,
bound
.val
);
}
env_ref
(
val
,
ty
,
owned_imm
.
)
{
let
addr
=
do_spill_noroot
(
bcx
,
val
);
Store
(
bcx
,
addr
,
bound
.val
);
}
env_ref
(
_
,
_
,
temporary
.
)
{
fail
"Cannot capture temporary upvar"
;
}
}
}
...
...
@@ -260,25 +285,38 @@ fn maybe_clone_tydesc(bcx: @block_ctxt,
// Given a context and a list of upvars, build a closure. This just
// collects the upvars and packages them up for store_environment.
fn
build_closure
(
cx
:
@
block_ctxt
,
upvars
:
freevar_info
,
fn
build_closure
(
bcx0
:
@
block_ctxt
,
cap_vars
:
[
capture
::
capture_var
]
,
ck
:
ty
::
closure_kind
)
->
closure_result
{
// If we need to, package up the iterator body to call
let
env_vals
=
[];
let
tcx
=
bcx_tcx
(
cx
);
// Package up the upvars
vec
::
iter
(
*
upvars
)
{
|
upvar
|
let
lv
=
trans_local_var
(
cx
,
upvar
.def
);
let
nid
=
ast_util
::
def_id_of_def
(
upvar
.def
)
.node
;
let
bcx
=
bcx0
;
let
tcx
=
bcx_tcx
(
bcx
);
// Package up the captured upvars
vec
::
iter
(
cap_vars
)
{
|
cap_var
|
let
lv
=
trans_local_var
(
bcx
,
cap_var
.def
);
let
nid
=
ast_util
::
def_id_of_def
(
cap_var
.def
)
.node
;
let
ty
=
ty
::
node_id_to_monotype
(
tcx
,
nid
);
alt
ck
{
ty
::
closure_block
.
{
ty
=
ty
::
mk_mut_ptr
(
tcx
,
ty
);
}
ty
::
closure_send
.
|
ty
::
closure_shared
.
{}
alt
cap_var
.mode
{
capture
::
cap_ref
.
{
assert
ck
==
ty
::
closure_block
;
ty
=
ty
::
mk_mut_ptr
(
tcx
,
ty
);
env_vals
+=
[
env_ref
(
lv
.val
,
ty
,
lv
.kind
)];
}
capture
::
cap_copy
.
{
env_vals
+=
[
env_copy
(
lv
.val
,
ty
,
lv
.kind
)];
}
capture
::
cap_move
.
{
env_vals
+=
[
env_move
(
lv
.val
,
ty
,
lv
.kind
)];
}
capture
::
cap_drop
.
{
bcx
=
drop_ty
(
bcx
,
lv
.val
,
ty
);
}
}
env_vals
+=
[
env_direct
(
lv
.val
,
ty
,
lv
.kind
==
owned
)];
}
ret
store_environment
(
cx
,
copy
cx
.fcx.lltydescs
,
env_vals
,
ck
);
ret
store_environment
(
bcx
,
copy
b
cx
.fcx.lltydescs
,
env_vals
,
ck
);
}
// Given an enclosing block context, a new function context, a closure type,
...
...
@@ -287,7 +325,7 @@ fn build_closure(cx: @block_ctxt,
fn
load_environment
(
enclosing_cx
:
@
block_ctxt
,
fcx
:
@
fn_ctxt
,
boxed_closure_ty
:
ty
::
t
,
upvars
:
freevar_info
,
cap_vars
:
[
capture
::
capture_var
]
,
ck
:
ty
::
closure_kind
)
{
let
bcx
=
new_raw_block_ctxt
(
fcx
,
fcx
.llloadenv
);
...
...
@@ -311,23 +349,34 @@ fn load_environment(enclosing_cx: @block_ctxt,
// Populate the upvars from the environment.
let
path
=
[
0
,
abi
::
box_rc_field_body
,
abi
::
closure_elt_bindings
];
vec
::
iteri
(
*
upvars
)
{
|
i
,
upvar
|
check
type_is_tup_like
(
bcx
,
boxed_closure_ty
);
let
upvarptr
=
GEP_tup_like
(
bcx
,
boxed_closure_ty
,
llclosure
,
path
+
[
i
as
int
]);
bcx
=
upvarptr
.bcx
;
let
llupvarptr
=
upvarptr
.val
;
alt
ck
{
ty
::
closure_block
.
{
llupvarptr
=
Load
(
bcx
,
llupvarptr
);
}
ty
::
closure_send
.
|
ty
::
closure_shared
.
{
}
let
i
=
0u
;
vec
::
iter
(
cap_vars
)
{
|
cap_var
|
alt
cap_var
.mode
{
capture
::
cap_drop
.
{
/* ignore */
}
_
{
check
type_is_tup_like
(
bcx
,
boxed_closure_ty
);
let
upvarptr
=
GEP_tup_like
(
bcx
,
boxed_closure_ty
,
llclosure
,
path
+
[
i
as
int
]);
bcx
=
upvarptr
.bcx
;
let
llupvarptr
=
upvarptr
.val
;
alt
ck
{
ty
::
closure_block
.
{
llupvarptr
=
Load
(
bcx
,
llupvarptr
);
}
ty
::
closure_send
.
|
ty
::
closure_shared
.
{
}
}
let
def_id
=
ast_util
::
def_id_of_def
(
cap_var
.def
);
fcx
.llupvars
.insert
(
def_id
.node
,
llupvarptr
);
i
+=
1u
;
}
}
let
def_id
=
ast_util
::
def_id_of_def
(
upvar
.def
);
fcx
.llupvars
.insert
(
def_id
.node
,
llupvarptr
);
}
}
fn
trans_expr_fn
(
bcx
:
@
block_ctxt
,
f
:
ast
::
_
fn
,
sp
:
span
,
id
:
ast
::
node_id
,
dest
:
dest
)
->
@
block_ctxt
{
fn
trans_expr_fn
(
bcx
:
@
block_ctxt
,
f
:
ast
::
_
fn
,
sp
:
span
,
id
:
ast
::
node_id
,
cap_clause
:
ast
::
capture_clause
,
dest
:
dest
)
->
@
block_ctxt
{
if
dest
==
ignore
{
ret
bcx
;
}
let
ccx
=
bcx_ccx
(
bcx
),
bcx
=
bcx
;
let
fty
=
node_id_type
(
ccx
,
id
);
...
...
@@ -339,10 +388,11 @@ fn trans_expr_fn(bcx: @block_ctxt, f: ast::_fn, sp: span,
register_fn
(
ccx
,
sp
,
sub_cx
.path
,
"anon fn"
,
[],
id
);
let
trans_closure_env
=
lambda
(
ck
:
ty
::
closure_kind
)
->
ValueRef
{
let
upvars
=
get_freevars
(
ccx
.tcx
,
id
);
let
{
llbox
,
box_ty
,
bcx
}
=
build_closure
(
bcx
,
upvars
,
ck
);
let
cap_vars
=
capture
::
compute_capture_vars
(
ccx
.tcx
,
id
,
f
.proto
,
cap_clause
);
let
{
llbox
,
box_ty
,
bcx
}
=
build_closure
(
bcx
,
cap_vars
,
ck
);
trans_closure
(
sub_cx
,
sp
,
f
,
llfn
,
no_self
,
[],
id
,
{|
fcx
|
load_environment
(
bcx
,
fcx
,
box_ty
,
up
vars
,
ck
);
load_environment
(
bcx
,
fcx
,
box_ty
,
cap_
vars
,
ck
);
});
llbox
};
...
...
@@ -420,7 +470,7 @@ fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
let
sp
=
cx
.sp
;
let
llclosurety
=
T_ptr
(
type_of
(
ccx
,
sp
,
outgoing_fty
));
let
src_loc
=
PointerCast
(
bcx
,
cl
,
llclosurety
);
([
env_
direct
(
src_loc
,
pair_ty
,
true
)],
none
)
([
env_
copy
(
src_loc
,
pair_ty
,
owned
)],
none
)
}
none
.
{
([],
some
(
f_res
.val
))
}
};
...
...
src/comp/middle/tstate/pre_post_conditions.rs
浏览文件 @
55a2fd18
...
...
@@ -347,6 +347,13 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
handle_var_def
(
fcx
,
rslt
,
def
.def
,
"upvar"
);
}
let
use_cap_item
=
lambda
(
&&
cap_item
:
@
capture_item
)
{
let
d
=
local_node_id_to_local_def_id
(
fcx
,
cap_item
.id
);
option
::
may
(
d
,
{
|
id
|
use_var
(
fcx
,
id
)
});
};
vec
::
iter
(
cap_clause
.copies
,
use_cap_item
);
vec
::
iter
(
cap_clause
.moves
,
use_cap_item
);
vec
::
iter
(
cap_clause
.moves
)
{
|
cap_item
|
log
(
"forget_in_postcond: "
,
cap_item
);
forget_in_postcond
(
fcx
,
e
.id
,
cap_item
.id
);
...
...
src/comp/middle/typeck.rs
浏览文件 @
55a2fd18
...
...
@@ -1939,9 +1939,8 @@ fn check_binop_type_compat(fcx: @fn_ctxt, span: span, ty: ty::t,
if
!
arm_non_bot
{
result_ty
=
ty
::
mk_bot
(
tcx
);
}
write
::
ty_only_fixup
(
fcx
,
id
,
result_ty
);
}
ast
::
expr_fn
(
f
,
captures
)
{
// NDM captures
let
cx
=
@
{
tcx
:
tcx
};
let
fty
=
ty_of_fn_decl
(
cx
.tcx
,
m_check_tyvar
(
fcx
),
f
.decl
,
ast
::
expr_fn
(
f
,
captures
)
{
let
fty
=
ty_of_fn_decl
(
tcx
,
m_check_tyvar
(
fcx
),
f
.decl
,
f
.proto
,
[],
none
)
.ty
;
write
::
ty_only_fixup
(
fcx
,
id
,
fty
);
...
...
@@ -1956,6 +1955,8 @@ fn check_binop_type_compat(fcx: @fn_ctxt, span: span, ty: ty::t,
if
f
.proto
==
ast
::
proto_block
{
write
::
ty_only_fixup
(
fcx
,
id
,
expected
);
}
capture
::
check_capture_clause
(
tcx
,
expr
.id
,
f
.proto
,
*
captures
);
}
ast
::
expr_block
(
b
)
{
// If this is an unchecked block, turn off purity-checking
...
...
src/comp/rustc.rc
浏览文件 @
55a2fd18
...
...
@@ -38,6 +38,7 @@ mod middle {
mod
shape
;
mod
gc
;
mod
debuginfo
;
mod
capture
;
mod
tstate
{
mod
ck
;
...
...
src/comp/syntax/ast.rs
浏览文件 @
55a2fd18
...
...
@@ -261,6 +261,10 @@ fn proto_kind(p: proto) -> kind {
expr_mac
(
mac
);
}
// AST nodes that represent a capture clause, which is used to declare
// variables that are copied or moved explicitly into the closure. In some
// cases, local variables can also be copied implicitly into the closure if
// they are used in the closure body.
type
capture_item
=
{
id
:
int
,
name
:
ident
,
// Currently, can only capture a local var.
...
...
src/test/compile-fail/cap-clause-both-copy-and-move.rs
0 → 100644
浏览文件 @
55a2fd18
// error-pattern:error: Variable 'x' captured more than once
fn
main
()
{
let
x
=
5
;
let
y
=
sendfn
[
move
x
;
copy
x
]()
->
int
{
x
};
}
\ No newline at end of file
src/test/compile-fail/cap-clause-double-copy.rs
0 → 100644
浏览文件 @
55a2fd18
// error-pattern:error: Variable 'x' captured more than once
fn
main
()
{
let
x
=
5
;
let
y
=
sendfn
[
copy
x
,
x
]()
->
int
{
x
};
}
src/test/compile-fail/cap-clause-double-move.rs
0 → 100644
浏览文件 @
55a2fd18
// error-pattern: error: Variable 'x' captured more than once
fn
main
()
{
let
x
=
5
;
let
y
=
sendfn
[
move
x
,
x
]()
->
int
{
x
};
}
src/test/compile-fail/cap-clause-move-upvar.rs
0 → 100644
浏览文件 @
55a2fd18
// error-pattern: error: Upvars (like 'x') cannot be moved into a closure
fn
main
()
{
let
x
=
5
;
let
_
y
=
sendfn
[
move
x
]()
->
int
{
let
_
z
=
sendfn
[
move
x
]()
->
int
{
x
};
22
};
}
src/test/compile-fail/cap-clause-use-after-move.rs
0 → 100644
浏览文件 @
55a2fd18
// error-pattern:Unsatisfied precondition constraint
fn
main
()
{
let
x
=
5
;
let
_
y
=
sendfn
[
move
x
]()
{
};
let
_
z
=
x
;
//< error: Unsatisfied precondition constraint
}
src/test/run-pass/cap-clause-move.rs
0 → 100644
浏览文件 @
55a2fd18
// error-pattern: warning: Captured variable 'y' not used in closure
fn
main
()
{
let
x
=
~
1
;
let
y
=
ptr
::
addr_of
(
*
x
)
as
uint
;
let
lam_copy
=
lambda
[
copy
x
]()
->
uint
{
ptr
::
addr_of
(
*
x
)
as
uint
};
let
lam_move
=
lambda
[
move
x
]()
->
uint
{
ptr
::
addr_of
(
*
x
)
as
uint
};
assert
lam_copy
()
!=
y
;
assert
lam_move
()
==
y
;
let
x
=
~
2
;
let
y
=
ptr
::
addr_of
(
*
x
)
as
uint
;
let
snd_copy
=
sendfn
[
copy
x
]()
->
uint
{
ptr
::
addr_of
(
*
x
)
as
uint
};
let
snd_move
=
sendfn
[
move
x
]()
->
uint
{
ptr
::
addr_of
(
*
x
)
as
uint
};
assert
snd_copy
()
!=
y
;
assert
snd_move
()
==
y
;
}
src/test/run-pass/cap-clause-not-used.rs
0 → 100644
浏览文件 @
55a2fd18
// error-pattern: warning: Captured variable 'y' not used in closure
fn
main
()
{
let
x
=
5
;
let
_
y
=
sendfn
[
copy
x
]()
{
};
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录