Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
a84eb95a
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,发现更多精彩内容 >>
提交
a84eb95a
编写于
2月 20, 2017
作者:
A
Ariel Ben-Yehuda
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
check_match: don't treat privately uninhabited types as uninhabited
Fixes #38972.
上级
306035c2
变更
5
显示空白变更内容
内联
并排
Showing
5 changed file
with
144 addition
and
37 deletion
+144
-37
src/librustc_const_eval/_match.rs
src/librustc_const_eval/_match.rs
+62
-30
src/librustc_const_eval/check_match.rs
src/librustc_const_eval/check_match.rs
+20
-0
src/test/compile-fail/match-privately-empty.rs
src/test/compile-fail/match-privately-empty.rs
+30
-0
src/test/compile-fail/uninhabited-matches-feature-gated.rs
src/test/compile-fail/uninhabited-matches-feature-gated.rs
+3
-7
src/test/run-pass/issue-38972.rs
src/test/run-pass/issue-38972.rs
+29
-0
未找到文件。
src/librustc_const_eval/_match.rs
浏览文件 @
a84eb95a
...
...
@@ -196,6 +196,28 @@ fn lower_byte_str_pattern<'p>(&mut self, pat: &'p Pattern<'tcx>) -> Vec<&'p Patt
}
})
.clone
()
}
fn
is_uninhabited
(
&
self
,
ty
:
Ty
<
'tcx
>
)
->
bool
{
if
self
.tcx.sess.features
.borrow
()
.never_type
{
ty
.is_uninhabited_from
(
self
.module
,
self
.tcx
)
}
else
{
false
}
}
fn
is_variant_uninhabited
(
&
self
,
variant
:
&
'tcx
ty
::
VariantDef
,
substs
:
&
'tcx
ty
::
subst
::
Substs
<
'tcx
>
)
->
bool
{
if
self
.tcx.sess.features
.borrow
()
.never_type
{
let
forest
=
variant
.uninhabited_from
(
&
mut
FxHashMap
::
default
(),
self
.tcx
,
substs
,
AdtKind
::
Enum
);
forest
.contains
(
self
.tcx
,
self
.module
)
}
else
{
false
}
}
}
#[derive(Clone,
Debug,
PartialEq)]
...
...
@@ -379,48 +401,32 @@ fn apply_constructor<'a>(
fn
all_constructors
<
'a
,
'tcx
:
'a
>
(
cx
:
&
mut
MatchCheckCtxt
<
'a
,
'tcx
>
,
pcx
:
PatternContext
<
'tcx
>
)
->
Vec
<
Constructor
>
{
let
check_inhabited
=
cx
.tcx.sess.features
.borrow
()
.never_type
;
debug!
(
"all_constructors({:?})"
,
pcx
.ty
);
match
pcx
.ty.sty
{
ty
::
TyBool
=>
[
true
,
false
]
.iter
()
.map
(|
b
|
ConstantValue
(
ConstVal
::
Bool
(
*
b
)))
.collect
(),
ty
::
TySlice
(
ref
sub_ty
)
=>
{
if
sub_ty
.is_uninhabited_from
(
cx
.module
,
cx
.tcx
)
&&
check_inhabited
{
if
cx
.is_uninhabited
(
sub_ty
)
{
vec!
[
Slice
(
0
)]
}
else
{
(
0
..
pcx
.max_slice_length
+
1
)
.map
(|
length
|
Slice
(
length
))
.collect
()
}
}
ty
::
TyArray
(
ref
sub_ty
,
length
)
=>
{
if
length
==
0
||
!
(
sub_ty
.is_uninhabited_from
(
cx
.module
,
cx
.tcx
)
&&
check_inhabited
)
{
vec!
[
Slice
(
length
)]
}
else
{
if
length
>
0
&&
cx
.is_uninhabited
(
sub_ty
)
{
vec!
[]
}
else
{
vec!
[
Slice
(
length
)]
}
}
ty
::
TyAdt
(
def
,
substs
)
if
def
.is_enum
()
&&
def
.variants
.len
()
!=
1
=>
{
def
.variants
.iter
()
.filter_map
(|
v
|
{
let
mut
visited
=
FxHashMap
::
default
();
let
forest
=
v
.uninhabited_from
(
&
mut
visited
,
cx
.tcx
,
substs
,
AdtKind
::
Enum
);
if
forest
.contains
(
cx
.tcx
,
cx
.module
)
&&
check_inhabited
{
None
}
else
{
Some
(
Variant
(
v
.did
))
}
})
.collect
()
def
.variants
.iter
()
.filter
(|
v
|
!
cx
.is_variant_uninhabited
(
v
,
substs
))
.map
(|
v
|
Variant
(
v
.did
))
.collect
()
}
_
=>
{
if
pcx
.ty
.is_uninhabited_from
(
cx
.module
,
cx
.tcx
)
&&
check_inhabited
{
if
cx
.is_uninhabited
(
pcx
.ty
)
{
vec!
[]
}
else
{
vec!
[
Single
]
...
...
@@ -564,7 +570,6 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
assert
!
(
rows
.iter
()
.all
(|
r
|
r
.len
()
==
v
.len
()));
let
pcx
=
PatternContext
{
ty
:
rows
.iter
()
.map
(|
r
|
r
[
0
]
.ty
)
.find
(|
ty
|
!
ty
.references_error
())
.unwrap_or
(
v
[
0
]
.ty
),
...
...
@@ -590,7 +595,6 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
let
missing_ctors
:
Vec
<
Constructor
>
=
all_ctors
.iter
()
.filter
(|
c
|
{
!
used_ctors
.contains
(
*
c
)
})
.cloned
()
.collect
();
debug!
(
"missing_ctors = {:?}"
,
missing_ctors
);
// `missing_ctors` is the set of constructors from the same type as the
// first column of `matrix` that are matched only by wildcard patterns
...
...
@@ -599,8 +603,23 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
// Therefore, if there is some pattern that is unmatched by `matrix`,
// it will still be unmatched if the first constructor is replaced by
// any of the constructors in `missing_ctors`
if
missing_ctors
.is_empty
()
{
//
// However, if our scrutinee is *privately* an empty enum, we
// must treat it as though it had an "unknown" constructor (in
// that case, all other patterns obviously can't be variants)
// to avoid exposing its emptyness. See the `match_privately_empty`
// test for details.
//
// FIXME: currently the only way I know of something can
// be a privately-empty enum is when the never_type
// feature flag is not present, so this is only
// needed for that case.
let
is_privately_empty
=
all_ctors
.is_empty
()
&&
!
cx
.is_uninhabited
(
pcx
.ty
);
debug!
(
"missing_ctors={:?} is_privately_empty={:?}"
,
missing_ctors
,
is_privately_empty
);
if
missing_ctors
.is_empty
()
&&
!
is_privately_empty
{
all_ctors
.into_iter
()
.map
(|
c
|
{
is_useful_specialized
(
cx
,
matrix
,
v
,
c
.clone
(),
pcx
.ty
,
witness
)
})
.find
(|
result
|
result
.is_useful
())
.unwrap_or
(
NotUseful
)
...
...
@@ -649,6 +668,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
lty
:
Ty
<
'tcx
>
,
witness
:
WitnessPreference
)
->
Usefulness
<
'tcx
>
{
debug!
(
"is_useful_specialized({:?}, {:?}, {:?})"
,
v
,
ctor
,
lty
);
let
sub_pat_tys
=
constructor_sub_pattern_tys
(
cx
,
&
ctor
,
lty
);
let
wild_patterns_owned
:
Vec
<
_
>
=
sub_pat_tys
.iter
()
.map
(|
ty
|
{
Pattern
{
...
...
@@ -754,7 +774,19 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
ty
::
TyRef
(
_
,
ref
ty_and_mut
)
=>
vec!
[
ty_and_mut
.ty
],
ty
::
TyAdt
(
adt
,
substs
)
=>
{
adt
.variants
[
ctor
.variant_index_for_adt
(
adt
)]
.fields
.iter
()
.map
(|
field
|
{
let
is_visible
=
adt
.is_enum
()
||
field
.vis
.is_accessible_from
(
cx
.module
,
cx
.tcx
);
if
is_visible
{
field
.ty
(
cx
.tcx
,
substs
)
}
else
{
// Treat all non-visible fields as nil. They
// can't appear in any other pattern from
// this match (because they are private),
// so their type does not matter - but
// we don't want to know they are
// uninhabited.
cx
.tcx
.mk_nil
()
}
})
.collect
()
}
_
=>
vec!
[],
...
...
src/librustc_const_eval/check_match.rs
浏览文件 @
a84eb95a
...
...
@@ -177,6 +177,26 @@ fn check_match(
// Fourth, check for unreachable arms.
check_arms
(
cx
,
&
inlined_arms
,
source
);
// Then, if the match has no arms, check whether the scrutinee
// is uninhabited.
let
pat_ty
=
self
.tables
.node_id_to_type
(
scrut
.id
);
let
module
=
self
.tcx.hir
.local_def_id
(
self
.tcx.hir
.get_module_parent
(
scrut
.id
));
if
inlined_arms
.is_empty
()
{
if
!
pat_ty
.is_uninhabited_from
(
module
,
self
.tcx
)
{
// We know the type is inhabited, so this must be wrong
let
mut
err
=
create_e0004
(
self
.tcx.sess
,
scrut
.span
,
format!
(
"non-exhaustive patterns: type {}
\
is non-empty"
,
pat_ty
));
span_help!
(
&
mut
err
,
scrut
.span
,
"Please ensure that all possible cases are being handled;
\
possibly adding wildcards or more match arms."
);
err
.emit
();
}
// If the type *is* uninhabited, it's vacuously exhaustive
return
;
}
let
matrix
:
Matrix
=
inlined_arms
.iter
()
.filter
(|
&&
(
_
,
guard
)|
guard
.is_none
())
...
...
src/test/compile-fail/match-privately-empty.rs
0 → 100644
浏览文件 @
a84eb95a
// Copyright 2017 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(never_type)]
mod
private
{
pub
struct
Private
{
_
bot
:
!
,
pub
misc
:
bool
,
}
pub
const
DATA
:
Option
<
Private
>
=
None
;
}
fn
main
()
{
match
private
::
DATA
{
//~^ ERROR non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered
None
=>
{}
Some
(
private
::
Private
{
misc
:
false
,
..
})
=>
{}
}
}
src/test/compile-fail/uninhabited-matches-feature-gated.rs
浏览文件 @
a84eb95a
...
...
@@ -19,16 +19,13 @@ fn main() {
};
let
x
:
&
Void
=
unsafe
{
std
::
mem
::
uninitialized
()
};
let
_
=
match
x
{};
//~^ ERROR non-exhaustive
let
_
=
match
x
{};
// okay
let
x
:
(
Void
,)
=
unsafe
{
std
::
mem
::
uninitialized
()
};
let
_
=
match
x
{};
//~^ ERROR non-exhaustive
let
_
=
match
x
{};
// okay
let
x
:
[
Void
;
1
]
=
unsafe
{
std
::
mem
::
uninitialized
()
};
let
_
=
match
x
{};
//~^ ERROR non-exhaustive
let
_
=
match
x
{};
// okay
let
x
:
&
[
Void
]
=
unsafe
{
std
::
mem
::
uninitialized
()
};
let
_
=
match
x
{
//~ ERROR non-exhaustive
...
...
@@ -47,4 +44,3 @@ fn main() {
let
Ok
(
x
)
=
x
;
//~^ ERROR refutable
}
src/test/run-pass/issue-38972.rs
0 → 100644
浏览文件 @
a84eb95a
// Copyright 2017 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.
// This issue tracks a regression (a new warning) without
// feature(never_type). When we make that the default, please
// remove this test.
enum
Foo
{
}
fn
make_foo
()
->
Option
<
Foo
>
{
None
}
fn
use_foo
(
v
:
&
Foo
)
->
!
{
match
v
{
}
}
#[deny(warnings)]
fn
main
()
{
match
make_foo
()
{
None
=>
{},
Some
(
ref
v
)
=>
use_foo
(
v
),
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录