diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 0464b2f3454..1521b7a69ab 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -415,7 +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); - if self.tables.expr_ty(call_expr).conservative_is_uninhabited() { + if self.tables.expr_ty(call_expr).conservative_is_uninhabited(self.tcx) { self.add_unreachable_node() } else { ret diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 6e3db217d7a..2b9a44429a0 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1197,7 +1197,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprKind::Call(ref f, ref args) => { - let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited() { + let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited(self.ir.tcx) { self.s.exit_ln } else { succ @@ -1207,7 +1207,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprKind::MethodCall(.., ref args) => { - let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited() { + let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited(self.ir.tcx) { self.s.exit_ln } else { succ diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 037adb2c53c..152d9a32303 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1543,14 +1543,40 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - pub fn conservative_is_uninhabited(&self) -> bool { + pub fn conservative_is_uninhabited(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> 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 + ty::Adt(def, _) => { + // Any ADT is uninhabited if: + // (a) It has no variants (i.e. an empty `enum`); + // (b) Each of its variants (a single one in the case of a `struct`) has at least + // one uninhabited field. + def.variants.iter().all(|var| { + var.fields.iter().any(|field| { + tcx.type_of(field.did).conservative_is_uninhabited(tcx) + }) + }) + } + ty::Tuple(tys) => tys.iter().any(|ty| ty.conservative_is_uninhabited(tcx)), + ty::Array(ty, len) => { + match len.val.try_to_scalar() { + // If the array is definitely non-empty, it's uninhabited if + // the type of its elements is uninhabited. + Some(n) if !n.is_null() => ty.conservative_is_uninhabited(tcx), + _ => false + } + } + ty::Ref(..) => { + // Though references to uninhabited types are trivially uninhabited + // theoretically, null references are permitted in unsafe code (as + // long as the value is not dereferenced), so we treat all references + // as inhabited. + false + } + _ => false, } } 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 39019b35beb..aea48ead428 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1546,7 +1546,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } None => { - if !sig.output().conservative_is_uninhabited() { + if !sig.output().conservative_is_uninhabited(self.tcx()) { 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 77cb4820ba4..4b12562887a 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -331,7 +331,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { func: fun, args, cleanup: Some(cleanup), - destination: if expr.ty.conservative_is_uninhabited() { + destination: if expr.ty.conservative_is_uninhabited(this.hir.tcx()) { 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 1f1967eca6a..5a83fe76d7c 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -230,7 +230,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 { - pat_ty.conservative_is_uninhabited() + pat_ty.conservative_is_uninhabited(self.tcx) }; if !scrutinee_is_uninhabited { // We know the type is inhabited, so this must be wrong