Fiddle ParamEnv through to a place that used to use ParamEnv::empty in a buggy manner

This commit is contained in:
Oliver Scherer 2020-03-16 18:51:55 +01:00
parent 59f4ba9504
commit 7894509b00
5 changed files with 64 additions and 24 deletions

View File

@ -90,30 +90,46 @@ impl<'tcx> TyCtxt<'tcx> {
/// ``` /// ```
/// This code should only compile in modules where the uninhabitedness of Foo is /// This code should only compile in modules where the uninhabitedness of Foo is
/// visible. /// visible.
pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool { pub fn is_ty_uninhabited_from(
self,
module: DefId,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
// To check whether this type is uninhabited at all (not just from the // To check whether this type is uninhabited at all (not just from the
// given node), you could check whether the forest is empty. // given node), you could check whether the forest is empty.
// ``` // ```
// forest.is_empty() // forest.is_empty()
// ``` // ```
ty.uninhabited_from(self).contains(self, module) ty.uninhabited_from(self, param_env).contains(self, module)
} }
pub fn is_ty_uninhabited_from_any_module(self, ty: Ty<'tcx>) -> bool { pub fn is_ty_uninhabited_from_any_module(
!ty.uninhabited_from(self).is_empty() self,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
!ty.uninhabited_from(self, param_env).is_empty()
} }
} }
impl<'tcx> AdtDef { impl<'tcx> AdtDef {
/// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited. /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited.
fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>) -> DefIdForest { fn uninhabited_from(
&self,
tcx: TyCtxt<'tcx>,
substs: SubstsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> DefIdForest {
// Non-exhaustive ADTs from other crates are always considered inhabited. // Non-exhaustive ADTs from other crates are always considered inhabited.
if self.is_variant_list_non_exhaustive() && !self.did.is_local() { if self.is_variant_list_non_exhaustive() && !self.did.is_local() {
DefIdForest::empty() DefIdForest::empty()
} else { } else {
DefIdForest::intersection( DefIdForest::intersection(
tcx, tcx,
self.variants.iter().map(|v| v.uninhabited_from(tcx, substs, self.adt_kind())), self.variants
.iter()
.map(|v| v.uninhabited_from(tcx, substs, self.adt_kind(), param_env)),
) )
} }
} }
@ -126,6 +142,7 @@ impl<'tcx> VariantDef {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
substs: SubstsRef<'tcx>, substs: SubstsRef<'tcx>,
adt_kind: AdtKind, adt_kind: AdtKind,
param_env: ty::ParamEnv<'tcx>,
) -> DefIdForest { ) -> DefIdForest {
let is_enum = match adt_kind { let is_enum = match adt_kind {
// For now, `union`s are never considered uninhabited. // For now, `union`s are never considered uninhabited.
@ -140,7 +157,7 @@ impl<'tcx> VariantDef {
} else { } else {
DefIdForest::union( DefIdForest::union(
tcx, tcx,
self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum)), self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum, param_env)),
) )
} }
} }
@ -153,8 +170,9 @@ impl<'tcx> FieldDef {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
substs: SubstsRef<'tcx>, substs: SubstsRef<'tcx>,
is_enum: bool, is_enum: bool,
param_env: ty::ParamEnv<'tcx>,
) -> DefIdForest { ) -> DefIdForest {
let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx); let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env);
// FIXME(canndrew): Currently enum fields are (incorrectly) stored with // FIXME(canndrew): Currently enum fields are (incorrectly) stored with
// `Visibility::Invisible` so we need to override `self.vis` if we're // `Visibility::Invisible` so we need to override `self.vis` if we're
// dealing with an enum. // dealing with an enum.
@ -176,20 +194,21 @@ impl<'tcx> FieldDef {
impl<'tcx> TyS<'tcx> { impl<'tcx> TyS<'tcx> {
/// Calculates the forest of `DefId`s from which this type is visibly uninhabited. /// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
fn uninhabited_from(&self, tcx: TyCtxt<'tcx>) -> DefIdForest { fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest {
match self.kind { match self.kind {
Adt(def, substs) => def.uninhabited_from(tcx, substs), Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
Never => DefIdForest::full(tcx), Never => DefIdForest::full(tcx),
Tuple(ref tys) => { Tuple(ref tys) => DefIdForest::union(
DefIdForest::union(tcx, tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx))) tcx,
} tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)),
),
Array(ty, len) => match len.try_eval_usize(tcx, ty::ParamEnv::empty()) { Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
// If the array is definitely non-empty, it's uninhabited if // If the array is definitely non-empty, it's uninhabited if
// the type of its elements is uninhabited. // the type of its elements is uninhabited.
Some(n) if n != 0 => ty.uninhabited_from(tcx), Some(n) if n != 0 => ty.uninhabited_from(tcx, param_env),
_ => DefIdForest::empty(), _ => DefIdForest::empty(),
}, },

View File

