Skip to content

Commit a45cbac

Browse files
committed
Make uninhabitedness checking more intelligent
1 parent a885411 commit a45cbac

File tree

7 files changed

+36
-10
lines changed

7 files changed

+36
-10
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
@@ -1209,7 +1209,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
12091209
}
12101210

12111211
hir::ExprKind::Call(ref f, ref args) => {
1212-
let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited() {
1212+
let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited(self.ir.tcx) {
12131213
self.s.exit_ln
12141214
} else {
12151215
succ
@@ -1219,7 +1219,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
12191219
}
12201220

12211221
hir::ExprKind::MethodCall(.., ref args) => {
1222-
let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited() {
1222+
let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited(self.ir.tcx) {
12231223
self.s.exit_ln
12241224
} else {
12251225
succ

src/librustc/ty/sty.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,14 +1489,40 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
14891489
}
14901490
}
14911491

1492-
pub fn conservative_is_uninhabited(&self) -> bool {
1492+
pub fn conservative_is_uninhabited(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
14931493
// Checks whether a type is definitely uninhabited. This is
14941494
// conservative: for some types that are uninhabited we return `false`,
14951495
// but we only return `true` for types that are definitely uninhabited.
14961496
match self.sty {
14971497
ty::Never => true,
1498-
ty::Adt(def, _) => def.variants.is_empty(),
1499-
_ => false
1498+
ty::Adt(def, _) => {
1499+
// Any ADT is uninhabited if:
1500+
// (a) It has no variants (i.e. an empty `enum`);
1501+
// (b) Each of its variants (a single one in the case of a `struct`) has at least
1502+
// one uninhabited field.
1503+
def.variants.iter().all(|var| {
1504+
var.fields.iter().any(|field| {
1505+
tcx.type_of(field.did).conservative_is_uninhabited(tcx)
1506+
})
1507+
})
1508+
}
1509+
ty::Tuple(tys) => tys.iter().any(|ty| ty.conservative_is_uninhabited(tcx)),
1510+
ty::Array(ty, len) => {
1511+
match len.val.try_to_scalar() {
1512+
// If the array is definitely non-empty, it's uninhabited if
1513+
// the type of its elements is uninhabited.
1514+
Some(n) if !n.is_null() => ty.conservative_is_uninhabited(tcx),
1515+
_ => false
1516+
}
1517+
}
1518+
ty::Ref(..) => {
1519+
// Though references to uninhabited types are trivially uninhabited
1520+
// theoretically, null references are permitted in unsafe code (as
1521+
// long as the value is not dereferenced), so we treat all references
1522+
// as inhabited.
1523+
false
1524+
}
1525+
_ => false,
15001526
}
15011527
}
15021528

src/librustc_codegen_llvm/mir/block.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
457457
// we can do what we like. Here, we declare that transmuting
458458
// into an uninhabited type is impossible, so anything following
459459
// it must be unreachable.
460-
assert!(sig.output().conservative_is_uninhabited());
460+
assert!(sig.output().conservative_is_uninhabited(bx.tcx()));
461461
bx.unreachable();
462462
}
463463
return;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1259,7 +1259,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
12591259
}
12601260
}
12611261
None => {
1262-
if !sig.output().conservative_is_uninhabited() {
1262+
if !sig.output().conservative_is_uninhabited(self.tcx()) {
12631263
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
12641264
}
12651265
}

src/librustc_mir/build/expr/into.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
319319
func: fun,
320320
args,
321321
cleanup: Some(cleanup),
322-
destination: if expr.ty.conservative_is_uninhabited() {
322+
destination: if expr.ty.conservative_is_uninhabited(this.hir.tcx()) {
323323
None
324324
} else {
325325
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
@@ -229,7 +229,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
229229
let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns {
230230
self.tcx.is_ty_uninhabited_from(module, pat_ty)
231231
} else {
232-
pat_ty.conservative_is_uninhabited()
232+
pat_ty.conservative_is_uninhabited(self.tcx)
233233
};
234234
if !scrutinee_is_uninhabited {
235235
// We know the type is inhabited, so this must be wrong

0 commit comments

Comments
 (0)