diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 197d3325f51..be1d973c2cd 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -113,9 +113,14 @@ impl<'a, 'gcx, 'tcx> AdtDef { tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: SubstsRef<'tcx>) -> DefIdForest { - DefIdForest::intersection(tcx, self.variants.iter().map(|v| { - v.uninhabited_from(tcx, substs, self.adt_kind()) - })) + // 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()) + })) + } } } @@ -134,9 +139,14 @@ impl<'a, 'gcx, 'tcx> VariantDef { AdtKind::Enum => true, AdtKind::Struct => false, }; - DefIdForest::union(tcx, self.fields.iter().map(|f| { - f.uninhabited_from(tcx, substs, is_enum) - })) + // Non-exhaustive variants from other crates are always considered inhabited. + if self.is_field_list_non_exhaustive() && !self.def_id.is_local() { + DefIdForest::empty() + } else { + DefIdForest::union(tcx, self.fields.iter().map(|f| { + f.uninhabited_from(tcx, substs, is_enum) + })) + } } } diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index edd36abc0b8..fd4416fc2b7 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -388,6 +388,18 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } } + fn is_non_exhaustive_variant<'p>(&self, pattern: &'p Pattern<'tcx>) -> bool + where 'a: 'p + { + match *pattern.kind { + PatternKind::Variant { adt_def, variant_index, .. } => { + let ref variant = adt_def.variants[variant_index]; + variant.is_field_list_non_exhaustive() + } + _ => false, + } + } + fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { match ty.sty { ty::Adt(adt_def, ..) => adt_def.is_variant_list_non_exhaustive(), @@ -1097,10 +1109,17 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]); if let Some(constructors) = pat_constructors(cx, v[0], pcx) { - debug!("is_useful - expanding constructors: {:#?}", constructors); - split_grouped_constructors(cx.tcx, constructors, matrix, pcx.ty).into_iter().map(|c| - is_useful_specialized(cx, matrix, v, c, pcx.ty, witness) - ).find(|result| result.is_useful()).unwrap_or(NotUseful) + let is_declared_nonexhaustive = cx.is_non_exhaustive_variant(v[0]) && !cx.is_local(pcx.ty); + debug!("is_useful - expanding constructors: {:#?}, is_declared_nonexhaustive: {:?}", + constructors, is_declared_nonexhaustive); + + if is_declared_nonexhaustive { + Useful + } else { + split_grouped_constructors(cx.tcx, constructors, matrix, pcx.ty).into_iter().map(|c| + is_useful_specialized(cx, matrix, v, c, pcx.ty, witness) + ).find(|result| result.is_useful()).unwrap_or(NotUseful) + } } else { debug!("is_useful - expanding wildcard"); diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 1a7266859ad..8c7155e1df3 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -208,7 +208,11 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { .map(|variant| variant.ident) .collect(); } - def.variants.is_empty() + + let is_non_exhaustive_and_non_local = + def.is_variant_list_non_exhaustive() && !def.did.is_local(); + + !(is_non_exhaustive_and_non_local) && def.variants.is_empty() }, _ => false } diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr index 261e95229a7..260c2e04d74 100644 --- a/src/test/ui/pattern/const-pat-ice.stderr +++ b/src/test/ui/pattern/const-pat-ice.stderr @@ -1,4 +1,4 @@ -thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1071:5 +thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1083:5 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. error: internal compiler error: unexpected panic diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs new file mode 100644 index 00000000000..8cb9a8cf1f6 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs @@ -0,0 +1,33 @@ +#![crate_type = "rlib"] +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub enum PartiallyInhabitedVariants { + Tuple(u8), + #[non_exhaustive] Struct { x: ! } +} + +pub struct IndirectUninhabitedEnum(UninhabitedEnum); + +pub struct IndirectUninhabitedStruct(UninhabitedStruct); + +pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + +pub struct IndirectUninhabitedVariants(UninhabitedVariants); diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs new file mode 100644 index 00000000000..80b9dc4c1c3 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs @@ -0,0 +1,38 @@ +// aux-build:uninhabited.rs +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +// This test checks that uninhabited non-exhaustive types cannot coerce to any type, as the never +// type can. + +struct A; + +fn can_coerce_never_type_to_anything(x: !) -> A { + x +} + +fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + x //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr new file mode 100644 index 00000000000..d05ee1d39ec --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr @@ -0,0 +1,47 @@ +error[E0308]: mismatched types + --> $DIR/coercions.rs:23:5 + | +LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found enum `uninhabited::UninhabitedEnum` + | + = note: expected type `A` + found type `uninhabited::UninhabitedEnum` + +error[E0308]: mismatched types + --> $DIR/coercions.rs:27:5 + | +LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found struct `uninhabited::UninhabitedTupleStruct` + | + = note: expected type `A` + found type `uninhabited::UninhabitedTupleStruct` + +error[E0308]: mismatched types + --> $DIR/coercions.rs:31:5 + | +LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found struct `uninhabited::UninhabitedStruct` + | + = note: expected type `A` + found type `uninhabited::UninhabitedStruct` + +error[E0308]: mismatched types + --> $DIR/coercions.rs:35:5 + | +LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found enum `uninhabited::UninhabitedVariants` + | + = note: expected type `A` + found type `uninhabited::UninhabitedVariants` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs new file mode 100644 index 00000000000..803a542f8aa --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs @@ -0,0 +1,46 @@ +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +struct A; + +// This test checks that uninhabited non-exhaustive types defined in the same crate cannot coerce +// to any type, as the never type can. + +fn can_coerce_never_type_to_anything(x: !) -> A { + x +} + +fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + x //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr new file mode 100644 index 00000000000..8f6b709bb1f --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr @@ -0,0 +1,47 @@ +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:31:5 + | +LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found enum `UninhabitedEnum` + | + = note: expected type `A` + found type `UninhabitedEnum` + +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:35:5 + | +LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found struct `UninhabitedTupleStruct` + | + = note: expected type `A` + found type `UninhabitedTupleStruct` + +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:39:5 + | +LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found struct `UninhabitedStruct` + | + = note: expected type `A` + found type `UninhabitedStruct` + +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:43:5 + | +LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found enum `UninhabitedVariants` + | + = note: expected type `A` + found type `UninhabitedVariants` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs new file mode 100644 index 00000000000..98a7fdbc504 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs @@ -0,0 +1,36 @@ +// aux-build:uninhabited.rs +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + IndirectUninhabitedEnum, + IndirectUninhabitedStruct, + IndirectUninhabitedTupleStruct, + IndirectUninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type through a level of +// indirection from an extern crate will not compile. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr new file mode 100644 index 00000000000..af82022e1da --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr @@ -0,0 +1,35 @@ +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `uninhabited::IndirectUninhabitedEnum` is not handled + --> $DIR/indirect_match.rs:19:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `uninhabited::IndirectUninhabitedStruct` is not handled + --> $DIR/indirect_match.rs:23:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `uninhabited::IndirectUninhabitedTupleStruct` is not handled + --> $DIR/indirect_match.rs:27:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `uninhabited::IndirectUninhabitedVariants` is not handled + --> $DIR/indirect_match.rs:33:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs new file mode 100644 index 00000000000..3c8d495e12c --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs @@ -0,0 +1,52 @@ +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub struct IndirectUninhabitedEnum(UninhabitedEnum); + +pub struct IndirectUninhabitedStruct(UninhabitedStruct); + +pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + +pub struct IndirectUninhabitedVariants(UninhabitedVariants); + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type through a level of +// indirection from the defining crate will not compile without `#![feature(exhaustive_patterns)]`. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr new file mode 100644 index 00000000000..27b120792d6 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr @@ -0,0 +1,59 @@ +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `IndirectUninhabitedEnum` is not handled + --> $DIR/indirect_match_same_crate.rs:35:11 + | +LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum); + | ---------------------------------------------------- + | | | + | | variant not covered + | `IndirectUninhabitedEnum` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `IndirectUninhabitedStruct` is not handled + --> $DIR/indirect_match_same_crate.rs:39:11 + | +LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct); + | -------------------------------------------------------- + | | | + | | variant not covered + | `IndirectUninhabitedStruct` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `IndirectUninhabitedTupleStruct` is not handled + --> $DIR/indirect_match_same_crate.rs:43:11 + | +LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + | ------------------------------------------------------------------ + | | | + | | variant not covered + | `IndirectUninhabitedTupleStruct` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `IndirectUninhabitedVariants` is not handled + --> $DIR/indirect_match_same_crate.rs:49:11 + | +LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants); + | ------------------------------------------------------------ + | | | + | | variant not covered + | `IndirectUninhabitedVariants` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs new file mode 100644 index 00000000000..be86519ecb1 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs @@ -0,0 +1,40 @@ +// aux-build:uninhabited.rs +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + IndirectUninhabitedEnum, + IndirectUninhabitedStruct, + IndirectUninhabitedTupleStruct, + IndirectUninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type through a level of +// indirection from an extern crate will not compile. In particular, this enables the +// `exhaustive_patterns` feature as this can change the branch used in the compiler to determine +// this. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr new file mode 100644 index 00000000000..17a8d010072 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr @@ -0,0 +1,35 @@ +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedEnum` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:23:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedStruct` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:27:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedTupleStruct` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:31:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedVariants` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs new file mode 100644 index 00000000000..5dbd38e07df --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs @@ -0,0 +1,58 @@ +// compile-pass +// skip-codegen +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub struct IndirectUninhabitedEnum(UninhabitedEnum); + +pub struct IndirectUninhabitedStruct(UninhabitedStruct); + +pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + +pub struct IndirectUninhabitedVariants(UninhabitedVariants); + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate +// will compile. In particular, this enables the `exhaustive_patterns` feature as this can +// change the branch used in the compiler to determine this. +// 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: IndirectUninhabitedEnum) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs new file mode 100644 index 00000000000..e54098d4d48 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs @@ -0,0 +1,34 @@ +// aux-build:uninhabited.rs +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate +// will not compile. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr new file mode 100644 index 00000000000..de39688f45a --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr @@ -0,0 +1,35 @@ +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty + --> $DIR/match.rs:19:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `uninhabited::UninhabitedStruct` is not handled + --> $DIR/match.rs:23:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `uninhabited::UninhabitedTupleStruct` is not handled + --> $DIR/match.rs:27:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: multiple patterns of type `uninhabited::UninhabitedVariants` are not handled + --> $DIR/match.rs:31:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs new file mode 100644 index 00000000000..6405dd3bd65 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs @@ -0,0 +1,42 @@ +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate +// will compile. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr new file mode 100644 index 00000000000..410285a39a9 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr @@ -0,0 +1,49 @@ +error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `UninhabitedStruct` is not handled + --> $DIR/match_same_crate.rs:31:11 + | +LL | pub struct UninhabitedStruct { + | - ----------------- variant not covered + | _| + | | +LL | | _priv: !, +LL | | } + | |_- `UninhabitedStruct` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `UninhabitedTupleStruct` is not handled + --> $DIR/match_same_crate.rs:35:11 + | +LL | pub struct UninhabitedTupleStruct(!); + | ------------------------------------- + | | | + | | variant not covered + | `UninhabitedTupleStruct` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: multiple patterns of type `UninhabitedVariants` are not handled + --> $DIR/match_same_crate.rs:39:11 + | +LL | / pub enum UninhabitedVariants { +LL | | #[non_exhaustive] Tuple(!), + | | ----- variant not covered +LL | | #[non_exhaustive] Struct { x: ! } + | | ------ variant not covered +LL | | } + | |_- `UninhabitedVariants` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs new file mode 100644 index 00000000000..900dfff652e --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs @@ -0,0 +1,37 @@ +// aux-build:uninhabited.rs +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate +// will not compile. In particular, this enables the `exhaustive_patterns` feature as this can +// change the branch used in the compiler to determine this. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr new file mode 100644 index 00000000000..48a888bc50b --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr @@ -0,0 +1,35 @@ +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:22:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedStruct` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:26:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedTupleStruct` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:30:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedVariants` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:34:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs new file mode 100644 index 00000000000..74922d4bcb5 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs @@ -0,0 +1,48 @@ +// compile-pass +// skip-codegen +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate +// will compile. In particular, this enables the `exhaustive_patterns` feature as this can +// change the branch used in the compiler to determine this. +// 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 {} +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs new file mode 100644 index 00000000000..97061310d19 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs @@ -0,0 +1,59 @@ +// aux-build:uninhabited.rs +// compile-pass +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] + +extern crate uninhabited; + +use uninhabited::{ + PartiallyInhabitedVariants, + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +fn uninhabited_enum() -> Option { + None +} + +fn uninhabited_variant() -> Option { + None +} + +fn partially_inhabited_variant() -> PartiallyInhabitedVariants { + PartiallyInhabitedVariants::Tuple(3) +} + +fn uninhabited_struct() -> Option { + None +} + +fn uninhabited_tuple_struct() -> Option { + None +} + +// This test checks that non-exhaustive types that would normally be considered uninhabited within +// the defining crate are not considered uninhabited from extern crates. + +fn main() { + match uninhabited_enum() { + Some(_x) => (), // This line would normally error. + None => (), + } + + match uninhabited_variant() { + Some(_x) => (), // This line would normally error. + None => (), + } + + // This line would normally error. + while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() { + } + + while let Some(_x) = uninhabited_struct() { // This line would normally error. + } + + while let Some(_x) = uninhabited_tuple_struct() { // This line would normally error. + } +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs new file mode 100644 index 00000000000..302a35cab5f --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs @@ -0,0 +1,71 @@ +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub enum PartiallyInhabitedVariants { + Tuple(u8), + #[non_exhaustive] Struct { x: ! } +} + +fn uninhabited_enum() -> Option { + None +} + +fn uninhabited_variant() -> Option { + None +} + +fn partially_inhabited_variant() -> PartiallyInhabitedVariants { + PartiallyInhabitedVariants::Tuple(3) +} + +fn uninhabited_struct() -> Option { + None +} + +fn uninhabited_tuple_struct() -> Option { + None +} + +// This test checks that non-exhaustive types that would normally be considered uninhabited within +// the defining crate are still considered uninhabited. + +fn main() { + match uninhabited_enum() { + Some(_x) => (), //~ ERROR unreachable pattern + None => (), + } + + match uninhabited_variant() { + Some(_x) => (), //~ ERROR unreachable pattern + None => (), + } + + while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() { + //~^ ERROR unreachable pattern + } + + while let Some(_x) = uninhabited_struct() { //~ ERROR unreachable pattern + } + + while let Some(_x) = uninhabited_tuple_struct() { //~ ERROR unreachable pattern + } +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr new file mode 100644 index 00000000000..72f37d9a60b --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr @@ -0,0 +1,38 @@ +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:53:9 + | +LL | Some(_x) => (), + | ^^^^^^^^ + | +note: lint level defined here + --> $DIR/patterns_same_crate.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:58:9 + | +LL | Some(_x) => (), + | ^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:62:15 + | +LL | while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:66:15 + | +LL | while let Some(_x) = uninhabited_struct() { + | ^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:69:15 + | +LL | while let Some(_x) = uninhabited_tuple_struct() { + | ^^^^^^^^ + +error: aborting due to 5 previous errors +