Skip to content

Commit b16da00

Browse files
Rollup merge of rust-lang#56110 - varkor:inhabitedness-union-enum, r=cramertj
Consider references and unions potentially inhabited during privacy-respecting inhabitedness checks It isn't settled exactly how references to uninhabited types and unions of uninhabited types should act, but we should be more conservative here, as it's likely it will be permitted to soundly have values of such types. This will also be more important in light of the changes at rust-lang#54125. cc @RalfJung
2 parents 317cbc8 + 1cdf5df commit b16da00

9 files changed

+105
-61
lines changed

src/librustc/ty/inhabitedness/mod.rs

+23-24
Original file line numberDiff line numberDiff line change
@@ -167,23 +167,16 @@ impl<'a, 'gcx, 'tcx> VariantDef {
167167
substs: &'tcx Substs<'tcx>,
168168
adt_kind: AdtKind) -> DefIdForest
169169
{
170-
match adt_kind {
171-
AdtKind::Union => {
172-
DefIdForest::intersection(tcx, self.fields.iter().map(|f| {
173-
f.uninhabited_from(visited, tcx, substs, false)
174-
}))
175-
},
176-
AdtKind::Struct => {
177-
DefIdForest::union(tcx, self.fields.iter().map(|f| {
178-
f.uninhabited_from(visited, tcx, substs, false)
179-
}))
180-
},
181-
AdtKind::Enum => {
182-
DefIdForest::union(tcx, self.fields.iter().map(|f| {
183-
f.uninhabited_from(visited, tcx, substs, true)
184-
}))
185-
},
186-
}
170+
let is_enum = match adt_kind {
171+
// For now, `union`s are never considered uninhabited.
172+
// The precise semantics of inhabitedness with respect to unions is currently undecided.
173+
AdtKind::Union => return DefIdForest::empty(),
174+
AdtKind::Enum => true,
175+
AdtKind::Struct => false,
176+
};
177+
DefIdForest::union(tcx, self.fields.iter().map(|f| {
178+
f.uninhabited_from(visited, tcx, substs, is_enum)
179+
}))
187180
}
188181
}
189182

@@ -194,8 +187,8 @@ impl<'a, 'gcx, 'tcx> FieldDef {
194187
visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
195188
tcx: TyCtxt<'a, 'gcx, 'tcx>,
196189
substs: &'tcx Substs<'tcx>,
197-
is_enum: bool) -> DefIdForest
198-
{
190+
is_enum: bool,
191+
) -> DefIdForest {
199192
let mut data_uninhabitedness = move || {
200193
self.ty(tcx, substs).uninhabited_from(visited, tcx)
201194
};
@@ -253,14 +246,16 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
253246
let substs_set = visited.get_mut(&def.did).unwrap();
254247
substs_set.remove(substs);
255248
ret
256-
},
249+
}
257250

258251
Never => DefIdForest::full(tcx),
252+
259253
Tuple(ref tys) => {
260254
DefIdForest::union(tcx, tys.iter().map(|ty| {
261255
ty.uninhabited_from(visited, tcx)
262256
}))
263-
},
257+
}
258+
264259
Array(ty, len) => {
265260
match len.assert_usize(tcx) {
266261
// If the array is definitely non-empty, it's uninhabited if
@@ -269,9 +264,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
269264
_ => DefIdForest::empty()
270265
}
271266
}
272-
Ref(_, ty, _) => {
273-
ty.uninhabited_from(visited, tcx)
274-
}
267+
268+
// References to uninitialised memory is valid for any type, including
269+
// uninhabited types, in unsafe code, so we treat all references as
270+
// inhabited.
271+
// The precise semantics of inhabitedness with respect to references is currently
272+
// undecided.
273+
Ref(..) => DefIdForest::empty(),
275274

276275
_ => DefIdForest::empty(),
277276
}

