Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
3fbfad35
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,发现更多精彩内容 >>
提交
3fbfad35
编写于
1月 30, 2015
作者:
B
bors
浏览文件
操作
浏览文件
下载
差异文件
Auto merge of #21604 - nikomatsakis:closure-move-indiv-vars, r=eddyb
r?
@EddyB
上级
1a51eb9c
ced10626
变更
30
隐藏空白更改
内联
并排
Showing
30 changed file
with
644 addition
and
480 deletion
+644
-480
src/liballoc/lib.rs
src/liballoc/lib.rs
+1
-0
src/libcore/ops.rs
src/libcore/ops.rs
+3
-0
src/librustc/lint/builtin.rs
src/librustc/lint/builtin.rs
+1
-0
src/librustc/metadata/common.rs
src/librustc/metadata/common.rs
+3
-1
src/librustc/metadata/decoder.rs
src/librustc/metadata/decoder.rs
+7
-0
src/librustc/metadata/encoder.rs
src/librustc/metadata/encoder.rs
+6
-0
src/librustc/middle/astencode.rs
src/librustc/middle/astencode.rs
+25
-41
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/expr_use_visitor.rs
+24
-42
src/librustc/middle/mem_categorization.rs
src/librustc/middle/mem_categorization.rs
+115
-120
src/librustc/middle/ty.rs
src/librustc/middle/ty.rs
+63
-103
src/librustc/util/ppaux.rs
src/librustc/util/ppaux.rs
+9
-0
src/librustc_driver/driver.rs
src/librustc_driver/driver.rs
+0
-2
src/librustc_driver/test.rs
src/librustc_driver/test.rs
+1
-2
src/librustc_resolve/lib.rs
src/librustc_resolve/lib.rs
+2
-7
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/base.rs
+14
-9
src/librustc_trans/trans/closure.rs
src/librustc_trans/trans/closure.rs
+30
-43
src/librustc_trans/trans/common.rs
src/librustc_trans/trans/common.rs
+2
-7
src/librustc_typeck/astconv.rs
src/librustc_typeck/astconv.rs
+3
-7
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/mod.rs
+5
-9
src/librustc_typeck/check/regionck.rs
src/librustc_typeck/check/regionck.rs
+28
-33
src/librustc_typeck/check/upvar.rs
src/librustc_typeck/check/upvar.rs
+90
-38
src/librustc_typeck/check/writeback.rs
src/librustc_typeck/check/writeback.rs
+13
-9
src/librustc_typeck/collect.rs
src/librustc_typeck/collect.rs
+12
-0
src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs
src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs
+4
-2
src/test/compile-fail/unboxed-closure-illegal-move.rs
src/test/compile-fail/unboxed-closure-illegal-move.rs
+5
-5
src/test/compile-fail/unboxed-closures-move-upvar-from-non-once-ref-closure.rs
.../unboxed-closures-move-upvar-from-non-once-ref-closure.rs
+24
-0
src/test/compile-fail/unboxed-closures-mutate-upvar.rs
src/test/compile-fail/unboxed-closures-mutate-upvar.rs
+62
-0
src/test/compile-fail/unboxed-closures-mutated-upvar-from-fn-closure.rs
...le-fail/unboxed-closures-mutated-upvar-from-fn-closure.rs
+24
-0
src/test/run-pass/unboxed-closures-counter-not-moved.rs
src/test/run-pass/unboxed-closures-counter-not-moved.rs
+36
-0
src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs
...ss/unboxed-closures-move-some-upvars-in-by-ref-closure.rs
+32
-0
未找到文件。
src/liballoc/lib.rs
浏览文件 @
3fbfad35
...
...
@@ -70,6 +70,7 @@
#![feature(lang_items,
unsafe_destructor)]
#![feature(box_syntax)]
#![feature(optin_builtin_traits)]
#![feature(unboxed_closures)]
#![allow(unknown_features)]
#![feature(int_uint)]
#![feature(core)]
#![feature(hash)]
...
...
src/libcore/ops.rs
浏览文件 @
3fbfad35
...
...
@@ -1183,6 +1183,7 @@ extern "rust-call" fn call_once(mut self, args: A) -> R {
#[unstable(feature
=
"core"
,
reason
=
"uncertain about variadic generics, input versus associated types"
)]
#[cfg(not(stage0))]
#[rustc_paren_sugar]
pub
trait
Fn
<
Args
>
{
type
Output
;
...
...
@@ -1195,6 +1196,7 @@ pub trait Fn<Args> {
#[unstable(feature
=
"core"
,
reason
=
"uncertain about variadic generics, input versus associated types"
)]
#[cfg(not(stage0))]
#[rustc_paren_sugar]
pub
trait
FnMut
<
Args
>
{
type
Output
;
...
...
@@ -1207,6 +1209,7 @@ pub trait FnMut<Args> {
#[unstable(feature
=
"core"
,
reason
=
"uncertain about variadic generics, input versus associated types"
)]
#[cfg(not(stage0))]
#[rustc_paren_sugar]
pub
trait
FnOnce
<
Args
>
{
type
Output
;
...
...
src/librustc/lint/builtin.rs
浏览文件 @
3fbfad35
...
...
@@ -670,6 +670,7 @@ fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) {
// FIXME: #19470 this shouldn't be needed forever
"old_orphan_check"
,
"old_impl_check"
,
"rustc_paren_sugar"
,
// FIXME: #18101 temporary unboxed closure hack
];
static
CRATE_ATTRS
:
&
'static
[
&
'static
str
]
=
&
[
...
...
src/librustc/metadata/common.rs
浏览文件 @
3fbfad35
...
...
@@ -140,7 +140,7 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f
tag_table_moves_map
=
0x52
,
tag_table_capture_map
=
0x53
,
tag_table_closures
=
0x54
,
tag_table_upvar_
borrow
_map
=
0x55
,
tag_table_upvar_
capture
_map
=
0x55
,
tag_table_capture_modes
=
0x56
,
tag_table_object_cast_map
=
0x57
,
}
...
...
@@ -265,3 +265,5 @@ pub struct LinkMeta {
pub
const
tag_macro_defs
:
uint
=
0xb5
;
pub
const
tag_macro_def
:
uint
=
0xb6
;
pub
const
tag_macro_def_body
:
uint
=
0xb7
;
pub
const
tag_paren_sugar
:
uint
=
0xb8
;
src/librustc/metadata/decoder.rs
浏览文件 @
3fbfad35
...
...
@@ -371,6 +371,11 @@ fn parse_unsafety(item_doc: rbml::Doc) -> ast::Unsafety {
}
}
fn
parse_paren_sugar
(
item_doc
:
rbml
::
Doc
)
->
bool
{
let
paren_sugar_doc
=
reader
::
get_doc
(
item_doc
,
tag_paren_sugar
);
reader
::
doc_as_u8
(
paren_sugar_doc
)
!=
0
}
fn
parse_polarity
(
item_doc
:
rbml
::
Doc
)
->
ast
::
ImplPolarity
{
let
polarity_doc
=
reader
::
get_doc
(
item_doc
,
tag_polarity
);
if
reader
::
doc_as_u8
(
polarity_doc
)
!=
0
{
...
...
@@ -400,8 +405,10 @@ pub fn get_trait_def<'tcx>(cdata: Cmd,
let
bounds
=
trait_def_bounds
(
item_doc
,
tcx
,
cdata
);
let
unsafety
=
parse_unsafety
(
item_doc
);
let
associated_type_names
=
parse_associated_type_names
(
item_doc
);
let
paren_sugar
=
parse_paren_sugar
(
item_doc
);
ty
::
TraitDef
{
paren_sugar
:
paren_sugar
,
unsafety
:
unsafety
,
generics
:
generics
,
bounds
:
bounds
,
...
...
src/librustc/metadata/encoder.rs
浏览文件 @
3fbfad35
...
...
@@ -1317,6 +1317,7 @@ fn add_to_index(item: &ast::Item, rbml_w: &Encoder,
encode_item_variances
(
rbml_w
,
ecx
,
item
.id
);
let
trait_def
=
ty
::
lookup_trait_def
(
tcx
,
def_id
);
encode_unsafety
(
rbml_w
,
trait_def
.unsafety
);
encode_paren_sugar
(
rbml_w
,
trait_def
.paren_sugar
);
encode_associated_type_names
(
rbml_w
,
trait_def
.associated_type_names
.as_slice
());
encode_generics
(
rbml_w
,
ecx
,
&
trait_def
.generics
,
tag_item_generics
);
encode_trait_ref
(
rbml_w
,
ecx
,
&*
trait_def
.trait_ref
,
tag_item_trait_ref
);
...
...
@@ -1697,6 +1698,11 @@ fn encode_unsafety(rbml_w: &mut Encoder, unsafety: ast::Unsafety) {
rbml_w
.wr_tagged_u8
(
tag_unsafety
,
byte
);
}
fn
encode_paren_sugar
(
rbml_w
:
&
mut
Encoder
,
paren_sugar
:
bool
)
{
let
byte
:
u8
=
if
paren_sugar
{
1
}
else
{
0
};
rbml_w
.wr_tagged_u8
(
tag_paren_sugar
,
byte
);
}
fn
encode_associated_type_names
(
rbml_w
:
&
mut
Encoder
,
names
:
&
[
ast
::
Name
])
{
rbml_w
.start_tag
(
tag_associated_type_names
);
for
&
name
in
names
.iter
()
{
...
...
src/librustc/middle/astencode.rs
浏览文件 @
3fbfad35
...
...
@@ -518,10 +518,6 @@ fn encode_freevar_entry(rbml_w: &mut Encoder, fv: &ty::Freevar) {
(
*
fv
)
.encode
(
rbml_w
)
.unwrap
();
}
fn
encode_capture_mode
(
rbml_w
:
&
mut
Encoder
,
cm
:
ast
::
CaptureClause
)
{
cm
.encode
(
rbml_w
)
.unwrap
();
}
trait
rbml_decoder_helper
{
fn
read_freevar_entry
(
&
mut
self
,
dcx
:
&
DecodeContext
)
->
ty
::
Freevar
;
...
...
@@ -559,6 +555,15 @@ fn tr(&self, dcx: &DecodeContext) -> ty::UpvarBorrow {
}
}
impl
tr
for
ty
::
UpvarCapture
{
fn
tr
(
&
self
,
dcx
:
&
DecodeContext
)
->
ty
::
UpvarCapture
{
match
*
self
{
ty
::
UpvarCapture
::
ByValue
=>
ty
::
UpvarCapture
::
ByValue
,
ty
::
UpvarCapture
::
ByRef
(
ref
data
)
=>
ty
::
UpvarCapture
::
ByRef
(
data
.tr
(
dcx
)),
}
}
}
// ______________________________________________________________________
// Encoding and decoding of MethodCallee
...
...
@@ -1210,34 +1215,20 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
});
for
freevar
in
fv
.iter
()
{
match
tcx
.capture_mode
(
id
)
{
ast
::
CaptureByRef
=>
{
rbml_w
.tag
(
c
::
tag_table_upvar_borrow_map
,
|
rbml_w
|
{
rbml_w
.id
(
id
);
rbml_w
.tag
(
c
::
tag_table_val
,
|
rbml_w
|
{
let
var_id
=
freevar
.def
.def_id
()
.node
;
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
var_id
,
closure_expr_id
:
id
};
let
upvar_borrow
=
tcx
.upvar_borrow_map
.borrow
()[
upvar_id
]
.clone
();
var_id
.encode
(
rbml_w
);
upvar_borrow
.encode
(
rbml_w
);
})
})
}
_
=>
{}
}
}
}
for
&
cm
in
tcx
.capture_modes
.borrow
()
.get
(
&
id
)
.iter
()
{
rbml_w
.tag
(
c
::
tag_table_capture_modes
,
|
rbml_w
|
{
rbml_w
.id
(
id
);
rbml_w
.tag
(
c
::
tag_table_val
,
|
rbml_w
|
{
encode_capture_mode
(
rbml_w
,
*
cm
);
rbml_w
.tag
(
c
::
tag_table_upvar_capture_map
,
|
rbml_w
|
{
rbml_w
.id
(
id
);
rbml_w
.tag
(
c
::
tag_table_val
,
|
rbml_w
|
{
let
var_id
=
freevar
.def
.def_id
()
.node
;
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
var_id
,
closure_expr_id
:
id
};
let
upvar_capture
=
tcx
.upvar_capture_map
.borrow
()[
upvar_id
]
.clone
();
var_id
.encode
(
rbml_w
);
upvar_capture
.encode
(
rbml_w
);
})
})
}
)
}
}
let
lid
=
ast
::
DefId
{
krate
:
ast
::
LOCAL_CRATE
,
node
:
id
};
...
...
@@ -1911,21 +1902,14 @@ fn decode_side_tables(dcx: &DecodeContext,
})
.unwrap
()
.into_iter
()
.collect
();
dcx
.tcx.freevars
.borrow_mut
()
.insert
(
id
,
fv_info
);
}
c
::
tag_table_upvar_
borrow
_map
=>
{
c
::
tag_table_upvar_
capture
_map
=>
{
let
var_id
:
ast
::
NodeId
=
Decodable
::
decode
(
val_dsr
)
.unwrap
();
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
dcx
.tr_id
(
var_id
),
closure_expr_id
:
id
};
let
ub
:
ty
::
UpvarBorrow
=
Decodable
::
decode
(
val_dsr
)
.unwrap
();
dcx
.tcx.upvar_borrow_map
.borrow_mut
()
.insert
(
upvar_id
,
ub
.tr
(
dcx
));
}
c
::
tag_table_capture_modes
=>
{
let
capture_mode
=
val_dsr
.read_capture_mode
();
dcx
.tcx
.capture_modes
.borrow_mut
()
.insert
(
id
,
capture_mode
);
let
ub
:
ty
::
UpvarCapture
=
Decodable
::
decode
(
val_dsr
)
.unwrap
();
dcx
.tcx.upvar_capture_map
.borrow_mut
()
.insert
(
upvar_id
,
ub
.tr
(
dcx
));
}
c
::
tag_table_tcache
=>
{
let
type_scheme
=
val_dsr
.read_type_scheme
(
dcx
);
...
...
src/librustc/middle/expr_use_visitor.rs
浏览文件 @
3fbfad35
...
...
@@ -366,6 +366,9 @@ fn delegate_consume(&mut self,
consume_id
:
ast
::
NodeId
,
consume_span
:
Span
,
cmt
:
mc
::
cmt
<
'tcx
>
)
{
debug!
(
"delegate_consume(consume_id={}, cmt={})"
,
consume_id
,
cmt
.repr
(
self
.tcx
()));
let
mode
=
copy_or_move
(
self
.typer
,
&
cmt
,
DirectRefMove
);
self
.delegate
.consume
(
consume_id
,
consume_span
,
cmt
,
mode
);
}
...
...
@@ -1208,53 +1211,32 @@ fn walk_captures(&mut self, closure_expr: &ast::Expr) {
debug!
(
"walk_captures({})"
,
closure_expr
.repr
(
self
.tcx
()));
ty
::
with_freevars
(
self
.tcx
(),
closure_expr
.id
,
|
freevars
|
{
match
self
.tcx
()
.capture_mode
(
closure_expr
.id
)
{
ast
::
CaptureByRef
=>
{
self
.walk_by_ref_captures
(
closure_expr
,
freevars
);
}
ast
::
CaptureByValue
=>
{
self
.walk_by_value_captures
(
closure_expr
,
freevars
);
for
freevar
in
freevars
.iter
()
{
let
id_var
=
freevar
.def
.def_id
()
.node
;
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
id_var
,
closure_expr_id
:
closure_expr
.id
};
let
upvar_capture
=
self
.typer
.upvar_capture
(
upvar_id
)
.unwrap
();
let
cmt_var
=
return_if_err!
(
self
.cat_captured_var
(
closure_expr
.id
,
closure_expr
.span
,
freevar
.def
));
match
upvar_capture
{
ty
::
UpvarCapture
::
ByValue
=>
{
let
mode
=
copy_or_move
(
self
.typer
,
&
cmt_var
,
CaptureMove
);
self
.delegate
.consume
(
closure_expr
.id
,
freevar
.span
,
cmt_var
,
mode
);
}
ty
::
UpvarCapture
::
ByRef
(
upvar_borrow
)
=>
{
self
.delegate
.borrow
(
closure_expr
.id
,
closure_expr
.span
,
cmt_var
,
upvar_borrow
.region
,
upvar_borrow
.kind
,
ClosureCapture
(
freevar
.span
));
}
}
}
});
}
fn
walk_by_ref_captures
(
&
mut
self
,
closure_expr
:
&
ast
::
Expr
,
freevars
:
&
[
ty
::
Freevar
])
{
for
freevar
in
freevars
.iter
()
{
let
id_var
=
freevar
.def
.def_id
()
.node
;
let
cmt_var
=
return_if_err!
(
self
.cat_captured_var
(
closure_expr
.id
,
closure_expr
.span
,
freevar
.def
));
// Lookup the kind of borrow the callee requires, as
// inferred by regionbk
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
id_var
,
closure_expr_id
:
closure_expr
.id
};
let
upvar_borrow
=
self
.typer
.upvar_borrow
(
upvar_id
)
.unwrap
();
self
.delegate
.borrow
(
closure_expr
.id
,
closure_expr
.span
,
cmt_var
,
upvar_borrow
.region
,
upvar_borrow
.kind
,
ClosureCapture
(
freevar
.span
));
}
}
fn
walk_by_value_captures
(
&
mut
self
,
closure_expr
:
&
ast
::
Expr
,
freevars
:
&
[
ty
::
Freevar
])
{
for
freevar
in
freevars
.iter
()
{
let
cmt_var
=
return_if_err!
(
self
.cat_captured_var
(
closure_expr
.id
,
closure_expr
.span
,
freevar
.def
));
let
mode
=
copy_or_move
(
self
.typer
,
&
cmt_var
,
CaptureMove
);
self
.delegate
.consume
(
closure_expr
.id
,
freevar
.span
,
cmt_var
,
mode
);
}
}
fn
cat_captured_var
(
&
mut
self
,
closure_id
:
ast
::
NodeId
,
closure_span
:
Span
,
...
...
src/librustc/middle/mem_categorization.rs
浏览文件 @
3fbfad35
...
...
@@ -277,9 +277,7 @@ fn node_method_origin(&self, method_call: ty::MethodCall)
fn
adjustments
<
'a
>
(
&
'a
self
)
->
&
'a
RefCell
<
NodeMap
<
ty
::
AutoAdjustment
<
'tcx
>>>
;
fn
is_method_call
(
&
self
,
id
:
ast
::
NodeId
)
->
bool
;
fn
temporary_scope
(
&
self
,
rvalue_id
:
ast
::
NodeId
)
->
Option
<
region
::
CodeExtent
>
;
fn
upvar_borrow
(
&
self
,
upvar_id
:
ty
::
UpvarId
)
->
Option
<
ty
::
UpvarBorrow
>
;
fn
capture_mode
(
&
self
,
closure_expr_id
:
ast
::
NodeId
)
->
ast
::
CaptureClause
;
fn
upvar_capture
(
&
self
,
upvar_id
:
ty
::
UpvarId
)
->
Option
<
ty
::
UpvarCapture
>
;
}
impl
MutabilityCategory
{
...
...
@@ -595,8 +593,7 @@ pub fn cat_def(&self,
match
ty
.sty
{
ty
::
ty_closure
(
closure_id
,
_
,
_
)
=>
{
let
kind
=
self
.typer
.closure_kind
(
closure_id
);
let
mode
=
self
.typer
.capture_mode
(
fn_node_id
);
self
.cat_upvar
(
id
,
span
,
var_id
,
fn_node_id
,
kind
,
mode
)
self
.cat_upvar
(
id
,
span
,
var_id
,
fn_node_id
,
kind
)
}
_
=>
{
self
.tcx
()
.sess
.span_bug
(
...
...
@@ -628,10 +625,13 @@ fn cat_upvar(&self,
span
:
Span
,
var_id
:
ast
::
NodeId
,
fn_node_id
:
ast
::
NodeId
,
kind
:
ty
::
ClosureKind
,
mode
:
ast
::
CaptureClause
)
->
McResult
<
cmt
<
'tcx
>>
{
// An upvar can have up to 3 components. The base is a
kind
:
ty
::
ClosureKind
)
->
McResult
<
cmt
<
'tcx
>>
{
// An upvar can have up to 3 components. We translate first to a
// `cat_upvar`, which is itself a fiction -- it represents the reference to the
// field from the environment.
//
// `cat_upvar`. Next, we add a deref through the implicit
// environment pointer with an anonymous free region 'env and
// appropriate borrow kind for closure kinds that take self by
...
...
@@ -650,135 +650,130 @@ fn cat_upvar(&self,
// Fn | copied -> &'env | upvar -> &'env -> &'up bk
// FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk
// FnOnce | copied | upvar -> &'up bk
let
var_ty
=
try!
(
self
.node_ty
(
var_id
));
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
var_id
,
closure_expr_id
:
fn_node_id
};
let
var_ty
=
try!
(
self
.node_ty
(
var_id
));
// Mutability of original variable itself
let
var_mutbl
=
MutabilityCategory
::
from_local
(
self
.tcx
(),
var_id
);
// Construct information about env pointer dereference, if any
let
mutbl
=
match
kind
{
ty
::
FnOnceClosureKind
=>
None
,
// None, env is by-value
ty
::
FnMutClosureKind
=>
match
mode
{
// Depends on capture type
ast
::
CaptureByValue
=>
Some
(
var_mutbl
),
// Mutable if the original var is
ast
::
CaptureByRef
=>
Some
(
McDeclared
)
// Mutable regardless
},
ty
::
FnClosureKind
=>
Some
(
McImmutable
)
// Never mutable
// Construct the upvar. This represents access to the field
// from the environment (perhaps we should eventually desugar
// this field further, but it will do for now).
let
cmt_result
=
cmt_
{
id
:
id
,
span
:
span
,
cat
:
cat_upvar
(
Upvar
{
id
:
upvar_id
,
kind
:
kind
}),
mutbl
:
var_mutbl
,
ty
:
var_ty
,
note
:
NoteNone
};
let
env_info
=
mutbl
.map
(|
env_mutbl
|
{
// Look up the node ID of the closure body so we can construct
// a free region within it
let
fn_body_id
=
{
let
fn_expr
=
match
self
.tcx
()
.map
.find
(
fn_node_id
)
{
Some
(
ast_map
::
NodeExpr
(
e
))
=>
e
,
_
=>
unreachable!
()
};
match
fn_expr
.node
{
ast
::
ExprClosure
(
_
,
_
,
_
,
ref
body
)
=>
body
.id
,
_
=>
unreachable!
()
}
};
// Region of environment pointer
let
env_region
=
ty
::
ReFree
(
ty
::
FreeRegion
{
scope
:
region
::
CodeExtent
::
from_node_id
(
fn_body_id
),
bound_region
:
ty
::
BrEnv
});
let
env_ptr
=
BorrowedPtr
(
if
env_mutbl
.is_mutable
()
{
ty
::
MutBorrow
}
else
{
ty
::
ImmBorrow
},
env_region
);
(
env_mutbl
,
env_ptr
)
});
// If this is a `FnMut` or `Fn` closure, then the above is
// conceptually a `&mut` or `&` reference, so we have to add a
// deref.
let
cmt_result
=
match
kind
{
ty
::
FnOnceClosureKind
=>
{
cmt_result
}
ty
::
FnMutClosureKind
=>
{
self
.env_deref
(
id
,
span
,
upvar_id
,
var_mutbl
,
ty
::
MutBorrow
,
cmt_result
)
}
ty
::
FnClosureKind
=>
{
self
.env_deref
(
id
,
span
,
upvar_id
,
var_mutbl
,
ty
::
ImmBorrow
,
cmt_result
)
}
};
// First, switch by capture mode
Ok
(
match
mode
{
ast
::
CaptureByValue
=>
{
let
mut
base
=
cmt_
{
// If this is a by-ref capture, then the upvar we loaded is
// actually a reference, so we have to add an implicit deref
// for that.
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
var_id
,
closure_expr_id
:
fn_node_id
};
let
upvar_capture
=
self
.typer
.upvar_capture
(
upvar_id
)
.unwrap
();
let
cmt_result
=
match
upvar_capture
{
ty
::
UpvarCapture
::
ByValue
=>
{
cmt_result
}
ty
::
UpvarCapture
::
ByRef
(
upvar_borrow
)
=>
{
let
ptr
=
BorrowedPtr
(
upvar_borrow
.kind
,
upvar_borrow
.region
);
cmt_
{
id
:
id
,
span
:
span
,
cat
:
cat_upvar
(
Upvar
{
id
:
upvar_id
,
kind
:
kind
}),
mutbl
:
var_mutbl
,
cat
:
cat_deref
(
Rc
::
new
(
cmt_result
),
0
,
ptr
),
mutbl
:
MutabilityCategory
::
from_borrow_kind
(
upvar_borrow
.kind
),
ty
:
var_ty
,
note
:
NoteNone
};
match
env_info
{
Some
((
env_mutbl
,
env_ptr
))
=>
{
// We need to add the env deref. This means
// that the above is actually immutable and
// has a ref type. However, nothing should
// actually look at the type, so we can get
// away with stuffing a `ty_err` in there
// instead of bothering to construct a proper
// one.
base
.mutbl
=
McImmutable
;
base
.ty
=
self
.tcx
()
.types.err
;
Rc
::
new
(
cmt_
{
id
:
id
,
span
:
span
,
cat
:
cat_deref
(
Rc
::
new
(
base
),
0
,
env_ptr
),
mutbl
:
env_mutbl
,
ty
:
var_ty
,
note
:
NoteClosureEnv
(
upvar_id
)
})
}
None
=>
Rc
::
new
(
base
)
note
:
NoteUpvarRef
(
upvar_id
)
}
},
ast
::
CaptureByRef
=>
{
// The type here is actually a ref (or ref of a ref),
// but we can again get away with not constructing one
// properly since it will never be used.
let
mut
base
=
cmt_
{
id
:
id
,
span
:
span
,
cat
:
cat_upvar
(
Upvar
{
id
:
upvar_id
,
kind
:
kind
}),
mutbl
:
McImmutable
,
ty
:
self
.tcx
()
.types.err
,
note
:
NoteNone
};
}
};
match
env_info
{
Some
((
env_mutbl
,
env_ptr
))
=>
{
base
=
cmt_
{
id
:
id
,
span
:
span
,
cat
:
cat_deref
(
Rc
::
new
(
base
),
0
,
env_ptr
),
mutbl
:
env_mutbl
,
ty
:
self
.tcx
()
.types.err
,
note
:
NoteClosureEnv
(
upvar_id
)
};
}
None
=>
{}
}
Ok
(
Rc
::
new
(
cmt_result
))
}
// Look up upvar borrow so we can get its region
let
upvar_borrow
=
self
.typer
.upvar_borrow
(
upvar_id
)
.unwrap
();
let
ptr
=
BorrowedPtr
(
upvar_borrow
.kind
,
upvar_borrow
.region
);
fn
env_deref
(
&
self
,
id
:
ast
::
NodeId
,
span
:
Span
,
upvar_id
:
ty
::
UpvarId
,
upvar_mutbl
:
MutabilityCategory
,
env_borrow_kind
:
ty
::
BorrowKind
,
cmt_result
:
cmt_
<
'tcx
>
)
->
cmt_
<
'tcx
>
{
// Look up the node ID of the closure body so we can construct
// a free region within it
let
fn_body_id
=
{
let
fn_expr
=
match
self
.tcx
()
.map
.find
(
upvar_id
.closure_expr_id
)
{
Some
(
ast_map
::
NodeExpr
(
e
))
=>
e
,
_
=>
unreachable!
()
};
Rc
::
new
(
cmt_
{
id
:
id
,
span
:
span
,
cat
:
cat_deref
(
Rc
::
new
(
base
),
0
,
ptr
),
mutbl
:
MutabilityCategory
::
from_borrow_kind
(
upvar_borrow
.kind
),
ty
:
var_ty
,
note
:
NoteUpvarRef
(
upvar_id
)
})
match
fn_expr
.node
{
ast
::
ExprClosure
(
_
,
_
,
_
,
ref
body
)
=>
body
.id
,
_
=>
unreachable!
()
}
})
};
// Region of environment pointer
let
env_region
=
ty
::
ReFree
(
ty
::
FreeRegion
{
scope
:
region
::
CodeExtent
::
from_node_id
(
fn_body_id
),
bound_region
:
ty
::
BrEnv
});
let
env_ptr
=
BorrowedPtr
(
env_borrow_kind
,
env_region
);
let
var_ty
=
cmt_result
.ty
;
// We need to add the env deref. This means
// that the above is actually immutable and
// has a ref type. However, nothing should
// actually look at the type, so we can get
// away with stuffing a `ty_err` in there
// instead of bothering to construct a proper
// one.
let
cmt_result
=
cmt_
{
mutbl
:
McImmutable
,
ty
:
self
.tcx
()
.types.err
,
..
cmt_result
};
let
mut
deref_mutbl
=
MutabilityCategory
::
from_borrow_kind
(
env_borrow_kind
);
// Issue #18335. If variable is declared as immutable, override the
// mutability from the environment and substitute an `&T` anyway.
match
upvar_mutbl
{
McImmutable
=>
{
deref_mutbl
=
McImmutable
;
}
McDeclared
|
McInherited
=>
{
}
}
cmt_
{
id
:
id
,
span
:
span
,
cat
:
cat_deref
(
Rc
::
new
(
cmt_result
),
0
,
env_ptr
),
mutbl
:
deref_mutbl
,
ty
:
var_ty
,
note
:
NoteClosureEnv
(
upvar_id
)
}
}
pub
fn
cat_rvalue_node
(
&
self
,
...
...
src/librustc/middle/ty.rs
浏览文件 @
3fbfad35
...
...
@@ -777,7 +777,7 @@ pub struct ctxt<'tcx> {
pub
populated_external_traits
:
RefCell
<
DefIdSet
>
,
/// Borrows
pub
upvar_
borrow_map
:
RefCell
<
UpvarBorrow
Map
>
,
pub
upvar_
capture_map
:
RefCell
<
UpvarCapture
Map
>
,
/// These two caches are used by const_eval when decoding external statics
/// and variants that are found.
...
...
@@ -803,9 +803,6 @@ pub struct ctxt<'tcx> {
/// Maps any item's def-id to its stability index.
pub
stability
:
RefCell
<
stability
::
Index
>
,
/// Maps closures to their capture clauses.
pub
capture_modes
:
RefCell
<
CaptureModeMap
>
,
/// Maps def IDs to true if and only if they're associated types.
pub
associated_types
:
RefCell
<
DefIdMap
<
bool
>>
,
...
...
@@ -1247,60 +1244,31 @@ pub enum BorrowKind {
MutBorrow
}
/// Information describing the borrowing of an upvar. This is computed
/// during `typeck`, specifically by `regionck`. The general idea is
/// that the compiler analyses treat closures like:
///
/// let closure: &'e fn() = || {
/// x = 1; // upvar x is assigned to
/// use(y); // upvar y is read
/// foo(&z); // upvar z is borrowed immutably
/// };
///
/// as if they were "desugared" to something loosely like:
///
/// struct Vars<'x,'y,'z> { x: &'x mut int,
/// y: &'y const int,
/// z: &'z int }
/// let closure: &'e fn() = {
/// fn f(env: &Vars) {
/// *env.x = 1;
/// use(*env.y);
/// foo(env.z);
/// }
/// let env: &'e mut Vars<'x,'y,'z> = &mut Vars { x: &'x mut x,
/// y: &'y const y,
/// z: &'z z };
/// (env, f)
/// };
///
/// This is basically what happens at runtime. The closure is basically
/// an existentially quantified version of the `(env, f)` pair.
///
/// This data structure indicates the region and mutability of a single
/// one of the `x...z` borrows.
///
/// It may not be obvious why each borrowed variable gets its own
/// lifetime (in the desugared version of the example, these are indicated
/// by the lifetime parameters `'x`, `'y`, and `'z` in the `Vars` definition).
/// Each such lifetime must encompass the lifetime `'e` of the closure itself,
/// but need not be identical to it. The reason that this makes sense:
///
/// - Callers are only permitted to invoke the closure, and hence to
/// use the pointers, within the lifetime `'e`, so clearly `'e` must
/// be a sublifetime of `'x...'z`.
/// - The closure creator knows which upvars were borrowed by the closure
/// and thus `x...z` will be reserved for `'x...'z` respectively.
/// - Through mutation, the borrowed upvars can actually escape
/// the closure, so sometimes it is necessary for them to be larger
/// than the closure lifetime itself.
/// Information describing the capture of an upvar. This is computed
/// during `typeck`, specifically by `regionck`.
#[derive(PartialEq,
Clone,
RustcEncodable,
RustcDecodable,
Debug,
Copy)]
pub
enum
UpvarCapture
{
/// Upvar is captured by value. This is always true when the
/// closure is labeled `move`, but can also be true in other cases
/// depending on inference.
ByValue
,
/// Upvar is captured by reference.
ByRef
(
UpvarBorrow
),
}
#[derive(PartialEq,
Clone,
RustcEncodable,
RustcDecodable,
Debug,
Copy)]
pub
struct
UpvarBorrow
{
/// The kind of borrow: by-ref upvars have access to shared
/// immutable borrows, which are not part of the normal language
/// syntax.
pub
kind
:
BorrowKind
,
/// Region of the resulting reference.
pub
region
:
ty
::
Region
,
}
pub
type
Upvar
BorrowMap
=
FnvHashMap
<
UpvarId
,
UpvarBorrow
>
;
pub
type
Upvar
CaptureMap
=
FnvHashMap
<
UpvarId
,
UpvarCapture
>
;
impl
Region
{
pub
fn
is_bound
(
&
self
)
->
bool
{
...
...
@@ -1320,7 +1288,7 @@ pub fn escapes_depth(&self, depth: u32) -> bool {
}
#[derive(Clone,
PartialEq,
PartialOrd,
Eq,
Ord,
Hash,
RustcEncodable,
RustcDecodable,
Debug,
Copy)]
RustcEncodable,
RustcDecodable,
Debug,
Copy)]
/// A "free" region `fr` can be interpreted as "some region
/// at least as big as the scope `fr.scope`".
pub
struct
FreeRegion
{
...
...
@@ -1329,7 +1297,7 @@ pub struct FreeRegion {
}
#[derive(Clone,
PartialEq,
PartialOrd,
Eq,
Ord,
Hash,
RustcEncodable,
RustcDecodable,
Debug,
Copy)]
RustcEncodable,
RustcDecodable,
Debug,
Copy)]
pub
enum
BoundRegion
{
/// An anonymous region parameter for a given fn (&T)
BrAnon
(
u32
),
...
...
@@ -2253,6 +2221,12 @@ pub struct TypeScheme<'tcx> {
pub
struct
TraitDef
<
'tcx
>
{
pub
unsafety
:
ast
::
Unsafety
,
/// If `true`, then this trait had the `#[rustc_paren_sugar]`
/// attribute, indicating that it should be used with `Foo()`
/// sugar. This is a temporary thing -- eventually any trait wil
/// be usable with the sugar (or without it).
pub
paren_sugar
:
bool
,
/// Generic type definitions. Note that `Self` is listed in here
/// as having a single bound, the trait itself (e.g., in the trait
/// `Eq`, there is a single bound `Self : Eq`). This is so that
...
...
@@ -2359,7 +2333,6 @@ pub fn mk_ctxt<'tcx>(s: Session,
named_region_map
:
resolve_lifetime
::
NamedRegionMap
,
map
:
ast_map
::
Map
<
'tcx
>
,
freevars
:
RefCell
<
FreevarMap
>
,
capture_modes
:
RefCell
<
CaptureModeMap
>
,
region_maps
:
middle
::
region
::
RegionMaps
,
lang_items
:
middle
::
lang_items
::
LanguageItems
,
stability
:
stability
::
Index
)
->
ctxt
<
'tcx
>
...
...
@@ -2413,7 +2386,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
used_mut_nodes
:
RefCell
::
new
(
NodeSet
()),
populated_external_types
:
RefCell
::
new
(
DefIdSet
()),
populated_external_traits
:
RefCell
::
new
(
DefIdSet
()),
upvar_
borrow
_map
:
RefCell
::
new
(
FnvHashMap
()),
upvar_
capture
_map
:
RefCell
::
new
(
FnvHashMap
()),
extern_const_statics
:
RefCell
::
new
(
DefIdMap
()),
extern_const_variants
:
RefCell
::
new
(
DefIdMap
()),
method_map
:
RefCell
::
new
(
FnvHashMap
()),
...
...
@@ -2422,7 +2395,6 @@ pub fn mk_ctxt<'tcx>(s: Session,
node_lint_levels
:
RefCell
::
new
(
FnvHashMap
()),
transmute_restrictions
:
RefCell
::
new
(
Vec
::
new
()),
stability
:
RefCell
::
new
(
stability
),
capture_modes
:
capture_modes
,
associated_types
:
RefCell
::
new
(
DefIdMap
()),
selection_cache
:
traits
::
SelectionCache
::
new
(),
repr_hint_cache
:
RefCell
::
new
(
DefIdMap
()),
...
...
@@ -5646,7 +5618,6 @@ pub fn closure_upvars<'tcx>(typer: &mc::Typer<'tcx>,
// implemented.
assert
!
(
closure_id
.krate
==
ast
::
LOCAL_CRATE
);
let
tcx
=
typer
.tcx
();
let
capture_mode
=
tcx
.capture_modes
.borrow
()[
closure_id
.node
]
.clone
();
match
tcx
.freevars
.borrow
()
.get
(
&
closure_id
.node
)
{
None
=>
Some
(
vec!
[]),
Some
(
ref
freevars
)
=>
{
...
...
@@ -5659,43 +5630,38 @@ pub fn closure_upvars<'tcx>(typer: &mc::Typer<'tcx>,
};
let
freevar_ty
=
freevar_ty
.subst
(
tcx
,
substs
);
match
capture_mode
{
ast
::
CaptureByValue
=>
{
Some
(
ClosureUpvar
{
def
:
freevar
.def
,
span
:
freevar
.span
,
ty
:
freevar_ty
})
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
freevar_def_id
.node
,
closure_expr_id
:
closure_id
.node
};
let
captured_freevar_ty
=
match
typer
.upvar_capture
(
upvar_id
)
{
Some
(
UpvarCapture
::
ByValue
)
=>
{
freevar_ty
}
ast
::
CaptureByRef
=>
{
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
freevar_def_id
.node
,
closure_expr_id
:
closure_id
.node
};
Some
(
UpvarCapture
::
ByRef
(
borrow
))
=>
{
mk_rptr
(
tcx
,
tcx
.mk_region
(
borrow
.region
),
ty
::
mt
{
ty
:
freevar_ty
,
mutbl
:
borrow
.kind
.to_mutbl_lossy
(),
})
}
// FIXME
let
freevar_ref_ty
=
match
typer
.upvar_borrow
(
upvar_id
)
{
Some
(
borrow
)
=>
{
mk_rptr
(
tcx
,
tcx
.mk_region
(
borrow
.region
),
ty
::
mt
{
ty
:
freevar_ty
,
mutbl
:
borrow
.kind
.to_mutbl_lossy
(),
})
}
None
=>
{
// FIXME(#16640) we should really return None here;
// but that requires better inference integration,
// for now gin up something.
freevar_ty
}
};
Some
(
ClosureUpvar
{
def
:
freevar
.def
,
span
:
freevar
.span
,
ty
:
freevar_ref_ty
,
})
None
=>
{
// FIXME(#16640) we should really return None here;
// but that requires better inference integration,
// for now gin up something.
freevar_ty
}
}
};
Some
(
ClosureUpvar
{
def
:
freevar
.def
,
span
:
freevar
.span
,
ty
:
captured_freevar_ty
,
})
})
.collect
()
}
...
...
@@ -6449,14 +6415,13 @@ pub fn to_user_str(&self) -> &'static str {
}
impl
<
'tcx
>
ctxt
<
'tcx
>
{
pub
fn
capture_mode
(
&
self
,
closure_expr_id
:
ast
::
NodeId
)
->
ast
::
CaptureClause
{
self
.capture_modes
.borrow
()[
closure_expr_id
]
.clone
()
}
pub
fn
is_method_call
(
&
self
,
expr_id
:
ast
::
NodeId
)
->
bool
{
self
.method_map
.borrow
()
.contains_key
(
&
MethodCall
::
expr
(
expr_id
))
}
pub
fn
upvar_capture
(
&
self
,
upvar_id
:
ty
::
UpvarId
)
->
Option
<
ty
::
UpvarCapture
>
{
Some
(
self
.upvar_capture_map
.borrow
()[
upvar_id
]
.clone
())
}
}
impl
<
'a
,
'tcx
>
mc
::
Typer
<
'tcx
>
for
ParameterEnvironment
<
'a
,
'tcx
>
{
...
...
@@ -6494,13 +6459,8 @@ fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent>
self
.tcx.region_maps
.temporary_scope
(
rvalue_id
)
}
fn
upvar_borrow
(
&
self
,
upvar_id
:
ty
::
UpvarId
)
->
Option
<
ty
::
UpvarBorrow
>
{
Some
(
self
.tcx.upvar_borrow_map
.borrow
()[
upvar_id
]
.clone
())
}
fn
capture_mode
(
&
self
,
closure_expr_id
:
ast
::
NodeId
)
->
ast
::
CaptureClause
{
self
.tcx
.capture_mode
(
closure_expr_id
)
fn
upvar_capture
(
&
self
,
upvar_id
:
ty
::
UpvarId
)
->
Option
<
ty
::
UpvarCapture
>
{
self
.tcx
.upvar_capture
(
upvar_id
)
}
fn
type_moves_by_default
(
&
self
,
span
:
Span
,
ty
:
Ty
<
'tcx
>
)
->
bool
{
...
...
src/librustc/util/ppaux.rs
浏览文件 @
3fbfad35
...
...
@@ -1292,6 +1292,15 @@ fn repr(&self, tcx: &ctxt) -> String {
}
}
impl
<
'tcx
>
Repr
<
'tcx
>
for
ty
::
UpvarCapture
{
fn
repr
(
&
self
,
tcx
:
&
ctxt
)
->
String
{
match
*
self
{
ty
::
UpvarCapture
::
ByValue
=>
format!
(
"ByValue"
),
ty
::
UpvarCapture
::
ByRef
(
ref
data
)
=>
format!
(
"ByRef({})"
,
data
.repr
(
tcx
)),
}
}
}
impl
<
'tcx
>
Repr
<
'tcx
>
for
ty
::
IntVid
{
fn
repr
(
&
self
,
_
tcx
:
&
ctxt
)
->
String
{
format!
(
"{:?}"
,
self
)
...
...
src/librustc_driver/driver.rs
浏览文件 @
3fbfad35
...
...
@@ -560,7 +560,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
let
resolve
::
CrateMap
{
def_map
,
freevars
,
capture_mode_map
,
export_map
,
trait_map
,
external_exports
,
...
...
@@ -606,7 +605,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
named_region_map
,
ast_map
,
freevars
,
capture_mode_map
,
region_map
,
lang_items
,
stability_index
);
...
...
src/librustc_driver/test.rs
浏览文件 @
3fbfad35
...
...
@@ -121,7 +121,7 @@ fn test_env<F>(source_string: &str,
// run just enough stuff to build a tcx:
let
lang_items
=
lang_items
::
collect_language_items
(
krate
,
&
sess
);
let
resolve
::
CrateMap
{
def_map
,
freevars
,
capture_mode_map
,
..
}
=
let
resolve
::
CrateMap
{
def_map
,
freevars
,
..
}
=
resolve
::
resolve_crate
(
&
sess
,
&
ast_map
,
&
lang_items
,
krate
,
resolve
::
MakeGlobMap
::
No
);
let
named_region_map
=
resolve_lifetime
::
krate
(
&
sess
,
krate
,
&
def_map
);
let
region_map
=
region
::
resolve_crate
(
&
sess
,
krate
);
...
...
@@ -132,7 +132,6 @@ fn test_env<F>(source_string: &str,
named_region_map
,
ast_map
,
freevars
,
capture_mode_map
,
region_map
,
lang_items
,
stability_index
);
...
...
src/librustc_resolve/lib.rs
浏览文件 @
3fbfad35
...
...
@@ -62,7 +62,7 @@
use
rustc
::
middle
::
pat_util
::
pat_bindings
;
use
rustc
::
middle
::
privacy
::
*
;
use
rustc
::
middle
::
subst
::{
ParamSpace
,
FnSpace
,
TypeSpace
};
use
rustc
::
middle
::
ty
::{
CaptureModeMap
,
Freevar
,
FreevarMap
,
TraitMap
,
GlobMap
};
use
rustc
::
middle
::
ty
::{
Freevar
,
FreevarMap
,
TraitMap
,
GlobMap
};
use
rustc
::
util
::
nodemap
::{
NodeMap
,
NodeSet
,
DefIdSet
,
FnvHashMap
};
use
rustc
::
util
::
lev_distance
::
lev_distance
;
...
...
@@ -900,7 +900,6 @@ struct Resolver<'a, 'tcx:'a> {
def_map
:
DefMap
,
freevars
:
RefCell
<
FreevarMap
>
,
freevars_seen
:
RefCell
<
NodeMap
<
NodeSet
>>
,
capture_mode_map
:
CaptureModeMap
,
export_map
:
ExportMap
,
trait_map
:
TraitMap
,
external_exports
:
ExternalExports
,
...
...
@@ -974,7 +973,6 @@ fn new(session: &'a Session,
def_map
:
RefCell
::
new
(
NodeMap
()),
freevars
:
RefCell
::
new
(
NodeMap
()),
freevars_seen
:
RefCell
::
new
(
NodeMap
()),
capture_mode_map
:
NodeMap
(),
export_map
:
NodeMap
(),
trait_map
:
NodeMap
(),
used_imports
:
HashSet
::
new
(),
...
...
@@ -4523,8 +4521,7 @@ fn resolve_expr(&mut self, expr: &Expr) {
visit
::
walk_expr
(
self
,
expr
);
}
ExprClosure
(
capture_clause
,
_
,
ref
fn_decl
,
ref
block
)
=>
{
self
.capture_mode_map
.insert
(
expr
.id
,
capture_clause
);
ExprClosure
(
_
,
_
,
ref
fn_decl
,
ref
block
)
=>
{
self
.resolve_function
(
ClosureRibKind
(
expr
.id
),
Some
(
&**
fn_decl
),
NoTypeParameters
,
&**
block
);
...
...
@@ -4835,7 +4832,6 @@ fn dump_module(&mut self, module_: Rc<Module>) {
pub
struct
CrateMap
{
pub
def_map
:
DefMap
,
pub
freevars
:
RefCell
<
FreevarMap
>
,
pub
capture_mode_map
:
RefCell
<
CaptureModeMap
>
,
pub
export_map
:
ExportMap
,
pub
trait_map
:
TraitMap
,
pub
external_exports
:
ExternalExports
,
...
...
@@ -4875,7 +4871,6 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
CrateMap
{
def_map
:
resolver
.def_map
,
freevars
:
resolver
.freevars
,
capture_mode_map
:
RefCell
::
new
(
resolver
.capture_mode_map
),
export_map
:
resolver
.export_map
,
trait_map
:
resolver
.trait_map
,
external_exports
:
resolver
.external_exports
,
...
...
src/librustc_trans/trans/base.rs
浏览文件 @
3fbfad35
...
...
@@ -1775,7 +1775,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
_
attributes
:
&
[
ast
::
Attribute
],
output_type
:
ty
::
FnOutput
<
'tcx
>
,
abi
:
Abi
,
closure_env
:
closure
::
ClosureEnv
<
'b
,
'tcx
>
)
{
closure_env
:
closure
::
ClosureEnv
<
'b
>
)
{
ccx
.stats
()
.n_closures
.set
(
ccx
.stats
()
.n_closures
.get
()
+
1
);
let
_
icx
=
push_ctxt
(
"trans_closure"
);
...
...
@@ -1784,12 +1784,17 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
debug!
(
"trans_closure(..., param_substs={})"
,
param_substs
.repr
(
ccx
.tcx
()));
let
has_env
=
match
closure_env
{
closure
::
ClosureEnv
::
Closure
(
_
)
=>
true
,
closure
::
ClosureEnv
::
NotClosure
=>
false
,
};
let
(
arena
,
fcx
):
(
TypedArena
<
_
>
,
FunctionContext
);
arena
=
TypedArena
::
new
();
fcx
=
new_fn_ctxt
(
ccx
,
llfndecl
,
fn_ast_id
,
closure_env
.kind
!=
closure
::
NotClosure
,
has_env
,
output_type
,
param_substs
,
Some
(
body
.span
),
...
...
@@ -1808,13 +1813,13 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
decl
.inputs
.iter
()
.map
(|
arg
|
node_id_type
(
bcx
,
arg
.id
))
.collect
::
<
Vec
<
_
>>
();
let
monomorphized_arg_types
=
match
closure_env
.kind
{
closure
::
NotClosure
=>
{
let
monomorphized_arg_types
=
match
closure_env
{
closure
::
ClosureEnv
::
NotClosure
=>
{
monomorphized_arg_types
}
// Tuple up closure argument types for the "rust-call" ABI.
closure
::
Closure
(
..
)
=>
{
closure
::
Closure
Env
::
Closure
(
_
)
=>
{
vec!
[
ty
::
mk_tup
(
ccx
.tcx
(),
monomorphized_arg_types
)]
}
};
...
...
@@ -1835,14 +1840,14 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
&
monomorphized_arg_types
[])
};
bcx
=
match
closure_env
.kind
{
closure
::
NotClosure
=>
{
bcx
=
match
closure_env
{
closure
::
ClosureEnv
::
NotClosure
=>
{
copy_args_to_allocas
(
bcx
,
arg_scope
,
&
decl
.inputs
[],
arg_datums
)
}
closure
::
Closure
(
..
)
=>
{
closure
::
Closure
Env
::
Closure
(
_
)
=>
{
copy_closure_args_to_allocas
(
bcx
,
arg_scope
,
...
...
@@ -1932,7 +1937,7 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
attrs
,
output_type
,
abi
,
closure
::
ClosureEnv
::
new
(
&
[],
closure
::
NotClosure
)
);
closure
::
ClosureEnv
::
NotClosure
);
}
pub
fn
trans_enum_variant
<
'a
,
'tcx
>
(
ccx
:
&
CrateContext
<
'a
,
'tcx
>
,
...
...
src/librustc_trans/trans/closure.rs
浏览文件 @
3fbfad35
...
...
@@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub
use
self
::
ClosureKind
::
*
;
use
back
::
link
::
mangle_internal_name_by_path_and_seq
;
use
middle
::
mem_categorization
::
Typer
;
use
trans
::
adt
;
...
...
@@ -33,9 +31,9 @@
fn
load_closure_environment
<
'blk
,
'tcx
>
(
bcx
:
Block
<
'blk
,
'tcx
>
,
arg_scope_id
:
ScopeId
,
freevar_mode
:
ast
::
CaptureClause
,
freevars
:
&
[
ty
::
Freevar
])
->
Block
<
'blk
,
'tcx
>
{
->
Block
<
'blk
,
'tcx
>
{
let
_
icx
=
push_ctxt
(
"closure::load_closure_environment"
);
// Special case for small by-value selfs.
...
...
@@ -65,18 +63,21 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
};
for
(
i
,
freevar
)
in
freevars
.iter
()
.enumerate
()
{
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
freevar
.def
.local_node_id
(),
closure_expr_id
:
closure_id
.node
};
let
upvar_capture
=
bcx
.tcx
()
.upvar_capture
(
upvar_id
)
.unwrap
();
let
mut
upvar_ptr
=
GEPi
(
bcx
,
llenv
,
&
[
0
,
i
]);
let
captured_by_ref
=
match
freevar_mode
{
ast
::
CaptureByRef
=>
{
let
captured_by_ref
=
match
upvar_capture
{
ty
::
UpvarCapture
::
ByValue
=>
false
,
ty
::
UpvarCapture
::
ByRef
(
..
)
=>
{
upvar_ptr
=
Load
(
bcx
,
upvar_ptr
);
true
}
ast
::
CaptureByValue
=>
false
};
let
def_id
=
freevar
.def
.def_id
();
bcx
.fcx.llupvars
.borrow_mut
()
.insert
(
def_id
.node
,
upvar_ptr
);
if
kind
==
ty
::
FnOnceClosureKind
&&
freevar_mode
==
ast
::
CaptureByValue
{
if
kind
==
ty
::
FnOnceClosureKind
&&
!
captured_by_ref
{
bcx
.fcx
.schedule_drop_mem
(
arg_scope_id
,
upvar_ptr
,
node_id_type
(
bcx
,
def_id
.node
))
...
...
@@ -96,38 +97,23 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
bcx
}
#[derive(PartialEq)]
pub
enum
ClosureKind
<
'tcx
>
{
pub
enum
ClosureEnv
<
'a
>
{
NotClosure
,
// See load_closure_environment.
Closure
(
ast
::
CaptureClause
)
Closure
(
&
'a
[
ty
::
Freevar
]),
}
pub
struct
ClosureEnv
<
'a
,
'tcx
>
{
freevars
:
&
'a
[
ty
::
Freevar
],
pub
kind
:
ClosureKind
<
'tcx
>
}
impl
<
'a
,
'tcx
>
ClosureEnv
<
'a
,
'tcx
>
{
pub
fn
new
(
freevars
:
&
'a
[
ty
::
Freevar
],
kind
:
ClosureKind
<
'tcx
>
)
->
ClosureEnv
<
'a
,
'tcx
>
{
ClosureEnv
{
freevars
:
freevars
,
kind
:
kind
}
}
pub
fn
load
<
'blk
>
(
self
,
bcx
:
Block
<
'blk
,
'tcx
>
,
arg_scope
:
ScopeId
)
->
Block
<
'blk
,
'tcx
>
{
// Don't bother to create the block if there's nothing to load
if
self
.freevars
.is_empty
()
{
return
bcx
;
}
match
self
.kind
{
NotClosure
=>
bcx
,
Closure
(
freevar_mode
)
=>
{
load_closure_environment
(
bcx
,
arg_scope
,
freevar_mode
,
self
.freevars
)
impl
<
'a
>
ClosureEnv
<
'a
>
{
pub
fn
load
<
'blk
,
'tcx
>
(
self
,
bcx
:
Block
<
'blk
,
'tcx
>
,
arg_scope
:
ScopeId
)
->
Block
<
'blk
,
'tcx
>
{
match
self
{
ClosureEnv
::
NotClosure
=>
bcx
,
ClosureEnv
::
Closure
(
freevars
)
=>
{
if
freevars
.is_empty
()
{
bcx
}
else
{
load_closure_environment
(
bcx
,
arg_scope
,
freevars
)
}
}
}
}
...
...
@@ -212,7 +198,6 @@ pub fn trans_closure_expr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
let
freevars
:
Vec
<
ty
::
Freevar
>
=
ty
::
with_freevars
(
bcx
.tcx
(),
id
,
|
fv
|
fv
.iter
()
.map
(|
&
fv
|
fv
)
.collect
());
let
freevar_mode
=
bcx
.tcx
()
.capture_mode
(
id
);
let
sig
=
ty
::
erase_late_bound_regions
(
bcx
.tcx
(),
&
function_type
.sig
);
...
...
@@ -225,8 +210,7 @@ pub fn trans_closure_expr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
&
[],
sig
.output
,
function_type
.abi
,
ClosureEnv
::
new
(
&
freevars
[],
Closure
(
freevar_mode
)));
ClosureEnv
::
Closure
(
&
freevars
[]));
// Don't hoist this to the top of the function. It's perfectly legitimate
// to have a zero-size closure (in which case dest will be `Ignore`) and
...
...
@@ -249,11 +233,14 @@ pub fn trans_closure_expr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
dest_addr
,
0
,
i
);
match
freevar_mode
{
ast
::
CaptureByValue
=>
{
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
freevar
.def
.local_node_id
(),
closure_expr_id
:
id
};
let
upvar_capture
=
bcx
.tcx
()
.upvar_capture
(
upvar_id
)
.unwrap
();
match
upvar_capture
{
ty
::
UpvarCapture
::
ByValue
=>
{
bcx
=
datum
.store_to
(
bcx
,
upvar_slot_dest
);
}
ast
::
CaptureByRef
=>
{
ty
::
UpvarCapture
::
ByRef
(
..
)
=>
{
Store
(
bcx
,
datum
.to_llref
(),
upvar_slot_dest
);
}
}
...
...
src/librustc_trans/trans/common.rs
浏览文件 @
3fbfad35
...
...
@@ -679,13 +679,8 @@ fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent>
self
.tcx
()
.region_maps
.temporary_scope
(
rvalue_id
)
}
fn
upvar_borrow
(
&
self
,
upvar_id
:
ty
::
UpvarId
)
->
Option
<
ty
::
UpvarBorrow
>
{
Some
(
self
.tcx
()
.upvar_borrow_map
.borrow
()[
upvar_id
]
.clone
())
}
fn
capture_mode
(
&
self
,
closure_expr_id
:
ast
::
NodeId
)
->
ast
::
CaptureClause
{
self
.tcx
()
.capture_modes
.borrow
()[
closure_expr_id
]
.clone
()
fn
upvar_capture
(
&
self
,
upvar_id
:
ty
::
UpvarId
)
->
Option
<
ty
::
UpvarCapture
>
{
Some
(
self
.tcx
()
.upvar_capture_map
.borrow
()[
upvar_id
]
.clone
())
}
fn
type_moves_by_default
(
&
self
,
span
:
Span
,
ty
:
Ty
<
'tcx
>
)
->
bool
{
...
...
src/librustc_typeck/astconv.rs
浏览文件 @
3fbfad35
...
...
@@ -614,11 +614,9 @@ fn ast_path_to_trait_ref<'a,'tcx>(
let
(
regions
,
types
,
assoc_bindings
)
=
match
path
.segments
.last
()
.unwrap
()
.parameters
{
ast
::
AngleBracketedParameters
(
ref
data
)
=>
{
// For now, require that parenthetical notation be used
// For now, require that parenthetical
5D
notation be used
// only with `Fn()` etc.
if
!
this
.tcx
()
.sess.features
.borrow
()
.unboxed_closures
&&
this
.tcx
()
.lang_items
.fn_trait_kind
(
trait_def_id
)
.is_some
()
{
if
!
this
.tcx
()
.sess.features
.borrow
()
.unboxed_closures
&&
trait_def
.paren_sugar
{
span_err!
(
this
.tcx
()
.sess
,
path
.span
,
E0215
,
"angle-bracket notation is not stable when
\
used with the `Fn` family of traits, use parentheses"
);
...
...
@@ -632,9 +630,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
ast
::
ParenthesizedParameters
(
ref
data
)
=>
{
// For now, require that parenthetical notation be used
// only with `Fn()` etc.
if
!
this
.tcx
()
.sess.features
.borrow
()
.unboxed_closures
&&
this
.tcx
()
.lang_items
.fn_trait_kind
(
trait_def_id
)
.is_none
()
{
if
!
this
.tcx
()
.sess.features
.borrow
()
.unboxed_closures
&&
!
trait_def
.paren_sugar
{
span_err!
(
this
.tcx
()
.sess
,
path
.span
,
E0216
,
"parenthetical notation is only stable when
\
used with the `Fn` family of traits"
);
...
...
src/librustc_typeck/check/mod.rs
浏览文件 @
3fbfad35
...
...
@@ -160,7 +160,7 @@ pub struct Inherited<'a, 'tcx: 'a> {
item_substs
:
RefCell
<
NodeMap
<
ty
::
ItemSubsts
<
'tcx
>>>
,
adjustments
:
RefCell
<
NodeMap
<
ty
::
AutoAdjustment
<
'tcx
>>>
,
method_map
:
MethodMap
<
'tcx
>
,
upvar_
borrow_map
:
RefCell
<
ty
::
UpvarBorrow
Map
>
,
upvar_
capture_map
:
RefCell
<
ty
::
UpvarCapture
Map
>
,
closures
:
RefCell
<
DefIdMap
<
ty
::
Closure
<
'tcx
>>>
,
object_cast_map
:
ObjectCastMap
<
'tcx
>
,
...
...
@@ -305,7 +305,7 @@ fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
}
fn
type_moves_by_default
(
&
self
,
span
:
Span
,
ty
:
Ty
<
'tcx
>
)
->
bool
{
let
ty
=
self
.infcx
()
.resolve_type_vars_if_possible
(
&
ty
);
traits
::
type_known_to_meet_builtin_bound
(
self
.infcx
(),
self
,
ty
,
ty
::
BoundCopy
,
span
)
!
traits
::
type_known_to_meet_builtin_bound
(
self
.infcx
(),
self
,
ty
,
ty
::
BoundCopy
,
span
)
}
fn
node_method_ty
(
&
self
,
method_call
:
ty
::
MethodCall
)
->
Option
<
Ty
<
'tcx
>>
{
...
...
@@ -330,12 +330,8 @@ fn is_method_call(&self, id: ast::NodeId) -> bool {
fn
temporary_scope
(
&
self
,
rvalue_id
:
ast
::
NodeId
)
->
Option
<
CodeExtent
>
{
self
.param_env
()
.temporary_scope
(
rvalue_id
)
}
fn
upvar_borrow
(
&
self
,
upvar_id
:
ty
::
UpvarId
)
->
Option
<
ty
::
UpvarBorrow
>
{
self
.inh.upvar_borrow_map
.borrow
()
.get
(
&
upvar_id
)
.cloned
()
}
fn
capture_mode
(
&
self
,
closure_expr_id
:
ast
::
NodeId
)
->
ast
::
CaptureClause
{
self
.ccx.tcx
.capture_mode
(
closure_expr_id
)
fn
upvar_capture
(
&
self
,
upvar_id
:
ty
::
UpvarId
)
->
Option
<
ty
::
UpvarCapture
>
{
self
.inh.upvar_capture_map
.borrow
()
.get
(
&
upvar_id
)
.cloned
()
}
}
...
...
@@ -378,7 +374,7 @@ fn new(tcx: &'a ty::ctxt<'tcx>,
adjustments
:
RefCell
::
new
(
NodeMap
()),
method_map
:
RefCell
::
new
(
FnvHashMap
()),
object_cast_map
:
RefCell
::
new
(
NodeMap
()),
upvar_
borrow
_map
:
RefCell
::
new
(
FnvHashMap
()),
upvar_
capture
_map
:
RefCell
::
new
(
FnvHashMap
()),
closures
:
RefCell
::
new
(
DefIdMap
()),
fn_sig_map
:
RefCell
::
new
(
NodeMap
()),
fulfillment_cx
:
RefCell
::
new
(
traits
::
FulfillmentContext
::
new
()),
...
...
src/librustc_typeck/check/regionck.rs
浏览文件 @
3fbfad35
...
...
@@ -742,16 +742,9 @@ fn check_expr_fn_block(rcx: &mut Rcx,
match
function_type
.sty
{
ty
::
ty_closure
(
_
,
region
,
_
)
=>
{
if
tcx
.capture_modes
.borrow
()[
expr
.id
]
.clone
()
==
ast
::
CaptureByRef
{
ty
::
with_freevars
(
tcx
,
expr
.id
,
|
freevars
|
{
if
!
freevars
.is_empty
()
{
// Variables being referenced must be constrained and registered
// in the upvar borrow map
constrain_free_variables_in_by_ref_closure
(
rcx
,
*
region
,
expr
,
freevars
);
}
})
}
ty
::
with_freevars
(
tcx
,
expr
.id
,
|
freevars
|
{
constrain_captured_variables
(
rcx
,
*
region
,
expr
,
freevars
);
})
}
_
=>
{
}
}
...
...
@@ -799,14 +792,14 @@ fn ensure_free_variable_types_outlive_closure_bound(
let
raw_var_ty
=
rcx
.resolve_node_type
(
var_node_id
);
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
var_node_id
,
closure_expr_id
:
expr
.id
};
let
var_ty
=
match
rcx
.fcx.inh.upvar_
borrow_map
.borrow
()
.get
(
&
upvar_id
)
{
Some
(
upvar_borrow
)
=>
{
let
var_ty
=
match
rcx
.fcx.inh.upvar_
capture_map
.borrow
()[
upvar_id
]
{
ty
::
UpvarCapture
::
ByRef
(
ref
upvar_borrow
)
=>
{
ty
::
mk_rptr
(
rcx
.tcx
(),
rcx
.tcx
()
.mk_region
(
upvar_borrow
.region
),
ty
::
mt
{
mutbl
:
upvar_borrow
.kind
.to_mutbl_lossy
(),
ty
:
raw_var_ty
})
}
None
=>
raw_var_ty
ty
::
UpvarCapture
::
ByValue
=>
raw_var_ty
,
};
// Check that the type meets the criteria of the existential bounds:
...
...
@@ -824,17 +817,17 @@ fn ensure_free_variable_types_outlive_closure_bound(
/// Make sure that all free variables referenced inside the closure outlive the closure's
/// lifetime bound. Also, create an entry in the upvar_borrows map with a region.
fn
constrain_
free_variables_in_by_ref_closure
(
fn
constrain_
captured_variables
(
rcx
:
&
mut
Rcx
,
region_bound
:
ty
::
Region
,
expr
:
&
ast
::
Expr
,
freevars
:
&
[
ty
::
Freevar
])
{
let
tcx
=
rcx
.fcx.ccx.tcx
;
debug!
(
"constrain_
free
_variables({}, {})"
,
debug!
(
"constrain_
captured
_variables({}, {})"
,
region_bound
.repr
(
tcx
),
expr
.repr
(
tcx
));
for
freevar
in
freevars
.iter
()
{
debug!
(
"
freevar def is
{:?}"
,
freevar
.def
);
debug!
(
"
constrain_captured_variables: freevar.def=
{:?}"
,
freevar
.def
);
// Identify the variable being closed over and its node-id.
let
def
=
freevar
.def
;
...
...
@@ -846,16 +839,20 @@ fn constrain_free_variables_in_by_ref_closure(
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
var_node_id
,
closure_expr_id
:
expr
.id
};
let
upvar_borrow
=
rcx
.fcx.inh.upvar_borrow_map
.borrow
()[
upvar_id
];
rcx
.fcx
.mk_subr
(
infer
::
FreeVariable
(
freevar
.span
,
var_node_id
),
region_bound
,
upvar_borrow
.region
);
// Guarantee that the closure does not outlive the variable itself.
let
enclosing_region
=
region_of_def
(
rcx
.fcx
,
def
);
debug!
(
"enclosing_region = {}"
,
enclosing_region
.repr
(
tcx
));
rcx
.fcx
.mk_subr
(
infer
::
FreeVariable
(
freevar
.span
,
var_node_id
),
region_bound
,
enclosing_region
);
match
rcx
.fcx.inh.upvar_capture_map
.borrow
()[
upvar_id
]
{
ty
::
UpvarCapture
::
ByValue
=>
{
}
ty
::
UpvarCapture
::
ByRef
(
upvar_borrow
)
=>
{
rcx
.fcx
.mk_subr
(
infer
::
FreeVariable
(
freevar
.span
,
var_node_id
),
region_bound
,
upvar_borrow
.region
);
// Guarantee that the closure does not outlive the variable itself.
let
enclosing_region
=
region_of_def
(
rcx
.fcx
,
def
);
debug!
(
"constrain_captured_variables: enclosing_region = {}"
,
enclosing_region
.repr
(
tcx
));
rcx
.fcx
.mk_subr
(
infer
::
FreeVariable
(
freevar
.span
,
var_node_id
),
region_bound
,
enclosing_region
);
}
}
}
}
}
...
...
@@ -1333,22 +1330,20 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
// Detect by-ref upvar `x`:
let
cause
=
match
note
{
mc
::
NoteUpvarRef
(
ref
upvar_id
)
=>
{
let
mut
upvar_borrow_map
=
rcx
.fcx.inh.upvar_borrow_map
.borrow_mut
();
match
upvar_borrow_map
.get_mut
(
upvar_id
)
{
Some
(
upvar_borrow
)
=>
{
let
upvar_capture_map
=
rcx
.fcx.inh.upvar_capture_map
.borrow_mut
();
match
upvar_capture_map
.get
(
upvar_id
)
{
Some
(
&
ty
::
UpvarCapture
::
ByRef
(
ref
upvar_borrow
))
=>
{
// The mutability of the upvar may have been modified
// by the above adjustment, so update our local variable.
ref_kind
=
upvar_borrow
.kind
;
infer
::
ReborrowUpvar
(
span
,
*
upvar_id
)
}
None
=>
{
_
=>
{
rcx
.tcx
()
.sess
.span_bug
(
span
,
&
format!
(
"Illegal upvar id: {}"
,
upvar_id
.repr
(
rcx
.tcx
()))[]);
upvar_id
.repr
(
rcx
.tcx
()))[]);
}
}
}
...
...
src/librustc_typeck/check/upvar.rs
浏览文件 @
3fbfad35
...
...
@@ -121,25 +121,29 @@ fn check_closure(&mut self,
capture_clause
:
ast
::
CaptureClause
,
_
body
:
&
ast
::
Block
)
{
match
capture_clause
{
ast
::
CaptureByValue
=>
{}
_
=>
{
ty
::
with_freevars
(
self
.tcx
(),
expr
.id
,
|
freevars
|
{
for
freevar
in
freevars
.iter
()
{
let
var_node_id
=
freevar
.def
.local_node_id
();
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
var_node_id
,
closure_expr_id
:
expr
.id
};
debug!
(
"seed upvar_id {:?}"
,
upvar_id
);
ty
::
with_freevars
(
self
.tcx
(),
expr
.id
,
|
freevars
|
{
for
freevar
in
freevars
.iter
()
{
let
var_node_id
=
freevar
.def
.local_node_id
();
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
var_node_id
,
closure_expr_id
:
expr
.id
};
debug!
(
"seed upvar_id {:?}"
,
upvar_id
);
let
capture_kind
=
match
capture_clause
{
ast
::
CaptureByValue
=>
{
ty
::
UpvarCapture
::
ByValue
}
ast
::
CaptureByRef
=>
{
let
origin
=
UpvarRegion
(
upvar_id
,
expr
.span
);
let
freevar_region
=
self
.infcx
()
.next_region_var
(
origin
);
let
upvar_borrow
=
ty
::
UpvarBorrow
{
kind
:
ty
::
ImmBorrow
,
region
:
freevar_region
};
self
.fcx.inh.upvar_borrow_map
.borrow_mut
()
.insert
(
upvar_id
,
upvar_borrow
);
ty
::
UpvarCapture
::
ByRef
(
upvar_borrow
)
}
});
};
self
.fcx.inh.upvar_capture_map
.borrow_mut
()
.insert
(
upvar_id
,
capture_kind
);
}
}
}
);
}
}
...
...
@@ -150,7 +154,7 @@ struct AdjustBorrowKind<'a,'tcx:'a> {
fcx
:
&
'a
FnCtxt
<
'a
,
'tcx
>
}
impl
<
'a
,
'tcx
>
AdjustBorrowKind
<
'a
,
'tcx
>
{
impl
<
'a
,
'tcx
>
AdjustBorrowKind
<
'a
,
'tcx
>
{
fn
new
(
fcx
:
&
'a
FnCtxt
<
'a
,
'tcx
>
)
->
AdjustBorrowKind
<
'a
,
'tcx
>
{
AdjustBorrowKind
{
fcx
:
fcx
}
}
...
...
@@ -172,6 +176,41 @@ fn analyze_fn(&mut self, decl: &ast::FnDecl, body: &ast::Block) {
euv
.walk_fn
(
decl
,
body
);
}
fn
adjust_upvar_borrow_kind_for_consume
(
&
self
,
cmt
:
mc
::
cmt
<
'tcx
>
,
mode
:
euv
::
ConsumeMode
)
{
debug!
(
"adjust_upvar_borrow_kind_for_consume(cmt={}, mode={:?})"
,
cmt
.repr
(
self
.tcx
()),
mode
);
// we only care about moves
match
mode
{
euv
::
Copy
=>
{
return
;
}
euv
::
Move
(
_
)
=>
{
}
}
// watch out for a move of the deref of a borrowed pointer;
// for that to be legal, the upvar would have to be borrowed
// by value instead
let
guarantor
=
cmt
.guarantor
();
debug!
(
"adjust_upvar_borrow_kind_for_consume: guarantor={}"
,
guarantor
.repr
(
self
.tcx
()));
match
guarantor
.cat
{
mc
::
cat_deref
(
_
,
_
,
mc
::
BorrowedPtr
(
..
))
|
mc
::
cat_deref
(
_
,
_
,
mc
::
Implicit
(
..
))
=>
{
if
let
mc
::
NoteUpvarRef
(
upvar_id
)
=
cmt
.note
{
debug!
(
"adjust_upvar_borrow_kind_for_consume:
\
setting upvar_id={:?} to by value"
,
upvar_id
);
let
mut
upvar_capture_map
=
self
.fcx.inh.upvar_capture_map
.borrow_mut
();
upvar_capture_map
.insert
(
upvar_id
,
ty
::
UpvarCapture
::
ByValue
);
}
}
_
=>
{
}
}
}
/// Indicates that `cmt` is being directly mutated (e.g., assigned
/// to). If cmt contains any by-ref upvars, this implies that
/// those upvars must be borrowed using an `&mut` borow.
...
...
@@ -195,8 +234,8 @@ fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) {
// upvar, then we need to modify the
// borrow_kind of the upvar to make sure it
// is inferred to mutable if necessary
let
mut
upvar_
borrow_map
=
self
.fcx.inh.upvar_borrow
_map
.borrow_mut
();
let
ub
=
&
mut
upvar_
borrow
_map
[
upvar_id
];
let
mut
upvar_
capture_map
=
self
.fcx.inh.upvar_capture
_map
.borrow_mut
();
let
ub
=
&
mut
upvar_
capture
_map
[
upvar_id
];
self
.adjust_upvar_borrow_kind
(
upvar_id
,
ub
,
ty
::
MutBorrow
);
}
else
{
// assignment to deref of an `&mut`
...
...
@@ -237,7 +276,7 @@ fn adjust_upvar_borrow_kind_for_unique(&self, cmt: mc::cmt<'tcx>) {
// upvar, then we need to modify the
// borrow_kind of the upvar to make sure it
// is inferred to unique if necessary
let
mut
ub
=
self
.fcx.inh.upvar_
borrow
_map
.borrow_mut
();
let
mut
ub
=
self
.fcx.inh.upvar_
capture
_map
.borrow_mut
();
let
ub
=
&
mut
ub
[
upvar_id
];
self
.adjust_upvar_borrow_kind
(
upvar_id
,
ub
,
ty
::
UniqueImmBorrow
);
}
else
{
...
...
@@ -262,23 +301,30 @@ fn adjust_upvar_borrow_kind_for_unique(&self, cmt: mc::cmt<'tcx>) {
/// some particular use.
fn
adjust_upvar_borrow_kind
(
&
self
,
upvar_id
:
ty
::
UpvarId
,
upvar_
borrow
:
&
mut
ty
::
UpvarBorrow
,
upvar_
capture
:
&
mut
ty
::
UpvarCapture
,
kind
:
ty
::
BorrowKind
)
{
debug!
(
"adjust_upvar_borrow_kind: id={:?} kind=({:?} -> {:?})"
,
upvar_id
,
upvar_borrow
.kind
,
kind
);
match
(
upvar_borrow
.kind
,
kind
)
{
// Take RHS:
(
ty
::
ImmBorrow
,
ty
::
UniqueImmBorrow
)
|
(
ty
::
ImmBorrow
,
ty
::
MutBorrow
)
|
(
ty
::
UniqueImmBorrow
,
ty
::
MutBorrow
)
=>
{
upvar_borrow
.kind
=
kind
;
debug!
(
"adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})"
,
upvar_id
,
upvar_capture
,
kind
);
match
*
upvar_capture
{
ty
::
UpvarCapture
::
ByValue
=>
{
// Upvar is already by-value, the strongest criteria.
}
// Take LHS:
(
ty
::
ImmBorrow
,
ty
::
ImmBorrow
)
|
(
ty
::
UniqueImmBorrow
,
ty
::
ImmBorrow
)
|
(
ty
::
UniqueImmBorrow
,
ty
::
UniqueImmBorrow
)
|
(
ty
::
MutBorrow
,
_
)
=>
{
ty
::
UpvarCapture
::
ByRef
(
ref
mut
upvar_borrow
)
=>
{
match
(
upvar_borrow
.kind
,
kind
)
{
// Take RHS:
(
ty
::
ImmBorrow
,
ty
::
UniqueImmBorrow
)
|
(
ty
::
ImmBorrow
,
ty
::
MutBorrow
)
|
(
ty
::
UniqueImmBorrow
,
ty
::
MutBorrow
)
=>
{
upvar_borrow
.kind
=
kind
;
}
// Take LHS:
(
ty
::
ImmBorrow
,
ty
::
ImmBorrow
)
|
(
ty
::
UniqueImmBorrow
,
ty
::
ImmBorrow
)
|
(
ty
::
UniqueImmBorrow
,
ty
::
UniqueImmBorrow
)
|
(
ty
::
MutBorrow
,
_
)
=>
{
}
}
}
}
}
...
...
@@ -308,9 +354,12 @@ impl<'a,'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a,'tcx> {
fn
consume
(
&
mut
self
,
_
consume_id
:
ast
::
NodeId
,
_
consume_span
:
Span
,
_
cmt
:
mc
::
cmt
<
'tcx
>
,
_
mode
:
euv
::
ConsumeMode
)
{}
cmt
:
mc
::
cmt
<
'tcx
>
,
mode
:
euv
::
ConsumeMode
)
{
debug!
(
"consume(cmt={},mode={:?})"
,
cmt
.repr
(
self
.tcx
()),
mode
);
self
.adjust_upvar_borrow_kind_for_consume
(
cmt
,
mode
);
}
fn
matched_pat
(
&
mut
self
,
_
matched_pat
:
&
ast
::
Pat
,
...
...
@@ -320,9 +369,12 @@ fn matched_pat(&mut self,
fn
consume_pat
(
&
mut
self
,
_
consume_pat
:
&
ast
::
Pat
,
_
cmt
:
mc
::
cmt
<
'tcx
>
,
_
mode
:
euv
::
ConsumeMode
)
{}
cmt
:
mc
::
cmt
<
'tcx
>
,
mode
:
euv
::
ConsumeMode
)
{
debug!
(
"consume_pat(cmt={},mode={:?})"
,
cmt
.repr
(
self
.tcx
()),
mode
);
self
.adjust_upvar_borrow_kind_for_consume
(
cmt
,
mode
);
}
fn
borrow
(
&
mut
self
,
borrow_id
:
ast
::
NodeId
,
...
...
src/librustc_typeck/check/writeback.rs
浏览文件 @
3fbfad35
...
...
@@ -182,16 +182,20 @@ fn visit_upvar_borrow_map(&self) {
return
;
}
for
(
upvar_id
,
upvar_borrow
)
in
self
.fcx.inh.upvar_borrow_map
.borrow
()
.iter
()
{
let
r
=
upvar_borrow
.region
;
let
r
=
self
.resolve
(
&
r
,
ResolvingUpvar
(
*
upvar_id
));
let
new_upvar_borrow
=
ty
::
UpvarBorrow
{
kind
:
upvar_borrow
.kind
,
region
:
r
};
debug!
(
"Upvar borrow for {} resolved to {}"
,
for
(
upvar_id
,
upvar_capture
)
in
self
.fcx.inh.upvar_capture_map
.borrow
()
.iter
()
{
let
new_upvar_capture
=
match
*
upvar_capture
{
ty
::
UpvarCapture
::
ByValue
=>
ty
::
UpvarCapture
::
ByValue
,
ty
::
UpvarCapture
::
ByRef
(
ref
upvar_borrow
)
=>
{
let
r
=
upvar_borrow
.region
;
let
r
=
self
.resolve
(
&
r
,
ResolvingUpvar
(
*
upvar_id
));
ty
::
UpvarCapture
::
ByRef
(
ty
::
UpvarBorrow
{
kind
:
upvar_borrow
.kind
,
region
:
r
})
}
};
debug!
(
"Upvar capture for {} resolved to {}"
,
upvar_id
.repr
(
self
.tcx
()),
new_upvar_borrow
.repr
(
self
.tcx
()));
self
.fcx
.tcx
()
.upvar_borrow_map
.borrow_mut
()
.insert
(
*
upvar_id
,
new_upvar_borrow
);
new_upvar_capture
.repr
(
self
.tcx
()));
self
.fcx
.tcx
()
.upvar_capture_map
.borrow_mut
()
.insert
(
*
upvar_id
,
new_upvar_capture
);
}
}
...
...
src/librustc_typeck/collect.rs
浏览文件 @
3fbfad35
...
...
@@ -855,6 +855,17 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
}
};
let
paren_sugar
=
ty
::
has_attr
(
tcx
,
def_id
,
"rustc_paren_sugar"
);
if
paren_sugar
&&
!
ccx
.tcx.sess.features
.borrow
()
.unboxed_closures
{
ccx
.tcx.sess
.span_err
(
it
.span
,
"the `#[rustc_paren_sugar]` attribute is a temporary means of controlling
\
which traits can use parenthetical notation"
);
span_help!
(
ccx
.tcx.sess
,
it
.span
,
"add `#![feature(unboxed_closures)]` to
\
the crate attributes to use it"
);
}
let
substs
=
ccx
.tcx
.mk_substs
(
mk_trait_substs
(
ccx
,
generics
));
let
ty_generics
=
ty_generics_for_trait
(
ccx
,
...
...
@@ -887,6 +898,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
});
let
trait_def
=
Rc
::
new
(
ty
::
TraitDef
{
paren_sugar
:
paren_sugar
,
unsafety
:
unsafety
,
generics
:
ty_generics
,
bounds
:
bounds
,
...
...
src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs
浏览文件 @
3fbfad35
...
...
@@ -58,8 +58,10 @@ fn test6() {
fn
test7
()
{
fn
foo
<
F
>
(
_
:
F
)
where
F
:
FnMut
(
Box
<
FnMut
(
isize
)
>
,
isize
)
{}
let
mut
f
=
|
&
mut
:
g
:
Box
<
FnMut
(
isize
)
>
,
b
:
isize
|
{};
f
(
box
|
a
|
{
//~ ERROR: cannot borrow `f` as immutable because it is also borrowed as mutable
foo
(
f
);
//~ ERROR: cannot move out of captured outer variable
f
(
box
|
a
|
{
foo
(
f
);
//~^ ERROR cannot move `f` into closure because it is borrowed
//~| ERROR cannot move out of captured outer variable in an `FnMut` closure
},
3
);
}
...
...
src/test/compile-fail/unboxed-closure-illegal-move.rs
浏览文件 @
3fbfad35
...
...
@@ -19,24 +19,24 @@ fn main() {
// By-ref cases
{
let
x
=
box
0u
s
;
let
f
=
|
&
:|
drop
(
x
);
//~ cannot move
let
f
=
|
&
:|
drop
(
x
);
//~
ERROR
cannot move
}
{
let
x
=
box
0u
s
;
let
f
=
|
&
mut
:|
drop
(
x
);
//~ cannot move
let
f
=
|
&
mut
:|
drop
(
x
);
//~
ERROR
cannot move
}
{
let
x
=
box
0u
s
;
let
f
=
|:|
drop
(
x
);
//
~ cannot mov
e
let
f
=
|:|
drop
(
x
);
//
OK -- FnOnc
e
}
// By-value cases
{
let
x
=
box
0u
s
;
let
f
=
move
|
&
:|
drop
(
x
);
//~ cannot move
let
f
=
move
|
&
:|
drop
(
x
);
//~
ERROR
cannot move
}
{
let
x
=
box
0u
s
;
let
f
=
move
|
&
mut
:|
drop
(
x
);
//~ cannot move
let
f
=
move
|
&
mut
:|
drop
(
x
);
//~
ERROR
cannot move
}
{
let
x
=
box
0u
s
;
...
...
src/test/compile-fail/unboxed-closures-move-upvar-from-non-once-ref-closure.rs
0 → 100644
浏览文件 @
3fbfad35
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that a by-ref `FnMut` closure gets an error when it tries to
// consume a value.
fn
call
<
F
>
(
f
:
F
)
where
F
:
Fn
()
{
f
();
}
fn
main
()
{
let
y
=
vec!
(
format!
(
"World"
));
call
(||
{
y
.into_iter
();
//~^ ERROR cannot move out of captured outer variable in an `Fn` closure
});
}
src/test/compile-fail/unboxed-closures-mutate-upvar.rs
0 → 100644
浏览文件 @
3fbfad35
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that we cannot mutate an outer variable that is not declared
// as `mut` through a closure. Also test that we CAN mutate a moved copy,
// unless this is a `Fn` closure. Issue #16749.
use
std
::
mem
;
fn
a
()
{
let
n
=
0u8
;
let
mut
f
=
|
&
mut
:|
{
//~ ERROR closure cannot assign
n
+=
1
;
};
}
fn
b
()
{
let
mut
n
=
0u8
;
let
mut
f
=
|
&
mut
:|
{
n
+=
1
;
// OK
};
}
fn
c
()
{
let
n
=
0u8
;
let
mut
f
=
move
|
&
mut
:|
{
// If we just did a straight-forward desugaring, this would
// compile, but we do something a bit more subtle, and hence
// we get an error.
n
+=
1
;
//~ ERROR cannot assign
};
}
fn
d
()
{
let
mut
n
=
0u8
;
let
mut
f
=
move
|
&
mut
:|
{
n
+=
1
;
// OK
};
}
fn
e
()
{
let
n
=
0u8
;
let
mut
f
=
move
|
&
:|
{
n
+=
1
;
//~ ERROR cannot assign
};
}
fn
f
()
{
let
mut
n
=
0u8
;
let
mut
f
=
move
|
&
:|
{
n
+=
1
;
//~ ERROR cannot assign
};
}
fn
main
()
{
}
src/test/compile-fail/unboxed-closures-mutated-upvar-from-fn-closure.rs
0 → 100644
浏览文件 @
3fbfad35
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that a by-ref `FnMut` closure gets an error when it tries to
// mutate a value.
fn
call
<
F
>
(
f
:
F
)
where
F
:
Fn
()
{
f
();
}
fn
main
()
{
let
mut
counter
=
0_u32
;
call
(||
{
counter
+=
1
;
//~^ ERROR cannot assign to data in a captured outer variable in an `Fn` closure
});
}
src/test/run-pass/unboxed-closures-counter-not-moved.rs
0 → 100644
浏览文件 @
3fbfad35
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that we mutate a counter on the stack only when we expect to.
fn
call
<
F
>
(
f
:
F
)
where
F
:
FnOnce
()
{
f
();
}
fn
main
()
{
let
y
=
vec!
(
format!
(
"Hello"
),
format!
(
"World"
));
let
mut
counter
=
22_u32
;
call
(||
{
// Move `y`, but do not move `counter`, even though it is read
// by value (note that it is also mutated).
for
item
in
y
.into_iter
()
{
let
v
=
counter
;
counter
+=
v
;
}
});
assert_eq!
(
counter
,
88
);
call
(
move
||
{
// this mutates a moved copy, and hence doesn't affect original
counter
+=
1
;
});
assert_eq!
(
counter
,
88
);
}
src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs
0 → 100644
浏览文件 @
3fbfad35
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that in a by-ref once closure we move some variables even as
// we capture others by mutable reference.
fn
call
<
F
>
(
f
:
F
)
where
F
:
FnOnce
()
{
f
();
}
fn
main
()
{
let
mut
x
=
vec!
(
format!
(
"Hello"
));
let
y
=
vec!
(
format!
(
"World"
));
call
(||
{
// Here: `x` must be captured with a mutable reference in
// order for us to append on it, and `y` must be captured by
// value.
for
item
in
y
.into_iter
()
{
x
.push
(
item
);
}
});
assert_eq!
(
x
.len
(),
2
);
assert_eq!
(
&*
x
[
0
],
"Hello"
);
assert_eq!
(
&*
x
[
1
],
"World"
);
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录