From 379ba8857bb32f3aa443bf17753f65d20d425e98 Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Tue, 11 Sep 2018 12:41:56 +0100
Subject: [PATCH] Check for uninhabitedness instead of never

---
 src/librustc/cfg/construct.rs                 |  3 +-
 src/librustc/middle/liveness.rs               |  6 ++--
 src/librustc/ty/sty.rs                        | 11 ++++++
 src/librustc_codegen_llvm/debuginfo/mod.rs    |  3 +-
 src/librustc_codegen_llvm/declare.rs          |  3 +-
 src/librustc_codegen_llvm/mir/block.rs        |  2 +-
 .../borrow_check/nll/type_check/mod.rs        |  3 +-
 src/librustc_mir/build/expr/into.rs           |  4 +--
 src/librustc_mir/hair/pattern/check_match.rs  | 11 +-----
 src/test/debuginfo/nil-enum.rs                | 34 ++++---------------
 10 files changed, 27 insertions(+), 53 deletions(-)

diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 1b97480920321..bbb2cd4592552 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -415,8 +415,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             args: I) -> CFGIndex {
         let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
         let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
-        // FIXME(canndrew): This is_never should probably be an is_uninhabited.
-        if self.tables.expr_ty(call_expr).is_never() {
+        if self.tables.expr_ty(call_expr).conservative_is_uninhabited() {
             self.add_unreachable_node()
         } else {
             ret
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index c34a0a654e6a9..a85e4ce4ea669 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -1122,8 +1122,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
           }
 
           hir::ExprKind::Call(ref f, ref args) => {
-            // FIXME(canndrew): This is_never should really be an is_uninhabited
-            let succ = if self.tables.expr_ty(expr).is_never() {
+            let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited() {
                 self.s.exit_ln
             } else {
                 succ
@@ -1133,8 +1132,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
           }
 
           hir::ExprKind::MethodCall(.., ref args) => {
-            // FIXME(canndrew): This is_never should really be an is_uninhabited
-            let succ = if self.tables.expr_ty(expr).is_never() {
+            let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited() {
                 self.s.exit_ln
             } else {
                 succ
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 962b115f1877a..01c48db2c4723 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -1472,6 +1472,17 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
         }
     }
 
+    pub fn conservative_is_uninhabited(&self) -> bool {
+        // Checks whether a type is definitely uninhabited. This is
+        // conservative: for some types that are uninhabited we return `false`,
+        // but we only return `true` for types that are definitely uninhabited.
+        match self.sty {
+            ty::Never => true,
+            ty::Adt(def, _) => def.variants.is_empty(),
+            _ => false
+        }
+    }
+
     pub fn is_primitive(&self) -> bool {
         match self.sty {
             Bool | Char | Int(_) | Uint(_) | Float(_) => true,
diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs
index 99919a940b405..41978f99c243f 100644
--- a/src/librustc_codegen_llvm/debuginfo/mod.rs
+++ b/src/librustc_codegen_llvm/debuginfo/mod.rs
@@ -279,7 +279,8 @@ pub fn create_function_debug_context(
         }
         None => {}
     };
-    if cx.layout_of(sig.output()).abi == ty::layout::Abi::Uninhabited {
+    // Tell LLVM that functions that return uninhabited types will not return.
+    if sig.output().conservative_is_uninhabited() {
         flags = flags | DIFlags::FlagNoReturn;
     }
 
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index 5e743ac51bc61..0cb01699412f5 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -23,7 +23,6 @@
 use llvm;
 use llvm::AttributePlace::Function;
 use rustc::ty::{self, Ty};
-use rustc::ty::layout::{self, LayoutOf};
 use rustc::session::config::Sanitizer;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_target::spec::PanicStrategy;
@@ -137,7 +136,7 @@ pub fn declare_fn(
     let fty = FnType::new(cx, sig, &[]);
     let llfn = declare_raw_fn(cx, name, fty.llvm_cconv(), fty.llvm_type(cx));
 
-    if cx.layout_of(sig.output()).abi == layout::Abi::Uninhabited {
+    if sig.output().conservative_is_uninhabited() {
         llvm::Attribute::NoReturn.apply_llfn(Function, llfn);
     }
 
diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs
index a534b4e478fb7..5dcdc8a3a68a0 100644
--- a/src/librustc_codegen_llvm/mir/block.rs
+++ b/src/librustc_codegen_llvm/mir/block.rs
@@ -457,7 +457,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
                         // we can do what we like. Here, we declare that transmuting
                         // into an uninhabited type is impossible, so anything following
                         // it must be unreachable.
-                        assert_eq!(bx.cx.layout_of(sig.output()).abi, layout::Abi::Uninhabited);
+                        assert!(sig.output().conservative_is_uninhabited());
                         bx.unreachable();
                     }
                     return;
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 82158acc9e6ab..d937060b20131 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -1173,8 +1173,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 }
             }
             None => {
-                // FIXME(canndrew): This is_never should probably be an is_uninhabited
-                if !sig.output().is_never() {
+                if !sig.output().conservative_is_uninhabited() {
                     span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
                 }
             }
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 59ebb7703ff61..7c4fdbd1350da 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -265,8 +265,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 exit_block.unit()
             }
             ExprKind::Call { ty, fun, args } => {
-                // FIXME(canndrew): This is_never should probably be an is_uninhabited
-                let diverges = expr.ty.is_never();
                 let intrinsic = match ty.sty {
                     ty::FnDef(def_id, _) => {
                         let f = ty.fn_sig(this.hir.tcx());
@@ -320,7 +318,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             func: fun,
                             args,
                             cleanup: Some(cleanup),
-                            destination: if diverges {
+                            destination: if expr.ty.conservative_is_uninhabited() {
                                 None
                             } else {
                                 Some((destination.clone(), success))
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index bf878145e1fb9..4479056a20ac6 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -229,7 +229,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
                 let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns {
                     self.tcx.is_ty_uninhabited_from(module, pat_ty)
                 } else {
-                    self.conservative_is_uninhabited(pat_ty)
+                    pat_ty.conservative_is_uninhabited()
                 };
                 if !scrutinee_is_uninhabited {
                     // We know the type is inhabited, so this must be wrong
@@ -257,15 +257,6 @@ 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::Never => true,
-            ty::Adt(def, _) => def.variants.is_empty(),
-            _ => false
-        }
-    }
-
     fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) {
         let module = self.tcx.hir.get_module_parent(pat.id);
         MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
diff --git a/src/test/debuginfo/nil-enum.rs b/src/test/debuginfo/nil-enum.rs
index 94377421c0b0c..7bb7efd7a519d 100644
--- a/src/test/debuginfo/nil-enum.rs
+++ b/src/test/debuginfo/nil-enum.rs
@@ -1,45 +1,23 @@
-// Copyright 2013-2014 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.
-
-// LLDB can't handle zero-sized values
+// LLDB can't handle zero-sized values.
 // ignore-lldb
 
-
 // compile-flags:-g
 // gdb-command:run
 
-// gdb-command:print first
+// gdb-command:print *first
 // gdbg-check:$1 = {<No data fields>}
 // gdbr-check:$1 = <error reading variable>
 
-// gdb-command:print second
-// gdbg-check:$2 = {<No data fields>}
-// gdbr-check:$2 = <error reading variable>
-
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
-enum ANilEnum {}
-enum AnotherNilEnum {}
+enum Void {}
 
-// This test relies on gdbg printing the string "{<No data fields>}" for empty
-// structs (which may change some time)
-// The error from gdbr is expected since nil enums are not supposed to exist.
 fn main() {
-    unsafe {
-        let first: ANilEnum = ::std::mem::zeroed();
-        let second: AnotherNilEnum = ::std::mem::zeroed();
+    let first: *const Void = 1 as *const _;
 
-        zzz(); // #break
-    }
+    zzz(); // #break
 }
 
-fn zzz() {()}
+fn zzz() {}