mirror of https://github.com/rust-lang/rust.git
Rollup merge of #128934 - Nadrieril:fix-empty-non-exhaustive, r=compiler-errors
Non-exhaustive structs may be empty This is a follow-up to a discrepancy noticed in https://github.com/rust-lang/rust/pull/122792: today, the following struct is considered inhabited (non-empty) outside its defining crate: ```rust #[non_exhaustive] pub struct UninhabitedStruct { pub never: !, // other fields } ``` `#[non_exhaustive]` on a struct should mean that adding fields to it isn't a breaking change. There is no way that adding fields to this struct could make it non-empty since the `never` field must stay and is inconstructible. I suspect this was implemented this way due to confusion with `#[non_exhaustive]` enums, which indeed should be considered non-empty outside their defining crate. I propose that we consider such a struct uninhabited (empty), just like it would be without the `#[non_exhaustive]` annotation. Code that doesn't pass today and will pass after this: ```rust // In a different crate fn empty_match_on_empty_struct<T>(x: UninhabitedStruct) -> T { match x {} } ``` This is not a breaking change. r? ``@compiler-errors``
This commit is contained in:
commit
e7504ac704
|
@ -81,10 +81,6 @@ impl<'tcx> VariantDef {
|
||||||
adt: ty::AdtDef<'_>,
|
adt: ty::AdtDef<'_>,
|
||||||
) -> InhabitedPredicate<'tcx> {
|
) -> InhabitedPredicate<'tcx> {
|
||||||
debug_assert!(!adt.is_union());
|
debug_assert!(!adt.is_union());
|
||||||
if self.is_field_list_non_exhaustive() && !self.def_id.is_local() {
|
|
||||||
// Non-exhaustive variants from other crates are always considered inhabited.
|
|
||||||
return InhabitedPredicate::True;
|
|
||||||
}
|
|
||||||
InhabitedPredicate::all(
|
InhabitedPredicate::all(
|
||||||
tcx,
|
tcx,
|
||||||
self.fields.iter().map(|field| {
|
self.fields.iter().map(|field| {
|
||||||
|
|
|
@ -229,17 +229,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
let variant =
|
let variant =
|
||||||
&adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
|
&adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
|
||||||
|
|
||||||
// In the cases of either a `#[non_exhaustive]` field list or a non-public
|
|
||||||
// field, we skip uninhabited fields in order not to reveal the
|
|
||||||
// uninhabitedness of the whole variant.
|
|
||||||
let is_non_exhaustive =
|
|
||||||
variant.is_field_list_non_exhaustive() && !adt.did().is_local();
|
|
||||||
let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
|
let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
|
||||||
let is_visible =
|
let is_visible =
|
||||||
adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
|
adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
|
||||||
let is_uninhabited = cx.is_uninhabited(*ty);
|
let is_uninhabited = cx.is_uninhabited(*ty);
|
||||||
let skip = is_uninhabited && (!is_visible || is_non_exhaustive);
|
let skip = is_uninhabited && !is_visible;
|
||||||
(ty, PrivateUninhabitedField(skip))
|
(ty, PrivateUninhabitedField(skip))
|
||||||
});
|
});
|
||||||
cx.dropless_arena.alloc_from_iter(tys)
|
cx.dropless_arena.alloc_from_iter(tys)
|
||||||
|
|
|
@ -7,11 +7,17 @@ pub enum UninhabitedEnum {
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct UninhabitedStruct {
|
pub struct UninhabitedStruct {
|
||||||
_priv: !,
|
pub never: !,
|
||||||
|
_priv: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct UninhabitedTupleStruct(!);
|
pub struct PrivatelyUninhabitedStruct {
|
||||||
|
never: !,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct UninhabitedTupleStruct(pub !);
|
||||||
|
|
||||||
pub enum UninhabitedVariants {
|
pub enum UninhabitedVariants {
|
||||||
#[non_exhaustive] Tuple(!),
|
#[non_exhaustive] Tuple(!),
|
||||||
|
|
|
@ -5,7 +5,7 @@ LL | match x {}
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: `IndirectUninhabitedEnum` defined here
|
note: `IndirectUninhabitedEnum` defined here
|
||||||
--> $DIR/auxiliary/uninhabited.rs:26:1
|
--> $DIR/auxiliary/uninhabited.rs:32:1
|
||||||
|
|
|
|
||||||
LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
|
LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -24,7 +24,7 @@ LL | match x {}
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: `IndirectUninhabitedStruct` defined here
|
note: `IndirectUninhabitedStruct` defined here
|
||||||
--> $DIR/auxiliary/uninhabited.rs:28:1
|
--> $DIR/auxiliary/uninhabited.rs:34:1
|
||||||
|
|
|
|
||||||
LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
|
LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -43,7 +43,7 @@ LL | match x {}
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: `IndirectUninhabitedTupleStruct` defined here
|
note: `IndirectUninhabitedTupleStruct` defined here
|
||||||
--> $DIR/auxiliary/uninhabited.rs:30:1
|
--> $DIR/auxiliary/uninhabited.rs:36:1
|
||||||
|
|
|
|
||||||
LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
|
LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -62,7 +62,7 @@ LL | match x {}
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: `IndirectUninhabitedVariants` defined here
|
note: `IndirectUninhabitedVariants` defined here
|
||||||
--> $DIR/auxiliary/uninhabited.rs:32:1
|
--> $DIR/auxiliary/uninhabited.rs:38:1
|
||||||
|
|
|
|
||||||
LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
|
LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
@ -5,7 +5,7 @@ LL | match x {}
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: `IndirectUninhabitedEnum` defined here
|
note: `IndirectUninhabitedEnum` defined here
|
||||||
--> $DIR/auxiliary/uninhabited.rs:26:1
|
--> $DIR/auxiliary/uninhabited.rs:32:1
|
||||||
|
|
|
|
||||||
LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
|
LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -24,7 +24,7 @@ LL | match x {}
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: `IndirectUninhabitedStruct` defined here
|
note: `IndirectUninhabitedStruct` defined here
|
||||||
--> $DIR/auxiliary/uninhabited.rs:28:1
|
--> $DIR/auxiliary/uninhabited.rs:34:1
|
||||||
|
|
|
|
||||||
LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
|
LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -43,7 +43,7 @@ LL | match x {}
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: `IndirectUninhabitedTupleStruct` defined here
|
note: `IndirectUninhabitedTupleStruct` defined here
|
||||||
--> $DIR/auxiliary/uninhabited.rs:30:1
|
--> $DIR/auxiliary/uninhabited.rs:36:1
|
||||||
|
|
|
|
||||||
LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
|
LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -62,7 +62,7 @@ LL | match x {}
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: `IndirectUninhabitedVariants` defined here
|
note: `IndirectUninhabitedVariants` defined here
|
||||||
--> $DIR/auxiliary/uninhabited.rs:32:1
|
--> $DIR/auxiliary/uninhabited.rs:38:1
|
||||||
|
|
|
|
||||||
LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
|
LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
@ -11,11 +11,12 @@ use uninhabited::PartiallyInhabitedVariants;
|
||||||
|
|
||||||
pub fn foo(x: PartiallyInhabitedVariants) {
|
pub fn foo(x: PartiallyInhabitedVariants) {
|
||||||
match x {
|
match x {
|
||||||
PartiallyInhabitedVariants::Struct { .. } => {},
|
PartiallyInhabitedVariants::Struct { .. } => {}
|
||||||
PartiallyInhabitedVariants::Struct { .. } => {},
|
|
||||||
//~^ ERROR unreachable pattern
|
//~^ ERROR unreachable pattern
|
||||||
_ => {},
|
PartiallyInhabitedVariants::Struct { .. } => {}
|
||||||
|
//~^ ERROR unreachable pattern
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() { }
|
fn main() {}
|
||||||
|
|
|
@ -1,16 +1,23 @@
|
||||||
error: unreachable pattern
|
error: unreachable pattern
|
||||||
--> $DIR/issue-65157-repeated-match-arm.rs:15:9
|
--> $DIR/issue-65157-repeated-match-arm.rs:14:9
|
||||||
|
|
|
|
||||||
LL | PartiallyInhabitedVariants::Struct { .. } => {},
|
LL | PartiallyInhabitedVariants::Struct { .. } => {}
|
||||||
| ----------------------------------------- matches all the relevant values
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `PartiallyInhabitedVariants` is uninhabited
|
||||||
LL | PartiallyInhabitedVariants::Struct { .. } => {},
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this
|
|
||||||
|
|
|
|
||||||
|
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/issue-65157-repeated-match-arm.rs:2:9
|
--> $DIR/issue-65157-repeated-match-arm.rs:2:9
|
||||||
|
|
|
|
||||||
LL | #![deny(unreachable_patterns)]
|
LL | #![deny(unreachable_patterns)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: unreachable pattern
|
||||||
|
--> $DIR/issue-65157-repeated-match-arm.rs:16:9
|
||||||
|
|
|
||||||
|
LL | PartiallyInhabitedVariants::Struct { .. } => {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `PartiallyInhabitedVariants` is uninhabited
|
||||||
|
|
|
||||||
|
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,7 @@
|
||||||
|
|
||||||
extern crate uninhabited;
|
extern crate uninhabited;
|
||||||
|
|
||||||
use uninhabited::{
|
use uninhabited::*;
|
||||||
UninhabitedEnum,
|
|
||||||
UninhabitedStruct,
|
|
||||||
UninhabitedTupleStruct,
|
|
||||||
UninhabitedVariants,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct A;
|
struct A;
|
||||||
|
|
||||||
|
@ -19,16 +14,20 @@ fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
|
||||||
match x {} //~ ERROR non-exhaustive patterns
|
match x {} //~ ERROR non-exhaustive patterns
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
|
fn empty_match_on_empty_struct(x: UninhabitedStruct) -> A {
|
||||||
|
match x {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cannot_empty_match_on_privately_empty_struct(x: PrivatelyUninhabitedStruct) -> A {
|
||||||
match x {} //~ ERROR non-exhaustive patterns
|
match x {} //~ ERROR non-exhaustive patterns
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
|
fn empty_match_on_empty_tuple_struct(x: UninhabitedTupleStruct) -> A {
|
||||||
match x {} //~ ERROR non-exhaustive patterns
|
match x {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
|
fn empty_match_on_enum_with_empty_variants_struct(x: UninhabitedVariants) -> A {
|
||||||
match x {} //~ ERROR non-exhaustive patterns
|
match x {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty
|
error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty
|
||||||
--> $DIR/match.rs:19:11
|
--> $DIR/match.rs:14:11
|
||||||
|
|
|
|
||||||
LL | match x {}
|
LL | match x {}
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: `UninhabitedEnum` defined here
|
note: `uninhabited::UninhabitedEnum` defined here
|
||||||
--> $DIR/auxiliary/uninhabited.rs:5:1
|
--> $DIR/auxiliary/uninhabited.rs:5:1
|
||||||
|
|
|
|
||||||
LL | pub enum UninhabitedEnum {
|
LL | pub enum UninhabitedEnum {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
= note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive
|
= note: the matched value is of type `uninhabited::UninhabitedEnum`, which is marked as non-exhaustive
|
||||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
|
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
|
||||||
|
|
|
|
||||||
LL ~ match x {
|
LL ~ match x {
|
||||||
|
@ -17,18 +17,18 @@ LL + _ => todo!(),
|
||||||
LL ~ }
|
LL ~ }
|
||||||
|
|
|
|
||||||
|
|
||||||
error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
|
error[E0004]: non-exhaustive patterns: type `uninhabited::PrivatelyUninhabitedStruct` is non-empty
|
||||||
--> $DIR/match.rs:23:11
|
--> $DIR/match.rs:22:11
|
||||||
|
|
|
|
||||||
LL | match x {}
|
LL | match x {}
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: `UninhabitedStruct` defined here
|
note: `uninhabited::PrivatelyUninhabitedStruct` defined here
|
||||||
--> $DIR/auxiliary/uninhabited.rs:9:1
|
--> $DIR/auxiliary/uninhabited.rs:15:1
|
||||||
|
|
|
|
||||||
LL | pub struct UninhabitedStruct {
|
LL | pub struct PrivatelyUninhabitedStruct {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
= note: the matched value is of type `UninhabitedStruct`
|
= note: the matched value is of type `uninhabited::PrivatelyUninhabitedStruct`
|
||||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
|
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
|
||||||
|
|
|
|
||||||
LL ~ match x {
|
LL ~ match x {
|
||||||
|
@ -36,48 +36,6 @@ LL + _ => todo!(),
|
||||||
LL ~ }
|
LL ~ }
|
||||||
|
|
|
|
||||||
|
|
||||||
error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
|
error: aborting due to 2 previous errors
|
||||||
--> $DIR/match.rs:27:11
|
|
||||||
|
|
|
||||||
LL | match x {}
|
|
||||||
| ^
|
|
||||||
|
|
|
||||||
note: `UninhabitedTupleStruct` defined here
|
|
||||||
--> $DIR/auxiliary/uninhabited.rs:14:1
|
|
||||||
|
|
|
||||||
LL | pub struct UninhabitedTupleStruct(!);
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
= note: the matched value is of type `UninhabitedTupleStruct`
|
|
||||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
|
|
||||||
|
|
|
||||||
LL ~ match x {
|
|
||||||
LL + _ => todo!(),
|
|
||||||
LL ~ }
|
|
||||||
|
|
|
||||||
|
|
||||||
error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
|
|
||||||
--> $DIR/match.rs:31:11
|
|
||||||
|
|
|
||||||
LL | match x {}
|
|
||||||
| ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
|
|
||||||
|
|
|
||||||
note: `UninhabitedVariants` defined here
|
|
||||||
--> $DIR/auxiliary/uninhabited.rs:16:1
|
|
||||||
|
|
|
||||||
LL | pub enum UninhabitedVariants {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
LL | #[non_exhaustive] Tuple(!),
|
|
||||||
| ----- not covered
|
|
||||||
LL | #[non_exhaustive] Struct { x: ! }
|
|
||||||
| ------ not covered
|
|
||||||
= note: the matched value is of type `UninhabitedVariants`
|
|
||||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
|
|
||||||
|
|
|
||||||
LL ~ match x {
|
|
||||||
LL + UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(),
|
|
||||||
LL ~ }
|
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0004`.
|
For more information about this error, try `rustc --explain E0004`.
|
||||||
|
|
|
@ -5,32 +5,28 @@
|
||||||
extern crate uninhabited;
|
extern crate uninhabited;
|
||||||
|
|
||||||
use uninhabited::{
|
use uninhabited::{
|
||||||
UninhabitedEnum,
|
UninhabitedEnum, UninhabitedStruct, UninhabitedTupleStruct, UninhabitedVariants,
|
||||||
UninhabitedStruct,
|
|
||||||
UninhabitedTupleStruct,
|
|
||||||
UninhabitedVariants,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct A;
|
struct A;
|
||||||
|
|
||||||
// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate
|
// This test checks that non-exhaustive enums are never considered uninhabited outside their
|
||||||
// will not compile. In particular, this enables the `exhaustive_patterns` feature as this can
|
// defining crate, and non-exhaustive structs are considered uninhabited the same way as normal
|
||||||
// change the branch used in the compiler to determine this.
|
// ones.
|
||||||
|
fn cannot_empty_match_on_non_exhaustive_empty_enum(x: UninhabitedEnum) -> A {
|
||||||
fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
|
|
||||||
match x {} //~ ERROR non-exhaustive patterns
|
match x {} //~ ERROR non-exhaustive patterns
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
|
fn empty_match_on_empty_struct(x: UninhabitedStruct) -> A {
|
||||||
match x {} //~ ERROR non-exhaustive patterns
|
match x {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
|
fn empty_match_on_empty_tuple_struct(x: UninhabitedTupleStruct) -> A {
|
||||||
match x {} //~ ERROR non-exhaustive patterns
|
match x {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
|
fn empty_match_on_enum_with_empty_variants_struct(x: UninhabitedVariants) -> A {
|
||||||
match x {} //~ ERROR non-exhaustive patterns
|
match x {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty
|
error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty
|
||||||
--> $DIR/match_with_exhaustive_patterns.rs:21:11
|
--> $DIR/match_with_exhaustive_patterns.rs:17:11
|
||||||
|
|
|
|
||||||
LL | match x {}
|
LL | match x {}
|
||||||
| ^
|
| ^
|
||||||
|
@ -17,67 +17,6 @@ LL + _ => todo!(),
|
||||||
LL ~ }
|
LL ~ }
|
||||||
|
|
|
|
||||||
|
|
||||||
error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
|
error: aborting due to 1 previous error
|
||||||
--> $DIR/match_with_exhaustive_patterns.rs:25:11
|
|
||||||
|
|
|
||||||
LL | match x {}
|
|
||||||
| ^
|
|
||||||
|
|
|
||||||
note: `UninhabitedStruct` defined here
|
|
||||||
--> $DIR/auxiliary/uninhabited.rs:9:1
|
|
||||||
|
|
|
||||||
LL | pub struct UninhabitedStruct {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
= note: the matched value is of type `UninhabitedStruct`
|
|
||||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
|
|
||||||
|
|
|
||||||
LL ~ match x {
|
|
||||||
LL + _ => todo!(),
|
|
||||||
LL ~ }
|
|
||||||
|
|
|
||||||
|
|
||||||
error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
|
|
||||||
--> $DIR/match_with_exhaustive_patterns.rs:29:11
|
|
||||||
|
|
|
||||||
LL | match x {}
|
|
||||||
| ^
|
|
||||||
|
|
|
||||||
note: `UninhabitedTupleStruct` defined here
|
|
||||||
--> $DIR/auxiliary/uninhabited.rs:14:1
|
|
||||||
|
|
|
||||||
LL | pub struct UninhabitedTupleStruct(!);
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
= note: the matched value is of type `UninhabitedTupleStruct`
|
|
||||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
|
|
||||||
|
|
|
||||||
LL ~ match x {
|
|
||||||
LL + _ => todo!(),
|
|
||||||
LL ~ }
|
|
||||||
|
|
|
||||||
|
|
||||||
error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
|
|
||||||
--> $DIR/match_with_exhaustive_patterns.rs:33:11
|
|
||||||
|
|
|
||||||
LL | match x {}
|
|
||||||
| ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
|
|
||||||
|
|
|
||||||
note: `UninhabitedVariants` defined here
|
|
||||||
--> $DIR/auxiliary/uninhabited.rs:16:1
|
|
||||||
|
|
|
||||||
LL | pub enum UninhabitedVariants {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
LL | #[non_exhaustive] Tuple(!),
|
|
||||||
| ----- not covered
|
|
||||||
LL | #[non_exhaustive] Struct { x: ! }
|
|
||||||
| ------ not covered
|
|
||||||
= note: the matched value is of type `UninhabitedVariants`
|
|
||||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
|
|
||||||
|
|
|
||||||
LL ~ match x {
|
|
||||||
LL + UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(),
|
|
||||||
LL ~ }
|
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0004`.
|
For more information about this error, try `rustc --explain E0004`.
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//@ check-pass
|
//@ check-pass
|
||||||
|
|
||||||
#![deny(unreachable_patterns)]
|
#![deny(unreachable_patterns)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
|
|
||||||
|
@ -9,11 +8,12 @@ pub enum UninhabitedEnum {
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct UninhabitedStruct {
|
pub struct UninhabitedStruct {
|
||||||
_priv: !,
|
pub never: !,
|
||||||
|
_priv: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct UninhabitedTupleStruct(!);
|
pub struct UninhabitedTupleStruct(pub !);
|
||||||
|
|
||||||
pub enum UninhabitedVariants {
|
pub enum UninhabitedVariants {
|
||||||
#[non_exhaustive] Tuple(!),
|
#[non_exhaustive] Tuple(!),
|
||||||
|
@ -22,24 +22,21 @@ pub enum UninhabitedVariants {
|
||||||
|
|
||||||
struct A;
|
struct A;
|
||||||
|
|
||||||
// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate
|
// This checks that `non_exhaustive` annotations do not affect exhaustiveness checking within the
|
||||||
// will compile. In particular, this enables the `exhaustive_patterns` feature as this can
|
// defining crate.
|
||||||
// change the branch used in the compiler to determine this.
|
fn empty_match_on_empty_enum(x: UninhabitedEnum) -> A {
|
||||||
// Codegen is skipped because tests with long names can cause issues on Windows CI, see #60648.
|
|
||||||
|
|
||||||
fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
|
|
||||||
match x {}
|
match x {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
|
fn empty_match_on_empty_struct(x: UninhabitedStruct) -> A {
|
||||||
match x {}
|
match x {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
|
fn empty_match_on_empty_tuple_struct(x: UninhabitedTupleStruct) -> A {
|
||||||
match x {}
|
match x {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
|
fn empty_match_on_enum_with_empty_variants_struct(x: UninhabitedVariants) -> A {
|
||||||
match x {}
|
match x {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
//@ aux-build:uninhabited.rs
|
//@ aux-build:uninhabited.rs
|
||||||
//@ build-pass (FIXME(62277): could be check-pass?)
|
|
||||||
#![deny(unreachable_patterns)]
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
extern crate uninhabited;
|
extern crate uninhabited;
|
||||||
|
|
||||||
use uninhabited::{
|
use uninhabited::{
|
||||||
PartiallyInhabitedVariants,
|
PartiallyInhabitedVariants, UninhabitedEnum, UninhabitedStruct, UninhabitedTupleStruct,
|
||||||
UninhabitedEnum,
|
|
||||||
UninhabitedStruct,
|
|
||||||
UninhabitedTupleStruct,
|
|
||||||
UninhabitedVariants,
|
UninhabitedVariants,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,27 +28,26 @@ fn uninhabited_tuple_struct() -> Option<UninhabitedTupleStruct> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
// This test checks that non-exhaustive types that would normally be considered uninhabited within
|
// This test checks that non-exhaustive enums are never considered uninhabited outside their
|
||||||
// the defining crate are not considered uninhabited from extern crates.
|
// defining crate, and non-exhaustive structs are considered uninhabited the same way as normal
|
||||||
|
// ones.
|
||||||
fn main() {
|
fn main() {
|
||||||
match uninhabited_enum() {
|
match uninhabited_enum() {
|
||||||
Some(_x) => (), // This line would normally error.
|
Some(_x) => (), // This would error without `non_exhaustive`
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
match uninhabited_variant() {
|
match uninhabited_variant() {
|
||||||
Some(_x) => (), // This line would normally error.
|
Some(_x) => (), //~ ERROR unreachable
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
// This line would normally error.
|
// This line would normally error.
|
||||||
while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() {
|
while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() {} //~ ERROR unreachable
|
||||||
|
|
||||||
|
while let Some(_x) = uninhabited_struct() { //~ ERROR unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Some(_x) = uninhabited_struct() { // This line would normally error.
|
while let Some(_x) = uninhabited_tuple_struct() { //~ ERROR unreachable
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(_x) = uninhabited_tuple_struct() { // This line would normally error.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/patterns.rs:41:9
|
||||||
|
|
|
||||||
|
LL | Some(_x) => (),
|
||||||
|
| ^^^^^^^^ matches no values because `UninhabitedVariants` is uninhabited
|
||||||
|
|
|
||||||
|
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/patterns.rs:2:9
|
||||||
|
|
|
||||||
|
LL | #![deny(unreachable_patterns)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/patterns.rs:46:15
|
||||||
|
|
|
||||||
|
LL | while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `!` is uninhabited
|
||||||
|
|
|
||||||
|
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||||
|
|
||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/patterns.rs:48:15
|
||||||
|
|
|
||||||
|
LL | while let Some(_x) = uninhabited_struct() {
|
||||||
|
| ^^^^^^^^ matches no values because `UninhabitedStruct` is uninhabited
|
||||||
|
|
|
||||||
|
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||||
|
|
||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/patterns.rs:51:15
|
||||||
|
|
|
||||||
|
LL | while let Some(_x) = uninhabited_tuple_struct() {
|
||||||
|
| ^^^^^^^^ matches no values because `UninhabitedTupleStruct` is uninhabited
|
||||||
|
|
|
||||||
|
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
|
@ -6,11 +6,12 @@ pub enum UninhabitedEnum {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct UninhabitedTupleStruct(!);
|
pub struct UninhabitedTupleStruct(pub !);
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct UninhabitedStruct {
|
pub struct UninhabitedStruct {
|
||||||
_priv: !,
|
pub never: !,
|
||||||
|
_priv: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum UninhabitedVariants {
|
pub enum UninhabitedVariants {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: unreachable pattern
|
error: unreachable pattern
|
||||||
--> $DIR/patterns_same_crate.rs:51:9
|
--> $DIR/patterns_same_crate.rs:52:9
|
||||||
|
|
|
|
||||||
LL | Some(_x) => (),
|
LL | Some(_x) => (),
|
||||||
| ^^^^^^^^ matches no values because `UninhabitedEnum` is uninhabited
|
| ^^^^^^^^ matches no values because `UninhabitedEnum` is uninhabited
|
||||||
|
@ -12,7 +12,7 @@ LL | #![deny(unreachable_patterns)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: unreachable pattern
|
error: unreachable pattern
|
||||||
--> $DIR/patterns_same_crate.rs:56:9
|
--> $DIR/patterns_same_crate.rs:57:9
|
||||||
|
|
|
|
||||||
LL | Some(_x) => (),
|
LL | Some(_x) => (),
|
||||||
| ^^^^^^^^ matches no values because `UninhabitedVariants` is uninhabited
|
| ^^^^^^^^ matches no values because `UninhabitedVariants` is uninhabited
|
||||||
|
@ -20,7 +20,7 @@ LL | Some(_x) => (),
|
||||||
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||||
|
|
||||||
error: unreachable pattern
|
error: unreachable pattern
|
||||||
--> $DIR/patterns_same_crate.rs:60:15
|
--> $DIR/patterns_same_crate.rs:61:15
|
||||||
|
|
|
|
||||||
LL | while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() {
|
LL | while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `!` is uninhabited
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `!` is uninhabited
|
||||||
|
@ -28,7 +28,7 @@ LL | while let PartiallyInhabitedVariants::Struct { x } = partially_inhabite
|
||||||
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||||
|
|
||||||
error: unreachable pattern
|
error: unreachable pattern
|
||||||
--> $DIR/patterns_same_crate.rs:64:15
|
--> $DIR/patterns_same_crate.rs:65:15
|
||||||
|
|
|
|
||||||
LL | while let Some(_x) = uninhabited_struct() {
|
LL | while let Some(_x) = uninhabited_struct() {
|
||||||
| ^^^^^^^^ matches no values because `UninhabitedStruct` is uninhabited
|
| ^^^^^^^^ matches no values because `UninhabitedStruct` is uninhabited
|
||||||
|
@ -36,7 +36,7 @@ LL | while let Some(_x) = uninhabited_struct() {
|
||||||
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||||
|
|
||||||
error: unreachable pattern
|
error: unreachable pattern
|
||||||
--> $DIR/patterns_same_crate.rs:67:15
|
--> $DIR/patterns_same_crate.rs:68:15
|
||||||
|
|
|
|
||||||
LL | while let Some(_x) = uninhabited_tuple_struct() {
|
LL | while let Some(_x) = uninhabited_tuple_struct() {
|
||||||
| ^^^^^^^^ matches no values because `UninhabitedTupleStruct` is uninhabited
|
| ^^^^^^^^ matches no values because `UninhabitedTupleStruct` is uninhabited
|
||||||
|
|
Loading…
Reference in New Issue