Skip to content

Commit 88afbf2

Browse files
committed
Make uninhabitedness checking more intelligent
1 parent 62b3590 commit 88afbf2

File tree

6 files changed

+35
-9
lines changed

6 files changed

+35
-9
lines changed

src/librustc/cfg/construct.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
415415
args: I) -> CFGIndex {
416416
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
417417
let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
418-
if self.tables.expr_ty(call_expr).conservative_is_uninhabited() {
418+
if self.tables.expr_ty(call_expr).conservative_is_uninhabited(self.tcx) {
419419
self.add_unreachable_node()
420420
} else {
421421
ret

src/librustc/middle/liveness.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,7 +1197,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
11971197
}
11981198

11991199
hir::ExprKind::Call(ref f, ref args) => {
1200-
let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited() {
1200+
let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited(self.ir.tcx) {
12011201
self.s.exit_ln
12021202
} else {
12031203
succ
@@ -1207,7 +1207,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
12071207
}
12081208

12091209
hir::ExprKind::MethodCall(.., ref args) => {
1210-
let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited() {
1210+
let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited(self.ir.tcx) {
12111211
self.s.exit_ln
12121212
} else {
12131213
succ

src/librustc/ty/sty.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,14 +1543,40 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
15431543
}
15441544
}
15451545

1546-
pub fn conservative_is_uninhabited(&self) -> bool {
1546+
pub fn conservative_is_uninhabited(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
15471547
// Checks whether a type is definitely uninhabited. This is
15481548
// conservative: for some types that are uninhabited we return `false`,
15491549
// but we only return `true` for types that are definitely uninhabited.
15501550
match self.sty {
15511551
ty::Never => true,
1552-
ty::Adt(def, _) => def.variants.is_empty(),
1553-
_ => false
1552+
ty::Adt(def, _) => {
1553+
// Any ADT is uninhabited if:
1554+
// (a) It has no variants (i.e. an empty `enum`);
1555+
// (b) Each of its variants (a single one in the case of a `struct`) has at least
1556+
// one uninhabited field.
1557+
def.variants.iter().all(|var| {
1558+
var.fields.iter().any(|field| {
1559+
tcx.type_of(field.did).conservative_is_uninhabited(tcx)
1560+
})
1561+
})
1562+
}
1563+
ty::Tuple(tys) => tys.iter().any(|ty| ty.conservative_is_uninhabited(tcx)),
1564+
ty::Array(ty, len) => {
1565+
match len.val.try_to_scalar() {
1566+
// If the array is definitely non-empty, it's uninhabited if
1567+
// the type of its elements is uninhabited.
1568+
Some(n) if !n.is_null() => ty.conservative_is_uninhabited(tcx),
1569+
_ => false
1570+
}
1571+
}
1572+
ty::Ref(..) => {
1573+
// Though references to uninhabited types are trivially uninhabited
1574+
// theoretically, null references are permitted in unsafe code (as
1575+
// long as the value is not dereferenced), so we treat all references
1576+
// as inhabited.
1577+
false
1578+
}
1579+
_ => false,
15541580
}
15551581
}
15561582

src/librustc_mir/borrow_check/nll/type_check/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1546,7 +1546,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
15461546
}
15471547
}
15481548
None => {
1549-
if !sig.output().conservative_is_uninhabited() {
1549+
if !sig.output().conservative_is_uninhabited(self.tcx()) {
15501550
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
15511551
}
15521552
}

src/librustc_mir/build/expr/into.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
331331
func: fun,
332332
args,
333333
cleanup: Some(cleanup),
334-
destination: if expr.ty.conservative_is_uninhabited() {
334+
destination: if expr.ty.conservative_is_uninhabited(this.hir.tcx()) {
335335
None
336336
} else {
337337
Some((destination.clone(), success))

src/librustc_mir/hair/pattern/check_match.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
230230
let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns {
231231
self.tcx.is_ty_uninhabited_from(module, pat_ty)
232232
} else {
233-
pat_ty.conservative_is_uninhabited()
233+
pat_ty.conservative_is_uninhabited(self.tcx)
234234
};
235235
if !scrutinee_is_uninhabited {
236236
// We know the type is inhabited, so this must be wrong

0 commit comments

Comments
 (0)