src/test/run-pass/binding/empty-types-in-patterns.rs

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ fn main() {
6060
let x: Result<u32, &!> = Ok(123);
6161
match x {
6262
Ok(y) => y,
63+
Err(_) => unimplemented!(),
6364
};
6465

6566
bar(&[]);
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// The precise semantics of inhabitedness with respect to unions and references is currently
2+
// undecided. This test file currently checks a conservative choice.
3+
4+
#![feature(exhaustive_patterns)]
5+
#![feature(never_type)]
6+
7+
#![allow(dead_code)]
8+
#![allow(unreachable_code)]
9+
10+
pub union Foo {
11+
foo: !,
12+
}
13+
14+
fn uninhab_ref() -> &'static ! {
15+
unimplemented!()
16+
}
17+
18+
fn uninhab_union() -> Foo {
19+
unimplemented!()
20+
}
21+
22+
fn match_on_uninhab() {
23+
match uninhab_ref() {
24+
//~^ ERROR non-exhaustive patterns: type `&'static !` is non-empty
25+
}
26+
27+
match uninhab_union() {
28+
//~^ ERROR non-exhaustive patterns: type `Foo` is non-empty
29+
}
30+
}
31+
32+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0004]: non-exhaustive patterns: type `&'static !` is non-empty
2+
--> $DIR/always-inhabited-union-ref.rs:23:11
3+
|
4+
LL | match uninhab_ref() {
5+
| ^^^^^^^^^^^^^
6+
|
7+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
8+
--> $DIR/always-inhabited-union-ref.rs:23:11
9+
|
10+
LL | match uninhab_ref() {
11+
| ^^^^^^^^^^^^^
12+
13+
error[E0004]: non-exhaustive patterns: type `Foo` is non-empty
14+
--> $DIR/always-inhabited-union-ref.rs:27:11
15+
|
16+
LL | match uninhab_union() {
17+
| ^^^^^^^^^^^^^^^
18+
|
19+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
20+
--> $DIR/always-inhabited-union-ref.rs:27:11
21+
|
22+
LL | match uninhab_union() {
23+
| ^^^^^^^^^^^^^^^
24+
25+
error: aborting due to 2 previous errors
26+
27+
For more information about this error, try `rustc --explain E0004`.

src/test/ui/inhabitedness-infinite-loop.rs

-26
This file was deleted.

src/test/ui/inhabitedness-infinite-loop.stderr

-4
This file was deleted.

src/test/ui/issues/issue-44402.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ fn test_a() {
3333

3434
fn test_b() {
3535
let x: Option<Bar> = None;
36-
match x { None => () }
36+
match x {
37+
Some(_) => (),
38+
None => ()
39+
}
3740
}
3841

3942
fn main() { }

src/test/ui/unreachable/unreachable-loop-patterns.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,26 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// compile-fail
12+
1113
#![feature(never_type)]
1214
#![feature(exhaustive_patterns)]
15+
16+
#![allow(unreachable_code)]
1317
#![deny(unreachable_patterns)]
1418

15-
fn main() {
16-
let x: &[!] = &[];
19+
enum Void {}
20+
21+
impl Iterator for Void {
22+
type Item = Void;
1723

18-
for _ in x {}
24+
fn next(&mut self) -> Option<Void> {
25+
None
26+
}
27+
}
28+
29+
fn main() {
30+
for _ in unimplemented!() as Void {}
1931
//~^ ERROR unreachable pattern
2032
}
2133

src/test/ui/unreachable/unreachable-loop-patterns.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error: unreachable pattern
2-
--> $DIR/unreachable-loop-patterns.rs:18:9
2+
--> $DIR/unreachable-loop-patterns.rs:30:9
33
|
4-
LL | for _ in x {}
4+
LL | for _ in unimplemented!() as Void {}
55
| ^
66
|
77
note: lint level defined here
8-
--> $DIR/unreachable-loop-patterns.rs:13:9
8+
--> $DIR/unreachable-loop-patterns.rs:17:9
99
|
1010
LL | #![deny(unreachable_patterns)]
1111
| ^^^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)