use a more conservative inhabitableness rule

This is a [breaking-change] from 1.15, because this used to compile:

```Rust
enum Void {}
fn foo(x: &Void) {
    match x {}
}
```
This commit is contained in:
Ariel Ben-Yehuda 2017-02-23 22:46:19 +02:00
parent a84eb95a7d
commit 87e544bca5
3 changed files with 19 additions and 9 deletions

View file

@ -182,7 +182,12 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
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) {
let scrutinee_is_uninhabited = if self.tcx.sess.features.borrow().never_type {
pat_ty.is_uninhabited_from(module, self.tcx)
} else {
self.conservative_is_uninhabited(pat_ty)
};
if !scrutinee_is_uninhabited {
// 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 {} \
@ -208,6 +213,15 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
})
}
fn conservative_is_uninhabited(&self, scrutinee_ty: Ty<'tcx>) -> bool {
// "rustc-1.0-style" uncontentious uninhabitableness check
match scrutinee_ty.sty {
ty::TyNever => true,
ty::TyAdt(def, _) => def.variants.is_empty(),
_ => false
}
}
fn check_irrefutable(&self, pat: &Pat, is_fn_arg: bool) {
let origin = if is_fn_arg {
"function argument"

View file

@ -19,13 +19,13 @@ fn main() {
};
let x: &Void = unsafe { std::mem::uninitialized() };
let _ = match x {}; // okay
let _ = match x {}; //~ ERROR non-exhaustive
let x: (Void,) = unsafe { std::mem::uninitialized() };
let _ = match x {}; // okay
let _ = match x {}; //~ ERROR non-exhaustive
let x: [Void; 1] = unsafe { std::mem::uninitialized() };
let _ = match x {}; // okay
let _ = match x {}; //~ ERROR non-exhaustive
let x: &[Void] = unsafe { std::mem::uninitialized() };
let _ = match x { //~ ERROR non-exhaustive

View file

@ -16,14 +16,10 @@ 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),
Some(_) => {}
}
}