Skip to content

Commit 2bb9c58

Browse files
committed
Add recursion limit to inhabitedness check
Fixes #39489. Add test aswell.
1 parent a3da24b commit 2bb9c58

File tree

5 files changed

+52
-14
lines changed

5 files changed

+52
-14
lines changed

src/librustc/ty/inhabitedness/mod.rs

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,14 @@ mod def_id_forest;
6262
// This code should only compile in modules where the uninhabitedness of Foo is
6363
// visible.
6464

65+
const ARBITRARY_RECURSION_LIMIT: u32 = 24;
66+
6567
impl<'a, 'gcx, 'tcx> AdtDef {
6668
/// Calculate the forest of DefIds from which this adt is visibly uninhabited.
6769
pub fn uninhabited_from(
6870
&self,
6971
visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
72+
recursion_depth: u32,
7073
tcx: TyCtxt<'a, 'gcx, 'tcx>,
7174
substs: &'tcx Substs<'tcx>) -> DefIdForest
7275
{
@@ -75,7 +78,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
7578
}
7679

7780
let ret = DefIdForest::intersection(tcx, self.variants.iter().map(|v| {
78-
v.uninhabited_from(visited, tcx, substs, self.adt_kind())
81+
v.uninhabited_from(visited, recursion_depth, tcx, substs, self.adt_kind())
7982
}));
8083
visited.remove(&(self.did, substs));
8184
ret
@@ -87,24 +90,25 @@ impl<'a, 'gcx, 'tcx> VariantDef {
8790
pub fn uninhabited_from(
8891
&self,
8992
visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
93+
recursion_depth: u32,
9094
tcx: TyCtxt<'a, 'gcx, 'tcx>,
9195
substs: &'tcx Substs<'tcx>,
9296
adt_kind: AdtKind) -> DefIdForest
9397
{
9498
match adt_kind {
9599
AdtKind::Union => {
96100
DefIdForest::intersection(tcx, self.fields.iter().map(|f| {
97-
f.uninhabited_from(visited, tcx, substs, false)
101+
f.uninhabited_from(visited, recursion_depth, tcx, substs, false)
98102
}))
99103
},
100104
AdtKind::Struct => {
101105
DefIdForest::union(tcx, self.fields.iter().map(|f| {
102-
f.uninhabited_from(visited, tcx, substs, false)
106+
f.uninhabited_from(visited, recursion_depth, tcx, substs, false)
103107
}))
104108
},
105109
AdtKind::Enum => {
106110
DefIdForest::union(tcx, self.fields.iter().map(|f| {
107-
f.uninhabited_from(visited, tcx, substs, true)
111+
f.uninhabited_from(visited, recursion_depth, tcx, substs, true)
108112
}))
109113
},
110114
}
@@ -116,11 +120,14 @@ impl<'a, 'gcx, 'tcx> FieldDef {
116120
pub fn uninhabited_from(
117121
&self,
118122
visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
123+
recursion_depth: u32,
119124
tcx: TyCtxt<'a, 'gcx, 'tcx>,
120125
substs: &'tcx Substs<'tcx>,
121126
is_enum: bool) -> DefIdForest
122127
{
123-
let mut data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(visited, tcx);
128+
let mut data_uninhabitedness = move || {
129+
self.ty(tcx, substs).uninhabited_from(visited, recursion_depth, tcx)
130+
};
124131
// FIXME(canndrew): Currently enum fields are (incorrectly) stored with
125132
// Visibility::Invisible so we need to override self.vis if we're
126133
// dealing with an enum.
@@ -145,8 +152,14 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
145152
pub fn uninhabited_from(
146153
&self,
147154
visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
155+
mut recursion_depth: u32,
148156
tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
149157
{
158+
recursion_depth += 1;
159+
if recursion_depth >= ARBITRARY_RECURSION_LIMIT {
160+
return DefIdForest::empty();
161+
}
162+
150163
match tcx.lift_to_global(&self) {
151164
Some(global_ty) => {
152165
{
@@ -155,13 +168,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
155168
return forest.clone();
156169
}
157170
}
158-
let forest = global_ty.uninhabited_from_inner(visited, tcx);
171+
let forest = global_ty.uninhabited_from_inner(visited, recursion_depth, tcx);
159172
let mut cache = tcx.inhabitedness_cache.borrow_mut();
160173
cache.insert(global_ty, forest.clone());
161174
forest
162175
},
163176
None => {
164-
let forest = self.uninhabited_from_inner(visited, tcx);
177+
let forest = self.uninhabited_from_inner(visited, recursion_depth, tcx);
165178
forest
166179
},
167180
}
@@ -170,28 +183,29 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
170183
fn uninhabited_from_inner(
171184
&self,
172185
visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
186+
recursion_depth: u32,
173187
tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
174188
{
175189
match self.sty {
176190
TyAdt(def, substs) => {
177-
def.uninhabited_from(visited, tcx, substs)
191+
def.uninhabited_from(visited, recursion_depth, tcx, substs)
178192
},
179193

180194
TyNever => DefIdForest::full(tcx),
181195
TyTuple(ref tys, _) => {
182196
DefIdForest::union(tcx, tys.iter().map(|ty| {
183-
ty.uninhabited_from(visited, tcx)
197+
ty.uninhabited_from(visited, recursion_depth, tcx)
184198
}))
185199
},
186200
TyArray(ty, len) => {
187201
if len == 0 {
188202
DefIdForest::empty()
189203
} else {
190-
ty.uninhabited_from(visited, tcx)
204+
ty.uninhabited_from(visited, recursion_depth, tcx)
191205
}
192206
}
193207
TyRef(_, ref tm) => {
194-
tm.ty.uninhabited_from(visited, tcx)
208+
tm.ty.uninhabited_from(visited, recursion_depth, tcx)
195209
}
196210

197211
_ => DefIdForest::empty(),

src/librustc/ty/sty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
10191019
/// visible.
10201020
pub fn is_uninhabited_from(&self, module: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
10211021
let mut visited = FxHashSet::default();
1022-
let forest = self.uninhabited_from(&mut visited, tcx);
1022+
let forest = self.uninhabited_from(&mut visited, 0, tcx);
10231023

10241024
// To check whether this type is uninhabited at all (not just from the
10251025
// given node) you could check whether the forest is empty.

src/librustc_const_eval/_match.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
405405
ty::TyAdt(def, substs) if def.is_enum() && def.variants.len() != 1 => {
406406
def.variants.iter().filter_map(|v| {
407407
let mut visited = FxHashSet::default();
408-
let forest = v.uninhabited_from(&mut visited,
408+
let forest = v.uninhabited_from(&mut visited, 0,
409409
cx.tcx, substs,
410410
AdtKind::Enum);
411411
if forest.contains(cx.tcx, cx.module)

src/librustc_mir/build/matches/simplify.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
103103
let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| {
104104
i == variant_index || {
105105
let mut visited = FxHashSet::default();
106-
let node_set = v.uninhabited_from(&mut visited,
106+
let node_set = v.uninhabited_from(&mut visited, 0,
107107
self.hir.tcx(),
108108
substs,
109109
adt_def.adt_kind());
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(never_type)]
12+
13+
struct Foo<'a, T: 'a> {
14+
ph: std::marker::PhantomData<T>,
15+
foo: &'a Foo<'a, (T, T)>,
16+
}
17+
18+
fn wub(f: Foo<!>) {
19+
match f {}
20+
//~^ ERROR non-exhaustive
21+
}
22+
23+
fn main() {}
24+

0 commit comments

Comments
 (0)