Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 34 additions & 15 deletions src/librustc/ty/inhabitedness/mod.rs
Original file line number Diff line number Diff line change
@@ -90,30 +90,46 @@ impl<'tcx> TyCtxt<'tcx> {
/// ```
/// This code should only compile in modules where the uninhabitedness of Foo is
/// 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
// given node), you could check whether the 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 {
!ty.uninhabited_from(self).is_empty()
pub fn is_ty_uninhabited_from_any_module(
self,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
!ty.uninhabited_from(self, param_env).is_empty()
}
}

impl<'tcx> AdtDef {
/// 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.
if self.is_variant_list_non_exhaustive() && !self.did.is_local() {
DefIdForest::empty()
} else {
DefIdForest::intersection(
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>,
substs: SubstsRef<'tcx>,
adt_kind: AdtKind,
param_env: ty::ParamEnv<'tcx>,
) -> DefIdForest {
let is_enum = match adt_kind {
// For now, `union`s are never considered uninhabited.
@@ -140,7 +157,7 @@ impl<'tcx> VariantDef {
} else {
DefIdForest::union(
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>,
substs: SubstsRef<'tcx>,
is_enum: bool,
param_env: ty::ParamEnv<'tcx>,
) -> 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
// `Visibility::Invisible` so we need to override `self.vis` if we're
// dealing with an enum.
@@ -176,20 +194,21 @@ impl<'tcx> FieldDef {

impl<'tcx> TyS<'tcx> {
/// 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 {
Adt(def, substs) => def.uninhabited_from(tcx, substs),
Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),

Never => DefIdForest::full(tcx),

Tuple(ref tys) => {
DefIdForest::union(tcx, tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx)))
}
Tuple(ref tys) => DefIdForest::union(
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
// 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(),
},

7 changes: 6 additions & 1 deletion src/librustc_lint/unused.rs
Original file line number Diff line number Diff line change
@@ -124,7 +124,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
descr_post: &str,
plural_len: usize,
) -> 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;
}
7 changes: 6 additions & 1 deletion src/librustc_mir_build/build/matches/simplify.rs
Original file line number Diff line number Diff line change
@@ -209,7 +209,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
i == variant_index || {
self.hir.tcx().features().exhaustive_patterns
&& !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()
}
}) && (adt_def.did.is_local()
4 changes: 2 additions & 2 deletions src/librustc_mir_build/hair/pattern/_match.rs
Original file line number Diff line number Diff line change
@@ -598,7 +598,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {

fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
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 {
false
}
@@ -1267,7 +1267,7 @@ fn all_constructors<'a, 'tcx>(
def.variants
.iter()
.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)
})
.map(|v| Variant(v.def_id))
21 changes: 16 additions & 5 deletions src/librustc_passes/liveness.rs
Original file line number Diff line number Diff line change
@@ -398,7 +398,7 @@ fn visit_fn<'tcx>(
intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id);

// 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);

// check for various error conditions
@@ -658,6 +658,7 @@ const ACC_USE: u32 = 4;
struct Liveness<'a, 'tcx> {
ir: &'a mut IrMaps<'tcx>,
tables: &'a ty::TypeckTables<'tcx>,
param_env: ty::ParamEnv<'tcx>,
s: Specials,
successors: Vec<LiveNode>,
rwu_table: RWUTable,
@@ -670,7 +671,7 @@ struct 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:
// - exit_ln represents the end of the fn, either by return or panic
// - implicit_ret_var is a pseudo-variable that represents
@@ -681,14 +682,16 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
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_vars = ir.num_vars;

Liveness {
ir,
tables,
param_env,
s: specials,
successors: vec![invalid_node(); num_live_nodes],
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) => {
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
} else {
succ
@@ -1137,7 +1144,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {

hir::ExprKind::MethodCall(.., ref args) => {
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
} else {
succ