Check for uninhabitedness instead of never
This commit is contained in:
parent
1137d29d5e
commit
62b359094f
@ -415,8 +415,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||||||
args: I) -> CFGIndex {
|
args: I) -> CFGIndex {
|
||||||
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
|
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
|
||||||
let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
|
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).conservative_is_uninhabited() {
|
||||||
if self.tables.expr_ty(call_expr).is_never() {
|
|
||||||
self.add_unreachable_node()
|
self.add_unreachable_node()
|
||||||
} else {
|
} else {
|
||||||
ret
|
ret
|
||||||
|
@ -1197,8 +1197,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::Call(ref f, ref args) => {
|
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).conservative_is_uninhabited() {
|
||||||
let succ = if self.tables.expr_ty(expr).is_never() {
|
|
||||||
self.s.exit_ln
|
self.s.exit_ln
|
||||||
} else {
|
} else {
|
||||||
succ
|
succ
|
||||||
@ -1208,8 +1207,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::MethodCall(.., ref args) => {
|
hir::ExprKind::MethodCall(.., ref args) => {
|
||||||
// FIXME(canndrew): This is_never should really be an is_uninhabited
|
let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited() {
|
||||||
let succ = if self.tables.expr_ty(expr).is_never() {
|
|
||||||
self.s.exit_ln
|
self.s.exit_ln
|
||||||
} else {
|
} else {
|
||||||
succ
|
succ
|
||||||
|
@ -1543,6 +1543,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 {
|
pub fn is_primitive(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Bool | Char | Int(_) | Uint(_) | Float(_) => true,
|
Bool | Char | Int(_) | Uint(_) | Float(_) => true,
|
||||||
|
@ -1546,8 +1546,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// FIXME(canndrew): This is_never should probably be an is_uninhabited
|
if !sig.output().conservative_is_uninhabited() {
|
||||||
if !sig.output().is_never() {
|
|
||||||
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
|
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,8 +275,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
exit_block.unit()
|
exit_block.unit()
|
||||||
}
|
}
|
||||||
ExprKind::Call { ty, fun, args, from_hir_call } => {
|
ExprKind::Call { ty, fun, args, from_hir_call } => {
|
||||||
// FIXME(canndrew): This is_never should probably be an is_uninhabited
|
let diverges = expr.ty.conservative_is_uninhabited();
|
||||||
let diverges = expr.ty.is_never();
|
|
||||||
let intrinsic = match ty.sty {
|
let intrinsic = match ty.sty {
|
||||||
ty::FnDef(def_id, _) => {
|
ty::FnDef(def_id, _) => {
|
||||||
let f = ty.fn_sig(this.hir.tcx());
|
let f = ty.fn_sig(this.hir.tcx());
|
||||||
@ -332,7 +331,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
func: fun,
|
func: fun,
|
||||||
args,
|
args,
|
||||||
cleanup: Some(cleanup),
|
cleanup: Some(cleanup),
|
||||||
destination: if diverges {
|
destination: if expr.ty.conservative_is_uninhabited() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some((destination.clone(), success))
|
Some((destination.clone(), success))
|
||||||
|
@ -230,7 +230,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
|||||||
let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns {
|
let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns {
|
||||||
self.tcx.is_ty_uninhabited_from(module, pat_ty)
|
self.tcx.is_ty_uninhabited_from(module, pat_ty)
|
||||||
} else {
|
} else {
|
||||||
self.conservative_is_uninhabited(pat_ty)
|
pat_ty.conservative_is_uninhabited()
|
||||||
};
|
};
|
||||||
if !scrutinee_is_uninhabited {
|
if !scrutinee_is_uninhabited {
|
||||||
// We know the type is inhabited, so this must be wrong
|
// We know the type is inhabited, so this must be wrong
|
||||||
@ -258,15 +258,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) {
|
fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) {
|
||||||
let module = self.tcx.hir().get_module_parent(pat.id);
|
let module = self.tcx.hir().get_module_parent(pat.id);
|
||||||
MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| {
|
MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| {
|
||||||
|
@ -1,55 +1,24 @@
|
|||||||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
// LLDB can't handle zero-sized values.
|
||||||
// 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.
|
|
||||||
|
|
||||||
// NOTE Instantiating an empty enum is UB. This test may break in the future.
|
|
||||||
|
|
||||||
// LLDB can't handle zero-sized values
|
|
||||||
// ignore-lldb
|
// ignore-lldb
|
||||||
|
|
||||||
|
|
||||||
// Require LLVM with DW_TAG_variant_part and a gdb that can read it.
|
|
||||||
// gdb 8.2.0 crashes on this test case, see
|
|
||||||
// https://sourceware.org/bugzilla/show_bug.cgi?id=23626
|
|
||||||
// This will be fixed in the next release, which will be >= 8.2.1.
|
|
||||||
// min-system-llvm-version: 7.0
|
|
||||||
// min-gdb-version: 8.2.1
|
|
||||||
|
|
||||||
// compile-flags:-g
|
// compile-flags:-g
|
||||||
// gdb-command:run
|
// gdb-command:run
|
||||||
|
|
||||||
// gdb-command:print first
|
// gdb-command:print *first
|
||||||
// gdbr-check:$1 = nil_enum::ANilEnum {<No data fields>}
|
// gdbg-check:$1 = {<No data fields>}
|
||||||
|
// gdbr-check:$1 = <error reading variable>
|
||||||
// gdb-command:print second
|
|
||||||
// gdbr-check:$2 = nil_enum::AnotherNilEnum {<No data fields>}
|
|
||||||
|
|
||||||
#![allow(unused_variables)]
|
#![allow(unused_variables)]
|
||||||
#![feature(omit_gdb_pretty_printer_section)]
|
#![feature(omit_gdb_pretty_printer_section)]
|
||||||
#![feature(maybe_uninit)]
|
#![feature(maybe_uninit)]
|
||||||
#![omit_gdb_pretty_printer_section]
|
#![omit_gdb_pretty_printer_section]
|
||||||
|
|
||||||
use std::mem::MaybeUninit;
|
enum Void {}
|
||||||
|
|
||||||
enum ANilEnum {}
|
|
||||||
enum AnotherNilEnum {}
|
|
||||||
|
|
||||||
// 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() {
|
fn main() {
|
||||||
unsafe {
|
let first: *const Void = 1 as *const _;
|
||||||
let first: ANilEnum = MaybeUninit::uninitialized().into_inner();
|
|
||||||
let second: AnotherNilEnum = MaybeUninit::uninitialized().into_inner();
|
|
||||||
|
|
||||||
zzz(); // #break
|
zzz(); // #break
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zzz() {()}
|
fn zzz() {}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user