diff --git a/.mailmap b/.mailmap index 679e9d79847c2..63a49cd413287 100644 --- a/.mailmap +++ b/.mailmap @@ -155,6 +155,8 @@ Mark Sinclair =Mark Sinclair <=125axel125@gmail.com> Markus Westerlind Markus Martin Hafskjold Thoresen Matej Lach Matej Ľach +Mateusz Mikuła +Mateusz Mikuła Matt Brubeck Matthew Auld Matthew McPherrin diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 197d3325f51cf..be1d973c2cdd5 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 edd36abc0b8a4..fd4416fc2b763 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 1a7266859ad9f..8c7155e1df351 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/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 0cefcf1ce034b..e3586c1854c17 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -170,10 +170,9 @@ pub fn transcribe( } LockstepIterSize::Contradiction(ref msg) => { - // FIXME: this should be impossible. I (mark-i-m) believe it would - // represent a bug in the macro_parser. - // FIXME #2887 blame macro invoker instead - cx.span_fatal(seq.span(), &msg[..]); + // This should never happen because the macro parser should generate + // properly-sized matches for all meta-vars. + cx.span_bug(seq.span(), &msg[..]); } LockstepIterSize::Constraint(len, _) => { @@ -188,14 +187,13 @@ pub fn transcribe( // Is the repetition empty? if len == 0 { if seq.op == quoted::KleeneOp::OneOrMore { - // FIXME: this should be impossible because we check for this in - // macro_parser.rs - // FIXME #2887 blame invoker - cx.span_fatal(sp.entire(), "this must repeat at least once"); + // This should be impossible because the macro parser would not + // match the given macro arm. + cx.span_bug(sp.entire(), "this must repeat at least once"); } } else { // 0 is the initial counter (we have done 0 repretitions so far). `len` - // is the total number of reptitions we should generate. + // is the total number of reptitions we should generate. repeats.push((0, len)); // The first time we encounter the sequence we push it to the stack. It diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 20759217b54a0..d0ba09af30b06 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -344,9 +344,22 @@ impl Decodable for Ident { } } -/// A symbol is an interned or gensymed string. The use of `newtype_index!` means -/// that `Option` only takes up 4 bytes, because `newtype_index!` reserves -/// the last 256 values for tagging purposes. +/// A symbol is an interned or gensymed string. A gensym is a symbol that is +/// never equal to any other symbol. E.g.: +/// ``` +/// assert_eq!(Symbol::intern("x"), Symbol::intern("x")) +/// assert_ne!(Symbol::gensym("x"), Symbol::intern("x")) +/// assert_ne!(Symbol::gensym("x"), Symbol::gensym("x")) +/// ``` +/// Conceptually, a gensym can be thought of as a normal symbol with an +/// invisible unique suffix. Gensyms are useful when creating new identifiers +/// that must not match any existing identifiers, e.g. during macro expansion +/// and syntax desugaring. +/// +/// Internally, a Symbol is implemented as an index, and all operations +/// (including hashing, equality, and ordering) operate on that index. The use +/// of `newtype_index!` means that `Option` only takes up 4 bytes, +/// because `newtype_index!` reserves the last 256 values for tagging purposes. /// /// Note that `Symbol` cannot directly be a `newtype_index!` because it implements /// `fmt::Debug`, `Encodable`, and `Decodable` in special ways. @@ -367,10 +380,6 @@ impl Symbol { with_interner(|interner| interner.intern(string)) } - pub fn interned(self) -> Self { - with_interner(|interner| interner.interned(self)) - } - /// Gensyms a new `usize`, using the current interner. pub fn gensym(string: &str) -> Self { with_interner(|interner| interner.gensym(string)) @@ -380,6 +389,7 @@ impl Symbol { with_interner(|interner| interner.gensymed(self)) } + // WARNING: this function is deprecated and will be removed in the future. pub fn is_gensymed(self) -> bool { with_interner(|interner| interner.is_gensymed(self)) } @@ -488,11 +498,11 @@ impl Interner { name } - pub fn interned(&self, symbol: Symbol) -> Symbol { + fn interned(&self, symbol: Symbol) -> Symbol { if (symbol.0.as_usize()) < self.strings.len() { symbol } else { - self.interned(self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]) + self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize] } } @@ -510,10 +520,15 @@ impl Interner { symbol.0.as_usize() >= self.strings.len() } + // Get the symbol as a string. `Symbol::as_str()` should be used in + // preference to this function. pub fn get(&self, symbol: Symbol) -> &str { match self.strings.get(symbol.0.as_usize()) { Some(string) => string, - None => self.get(self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]), + None => { + let symbol = self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]; + self.strings[symbol.0.as_usize()] + } } } } @@ -611,11 +626,17 @@ fn with_interner T>(f: F) -> T { GLOBALS.with(|globals| f(&mut *globals.symbol_interner.lock())) } -/// Represents a string stored in the interner. Because the interner outlives any thread -/// which uses this type, we can safely treat `string` which points to interner data, -/// as an immortal string, as long as this type never crosses between threads. -// FIXME: ensure that the interner outlives any thread which uses `LocalInternedString`, -// by creating a new thread right after constructing the interner. +/// An alternative to `Symbol` and `InternedString`, useful when the chars +/// within the symbol need to be accessed. It is best used for temporary +/// values. +/// +/// Because the interner outlives any thread which uses this type, we can +/// safely treat `string` which points to interner data, as an immortal string, +/// as long as this type never crosses between threads. +// +// FIXME: ensure that the interner outlives any thread which uses +// `LocalInternedString`, by creating a new thread right after constructing the +// interner. #[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)] pub struct LocalInternedString { string: &'static str, @@ -708,7 +729,19 @@ impl Encodable for LocalInternedString { } } -/// Represents a string stored in the string interner. +/// An alternative to `Symbol` that is focused on string contents. It has two +/// main differences to `Symbol`. +/// +/// First, its implementations of `Hash`, `PartialOrd` and `Ord` work with the +/// string chars rather than the symbol integer. This is useful when hash +/// stability is required across compile sessions, or a guaranteed sort +/// ordering is required. +/// +/// Second, gensym-ness is irrelevant. E.g.: +/// ``` +/// assert_ne!(Symbol::gensym("x"), Symbol::gensym("x")) +/// assert_eq!(Symbol::gensym("x").as_interned_str(), Symbol::gensym("x").as_interned_str()) +/// ``` #[derive(Clone, Copy, Eq)] pub struct InternedString { symbol: Symbol, @@ -725,6 +758,15 @@ impl InternedString { unsafe { f(&*str) } } + fn with2 R, R>(self, other: &InternedString, f: F) -> R { + let (self_str, other_str) = with_interner(|interner| { + (interner.get(self.symbol) as *const str, + interner.get(other.symbol) as *const str) + }); + // This is safe for the same reason that `with` is safe. + unsafe { f(&*self_str, &*other_str) } + } + pub fn as_symbol(self) -> Symbol { self.symbol } @@ -745,7 +787,7 @@ impl PartialOrd for InternedString { if self.symbol == other.symbol { return Some(Ordering::Equal); } - self.with(|self_str| other.with(|other_str| self_str.partial_cmp(other_str))) + self.with2(other, |self_str, other_str| self_str.partial_cmp(other_str)) } } @@ -754,7 +796,7 @@ impl Ord for InternedString { if self.symbol == other.symbol { return Ordering::Equal; } - self.with(|self_str| other.with(|other_str| self_str.cmp(&other_str))) + self.with2(other, |self_str, other_str| self_str.cmp(other_str)) } } @@ -794,12 +836,6 @@ impl<'a> PartialEq for &'a String { } } -impl std::convert::From for String { - fn from(val: InternedString) -> String { - val.as_symbol().to_string() - } -} - impl fmt::Debug for InternedString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.with(|str| fmt::Debug::fmt(&str, f)) diff --git a/src/test/incremental/issue-60629.rs b/src/test/incremental/issue-60629.rs new file mode 100644 index 0000000000000..4807af4b3cf70 --- /dev/null +++ b/src/test/incremental/issue-60629.rs @@ -0,0 +1,10 @@ +// revisions:rpass1 rpass2 + +struct A; + +#[cfg(rpass2)] +impl From for () { + fn from(_: A) {} +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-60674.rs b/src/test/ui/async-await/issue-60674.rs index 37e356e5baf48..ecb80803383b4 100644 --- a/src/test/ui/async-await/issue-60674.rs +++ b/src/test/ui/async-await/issue-60674.rs @@ -11,4 +11,10 @@ extern crate issue_60674; #[issue_60674::attr] async fn f(mut x: u8) {} +#[issue_60674::attr] +async fn g((mut x, y, mut z): (u8, u8, u8)) {} + +#[issue_60674::attr] +async fn g(mut x: u8, (a, mut b, c): (u8, u8, u8), y: u8) {} + fn main() {} diff --git a/src/test/ui/async-await/issue-60674.stdout b/src/test/ui/async-await/issue-60674.stdout index a93944db1c591..86c3591b3afc0 100644 --- a/src/test/ui/async-await/issue-60674.stdout +++ b/src/test/ui/async-await/issue-60674.stdout @@ -1 +1,3 @@ async fn f(mut x: u8) { } +async fn g((mut x, y, mut z): (u8, u8, u8)) { } +async fn g(mut x: u8, (a, mut b, c): (u8, u8, u8), y: u8) { } diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr index 261e95229a76e..260c2e04d74f7 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 0000000000000..8cb9a8cf1f613 --- /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 0000000000000..80b9dc4c1c338 --- /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 0000000000000..d05ee1d39ec35 --- /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 0000000000000..803a542f8aa4b --- /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 0000000000000..8f6b709bb1f34 --- /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 0000000000000..98a7fdbc5049a --- /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 0000000000000..af82022e1da99 --- /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 0000000000000..3c8d495e12cb6 --- /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 0000000000000..27b120792d6d1 --- /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 0000000000000..be86519ecb159 --- /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 0000000000000..17a8d01007205 --- /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 0000000000000..5dbd38e07df02 --- /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 0000000000000..e54098d4d48b9 --- /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 0000000000000..de39688f45a4d --- /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 0000000000000..6405dd3bd65b7 --- /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 0000000000000..410285a39a945 --- /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 0000000000000..900dfff652ea6 --- /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 0000000000000..48a888bc50be0 --- /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 0000000000000..74922d4bcb5d5 --- /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 0000000000000..97061310d19e2 --- /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 0000000000000..302a35cab5f90 --- /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 0000000000000..72f37d9a60ba8 --- /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 +