Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
e0eb3ccb
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,发现更多精彩内容 >>
提交
e0eb3ccb
编写于
1月 18, 2015
作者:
A
Ariel Ben-Yehuda
提交者:
Ariel Ben-Yehuda
1月 20, 2015
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Kill TraitStore
上级
4032b85a
变更
14
隐藏空白更改
内联
并排
Showing
14 changed file
with
14 addition
and
566 deletion
+14
-566
src/librustc/metadata/tydecode.rs
src/librustc/metadata/tydecode.rs
+0
-15
src/librustc/metadata/tyencode.rs
src/librustc/metadata/tyencode.rs
+0
-12
src/librustc/middle/astencode.rs
src/librustc/middle/astencode.rs
+0
-11
src/librustc/middle/infer/combine.rs
src/librustc/middle/infer/combine.rs
+0
-58
src/librustc/middle/ty.rs
src/librustc/middle/ty.rs
+2
-45
src/librustc/middle/ty_fold.rs
src/librustc/middle/ty_fold.rs
+0
-22
src/librustc/util/ppaux.rs
src/librustc/util/ppaux.rs
+5
-37
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/base.rs
+2
-14
src/librustc_trans/trans/closure.rs
src/librustc_trans/trans/closure.rs
+3
-319
src/librustc_trans/trans/debuginfo.rs
src/librustc_trans/trans/debuginfo.rs
+1
-10
src/librustc_trans/trans/expr.rs
src/librustc_trans/trans/expr.rs
+1
-12
src/librustc_trans/trans/type_.rs
src/librustc_trans/trans/type_.rs
+0
-8
src/librustc_typeck/astconv.rs
src/librustc_typeck/astconv.rs
+0
-2
src/librustc_typeck/check/closure.rs
src/librustc_typeck/check/closure.rs
+0
-1
未找到文件。
src/librustc/metadata/tydecode.rs
浏览文件 @
e0eb3ccb
...
...
@@ -243,19 +243,6 @@ fn parse_size(st: &mut PState) -> Option<uint> {
}
}
fn
parse_trait_store_
<
F
>
(
st
:
&
mut
PState
,
conv
:
&
mut
F
)
->
ty
::
TraitStore
where
F
:
FnMut
(
DefIdSource
,
ast
::
DefId
)
->
ast
::
DefId
,
{
match
next
(
st
)
{
'~'
=>
ty
::
UniqTraitStore
,
'&'
=>
ty
::
RegionTraitStore
(
parse_region_
(
st
,
conv
),
parse_mutability
(
st
)),
c
=>
{
st
.tcx.sess
.bug
(
&
format!
(
"parse_trait_store(): bad input '{}'"
,
c
)[])
}
}
}
fn
parse_vec_per_param_space
<
'a
,
'tcx
,
T
,
F
>
(
st
:
&
mut
PState
<
'a
,
'tcx
>
,
mut
f
:
F
)
->
VecPerParamSpace
<
T
>
where
...
...
@@ -662,14 +649,12 @@ fn parse_closure_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>,
{
let
unsafety
=
parse_unsafety
(
next
(
st
));
let
onceness
=
parse_onceness
(
next
(
st
));
let
store
=
parse_trait_store_
(
st
,
conv
);
let
bounds
=
parse_existential_bounds_
(
st
,
conv
);
let
sig
=
parse_sig_
(
st
,
conv
);
let
abi
=
parse_abi_set
(
st
);
ty
::
ClosureTy
{
unsafety
:
unsafety
,
onceness
:
onceness
,
store
:
store
,
bounds
:
bounds
,
sig
:
sig
,
abi
:
abi
,
...
...
src/librustc/metadata/tyencode.rs
浏览文件 @
e0eb3ccb
...
...
@@ -305,17 +305,6 @@ pub fn enc_trait_ref<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
enc_substs
(
w
,
cx
,
s
.substs
);
}
pub
fn
enc_trait_store
(
w
:
&
mut
SeekableMemWriter
,
cx
:
&
ctxt
,
s
:
ty
::
TraitStore
)
{
match
s
{
ty
::
UniqTraitStore
=>
mywrite!
(
w
,
"~"
),
ty
::
RegionTraitStore
(
re
,
m
)
=>
{
mywrite!
(
w
,
"&"
);
enc_region
(
w
,
cx
,
re
);
enc_mutability
(
w
,
m
);
}
}
}
fn
enc_unsafety
(
w
:
&
mut
SeekableMemWriter
,
p
:
ast
::
Unsafety
)
{
match
p
{
ast
::
Unsafety
::
Normal
=>
mywrite!
(
w
,
"n"
),
...
...
@@ -347,7 +336,6 @@ pub fn enc_closure_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
ft
:
&
ty
::
ClosureTy
<
'tcx
>
)
{
enc_unsafety
(
w
,
ft
.unsafety
);
enc_onceness
(
w
,
ft
.onceness
);
enc_trait_store
(
w
,
cx
,
ft
.store
);
enc_existential_bounds
(
w
,
cx
,
&
ft
.bounds
);
enc_fn_sig
(
w
,
cx
,
&
ft
.sig
);
enc_abi
(
w
,
ft
.abi
);
...
...
src/librustc/middle/astencode.rs
浏览文件 @
e0eb3ccb
...
...
@@ -515,17 +515,6 @@ fn tr(&self, dcx: &DecodeContext) -> ty::BoundRegion {
}
}
impl
tr
for
ty
::
TraitStore
{
fn
tr
(
&
self
,
dcx
:
&
DecodeContext
)
->
ty
::
TraitStore
{
match
*
self
{
ty
::
RegionTraitStore
(
r
,
m
)
=>
{
ty
::
RegionTraitStore
(
r
.tr
(
dcx
),
m
)
}
ty
::
UniqTraitStore
=>
ty
::
UniqTraitStore
}
}
}
// ______________________________________________________________________
// Encoding and decoding of freevar information
...
...
src/librustc/middle/infer/combine.rs
浏览文件 @
e0eb3ccb
...
...
@@ -202,39 +202,6 @@ fn bare_fn_tys(&self, a: &ty::BareFnTy<'tcx>,
sig
:
sig
})
}
fn
closure_tys
(
&
self
,
a
:
&
ty
::
ClosureTy
<
'tcx
>
,
b
:
&
ty
::
ClosureTy
<
'tcx
>
)
->
cres
<
'tcx
,
ty
::
ClosureTy
<
'tcx
>>
{
let
store
=
match
(
a
.store
,
b
.store
)
{
(
ty
::
RegionTraitStore
(
a_r
,
a_m
),
ty
::
RegionTraitStore
(
b_r
,
b_m
))
if
a_m
==
b_m
=>
{
let
r
=
try!
(
self
.contraregions
(
a_r
,
b_r
));
ty
::
RegionTraitStore
(
r
,
a_m
)
}
_
if
a
.store
==
b
.store
=>
{
a
.store
}
_
=>
{
return
Err
(
ty
::
terr_sigil_mismatch
(
expected_found
(
self
,
a
.store
,
b
.store
)))
}
};
let
unsafety
=
try!
(
self
.unsafeties
(
a
.unsafety
,
b
.unsafety
));
let
onceness
=
try!
(
self
.oncenesses
(
a
.onceness
,
b
.onceness
));
let
bounds
=
try!
(
self
.existential_bounds
(
&
a
.bounds
,
&
b
.bounds
));
let
sig
=
try!
(
self
.binders
(
&
a
.sig
,
&
b
.sig
));
let
abi
=
try!
(
self
.abi
(
a
.abi
,
b
.abi
));
Ok
(
ty
::
ClosureTy
{
unsafety
:
unsafety
,
onceness
:
onceness
,
store
:
store
,
bounds
:
bounds
,
sig
:
sig
,
abi
:
abi
,
})
}
fn
fn_sigs
(
&
self
,
a
:
&
ty
::
FnSig
<
'tcx
>
,
b
:
&
ty
::
FnSig
<
'tcx
>
)
->
cres
<
'tcx
,
ty
::
FnSig
<
'tcx
>>
{
if
a
.variadic
!=
b
.variadic
{
return
Err
(
ty
::
terr_variadic_mismatch
(
expected_found
(
self
,
a
.variadic
,
b
.variadic
)));
...
...
@@ -356,31 +323,6 @@ fn contraregions(&self, a: ty::Region, b: ty::Region)
fn
regions
(
&
self
,
a
:
ty
::
Region
,
b
:
ty
::
Region
)
->
cres
<
'tcx
,
ty
::
Region
>
;
fn
trait_stores
(
&
self
,
vk
:
ty
::
terr_vstore_kind
,
a
:
ty
::
TraitStore
,
b
:
ty
::
TraitStore
)
->
cres
<
'tcx
,
ty
::
TraitStore
>
{
debug!
(
"{}.trait_stores(a={:?}, b={:?})"
,
self
.tag
(),
a
,
b
);
match
(
a
,
b
)
{
(
ty
::
RegionTraitStore
(
a_r
,
a_m
),
ty
::
RegionTraitStore
(
b_r
,
b_m
))
if
a_m
==
b_m
=>
{
self
.contraregions
(
a_r
,
b_r
)
.and_then
(|
r
|
{
Ok
(
ty
::
RegionTraitStore
(
r
,
a_m
))
})
}
_
if
a
==
b
=>
{
Ok
(
a
)
}
_
=>
{
Err
(
ty
::
terr_trait_stores_differ
(
vk
,
expected_found
(
self
,
a
,
b
)))
}
}
}
fn
trait_refs
(
&
self
,
a
:
&
ty
::
TraitRef
<
'tcx
>
,
b
:
&
ty
::
TraitRef
<
'tcx
>
)
...
...
src/librustc/middle/ty.rs
浏览文件 @
e0eb3ccb
...
...
@@ -17,7 +17,6 @@
pub
use
self
::
InferRegion
::
*
;
pub
use
self
::
ImplOrTraitItemId
::
*
;
pub
use
self
::
UnboxedClosureKind
::
*
;
pub
use
self
::
TraitStore
::
*
;
pub
use
self
::
ast_ty_to_ty_cache_entry
::
*
;
pub
use
self
::
Variance
::
*
;
pub
use
self
::
AutoAdjustment
::
*
;
...
...
@@ -61,7 +60,7 @@
use
middle
::
ty_fold
::{
self
,
TypeFoldable
,
TypeFolder
};
use
middle
::
ty_walk
::
TypeWalker
;
use
util
::
ppaux
::{
note_and_explain_region
,
bound_region_ptr_to_string
};
use
util
::
ppaux
::
{
trait_store_to_string
,
ty_to_string
}
;
use
util
::
ppaux
::
ty_to_string
;
use
util
::
ppaux
::{
Repr
,
UserString
};
use
util
::
common
::{
memoized
,
ErrorReported
};
use
util
::
nodemap
::{
NodeMap
,
NodeSet
,
DefIdMap
,
DefIdSet
};
...
...
@@ -247,14 +246,6 @@ pub struct mt<'tcx> {
pub
mutbl
:
ast
::
Mutability
,
}
#[derive(Clone,
Copy,
PartialEq,
Eq,
Hash,
RustcEncodable,
RustcDecodable,
Show)]
pub
enum
TraitStore
{
/// Box<Trait>
UniqTraitStore
,
/// &Trait and &mut Trait
RegionTraitStore
(
Region
,
ast
::
Mutability
),
}
#[derive(Clone,
Copy,
Show)]
pub
struct
field_ty
{
pub
name
:
Name
,
...
...
@@ -1042,7 +1033,6 @@ pub struct BareFnTy<'tcx> {
pub
struct
ClosureTy
<
'tcx
>
{
pub
unsafety
:
ast
::
Unsafety
,
pub
onceness
:
ast
::
Onceness
,
pub
store
:
TraitStore
,
pub
bounds
:
ExistentialBounds
<
'tcx
>
,
pub
sig
:
PolyFnSig
<
'tcx
>
,
pub
abi
:
abi
::
Abi
,
...
...
@@ -1545,7 +1535,6 @@ pub enum type_err<'tcx> {
terr_onceness_mismatch
(
expected_found
<
Onceness
>
),
terr_abi_mismatch
(
expected_found
<
abi
::
Abi
>
),
terr_mutability
,
terr_sigil_mismatch
(
expected_found
<
TraitStore
>
),
terr_box_mutability
,
terr_ptr_mutability
,
terr_ref_mutability
,
...
...
@@ -1559,7 +1548,6 @@ pub enum type_err<'tcx> {
terr_regions_no_overlap
(
Region
,
Region
),
terr_regions_insufficiently_polymorphic
(
BoundRegion
,
Region
),
terr_regions_overly_polymorphic
(
BoundRegion
,
Region
),
terr_trait_stores_differ
(
terr_vstore_kind
,
expected_found
<
TraitStore
>
),
terr_sorts
(
expected_found
<
Ty
<
'tcx
>>
),
terr_integer_as_char
,
terr_int_mismatch
(
expected_found
<
IntVarValue
>
),
...
...
@@ -4194,19 +4182,6 @@ pub fn ty_fn_args<'tcx>(fty: Ty<'tcx>) -> ty::Binder<Vec<Ty<'tcx>>> {
ty_fn_sig
(
fty
)
.inputs
()
}
pub
fn
ty_closure_store
(
fty
:
Ty
)
->
TraitStore
{
match
fty
.sty
{
ty_unboxed_closure
(
..
)
=>
{
// Close enough for the purposes of all the callers of this
// function (which is soon to be deprecated anyhow).
UniqTraitStore
}
ref
s
=>
{
panic!
(
"ty_closure_store() called on non-closure type: {:?}"
,
s
)
}
}
}
pub
fn
ty_fn_ret
<
'tcx
>
(
fty
:
Ty
<
'tcx
>
)
->
Binder
<
FnOutput
<
'tcx
>>
{
match
fty
.sty
{
ty_bare_fn
(
_
,
ref
f
)
=>
f
.sig
.output
(),
...
...
@@ -4751,13 +4726,6 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
/// afterwards to present additional details, particularly when it comes to lifetime-related
/// errors.
pub
fn
type_err_to_str
<
'tcx
>
(
cx
:
&
ctxt
<
'tcx
>
,
err
:
&
type_err
<
'tcx
>
)
->
String
{
fn
tstore_to_closure
(
s
:
&
TraitStore
)
->
String
{
match
s
{
&
UniqTraitStore
=>
"proc"
.to_string
(),
&
RegionTraitStore
(
..
)
=>
"closure"
.to_string
()
}
}
match
*
err
{
terr_cyclic_ty
=>
"cyclic type of infinite size"
.to_string
(),
terr_mismatch
=>
"types differ"
.to_string
(),
...
...
@@ -4776,11 +4744,6 @@ fn tstore_to_closure(s: &TraitStore) -> String {
values
.expected
,
values
.found
)
}
terr_sigil_mismatch
(
values
)
=>
{
format!
(
"expected {}, found {}"
,
tstore_to_closure
(
&
values
.expected
),
tstore_to_closure
(
&
values
.found
))
}
terr_mutability
=>
"values differ in mutability"
.to_string
(),
terr_box_mutability
=>
{
"boxed values differ in mutability"
.to_string
()
...
...
@@ -4828,11 +4791,6 @@ fn tstore_to_closure(s: &TraitStore) -> String {
found bound lifetime parameter {}"
,
bound_region_ptr_to_string
(
cx
,
br
))
}
terr_trait_stores_differ
(
_
,
ref
values
)
=>
{
format!
(
"trait storage differs: expected `{}`, found `{}`"
,
trait_store_to_string
(
cx
,
(
*
values
)
.expected
),
trait_store_to_string
(
cx
,
(
*
values
)
.found
))
}
terr_sorts
(
values
)
=>
{
// A naive approach to making sure that we're not reporting silly errors such as:
// (expected closure, found closure).
...
...
@@ -7338,10 +7296,9 @@ fn references_error(&self) -> bool {
impl
<
'tcx
>
Repr
<
'tcx
>
for
ClosureTy
<
'tcx
>
{
fn
repr
(
&
self
,
tcx
:
&
ctxt
<
'tcx
>
)
->
String
{
format!
(
"ClosureTy({},{},{
:?},{
},{},{})"
,
format!
(
"ClosureTy({},{},{},{},{})"
,
self
.unsafety
,
self
.onceness
,
self
.store
,
self
.bounds
.repr
(
tcx
),
self
.sig
.repr
(
tcx
),
self
.abi
)
...
...
src/librustc/middle/ty_fold.rs
浏览文件 @
e0eb3ccb
...
...
@@ -124,10 +124,6 @@ fn fold_region(&mut self, r: ty::Region) -> ty::Region {
r
}
fn
fold_trait_store
(
&
mut
self
,
s
:
ty
::
TraitStore
)
->
ty
::
TraitStore
{
super_fold_trait_store
(
self
,
s
)
}
fn
fold_existential_bounds
(
&
mut
self
,
s
:
&
ty
::
ExistentialBounds
<
'tcx
>
)
->
ty
::
ExistentialBounds
<
'tcx
>
{
super_fold_existential_bounds
(
self
,
s
)
...
...
@@ -225,12 +221,6 @@ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> VecPerParamSpace<T>
}
}
impl
<
'tcx
>
TypeFoldable
<
'tcx
>
for
ty
::
TraitStore
{
fn
fold_with
<
F
:
TypeFolder
<
'tcx
>>
(
&
self
,
folder
:
&
mut
F
)
->
ty
::
TraitStore
{
folder
.fold_trait_store
(
*
self
)
}
}
impl
<
'tcx
>
TypeFoldable
<
'tcx
>
for
Ty
<
'tcx
>
{
fn
fold_with
<
F
:
TypeFolder
<
'tcx
>>
(
&
self
,
folder
:
&
mut
F
)
->
Ty
<
'tcx
>
{
folder
.fold_ty
(
*
self
)
...
...
@@ -699,7 +689,6 @@ pub fn super_fold_closure_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
->
ty
::
ClosureTy
<
'tcx
>
{
ty
::
ClosureTy
{
store
:
fty
.store
.fold_with
(
this
),
sig
:
fty
.sig
.fold_with
(
this
),
unsafety
:
fty
.unsafety
,
onceness
:
fty
.onceness
,
...
...
@@ -726,17 +715,6 @@ pub fn super_fold_mt<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
mutbl
:
mt
.mutbl
}
}
pub
fn
super_fold_trait_store
<
'tcx
,
T
:
TypeFolder
<
'tcx
>>
(
this
:
&
mut
T
,
trait_store
:
ty
::
TraitStore
)
->
ty
::
TraitStore
{
match
trait_store
{
ty
::
UniqTraitStore
=>
ty
::
UniqTraitStore
,
ty
::
RegionTraitStore
(
r
,
m
)
=>
{
ty
::
RegionTraitStore
(
r
.fold_with
(
this
),
m
)
}
}
}
pub
fn
super_fold_existential_bounds
<
'tcx
,
T
:
TypeFolder
<
'tcx
>>
(
this
:
&
mut
T
,
bounds
:
&
ty
::
ExistentialBounds
<
'tcx
>
)
...
...
src/librustc/util/ppaux.rs
浏览文件 @
e0eb3ccb
...
...
@@ -237,15 +237,6 @@ pub fn mt_to_string<'tcx>(cx: &ctxt<'tcx>, m: &mt<'tcx>) -> String {
ty_to_string
(
cx
,
m
.ty
))
}
pub
fn
trait_store_to_string
(
cx
:
&
ctxt
,
s
:
ty
::
TraitStore
)
->
String
{
match
s
{
ty
::
UniqTraitStore
=>
"Box "
.to_string
(),
ty
::
RegionTraitStore
(
r
,
m
)
=>
{
format!
(
"{}{}"
,
region_ptr_to_string
(
cx
,
r
),
mutability_to_string
(
m
))
}
}
}
pub
fn
vec_map_to_string
<
T
,
F
>
(
ts
:
&
[
T
],
f
:
F
)
->
String
where
F
:
FnMut
(
&
T
)
->
String
,
{
...
...
@@ -303,13 +294,6 @@ fn bare_fn_to_string<'tcx>(cx: &ctxt<'tcx>,
fn
closure_to_string
<
'tcx
>
(
cx
:
&
ctxt
<
'tcx
>
,
cty
:
&
ty
::
ClosureTy
<
'tcx
>
)
->
String
{
let
mut
s
=
String
::
new
();
match
cty
.store
{
ty
::
UniqTraitStore
=>
{}
ty
::
RegionTraitStore
(
region
,
_
)
=>
{
s
.push_str
(
&
region_to_string
(
cx
,
""
,
true
,
region
)[]);
}
}
match
cty
.unsafety
{
ast
::
Unsafety
::
Normal
=>
{}
ast
::
Unsafety
::
Unsafe
=>
{
...
...
@@ -320,22 +304,12 @@ fn closure_to_string<'tcx>(cx: &ctxt<'tcx>, cty: &ty::ClosureTy<'tcx>) -> String
let
bounds_str
=
cty
.bounds
.user_string
(
cx
);
match
cty
.store
{
ty
::
UniqTraitStore
=>
{
assert_eq!
(
cty
.onceness
,
ast
::
Once
);
s
.push_str
(
"proc"
);
push_sig_to_string
(
cx
,
&
mut
s
,
'('
,
')'
,
&
cty
.sig
,
&
bounds_str
[]);
}
ty
::
RegionTraitStore
(
..
)
=>
{
match
cty
.onceness
{
ast
::
Many
=>
{}
ast
::
Once
=>
s
.push_str
(
"once "
)
}
push_sig_to_string
(
cx
,
&
mut
s
,
'|'
,
'|'
,
&
cty
.sig
,
&
bounds_str
[]);
}
match
cty
.onceness
{
ast
::
Many
=>
{}
ast
::
Once
=>
s
.push_str
(
"once "
)
}
push_sig_to_string
(
cx
,
&
mut
s
,
'|'
,
'|'
,
&
cty
.sig
,
&
bounds_str
[]);
s
}
...
...
@@ -1090,12 +1064,6 @@ fn repr(&self, tcx: &ctxt<'tcx>) -> String {
}
}
impl
<
'tcx
>
Repr
<
'tcx
>
for
ty
::
TraitStore
{
fn
repr
(
&
self
,
tcx
:
&
ctxt
)
->
String
{
trait_store_to_string
(
tcx
,
*
self
)
}
}
impl
<
'tcx
>
Repr
<
'tcx
>
for
ty
::
BuiltinBound
{
fn
repr
(
&
self
,
_
tcx
:
&
ctxt
)
->
String
{
format!
(
"{:?}"
,
*
self
)
...
...
src/librustc_trans/trans/base.rs
浏览文件 @
e0eb3ccb
...
...
@@ -362,18 +362,6 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId,
}
}
// Returns a pointer to the body for the box. The box may be an opaque
// box. The result will be casted to the type of body_t, if it is statically
// known.
pub
fn
at_box_body
<
'blk
,
'tcx
>
(
bcx
:
Block
<
'blk
,
'tcx
>
,
body_t
:
Ty
<
'tcx
>
,
boxptr
:
ValueRef
)
->
ValueRef
{
let
_
icx
=
push_ctxt
(
"at_box_body"
);
let
ccx
=
bcx
.ccx
();
let
ty
=
Type
::
at_box
(
ccx
,
type_of
(
ccx
,
body_t
));
let
boxptr
=
PointerCast
(
bcx
,
boxptr
,
ty
.ptr_to
());
GEPi
(
bcx
,
boxptr
,
&
[
0u
,
abi
::
BOX_FIELD_BODY
])
}
fn
require_alloc_fn
<
'blk
,
'tcx
>
(
bcx
:
Block
<
'blk
,
'tcx
>
,
info_ty
:
Ty
<
'tcx
>
,
it
:
LangItem
)
->
ast
::
DefId
{
match
bcx
.tcx
()
.lang_items
.require
(
it
)
{
...
...
@@ -1832,7 +1820,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
.map
(|
arg
|
node_id_type
(
bcx
,
arg
.id
))
.collect
::
<
Vec
<
_
>>
();
let
monomorphized_arg_types
=
match
closure_env
.kind
{
closure
::
NotClosure
|
closure
::
BoxedClosure
(
..
)
=>
{
closure
::
NotClosure
=>
{
monomorphized_arg_types
}
...
...
@@ -1859,7 +1847,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
};
bcx
=
match
closure_env
.kind
{
closure
::
NotClosure
|
closure
::
BoxedClosure
(
..
)
=>
{
closure
::
NotClosure
=>
{
copy_args_to_allocas
(
bcx
,
arg_scope
,
&
decl
.inputs
[],
...
...
src/librustc_trans/trans/closure.rs
浏览文件 @
e0eb3ccb
...
...
@@ -10,270 +10,26 @@
pub
use
self
::
ClosureKind
::
*
;
use
back
::
abi
;
use
back
::
link
::
mangle_internal_name_by_path_and_seq
;
use
llvm
::
ValueRef
;
use
middle
::
mem_categorization
::
Typer
;
use
trans
::
adt
;
use
trans
::
base
::
*
;
use
trans
::
build
::
*
;
use
trans
::
cleanup
::{
CleanupMethods
,
ScopeId
};
use
trans
::
common
::
*
;
use
trans
::
datum
::{
Datum
,
Lvalue
,
rvalue_scratch_datum
};
use
trans
::
datum
::{
Datum
,
rvalue_scratch_datum
};
use
trans
::
datum
::{
Rvalue
,
ByValue
};
use
trans
::
debuginfo
;
use
trans
::
expr
;
use
trans
::
monomorphize
::{
self
,
MonoId
};
use
trans
::
type_of
::
*
;
use
trans
::
type_
::
Type
;
use
middle
::
ty
::{
self
,
Ty
,
UnboxedClosureTyper
};
use
middle
::
ty
::{
self
,
UnboxedClosureTyper
};
use
middle
::
subst
::{
Substs
};
use
session
::
config
::
FullDebugInfo
;
use
util
::
ppaux
::
ty_to_string
;
use
syntax
::
ast
;
use
syntax
::
ast_util
;
// ___Good to know (tm)__________________________________________________
//
// The layout of a closure environment in memory is
// roughly as follows:
//
// struct rust_opaque_box { // see rust_internal.h
// unsigned ref_count; // obsolete (part of @T's header)
// fn(void*) *drop_glue; // destructor (for proc)
// rust_opaque_box *prev; // obsolete (part of @T's header)
// rust_opaque_box *next; // obsolete (part of @T's header)
// struct closure_data {
// upvar1_t upvar1;
// ...
// upvarN_t upvarN;
// }
// };
//
// Note that the closure is itself a rust_opaque_box. This is true
// even for ~fn and ||, because we wish to keep binary compatibility
// between all kinds of closures. The allocation strategy for this
// closure depends on the closure type. For a sendfn, the closure
// (and the referenced type descriptors) will be allocated in the
// exchange heap. For a fn, the closure is allocated in the task heap
// and is reference counted. For a block, the closure is allocated on
// the stack.
//
// ## Opaque closures and the embedded type descriptor ##
//
// One interesting part of closures is that they encapsulate the data
// that they close over. So when I have a ptr to a closure, I do not
// know how many type descriptors it contains nor what upvars are
// captured within. That means I do not know precisely how big it is
// nor where its fields are located. This is called an "opaque
// closure".
//
// Typically an opaque closure suffices because we only manipulate it
// by ptr. The routine Type::at_box().ptr_to() returns an appropriate
// type for such an opaque closure; it allows access to the box fields,
// but not the closure_data itself.
//
// But sometimes, such as when cloning or freeing a closure, we need
// to know the full information. That is where the type descriptor
// that defines the closure comes in handy. We can use its take and
// drop glue functions to allocate/free data as needed.
//
// ## Subtleties concerning alignment ##
//
// It is important that we be able to locate the closure data *without
// knowing the kind of data that is being bound*. This can be tricky
// because the alignment requirements of the bound data affects the
// alignment requires of the closure_data struct as a whole. However,
// right now this is a non-issue in any case, because the size of the
// rust_opaque_box header is always a multiple of 16-bytes, which is
// the maximum alignment requirement we ever have to worry about.
//
// The only reason alignment matters is that, in order to learn what data
// is bound, we would normally first load the type descriptors: but their
// location is ultimately depend on their content! There is, however, a
// workaround. We can load the tydesc from the rust_opaque_box, which
// describes the closure_data struct and has self-contained derived type
// descriptors, and read the alignment from there. It's just annoying to
// do. Hopefully should this ever become an issue we'll have monomorphized
// and type descriptors will all be a bad dream.
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#[derive(Copy)]
pub
struct
EnvValue
<
'tcx
>
{
action
:
ast
::
CaptureClause
,
datum
:
Datum
<
'tcx
,
Lvalue
>
}
impl
<
'tcx
>
EnvValue
<
'tcx
>
{
pub
fn
to_string
<
'a
>
(
&
self
,
ccx
:
&
CrateContext
<
'a
,
'tcx
>
)
->
String
{
format!
(
"{:?}({})"
,
self
.action
,
self
.datum
.to_string
(
ccx
))
}
}
// Given a closure ty, emits a corresponding tuple ty
pub
fn
mk_closure_tys
<
'tcx
>
(
tcx
:
&
ty
::
ctxt
<
'tcx
>
,
bound_values
:
&
[
EnvValue
<
'tcx
>
])
->
Ty
<
'tcx
>
{
// determine the types of the values in the env. Note that this
// is the actual types that will be stored in the map, not the
// logical types as the user sees them, so by-ref upvars must be
// converted to ptrs.
let
bound_tys
=
bound_values
.iter
()
.map
(|
bv
|
{
match
bv
.action
{
ast
::
CaptureByValue
=>
bv
.datum.ty
,
ast
::
CaptureByRef
=>
ty
::
mk_mut_ptr
(
tcx
,
bv
.datum.ty
)
}
})
.collect
();
let
cdata_ty
=
ty
::
mk_tup
(
tcx
,
bound_tys
);
debug!
(
"cdata_ty={}"
,
ty_to_string
(
tcx
,
cdata_ty
));
return
cdata_ty
;
}
fn
tuplify_box_ty
<
'tcx
>
(
tcx
:
&
ty
::
ctxt
<
'tcx
>
,
t
:
Ty
<
'tcx
>
)
->
Ty
<
'tcx
>
{
let
ptr
=
ty
::
mk_imm_ptr
(
tcx
,
tcx
.types.i8
);
ty
::
mk_tup
(
tcx
,
vec!
(
tcx
.types.uint
,
ty
::
mk_nil_ptr
(
tcx
),
ptr
,
ptr
,
t
))
}
pub
struct
ClosureResult
<
'blk
,
'tcx
:
'blk
>
{
llbox
:
ValueRef
,
// llvalue of ptr to closure
cdata_ty
:
Ty
<
'tcx
>
,
// type of the closure data
bcx
:
Block
<
'blk
,
'tcx
>
// final bcx
}
// Given a block context and a list of tydescs and values to bind
// construct a closure out of them. If copying is true, it is a
// heap allocated closure that copies the upvars into environment.
// Otherwise, it is stack allocated and copies pointers to the upvars.
pub
fn
store_environment
<
'blk
,
'tcx
>
(
bcx
:
Block
<
'blk
,
'tcx
>
,
bound_values
:
Vec
<
EnvValue
<
'tcx
>>
)
->
ClosureResult
<
'blk
,
'tcx
>
{
let
_
icx
=
push_ctxt
(
"closure::store_environment"
);
let
ccx
=
bcx
.ccx
();
let
tcx
=
ccx
.tcx
();
// compute the type of the closure
let
cdata_ty
=
mk_closure_tys
(
tcx
,
&
bound_values
[]);
// cbox_ty has the form of a tuple: (a, b, c) we want a ptr to a
// tuple. This could be a ptr in uniq or a box or on stack,
// whatever.
let
cbox_ty
=
tuplify_box_ty
(
tcx
,
cdata_ty
);
let
cboxptr_ty
=
ty
::
mk_ptr
(
tcx
,
ty
::
mt
{
ty
:
cbox_ty
,
mutbl
:
ast
::
MutImmutable
});
let
llboxptr_ty
=
type_of
(
ccx
,
cboxptr_ty
);
// If there are no bound values, no point in allocating anything.
if
bound_values
.is_empty
()
{
return
ClosureResult
{
llbox
:
C_null
(
llboxptr_ty
),
cdata_ty
:
cdata_ty
,
bcx
:
bcx
};
}
// allocate closure in the heap
let
llbox
=
alloc_ty
(
bcx
,
cbox_ty
,
"__closure"
);
let
llbox
=
PointerCast
(
bcx
,
llbox
,
llboxptr_ty
);
debug!
(
"tuplify_box_ty = {}"
,
ty_to_string
(
tcx
,
cbox_ty
));
// Copy expr values into boxed bindings.
let
mut
bcx
=
bcx
;
for
(
i
,
bv
)
in
bound_values
.into_iter
()
.enumerate
()
{
debug!
(
"Copy {} into closure"
,
bv
.to_string
(
ccx
));
if
ccx
.sess
()
.asm_comments
()
{
add_comment
(
bcx
,
&
format!
(
"Copy {} into closure"
,
bv
.to_string
(
ccx
))[]);
}
let
bound_data
=
GEPi
(
bcx
,
llbox
,
&
[
0u
,
abi
::
BOX_FIELD_BODY
,
i
]);
match
bv
.action
{
ast
::
CaptureByValue
=>
{
bcx
=
bv
.datum
.store_to
(
bcx
,
bound_data
);
}
ast
::
CaptureByRef
=>
{
Store
(
bcx
,
bv
.datum
.to_llref
(),
bound_data
);
}
}
}
ClosureResult
{
llbox
:
llbox
,
cdata_ty
:
cdata_ty
,
bcx
:
bcx
}
}
// 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
<
'blk
,
'tcx
>
(
bcx0
:
Block
<
'blk
,
'tcx
>
,
freevar_mode
:
ast
::
CaptureClause
,
freevars
:
&
Vec
<
ty
::
Freevar
>
)
->
ClosureResult
<
'blk
,
'tcx
>
{
let
_
icx
=
push_ctxt
(
"closure::build_closure"
);
// If we need to, package up the iterator body to call
let
bcx
=
bcx0
;
// Package up the captured upvars
let
mut
env_vals
=
Vec
::
new
();
for
freevar
in
freevars
.iter
()
{
let
datum
=
expr
::
trans_local_var
(
bcx
,
freevar
.def
);
env_vals
.push
(
EnvValue
{
action
:
freevar_mode
,
datum
:
datum
});
}
store_environment
(
bcx
,
env_vals
)
}
// Given an enclosing block context, a new function context, a closure type,
// and a list of upvars, generate code to load and populate the environment
// with the upvars and type descriptors.
fn
load_environment
<
'blk
,
'tcx
>
(
bcx
:
Block
<
'blk
,
'tcx
>
,
cdata_ty
:
Ty
<
'tcx
>
,
freevars
:
&
[
ty
::
Freevar
],
store
:
ty
::
TraitStore
)
->
Block
<
'blk
,
'tcx
>
{
let
_
icx
=
push_ctxt
(
"closure::load_environment"
);
// Load a pointer to the closure data, skipping over the box header:
let
llcdata
=
at_box_body
(
bcx
,
cdata_ty
,
bcx
.fcx.llenv
.unwrap
());
// Store the pointer to closure data in an alloca for debug info because that's what the
// llvm.dbg.declare intrinsic expects
let
env_pointer_alloca
=
if
bcx
.sess
()
.opts.debuginfo
==
FullDebugInfo
{
let
alloc
=
alloc_ty
(
bcx
,
ty
::
mk_mut_ptr
(
bcx
.tcx
(),
cdata_ty
),
"__debuginfo_env_ptr"
);
Store
(
bcx
,
llcdata
,
alloc
);
Some
(
alloc
)
}
else
{
None
};
// Populate the upvars from the environment
let
mut
i
=
0u
;
for
freevar
in
freevars
.iter
()
{
let
mut
upvarptr
=
GEPi
(
bcx
,
llcdata
,
&
[
0u
,
i
]);
let
captured_by_ref
=
match
store
{
ty
::
RegionTraitStore
(
..
)
=>
{
upvarptr
=
Load
(
bcx
,
upvarptr
);
true
}
ty
::
UniqTraitStore
=>
false
};
let
def_id
=
freevar
.def
.def_id
();
bcx
.fcx.llupvars
.borrow_mut
()
.insert
(
def_id
.node
,
upvarptr
);
if
let
Some
(
env_pointer_alloca
)
=
env_pointer_alloca
{
debuginfo
::
create_captured_var_metadata
(
bcx
,
def_id
.node
,
env_pointer_alloca
,
i
,
captured_by_ref
,
freevar
.span
);
}
i
+=
1u
;
}
bcx
}
fn
load_unboxed_closure_environment
<
'blk
,
'tcx
>
(
bcx
:
Block
<
'blk
,
'tcx
>
,
...
...
@@ -281,7 +37,7 @@ fn load_unboxed_closure_environment<'blk, 'tcx>(
freevar_mode
:
ast
::
CaptureClause
,
freevars
:
&
[
ty
::
Freevar
])
->
Block
<
'blk
,
'tcx
>
{
let
_
icx
=
push_ctxt
(
"closure::load_environment"
);
let
_
icx
=
push_ctxt
(
"closure::load_
unboxed_closure_
environment"
);
// Special case for small by-value selfs.
let
closure_id
=
ast_util
::
local_def
(
bcx
.fcx.id
);
...
...
@@ -341,17 +97,9 @@ fn load_unboxed_closure_environment<'blk, 'tcx>(
bcx
}
fn
fill_fn_pair
(
bcx
:
Block
,
pair
:
ValueRef
,
llfn
:
ValueRef
,
llenvptr
:
ValueRef
)
{
Store
(
bcx
,
llfn
,
GEPi
(
bcx
,
pair
,
&
[
0u
,
abi
::
FAT_PTR_ADDR
]));
let
llenvptr
=
PointerCast
(
bcx
,
llenvptr
,
Type
::
i8p
(
bcx
.ccx
()));
Store
(
bcx
,
llenvptr
,
GEPi
(
bcx
,
pair
,
&
[
0u
,
abi
::
FAT_PTR_EXTRA
]));
}
#[derive(PartialEq)]
pub
enum
ClosureKind
<
'tcx
>
{
NotClosure
,
// See load_environment.
BoxedClosure
(
Ty
<
'tcx
>
,
ty
::
TraitStore
),
// See load_unboxed_closure_environment.
UnboxedClosure
(
ast
::
CaptureClause
)
}
...
...
@@ -379,9 +127,6 @@ pub fn load<'blk>(self, bcx: Block<'blk, 'tcx>, arg_scope: ScopeId)
match
self
.kind
{
NotClosure
=>
bcx
,
BoxedClosure
(
cdata_ty
,
store
)
=>
{
load_environment
(
bcx
,
cdata_ty
,
self
.freevars
,
store
)
}
UnboxedClosure
(
freevar_mode
)
=>
{
load_unboxed_closure_environment
(
bcx
,
arg_scope
,
freevar_mode
,
self
.freevars
)
}
...
...
@@ -389,67 +134,6 @@ pub fn load<'blk>(self, bcx: Block<'blk, 'tcx>, arg_scope: ScopeId)
}
}
/// Translates the body of a closure expression.
///
/// - `store`
/// - `decl`
/// - `body`
/// - `id`: The id of the closure expression.
/// - `cap_clause`: information about captured variables, if any.
/// - `dest`: where to write the closure value, which must be a
/// (fn ptr, env) pair
pub
fn
trans_expr_fn
<
'blk
,
'tcx
>
(
bcx
:
Block
<
'blk
,
'tcx
>
,
store
:
ty
::
TraitStore
,
decl
:
&
ast
::
FnDecl
,
body
:
&
ast
::
Block
,
id
:
ast
::
NodeId
,
dest
:
expr
::
Dest
)
->
Block
<
'blk
,
'tcx
>
{
let
_
icx
=
push_ctxt
(
"closure::trans_expr_fn"
);
let
dest_addr
=
match
dest
{
expr
::
SaveIn
(
p
)
=>
p
,
expr
::
Ignore
=>
{
return
bcx
;
// closure construction is non-side-effecting
}
};
let
ccx
=
bcx
.ccx
();
let
tcx
=
bcx
.tcx
();
let
fty
=
node_id_type
(
bcx
,
id
);
let
s
=
tcx
.map
.with_path
(
id
,
|
path
|
{
mangle_internal_name_by_path_and_seq
(
path
,
"closure"
)
});
let
llfn
=
decl_internal_rust_fn
(
ccx
,
fty
,
&
s
[]);
// set an inline hint for all closures
set_inline_hint
(
llfn
);
let
freevar_mode
=
tcx
.capture_mode
(
id
);
let
freevars
:
Vec
<
ty
::
Freevar
>
=
ty
::
with_freevars
(
tcx
,
id
,
|
fv
|
fv
.iter
()
.map
(|
&
fv
|
fv
)
.collect
());
let
ClosureResult
{
llbox
,
cdata_ty
,
bcx
}
=
build_closure
(
bcx
,
freevar_mode
,
&
freevars
);
trans_closure
(
ccx
,
decl
,
body
,
llfn
,
bcx
.fcx.param_substs
,
id
,
&
[],
ty
::
erase_late_bound_regions
(
ccx
.tcx
(),
&
ty
::
ty_fn_ret
(
fty
)),
ty
::
ty_fn_abi
(
fty
),
ClosureEnv
::
new
(
&
freevars
[],
BoxedClosure
(
cdata_ty
,
store
)));
fill_fn_pair
(
bcx
,
dest_addr
,
llfn
,
llbox
);
bcx
}
/// Returns the LLVM function declaration for an unboxed closure, creating it
/// if necessary. If the ID does not correspond to a closure ID, returns None.
pub
fn
get_or_create_declaration_if_unboxed_closure
<
'a
,
'tcx
>
(
ccx
:
&
CrateContext
<
'a
,
'tcx
>
,
...
...
src/librustc_trans/trans/debuginfo.rs
浏览文件 @
e0eb3ccb
...
...
@@ -552,7 +552,6 @@ fn get_unique_type_id_of_closure_type<'a>(&mut self,
unique_type_id
:
&
mut
String
)
{
let
ty
::
ClosureTy
{
unsafety
,
onceness
,
store
,
ref
bounds
,
ref
sig
,
abi
:
_
}
=
closure_ty
;
...
...
@@ -564,15 +563,7 @@ fn get_unique_type_id_of_closure_type<'a>(&mut self,
unique_type_id
.push_str
(
"once "
);
}
match
store
{
ty
::
UniqTraitStore
=>
unique_type_id
.push_str
(
"~|"
),
ty
::
RegionTraitStore
(
_
,
ast
::
MutMutable
)
=>
{
unique_type_id
.push_str
(
"&mut|"
)
}
ty
::
RegionTraitStore
(
_
,
ast
::
MutImmutable
)
=>
{
unique_type_id
.push_str
(
"&|"
)
}
};
unique_type_id
.push_str
(
"|"
);
let
sig
=
ty
::
erase_late_bound_regions
(
cx
.tcx
(),
sig
);
...
...
src/librustc_trans/trans/expr.rs
浏览文件 @
e0eb3ccb
...
...
@@ -65,7 +65,6 @@
use
trans
::
type_
::
Type
;
use
syntax
::{
ast
,
ast_util
,
codemap
};
use
syntax
::
print
::
pprust
::{
expr_to_string
};
use
syntax
::
ptr
::
P
;
use
syntax
::
parse
::
token
;
use
std
::
rc
::
Rc
;
...
...
@@ -1102,17 +1101,7 @@ fn make_field(field_name: &str, expr: P<ast::Expr>) -> ast::Field {
// closure or an older, legacy style closure. Store this
// into a variable to ensure the the RefCell-lock is
// released before we recurse.
let
is_unboxed_closure
=
bcx
.tcx
()
.unboxed_closures
.borrow
()
.contains_key
(
&
ast_util
::
local_def
(
expr
.id
));
if
is_unboxed_closure
{
closure
::
trans_unboxed_closure
(
bcx
,
&**
decl
,
&**
body
,
expr
.id
,
dest
)
}
else
{
let
expr_ty
=
expr_ty
(
bcx
,
expr
);
let
store
=
ty
::
ty_closure_store
(
expr_ty
);
debug!
(
"translating block function {} with type {}"
,
expr_to_string
(
expr
),
expr_ty
.repr
(
tcx
));
closure
::
trans_expr_fn
(
bcx
,
store
,
&**
decl
,
&**
body
,
expr
.id
,
dest
)
}
closure
::
trans_unboxed_closure
(
bcx
,
&**
decl
,
&**
body
,
expr
.id
,
dest
)
}
ast
::
ExprCall
(
ref
f
,
ref
args
)
=>
{
if
bcx
.tcx
()
.is_method_call
(
expr
.id
)
{
...
...
src/librustc_trans/trans/type_.rs
浏览文件 @
e0eb3ccb
...
...
@@ -227,14 +227,6 @@ pub fn opaque_vec(ccx: &CrateContext) -> Type {
Type
::
vec
(
ccx
,
&
Type
::
i8
(
ccx
))
}
// The box pointed to by @T.
pub
fn
at_box
(
ccx
:
&
CrateContext
,
ty
:
Type
)
->
Type
{
Type
::
struct_
(
ccx
,
&
[
ccx
.int_type
(),
Type
::
glue_fn
(
ccx
,
Type
::
i8p
(
ccx
))
.ptr_to
(),
Type
::
i8p
(
ccx
),
Type
::
i8p
(
ccx
),
ty
],
false
)
}
pub
fn
vtable_ptr
(
ccx
:
&
CrateContext
)
->
Type
{
Type
::
glue_fn
(
ccx
,
Type
::
i8p
(
ccx
))
.ptr_to
()
.ptr_to
()
}
...
...
src/librustc_typeck/astconv.rs
浏览文件 @
e0eb3ccb
...
...
@@ -1459,7 +1459,6 @@ pub fn ty_of_closure<'tcx>(
unsafety
:
ast
::
Unsafety
,
onceness
:
ast
::
Onceness
,
bounds
:
ty
::
ExistentialBounds
<
'tcx
>
,
store
:
ty
::
TraitStore
,
decl
:
&
ast
::
FnDecl
,
abi
:
abi
::
Abi
,
expected_sig
:
Option
<
ty
::
FnSig
<
'tcx
>>
)
...
...
@@ -1510,7 +1509,6 @@ pub fn ty_of_closure<'tcx>(
ty
::
ClosureTy
{
unsafety
:
unsafety
,
onceness
:
onceness
,
store
:
store
,
bounds
:
bounds
,
abi
:
abi
,
sig
:
ty
::
Binder
(
ty
::
FnSig
{
inputs
:
input_tys
,
...
...
src/librustc_typeck/check/closure.rs
浏览文件 @
e0eb3ccb
...
...
@@ -96,7 +96,6 @@ fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
//
// FIXME(pcwalton): Refactor this API.
ty
::
region_existential_bound
(
ty
::
ReStatic
),
ty
::
RegionTraitStore
(
ty
::
ReStatic
,
ast
::
MutImmutable
),
decl
,
abi
::
RustCall
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录