@ -124,7 +124,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
descr_post: &str, descr_post: &str,
plural_len: usize, plural_len: usize,
) -> bool { ) -> bool {
if ty.is_unit() || cx.tcx.is_ty_uninhabited_from(cx.tcx.parent_module(expr.hir_id), ty) if ty.is_unit()
|| cx.tcx.is_ty_uninhabited_from(
cx.tcx.parent_module(expr.hir_id),
ty,
cx.param_env,
)
{ {
return true; return true;
} }

View File

@ -209,7 +209,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
i == variant_index || { i == variant_index || {
self.hir.tcx().features().exhaustive_patterns self.hir.tcx().features().exhaustive_patterns
&& !v && !v
.uninhabited_from(self.hir.tcx(), substs, adt_def.adt_kind()) .uninhabited_from(
self.hir.tcx(),
substs,
adt_def.adt_kind(),
self.hir.param_env,
)
.is_empty() .is_empty()
} }
}) && (adt_def.did.is_local() }) && (adt_def.did.is_local()

View File

@ -598,7 +598,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
if self.tcx.features().exhaustive_patterns { if self.tcx.features().exhaustive_patterns {
self.tcx.is_ty_uninhabited_from(self.module, ty) self.tcx.is_ty_uninhabited_from(self.module, ty, self.param_env)
} else { } else {
false false
} }
@ -1267,7 +1267,7 @@ fn all_constructors<'a, 'tcx>(
def.variants def.variants
.iter() .iter()
.filter(|v| { .filter(|v| {
!v.uninhabited_from(cx.tcx, substs, def.adt_kind()) !v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env)
.contains(cx.tcx, cx.module) .contains(cx.tcx, cx.module)
}) })
.map(|v| Variant(v.def_id)) .map(|v| Variant(v.def_id))

View File

@ -398,7 +398,7 @@ fn visit_fn<'tcx>(
intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id); intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id);
// compute liveness // compute liveness
let mut lsets = Liveness::new(&mut fn_maps, body_id); let mut lsets = Liveness::new(&mut fn_maps, def_id);
let entry_ln = lsets.compute(&body.value); let entry_ln = lsets.compute(&body.value);
// check for various error conditions // check for various error conditions
@ -658,6 +658,7 @@ const ACC_USE: u32 = 4;
struct Liveness<'a, 'tcx> { struct Liveness<'a, 'tcx> {
ir: &'a mut IrMaps<'tcx>, ir: &'a mut IrMaps<'tcx>,
tables: &'a ty::TypeckTables<'tcx>, tables: &'a ty::TypeckTables<'tcx>,
param_env: ty::ParamEnv<'tcx>,
s: Specials, s: Specials,
successors: Vec<LiveNode>, successors: Vec<LiveNode>,
rwu_table: RWUTable, rwu_table: RWUTable,
@ -670,7 +671,7 @@ struct Liveness<'a, 'tcx> {
} }
impl<'a, 'tcx> Liveness<'a, 'tcx> { impl<'a, 'tcx> Liveness<'a, 'tcx> {
fn new(ir: &'a mut IrMaps<'tcx>, body: hir::BodyId) -> Liveness<'a, 'tcx> { fn new(ir: &'a mut IrMaps<'tcx>, def_id: DefId) -> Liveness<'a, 'tcx> {
// Special nodes and variables: // Special nodes and variables:
// - exit_ln represents the end of the fn, either by return or panic // - exit_ln represents the end of the fn, either by return or panic
// - implicit_ret_var is a pseudo-variable that represents // - implicit_ret_var is a pseudo-variable that represents
@ -681,7 +682,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
clean_exit_var: ir.add_variable(CleanExit), clean_exit_var: ir.add_variable(CleanExit),
}; };
let tables = ir.tcx.body_tables(body); let tables = ir.tcx.typeck_tables_of(def_id);
let param_env = ir.tcx.param_env(def_id);
let num_live_nodes = ir.num_live_nodes; let num_live_nodes = ir.num_live_nodes;
let num_vars = ir.num_vars; let num_vars = ir.num_vars;
@ -689,6 +691,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
Liveness { Liveness {
ir, ir,
tables, tables,
param_env,
s: specials, s: specials,
successors: vec![invalid_node(); num_live_nodes], successors: vec![invalid_node(); num_live_nodes],
rwu_table: RWUTable::new(num_live_nodes * num_vars), rwu_table: RWUTable::new(num_live_nodes * num_vars),
@ -1126,7 +1129,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
hir::ExprKind::Call(ref f, ref args) => { hir::ExprKind::Call(ref f, ref args) => {
let m = self.ir.tcx.parent_module(expr.hir_id); let m = self.ir.tcx.parent_module(expr.hir_id);
let succ = if self.ir.tcx.is_ty_uninhabited_from(m, self.tables.expr_ty(expr)) { let succ = if self.ir.tcx.is_ty_uninhabited_from(
m,
self.tables.expr_ty(expr),
self.param_env,
) {
self.s.exit_ln self.s.exit_ln
} else { } else {
succ succ
@ -1137,7 +1144,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
hir::ExprKind::MethodCall(.., ref args) => { hir::ExprKind::MethodCall(.., ref args) => {
let m = self.ir.tcx.parent_module(expr.hir_id); let m = self.ir.tcx.parent_module(expr.hir_id);
let succ = if self.ir.tcx.is_ty_uninhabited_from(m, self.tables.expr_ty(expr)) { let succ = if self.ir.tcx.is_ty_uninhabited_from(
m,
self.tables.expr_ty(expr),
self.param_env,
) {
self.s.exit_ln self.s.exit_ln
} else { } else {
succ succ