about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-02-23 22:46:19 +0200
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-02-23 22:46:22 +0200
commit87e544bca5ae1bd187f11239abcab1f73c836049 (patch)
tree4f8a4cbb3a2417928423467c5bf0eec7ff7c64ac
parenta84eb95a7db9460d317eeef62da106459a346f0b (diff)
downloadrust-87e544bca5ae1bd187f11239abcab1f73c836049.tar.gz
rust-87e544bca5ae1bd187f11239abcab1f73c836049.zip
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 {}
}
```
-rw-r--r--src/librustc_const_eval/check_match.rs16
-rw-r--r--src/test/compile-fail/uninhabited-matches-feature-gated.rs6
-rw-r--r--src/test/run-pass/issue-38972.rs6
3 files changed, 19 insertions, 9 deletions
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index e5362a70e53..9b30946c0be 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -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"
diff --git a/src/test/compile-fail/uninhabited-matches-feature-gated.rs b/src/test/compile-fail/uninhabited-matches-feature-gated.rs
index 68781a407cc..0c3ea53a903 100644
--- a/src/test/compile-fail/uninhabited-matches-feature-gated.rs
+++ b/src/test/compile-fail/uninhabited-matches-feature-gated.rs
@@ -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
diff --git a/src/test/run-pass/issue-38972.rs b/src/test/run-pass/issue-38972.rs
index 9c440503214..d5df84e0fb0 100644
--- a/src/test/run-pass/issue-38972.rs
+++ b/src/test/run-pass/issue-38972.rs
@@ -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(_) => {}
     }
 }