Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
9235c9ff
R
Rust
项目概览
int
/
Rust
12 个月 前同步成功
通知
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,发现更多精彩内容 >>
提交
9235c9ff
编写于
5月 10, 2018
作者:
E
Eduard-Mihai Burtescu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
rustc: leave space for fields of uninhabited types to allow partial initialization.
上级
95d0b9e9
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
124 addition
and
46 deletion
+124
-46
src/librustc/ty/layout.rs
src/librustc/ty/layout.rs
+50
-23
src/librustc_target/abi/mod.rs
src/librustc_target/abi/mod.rs
+1
-12
src/librustc_trans/mir/operand.rs
src/librustc_trans/mir/operand.rs
+3
-6
src/librustc_trans/type_of.rs
src/librustc_trans/type_of.rs
+1
-1
src/test/run-pass/issue-46845.rs
src/test/run-pass/issue-46845.rs
+3
-1
src/test/run-pass/issue-49298.rs
src/test/run-pass/issue-49298.rs
+34
-0
src/test/run-pass/issue-50442.rs
src/test/run-pass/issue-50442.rs
+21
-0
src/test/run-pass/type-sizes.rs
src/test/run-pass/type-sizes.rs
+11
-3
未找到文件。
src/librustc/ty/layout.rs
浏览文件 @
9235c9ff
...
...
@@ -325,10 +325,6 @@ enum StructKind {
offsets
.len
(),
ty
);
}
if
field
.abi
==
Abi
::
Uninhabited
{
return
Ok
(
LayoutDetails
::
uninhabited
(
fields
.len
()));
}
if
field
.is_unsized
()
{
sized
=
false
;
}
...
...
@@ -451,6 +447,10 @@ enum StructKind {
}
}
if
sized
&&
fields
.iter
()
.any
(|
f
|
f
.abi
==
Abi
::
Uninhabited
)
{
abi
=
Abi
::
Uninhabited
;
}
Ok
(
LayoutDetails
{
variants
:
Variants
::
Single
{
index
:
0
},
fields
:
FieldPlacement
::
Arbitrary
{
...
...
@@ -497,7 +497,13 @@ enum StructKind {
// The never type.
ty
::
TyNever
=>
{
tcx
.intern_layout
(
LayoutDetails
::
uninhabited
(
0
))
tcx
.intern_layout
(
LayoutDetails
{
variants
:
Variants
::
Single
{
index
:
0
},
fields
:
FieldPlacement
::
Union
(
0
),
abi
:
Abi
::
Uninhabited
,
align
:
dl
.i8_align
,
size
:
Size
::
from_bytes
(
0
)
})
}
// Potentially-fat pointers.
...
...
@@ -711,27 +717,37 @@ enum StructKind {
}));
}
let
(
inh_first
,
inh_second
)
=
{
let
mut
inh_variants
=
(
0
..
variants
.len
())
.filter
(|
&
v
|
{
variants
[
v
]
.iter
()
.all
(|
f
|
f
.abi
!=
Abi
::
Uninhabited
)
// A variant is absent if it's uninhabited and only has ZST fields.
// Present uninhabited variants only require space for their fields,
// but *not* an encoding of the discriminant (e.g. a tag value).
// See issue #49298 for more details on the need to leave space
// for non-ZST uninhabited data (mostly partial initialization).
let
absent
=
|
fields
:
&
[
TyLayout
]|
{
let
uninhabited
=
fields
.iter
()
.any
(|
f
|
f
.abi
==
Abi
::
Uninhabited
);
let
is_zst
=
fields
.iter
()
.all
(|
f
|
f
.is_zst
());
uninhabited
&&
is_zst
};
let
(
present_first
,
present_second
)
=
{
let
mut
present_variants
=
(
0
..
variants
.len
())
.filter
(|
&
v
|
{
!
absent
(
&
variants
[
v
])
});
(
inh_variants
.next
(),
inh
_variants
.next
())
(
present_variants
.next
(),
present
_variants
.next
())
};
if
inh
_first
.is_none
()
{
// Uninhabited because it has no variants, or only
uninhabited
ones.
return
Ok
(
tcx
.intern_layout
(
LayoutDetails
::
uninhabited
(
0
)
));
if
present
_first
.is_none
()
{
// Uninhabited because it has no variants, or only
absent
ones.
return
tcx
.layout_raw
(
param_env
.and
(
tcx
.types.never
));
}
let
is_struct
=
!
def
.is_enum
()
||
// Only one variant is
inhabited
.
(
inh
_second
.is_none
()
&&
// Only one variant is
present
.
(
present
_second
.is_none
()
&&
// Representation optimizations are allowed.
!
def
.repr
.inhibit_enum_layout_opt
());
if
is_struct
{
// Struct, or univariant enum equivalent to a struct.
// (Typechecking will reject discriminant-sizing attrs.)
let
v
=
inh
_first
.unwrap
();
let
v
=
present
_first
.unwrap
();
let
kind
=
if
def
.is_enum
()
||
variants
[
v
]
.len
()
==
0
{
StructKind
::
AlwaysSized
}
else
{
...
...
@@ -773,7 +789,7 @@ enum StructKind {
// Find one non-ZST variant.
'variants
:
for
(
v
,
fields
)
in
variants
.iter
()
.enumerate
()
{
if
fields
.iter
()
.any
(|
f
|
f
.abi
==
Abi
::
Uninhabited
)
{
if
absent
(
fields
)
{
continue
'variants
;
}
for
f
in
fields
{
...
...
@@ -816,7 +832,7 @@ enum StructKind {
let
offset
=
st
[
i
]
.fields
.offset
(
field_index
)
+
offset
;
let
size
=
st
[
i
]
.size
;
let
abi
=
match
st
[
i
]
.abi
{
let
mut
abi
=
match
st
[
i
]
.abi
{
Abi
::
Scalar
(
_
)
=>
Abi
::
Scalar
(
niche
.clone
()),
Abi
::
ScalarPair
(
ref
first
,
ref
second
)
=>
{
// We need to use scalar_unit to reset the
...
...
@@ -833,6 +849,10 @@ enum StructKind {
_
=>
Abi
::
Aggregate
{
sized
:
true
},
};
if
st
.iter
()
.all
(|
v
|
v
.abi
==
Abi
::
Uninhabited
)
{
abi
=
Abi
::
Uninhabited
;
}
return
Ok
(
tcx
.intern_layout
(
LayoutDetails
{
variants
:
Variants
::
NicheFilling
{
dataful_variant
:
i
,
...
...
@@ -959,9 +979,6 @@ enum StructKind {
let
old_ity_size
=
min_ity
.size
();
let
new_ity_size
=
ity
.size
();
for
variant
in
&
mut
layout_variants
{
if
variant
.abi
==
Abi
::
Uninhabited
{
continue
;
}
match
variant
.fields
{
FieldPlacement
::
Arbitrary
{
ref
mut
offsets
,
..
}
=>
{
for
i
in
offsets
{
...
...
@@ -1055,6 +1072,11 @@ enum StructKind {
}
}
}
if
layout_variants
.iter
()
.all
(|
v
|
v
.abi
==
Abi
::
Uninhabited
)
{
abi
=
Abi
::
Uninhabited
;
}
tcx
.intern_layout
(
LayoutDetails
{
variants
:
Variants
::
Tagged
{
tag
,
...
...
@@ -1523,9 +1545,14 @@ fn for_variant(this: TyLayout<'tcx>, cx: C, variant_index: usize) -> TyLayout<'t
ty
::
TyAdt
(
def
,
_
)
=>
def
.variants
[
variant_index
]
.fields
.len
(),
_
=>
bug!
()
};
let
mut
details
=
LayoutDetails
::
uninhabited
(
fields
);
details
.variants
=
Variants
::
Single
{
index
:
variant_index
};
cx
.tcx
()
.intern_layout
(
details
)
let
tcx
=
cx
.tcx
();
tcx
.intern_layout
(
LayoutDetails
{
variants
:
Variants
::
Single
{
index
:
variant_index
},
fields
:
FieldPlacement
::
Union
(
fields
),
abi
:
Abi
::
Uninhabited
,
align
:
tcx
.data_layout.i8_align
,
size
:
Size
::
from_bytes
(
0
)
})
}
Variants
::
NicheFilling
{
ref
variants
,
..
}
|
...
...
src/librustc_target/abi/mod.rs
浏览文件 @
9235c9ff
...
...
@@ -761,17 +761,6 @@ pub fn scalar<C: HasDataLayout>(cx: C, scalar: Scalar) -> Self {
align
,
}
}
pub
fn
uninhabited
(
field_count
:
usize
)
->
Self
{
let
align
=
Align
::
from_bytes
(
1
,
1
)
.unwrap
();
LayoutDetails
{
variants
:
Variants
::
Single
{
index
:
0
},
fields
:
FieldPlacement
::
Union
(
field_count
),
abi
:
Abi
::
Uninhabited
,
align
,
size
:
Size
::
from_bytes
(
0
)
}
}
}
/// The details of the layout of a type, alongside the type itself.
...
...
@@ -826,10 +815,10 @@ pub fn is_unsized(&self) -> bool {
/// Returns true if the type is a ZST and not unsized.
pub
fn
is_zst
(
&
self
)
->
bool
{
match
self
.abi
{
Abi
::
Uninhabited
=>
true
,
Abi
::
Scalar
(
_
)
|
Abi
::
ScalarPair
(
..
)
|
Abi
::
Vector
{
..
}
=>
false
,
Abi
::
Uninhabited
=>
self
.size
.bytes
()
==
0
,
Abi
::
Aggregate
{
sized
}
=>
sized
&&
self
.size
.bytes
()
==
0
}
}
...
...
src/librustc_trans/mir/operand.rs
浏览文件 @
9235c9ff
...
...
@@ -223,12 +223,9 @@ pub fn extract_field(&self, bx: &Builder<'a, 'tcx>, i: usize) -> OperandRef<'tcx
let
offset
=
self
.layout.fields
.offset
(
i
);
let
mut
val
=
match
(
self
.val
,
&
self
.layout.abi
)
{
// If we're uninhabited, or the field is ZST, it has no data.
_
if
self
.layout.abi
==
layout
::
Abi
::
Uninhabited
||
field
.is_zst
()
=>
{
return
OperandRef
{
val
:
OperandValue
::
Immediate
(
C_undef
(
field
.immediate_llvm_type
(
bx
.cx
))),
layout
:
field
};
// If the field is ZST, it has no data.
_
if
field
.is_zst
()
=>
{
return
OperandRef
::
new_zst
(
bx
.cx
,
field
);
}
// Newtype of a scalar, scalar pair or vector.
...
...
src/librustc_trans/type_of.rs
浏览文件 @
9235c9ff
...
...
@@ -213,10 +213,10 @@ fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size)
impl
<
'tcx
>
LayoutLlvmExt
<
'tcx
>
for
TyLayout
<
'tcx
>
{
fn
is_llvm_immediate
(
&
self
)
->
bool
{
match
self
.abi
{
layout
::
Abi
::
Uninhabited
|
layout
::
Abi
::
Scalar
(
_
)
|
layout
::
Abi
::
Vector
{
..
}
=>
true
,
layout
::
Abi
::
ScalarPair
(
..
)
=>
false
,
layout
::
Abi
::
Uninhabited
|
layout
::
Abi
::
Aggregate
{
..
}
=>
self
.is_zst
()
}
}
...
...
src/test/run-pass/issue-46845.rs
浏览文件 @
9235c9ff
...
...
@@ -24,6 +24,7 @@ union Foo {
}
// If all the variants are uninhabited, however, the union should be uninhabited.
// NOTE(#49298) the union being uninhabited shouldn't change its size.
union
Bar
{
_
a
:
(
Never
,
u64
),
_
b
:
(
u64
,
Never
)
...
...
@@ -31,7 +32,8 @@ union Bar {
fn
main
()
{
assert_eq!
(
mem
::
size_of
::
<
Foo
>
(),
8
);
assert_eq!
(
mem
::
size_of
::
<
Bar
>
(),
0
);
// See the note on `Bar`'s definition for why this isn't `0`.
assert_eq!
(
mem
::
size_of
::
<
Bar
>
(),
8
);
let
f
=
[
Foo
{
a
:
42
},
Foo
{
a
:
10
}];
println!
(
"{}"
,
unsafe
{
f
[
0
]
.a
});
...
...
src/test/run-pass/issue-49298.rs
0 → 100644
浏览文件 @
9235c9ff
// Copyright 2018 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.
#![feature(test)]
extern
crate
test
;
enum
Void
{}
fn
main
()
{
let
mut
x
:
(
Void
,
usize
);
let
mut
y
=
42
;
x
.1
=
13
;
// Make sure `y` stays on the stack.
test
::
black_box
(
&
mut
y
);
// Check that the write to `x.1` did not overwrite `y`.
// Note that this doesn't fail with optimizations enabled,
// because we can't keep `x.1` on the stack, like we can `y`,
// as we can't borrow partially initialized variables.
assert_eq!
(
y
.to_string
(),
"42"
);
// Check that `(Void, usize)` has space for the `usize` field.
assert_eq!
(
std
::
mem
::
size_of
::
<
(
Void
,
usize
)
>
(),
std
::
mem
::
size_of
::
<
usize
>
());
}
src/test/run-pass/issue-50442.rs
0 → 100644
浏览文件 @
9235c9ff
// Copyright 2018 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.
enum
Void
{}
enum
Foo
{
A
(
i32
),
B
(
Void
),
C
(
i32
)
}
fn
main
()
{
let
_
foo
=
Foo
::
A
(
0
);
}
src/test/run-pass/type-sizes.rs
浏览文件 @
9235c9ff
...
...
@@ -68,9 +68,15 @@ enum EnumSingle5 {
A
=
42
as
u8
,
}
enum
NicheFilledEnumWithInhabitedVariant
{
enum
EnumWithMaybeUninhabitedVariant
<
T
>
{
A
(
&
'static
()),
B
(
&
'static
(),
!
),
B
(
&
'static
(),
T
),
C
,
}
enum
NicheFilledEnumWithAbsentVariant
{
A
(
&
'static
()),
B
((),
!
),
C
,
}
...
...
@@ -107,5 +113,7 @@ pub fn main() {
assert_eq!
(
size_of
::
<
EnumSingle4
>
(),
1
);
assert_eq!
(
size_of
::
<
EnumSingle5
>
(),
1
);
assert_eq!
(
size_of
::
<
NicheFilledEnumWithInhabitedVariant
>
(),
size_of
::
<&
'static
()
>
());
assert_eq!
(
size_of
::
<
EnumWithMaybeUninhabitedVariant
<!>>
(),
size_of
::
<
EnumWithMaybeUninhabitedVariant
<
()
>>
());
assert_eq!
(
size_of
::
<
NicheFilledEnumWithAbsentVariant
>
(),
size_of
::
<&
'static
()
>
());
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录