diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-12-13 20:35:28 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-12-13 20:35:28 +0100 |
| commit | df9e491fb238ff7b7bfee8dd2d3f01158ac8b0d3 (patch) | |
| tree | 40e01a66c07aed56b80b80b010e18bd84d73deaf /src | |
| parent | 3964a55ba59bb6c3d4badcbddc49f6929ef76862 (diff) | |
| parent | fbd2cd09e6fd044cad02af97e581853f1875ab2a (diff) | |
| download | rust-df9e491fb238ff7b7bfee8dd2d3f01158ac8b0d3.tar.gz rust-df9e491fb238ff7b7bfee8dd2d3f01158ac8b0d3.zip | |
Rollup merge of #67026 - Nadrieril:improve-usefulness-empty, r=varkor,Centril,estebank
Improve diagnostics and code for exhaustiveness of empty matches There was a completely separate check and diagnostics for the case of an empty match. This led to slightly different error messages and duplicated code. This improves code reuse and generally clarifies what happens for empty matches. This also clarifies the action of the `exhaustive_patterns` feature, and ensures that this feature doesn't change diagnostics in places it doesn't need to.
Diffstat (limited to 'src')
20 files changed, 889 insertions, 182 deletions
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 37a9381271a..c3720328506 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -238,7 +238,7 @@ use super::{FieldPat, Pat, PatKind, PatRange}; use rustc::hir::def_id::DefId; use rustc::hir::{HirId, RangeEnd}; use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx}; -use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef}; use rustc::lint; use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar}; @@ -354,7 +354,7 @@ impl PatternFolder<'tcx> for LiteralExpander<'tcx> { } impl<'tcx> Pat<'tcx> { - fn is_wildcard(&self) -> bool { + pub(super) fn is_wildcard(&self) -> bool { match *self.kind { PatKind::Binding { subpattern: None, .. } | PatKind::Wild => true, _ => false, @@ -596,9 +596,21 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } } - fn is_local(&self, ty: Ty<'tcx>) -> bool { + // Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. + pub fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { match ty.kind { - ty::Adt(adt_def, ..) => adt_def.did.is_local(), + ty::Adt(def, ..) => { + def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local() + } + _ => false, + } + } + + // Returns whether the given variant is from another crate and has its fields declared + // `#[non_exhaustive]`. + fn is_foreign_non_exhaustive_variant(&self, ty: Ty<'tcx>, variant: &VariantDef) -> bool { + match ty.kind { + ty::Adt(def, ..) => variant.is_field_list_non_exhaustive() && !def.did.is_local(), _ => false, } } @@ -758,6 +770,10 @@ impl<'tcx> Constructor<'tcx> { // Returns the set of constructors covered by `self` but not by // anything in `other_ctors`. fn subtract_ctors(&self, other_ctors: &Vec<Constructor<'tcx>>) -> Vec<Constructor<'tcx>> { + if other_ctors.is_empty() { + return vec![self.clone()]; + } + match self { // Those constructors can only match themselves. Single | Variant(_) | ConstantValue(..) | FloatRange(..) => { @@ -858,8 +874,7 @@ impl<'tcx> Constructor<'tcx> { vec![Pat::wildcard_from_ty(substs.type_at(0))] } else { let variant = &adt.variants[self.variant_index_for_adt(cx, adt)]; - let is_non_exhaustive = - variant.is_field_list_non_exhaustive() && !cx.is_local(ty); + let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(ty, variant); variant .fields .iter() @@ -1205,6 +1220,8 @@ impl<'tcx> Witness<'tcx> { /// /// We make sure to omit constructors that are statically impossible. E.g., for /// `Option<!>`, we do not include `Some(_)` in the returned list of constructors. +/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by +/// `cx.is_uninhabited()`). fn all_constructors<'a, 'tcx>( cx: &mut MatchCheckCtxt<'a, 'tcx>, pcx: PatCtxt<'tcx>, @@ -1235,47 +1252,45 @@ fn all_constructors<'a, 'tcx>( vec![Slice(Slice { array_len: None, kind })] } ty::Adt(def, substs) if def.is_enum() => { - let ctors: Vec<_> = def - .variants - .iter() - .filter(|v| { - !cx.tcx.features().exhaustive_patterns - || !v - .uninhabited_from(cx.tcx, substs, def.adt_kind()) + let ctors: Vec<_> = if cx.tcx.features().exhaustive_patterns { + // If `exhaustive_patterns` is enabled, we exclude variants known to be + // uninhabited. + def.variants + .iter() + .filter(|v| { + !v.uninhabited_from(cx.tcx, substs, def.adt_kind()) .contains(cx.tcx, cx.module) - }) - .map(|v| Variant(v.def_id)) - .collect(); - - // If our scrutinee is *privately* an empty enum, we must treat it as though it had an - // "unknown" constructor (in that case, all other patterns obviously can't be variants) - // to avoid exposing its emptyness. See the `match_privately_empty` test for details. - // FIXME: currently the only way I know of something can be a privately-empty enum is - // when the exhaustive_patterns feature flag is not present, so this is only needed for - // that case. - let is_privately_empty = ctors.is_empty() && !cx.is_uninhabited(pcx.ty); - // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an - // additionnal "unknown" constructor. - let is_declared_nonexhaustive = - def.is_variant_list_non_exhaustive() && !cx.is_local(pcx.ty); - - if is_privately_empty || is_declared_nonexhaustive { - // There is no point in enumerating all possible variants, because the user can't - // actually match against them themselves. So we return only the fictitious - // constructor. - // E.g., in an example like: - // ``` - // let err: io::ErrorKind = ...; - // match err { - // io::ErrorKind::NotFound => {}, - // } - // ``` - // we don't want to show every possible IO error, but instead have only `_` as the - // witness. - vec![NonExhaustive] + }) + .map(|v| Variant(v.def_id)) + .collect() } else { - ctors - } + def.variants.iter().map(|v| Variant(v.def_id)).collect() + }; + + // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an + // additional "unknown" constructor. + // There is no point in enumerating all possible variants, because the user can't + // actually match against them all themselves. So we always return only the fictitious + // constructor. + // E.g., in an example like: + // ``` + // let err: io::ErrorKind = ...; + // match err { + // io::ErrorKind::NotFound => {}, + // } + // ``` + // we don't want to show every possible IO error, but instead have only `_` as the + // witness. + let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty); + + // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it + // as though it had an "unknown" constructor to avoid exposing its emptyness. Note that + // an empty match will still be considered exhaustive because that case is handled + // separately in `check_match`. + let is_secretly_empty = + def.variants.is_empty() && !cx.tcx.features().exhaustive_patterns; + + if is_secretly_empty || is_declared_nonexhaustive { vec![NonExhaustive] } else { ctors } } ty::Char => { vec![ @@ -1605,6 +1620,7 @@ pub fn is_useful<'p, 'tcx>( v: &PatStack<'p, 'tcx>, witness_preference: WitnessPreference, hir_id: HirId, + is_top_level: bool, ) -> Usefulness<'tcx, 'p> { let &Matrix(ref rows) = matrix; debug!("is_useful({:#?}, {:#?})", matrix, v); @@ -1632,7 +1648,7 @@ pub fn is_useful<'p, 'tcx>( let mut unreachable_pats = Vec::new(); let mut any_is_useful = false; for v in vs { - let res = is_useful(cx, &matrix, &v, witness_preference, hir_id); + let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, false); match res { Useful(pats) => { any_is_useful = true; @@ -1732,7 +1748,7 @@ pub fn is_useful<'p, 'tcx>( } else { let matrix = matrix.specialize_wildcard(); let v = v.to_tail(); - let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id); + let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id, false); // In this case, there's at least one "free" // constructor that is only matched against by @@ -1761,7 +1777,10 @@ pub fn is_useful<'p, 'tcx>( // `(<direction-1>, <direction-2>, true)` - we are // satisfied with `(_, _, true)`. In this case, // `used_ctors` is empty. - if missing_ctors.all_ctors_are_missing() { + // The exception is: if we are at the top-level, for example in an empty match, we + // sometimes prefer reporting the list of constructors instead of just `_`. + let report_ctors_rather_than_wildcard = is_top_level && !IntRange::is_integral(pcx.ty); + if missing_ctors.all_ctors_are_missing() && !report_ctors_rather_than_wildcard { // All constructors are unused. Add a wild pattern // rather than each individual constructor. usefulness.apply_wildcard(pcx.ty) @@ -1793,7 +1812,7 @@ fn is_useful_specialized<'p, 'tcx>( cx.pattern_arena.alloc_from_iter(ctor.wildcard_subpatterns(cx, lty)); let matrix = matrix.specialize_constructor(cx, &ctor, ctor_wild_subpatterns); v.specialize_constructor(cx, &ctor, ctor_wild_subpatterns) - .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id)) + .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, false)) .map(|u| u.apply_constructor(cx, &ctor, lty)) .unwrap_or(NotUseful) } @@ -2308,7 +2327,7 @@ fn specialize_one_pattern<'p, 'tcx>( PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { let ref variant = adt_def.variants[variant_index]; - let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(pat.ty); + let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(pat.ty, variant); Some(Variant(variant.def_id)) .filter(|variant_constructor| variant_constructor == constructor) .map(|_| { diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 737af3e1358..8156cfe7ab5 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -148,8 +148,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { self.tables, ); patcx.include_lint_checks(); - let pattern: &_ = - cx.pattern_arena.alloc(expand_pattern(cx, patcx.lower_pattern(&arm.pat))); + let pattern = patcx.lower_pattern(&arm.pat); + let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern)); if !patcx.errors.is_empty() { patcx.report_inlining_errors(arm.pat.span); have_errors = true; @@ -166,73 +166,12 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { // Fourth, check for unreachable arms. let matrix = check_arms(cx, &inlined_arms, source); - // Then, if the match has no arms, check whether the scrutinee - // is uninhabited. - let pat_ty = self.tables.node_type(scrut.hir_id); - let module = self.tcx.hir().get_module_parent(scrut.hir_id); - let mut def_span = None; - let mut missing_variants = vec![]; - if inlined_arms.is_empty() { - let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns { - self.tcx.is_ty_uninhabited_from(module, pat_ty) - } else { - match pat_ty.kind { - ty::Never => true, - ty::Adt(def, _) => { - def_span = self.tcx.hir().span_if_local(def.did); - if def.variants.len() < 4 && !def.variants.is_empty() { - // keep around to point at the definition of non-covered variants - missing_variants = - def.variants.iter().map(|variant| variant.ident).collect(); - } - - 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, - } - }; - if !scrutinee_is_uninhabited { - // We know the type is inhabited, so this must be wrong - let mut err = create_e0004( - self.tcx.sess, - scrut.span, - format!( - "non-exhaustive patterns: {}", - match missing_variants.len() { - 0 => format!("type `{}` is non-empty", pat_ty), - 1 => format!( - "pattern `{}` of type `{}` is not handled", - missing_variants[0].name, pat_ty, - ), - _ => format!( - "multiple patterns of type `{}` are not handled", - pat_ty - ), - } - ), - ); - err.help( - "ensure that all possible cases are being handled, \ - possibly by adding wildcards or more match arms", - ); - if let Some(sp) = def_span { - err.span_label(sp, format!("`{}` defined here", pat_ty)); - } - // point at the definition of non-covered enum variants - for variant in &missing_variants { - err.span_label(variant.span, "variant not covered"); - } - err.emit(); - } - // If the type *is* uninhabited, it's vacuously exhaustive - return; - } - + // Fifth, check if the match is exhaustive. let scrut_ty = self.tables.node_type(scrut.hir_id); - check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id); + // Note: An empty match isn't the same as an empty matrix for diagnostics purposes, + // since an empty matrix can occur when there are arms, if those arms all have guards. + let is_empty_match = inlined_arms.is_empty(); + check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match); }) } @@ -390,7 +329,7 @@ fn check_arms<'p, 'tcx>( for (arm_index, (pat, hir_pat, has_guard)) in arms.iter().enumerate() { let v = PatStack::from_pattern(pat); - match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) { + match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id, true) { NotUseful => { match source { hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(), @@ -478,7 +417,8 @@ fn check_not_useful<'p, 'tcx>( hir_id: HirId, ) -> Result<(), Vec<super::Pat<'tcx>>> { let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(ty)); - match is_useful(cx, matrix, &PatStack::from_pattern(wild_pattern), ConstructWitness, hir_id) { + let v = PatStack::from_pattern(wild_pattern); + match is_useful(cx, matrix, &v, ConstructWitness, hir_id, true) { NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable. UsefulWithWitness(pats) => Err(if pats.is_empty() { bug!("Exhaustiveness check returned no witnesses") @@ -495,25 +435,60 @@ fn check_exhaustive<'p, 'tcx>( sp: Span, matrix: &Matrix<'p, 'tcx>, hir_id: HirId, + is_empty_match: bool, ) { + // In the absence of the `exhaustive_patterns` feature, empty matches are not detected by + // `is_useful` to exhaustively match uninhabited types, so we manually check here. + if is_empty_match && !cx.tcx.features().exhaustive_patterns { + let scrutinee_is_visibly_uninhabited = match scrut_ty.kind { + ty::Never => true, + ty::Adt(def, _) => { + def.is_enum() + && def.variants.is_empty() + && !cx.is_foreign_non_exhaustive_enum(scrut_ty) + } + _ => false, + }; + if scrutinee_is_visibly_uninhabited { + // If the type *is* uninhabited, an empty match is vacuously exhaustive. + return; + } + } + let witnesses = match check_not_useful(cx, scrut_ty, matrix, hir_id) { Ok(_) => return, Err(err) => err, }; - let joined_patterns = joined_uncovered_patterns(&witnesses); - let mut err = create_e0004( - cx.tcx.sess, - sp, - format!("non-exhaustive patterns: {} not covered", joined_patterns), - ); - err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); + let non_empty_enum = match scrut_ty.kind { + ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(), + _ => false, + }; + // In the case of an empty match, replace the '`_` not covered' diagnostic with something more + // informative. + let mut err; + if is_empty_match && !non_empty_enum { + err = create_e0004( + cx.tcx.sess, + sp, + format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty), + ); + } else { + let joined_patterns = joined_uncovered_patterns(&witnesses); + err = create_e0004( + cx.tcx.sess, + sp, + format!("non-exhaustive patterns: {} not covered", joined_patterns), + ); + err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); + }; + adt_defined_here(cx, &mut err, scrut_ty, &witnesses); err.help( "ensure that all possible cases are being handled, \ possibly by adding wildcards or more match arms", - ) - .emit(); + ); + err.emit(); } fn joined_uncovered_patterns(witnesses: &[super::Pat<'_>]) -> String { diff --git a/src/test/ui/error-codes/E0004-2.stderr b/src/test/ui/error-codes/E0004-2.stderr index db0a2b5a085..f5b41cd1cc0 100644 --- a/src/test/ui/error-codes/E0004-2.stderr +++ b/src/test/ui/error-codes/E0004-2.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: multiple patterns of type `std::option::Option<i32>` are not handled +error[E0004]: non-exhaustive patterns: `None` and `Some(_)` not covered --> $DIR/E0004-2.rs:4:11 | LL | match x { } - | ^ + | ^ patterns `None` and `Some(_)` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms diff --git a/src/test/ui/issues/issue-3601.stderr b/src/test/ui/issues/issue-3601.stderr index fa0fa3345f5..445eb4107d1 100644 --- a/src/test/ui/issues/issue-3601.stderr +++ b/src/test/ui/issues/issue-3601.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `_` not covered +error[E0004]: non-exhaustive patterns: `Box(_)` not covered --> $DIR/issue-3601.rs:30:44 | LL | box NodeKind::Element(ed) => match ed.kind { - | ^^^^^^^ pattern `_` not covered + | ^^^^^^^ pattern `Box(_)` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms diff --git a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr index 792ab6f59a4..1b1096c977a 100644 --- a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr +++ b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr @@ -9,8 +9,13 @@ LL | match uninhab_ref() { error[E0004]: non-exhaustive patterns: type `Foo` is non-empty --> $DIR/always-inhabited-union-ref.rs:27:11 | -LL | match uninhab_union() { - | ^^^^^^^^^^^^^^^ +LL | / pub union Foo { +LL | | foo: !, +LL | | } + | |_- `Foo` defined here +... +LL | match uninhab_union() { + | ^^^^^^^^^^^^^^^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs new file mode 100644 index 00000000000..57b6b910ca1 --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs @@ -0,0 +1,93 @@ +#![feature(never_type)] +#![feature(exhaustive_patterns)] +#![deny(unreachable_patterns)] +enum Foo {} + +struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here +union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here + foo: (), +} +union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here + foo: (), + bar: (), +} +enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here + Foo(bool), + //~^ not covered + //~| not covered +} +enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here + Foo(bool), + //~^ not covered + //~| not covered + Bar, + //~^ not covered + //~| not covered +} +enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here + V1, V2, V3, V4, V5, +} + +macro_rules! match_empty { + ($e:expr) => { + match $e {} + }; +} +macro_rules! match_false { + ($e:expr) => { + match $e { + _ if false => {} + } + }; +} + +fn foo(x: Foo) { + match_empty!(x); // ok + match x { + _ => {}, //~ ERROR unreachable pattern + } + match x { + _ if false => {}, //~ ERROR unreachable pattern + } +} + +fn main() { + match None::<!> { + None => {} + Some(_) => {} //~ ERROR unreachable pattern + } + match None::<Foo> { + None => {} + Some(_) => {} //~ ERROR unreachable pattern + } + + match_empty!(0u8); + //~^ ERROR type `u8` is non-empty + match_empty!(NonEmptyStruct(true)); + //~^ ERROR type `NonEmptyStruct` is non-empty + match_empty!((NonEmptyUnion1 { foo: () })); + //~^ ERROR type `NonEmptyUnion1` is non-empty + match_empty!((NonEmptyUnion2 { foo: () })); + //~^ ERROR type `NonEmptyUnion2` is non-empty + match_empty!(NonEmptyEnum1::Foo(true)); + //~^ ERROR `Foo(_)` not covered + match_empty!(NonEmptyEnum2::Foo(true)); + //~^ ERROR `Foo(_)` and `Bar` not covered + match_empty!(NonEmptyEnum5::V1); + //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered + + match_false!(0u8); + //~^ ERROR `_` not covered + match_false!(NonEmptyStruct(true)); + //~^ ERROR `NonEmptyStruct(_)` not covered + match_false!((NonEmptyUnion1 { foo: () })); + //~^ ERROR `NonEmptyUnion1 { .. }` not covered + match_false!((NonEmptyUnion2 { foo: () })); + //~^ ERROR `NonEmptyUnion2 { .. }` not covered + match_false!(NonEmptyEnum1::Foo(true)); + //~^ ERROR `Foo(_)` not covered + match_false!(NonEmptyEnum2::Foo(true)); + //~^ ERROR `Foo(_)` and `Bar` not covered + match_false!(NonEmptyEnum5::V1); + //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered +} diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr new file mode 100644 index 00000000000..f242ecf2dae --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr @@ -0,0 +1,223 @@ +error: unreachable pattern + --> $DIR/match-empty-exhaustive_patterns.rs:47:9 + | +LL | _ => {}, + | ^ + | +note: lint level defined here + --> $DIR/match-empty-exhaustive_patterns.rs:3:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/match-empty-exhaustive_patterns.rs:50:9 + | +LL | _ if false => {}, + | ^ + +error: unreachable pattern + --> $DIR/match-empty-exhaustive_patterns.rs:57:9 + | +LL | Some(_) => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/match-empty-exhaustive_patterns.rs:61:9 + | +LL | Some(_) => {} + | ^^^^^^^ + +error[E0004]: non-exhaustive patterns: type `u8` is non-empty + --> $DIR/match-empty-exhaustive_patterns.rs:64:18 + | +LL | match_empty!(0u8); + | ^^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty + --> $DIR/match-empty-exhaustive_patterns.rs:66:18 + | +LL | struct NonEmptyStruct(bool); + | ---------------------------- `NonEmptyStruct` defined here +... +LL | match_empty!(NonEmptyStruct(true)); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty + --> $DIR/match-empty-exhaustive_patterns.rs:68:18 + | +LL | / union NonEmptyUnion1 { +LL | | foo: (), +LL | | } + | |_- `NonEmptyUnion1` defined here +... +LL | match_empty!((NonEmptyUnion1 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty + --> $DIR/match-empty-exhaustive_patterns.rs:70:18 + | +LL | / union NonEmptyUnion2 { +LL | | foo: (), +LL | | bar: (), +LL | | } + | |_- `NonEmptyUnion2` defined here +... +LL | match_empty!((NonEmptyUnion2 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `Foo(_)` not covered + --> $DIR/match-empty-exhaustive_patterns.rs:72:18 + | +LL | / enum NonEmptyEnum1 { +LL | | Foo(bool), + | | --- not covered +LL | | +LL | | +LL | | } + | |_- `NonEmptyEnum1` defined here +... +LL | match_empty!(NonEmptyEnum1::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered + --> $DIR/match-empty-exhaustive_patterns.rs:74:18 + | +LL | / enum NonEmptyEnum2 { +LL | | Foo(bool), + | | --- not covered +LL | | +LL | | +LL | | Bar, + | | --- not covered +LL | | +LL | | +LL | | } + | |_- `NonEmptyEnum2` defined here +... +LL | match_empty!(NonEmptyEnum2::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered + --> $DIR/match-empty-exhaustive_patterns.rs:76:18 + | +LL | / enum NonEmptyEnum5 { +LL | | V1, V2, V3, V4, V5, +LL | | } + | |_- `NonEmptyEnum5` defined here +... +LL | match_empty!(NonEmptyEnum5::V1); + | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/match-empty-exhaustive_patterns.rs:79:18 + | +LL | match_false!(0u8); + | ^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered + --> $DIR/match-empty-exhaustive_patterns.rs:81:18 + | +LL | struct NonEmptyStruct(bool); + | ---------------------------- `NonEmptyStruct` defined here +... +LL | match_false!(NonEmptyStruct(true)); + | ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered + --> $DIR/match-empty-exhaustive_patterns.rs:83:18 + | +LL | / union NonEmptyUnion1 { +LL | | foo: (), +LL | | } + | |_- `NonEmptyUnion1` defined here +... +LL | match_false!((NonEmptyUnion1 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered + --> $DIR/match-empty-exhaustive_patterns.rs:85:18 + | +LL | / union NonEmptyUnion2 { +LL | | foo: (), +LL | | bar: (), +LL | | } + | |_- `NonEmptyUnion2` defined here +... +LL | match_false!((NonEmptyUnion2 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `Foo(_)` not covered + --> $DIR/match-empty-exhaustive_patterns.rs:87:18 + | +LL | / enum NonEmptyEnum1 { +LL | | Foo(bool), + | | --- not covered +LL | | +LL | | +LL | | } + | |_- `NonEmptyEnum1` defined here +... +LL | match_false!(NonEmptyEnum1::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered + --> $DIR/match-empty-exhaustive_patterns.rs:89:18 + | +LL | / enum NonEmptyEnum2 { +LL | | Foo(bool), + | | --- not covered +LL | | +LL | | +LL | | Bar, + | | --- not covered +LL | | +LL | | +LL | | } + | |_- `NonEmptyEnum2` defined here +... +LL | match_false!(NonEmptyEnum2::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered + --> $DIR/match-empty-exhaustive_patterns.rs:91:18 + | +LL | / enum NonEmptyEnum5 { +LL | | V1, V2, V3, V4, V5, +LL | | } + | |_- `NonEmptyEnum5` defined here +... +LL | match_false!(NonEmptyEnum5::V1); + | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 18 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/match-empty.rs b/src/test/ui/pattern/usefulness/match-empty.rs new file mode 100644 index 00000000000..f7577125d8a --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-empty.rs @@ -0,0 +1,92 @@ +#![feature(never_type)] +#![deny(unreachable_patterns)] +enum Foo {} + +struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here +union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here + foo: (), +} +union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here + foo: (), + bar: (), +} +enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here + Foo(bool), + //~^ not covered + //~| not covered +} +enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here + Foo(bool), + //~^ not covered + //~| not covered + Bar, + //~^ not covered + //~| not covered +} +enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here + V1, V2, V3, V4, V5, +} + +macro_rules! match_empty { + ($e:expr) => { + match $e {} + }; +} +macro_rules! match_false { + ($e:expr) => { + match $e { + _ if false => {} + } + }; +} + +fn foo(x: Foo) { + match_empty!(x); // ok + match_false!(x); // Not detected as unreachable nor exhaustive. + //~^ ERROR non-exhaustive patterns: `_` not covered + match x { + _ => {}, // Not detected as unreachable, see #55123. + } +} + +fn main() { + // `exhaustive_patterns` is not on, so uninhabited branches are not detected as unreachable. + match None::<!> { + None => {} + Some(_) => {} + } + match None::<Foo> { + None => {} + Some(_) => {} + } + + match_empty!(0u8); + //~^ ERROR type `u8` is non-empty + match_empty!(NonEmptyStruct(true)); + //~^ ERROR type `NonEmptyStruct` is non-empty + match_empty!((NonEmptyUnion1 { foo: () })); + //~^ ERROR type `NonEmptyUnion1` is non-empty + match_empty!((NonEmptyUnion2 { foo: () })); + //~^ ERROR type `NonEmptyUnion2` is non-empty + match_empty!(NonEmptyEnum1::Foo(true)); + //~^ ERROR `Foo(_)` not covered + match_empty!(NonEmptyEnum2::Foo(true)); + //~^ ERROR `Foo(_)` and `Bar` not covered + match_empty!(NonEmptyEnum5::V1); + //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered + + match_false!(0u8); + //~^ ERROR `_` not covered + match_false!(NonEmptyStruct(true)); + //~^ ERROR `NonEmptyStruct(_)` not covered + match_false!((NonEmptyUnion1 { foo: () })); + //~^ ERROR `NonEmptyUnion1 { .. }` not covered + match_false!((NonEmptyUnion2 { foo: () })); + //~^ ERROR `NonEmptyUnion2 { .. }` not covered + match_false!(NonEmptyEnum1::Foo(true)); + //~^ ERROR `Foo(_)` not covered + match_false!(NonEmptyEnum2::Foo(true)); + //~^ ERROR `Foo(_)` and `Bar` not covered + match_false!(NonEmptyEnum5::V1); + //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered +} diff --git a/src/test/ui/pattern/usefulness/match-empty.stderr b/src/test/ui/pattern/usefulness/match-empty.stderr new file mode 100644 index 00000000000..72e3fc0a167 --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-empty.stderr @@ -0,0 +1,204 @@ +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/match-empty.rs:45:18 + | +LL | enum Foo {} + | ----------- `Foo` defined here +... +LL | match_false!(x); // Not detected as unreachable nor exhaustive. + | ^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `u8` is non-empty + --> $DIR/match-empty.rs:63:18 + | +LL | match_empty!(0u8); + | ^^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty + --> $DIR/match-empty.rs:65:18 + | +LL | struct NonEmptyStruct(bool); + | ---------------------------- `NonEmptyStruct` defined here +... +LL | match_empty!(NonEmptyStruct(true)); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty + --> $DIR/match-empty.rs:67:18 + | +LL | / union NonEmptyUnion1 { +LL | | foo: (), +LL | | } + | |_- `NonEmptyUnion1` defined here +... +LL | match_empty!((NonEmptyUnion1 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty + --> $DIR/match-empty.rs:69:18 + | +LL | / union NonEmptyUnion2 { +LL | | foo: (), +LL | | bar: (), +LL | | } + | |_- `NonEmptyUnion2` defined here +... +LL | match_empty!((NonEmptyUnion2 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `Foo(_)` not covered + --> $DIR/match-empty.rs:71:18 + | +LL | / enum NonEmptyEnum1 { +LL | | Foo(bool), + | | --- not covered +LL | | +LL | | +LL | | } + | |_- `NonEmptyEnum1` defined here +... +LL | match_empty!(NonEmptyEnum1::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered + --> $DIR/match-empty.rs:73:18 + | +LL | / enum NonEmptyEnum2 { +LL | | Foo(bool), + | | --- not covered +LL | | +LL | | +LL | | Bar, + | | --- not covered +LL | | +LL | | +LL | | } + | |_- `NonEmptyEnum2` defined here +... +LL | match_empty!(NonEmptyEnum2::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered + --> $DIR/match-empty.rs:75:18 + | +LL | / enum NonEmptyEnum5 { +LL | | V1, V2, V3, V4, V5, +LL | | } + | |_- `NonEmptyEnum5` defined here +... +LL | match_empty!(NonEmptyEnum5::V1); + | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/match-empty.rs:78:18 + | +LL | match_false!(0u8); + | ^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered + --> $DIR/match-empty.rs:80:18 + | +LL | struct NonEmptyStruct(bool); + | ---------------------------- `NonEmptyStruct` defined here +... +LL | match_false!(NonEmptyStruct(true)); + | ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered + --> $DIR/match-empty.rs:82:18 + | +LL | / union NonEmptyUnion1 { +LL | | foo: (), +LL | | } + | |_- `NonEmptyUnion1` defined here +... +LL | match_false!((NonEmptyUnion1 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered + --> $DIR/match-empty.rs:84:18 + | +LL | / union NonEmptyUnion2 { +LL | | foo: (), +LL | | bar: (), +LL | | } + | |_- `NonEmptyUnion2` defined here +... +LL | match_false!((NonEmptyUnion2 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `Foo(_)` not covered + --> $DIR/match-empty.rs:86:18 + | +LL | / enum NonEmptyEnum1 { +LL | | Foo(bool), + | | --- not covered +LL | | +LL | | +LL | | } + | |_- `NonEmptyEnum1` defined here +... +LL | match_false!(NonEmptyEnum1::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered + --> $DIR/match-empty.rs:88:18 + | +LL | / enum NonEmptyEnum2 { +LL | | Foo(bool), + | | --- not covered +LL | | +LL | | +LL | | Bar, + | | --- not covered +LL | | +LL | | +LL | | } + | |_- `NonEmptyEnum2` defined here +... +LL | match_false!(NonEmptyEnum2::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered + --> $DIR/match-empty.rs:90:18 + | +LL | / enum NonEmptyEnum5 { +LL | | V1, V2, V3, V4, V5, +LL | | } + | |_- `NonEmptyEnum5` defined here +... +LL | match_false!(NonEmptyEnum5::V1); + | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 15 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs index bbc25d40256..8516bafef9b 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs @@ -6,3 +6,6 @@ pub enum NonExhaustiveEnum { Tuple(u32), Struct { field: u32 } } + +#[non_exhaustive] +pub enum EmptyNonExhaustiveEnum {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.rs b/src/test/ui/rfc-2008-non-exhaustive/enum.rs index 7423a970e2e..802f20b4bed 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/enum.rs @@ -1,7 +1,14 @@ // aux-build:enums.rs extern crate enums; -use enums::NonExhaustiveEnum; +use enums::{EmptyNonExhaustiveEnum, NonExhaustiveEnum}; + +fn empty(x: EmptyNonExhaustiveEnum) { + match x {} //~ ERROR type `enums::EmptyNonExhaustiveEnum` is non-empty + match x { + _ => {}, // ok + } +} fn main() { let enum_unit = NonExhaustiveEnum::Unit; @@ -13,6 +20,9 @@ fn main() { NonExhaustiveEnum::Struct { .. } => "third" }; + match enum_unit {}; + //~^ ERROR non-exhaustive patterns: `_` not covered [E0004] + // Everything below this is expected to compile successfully. let enum_unit = NonExhaustiveEnum::Unit; diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr index b5c1a4ebba4..a2bdcbaa447 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr @@ -1,11 +1,27 @@ +error[E0004]: non-exhaustive patterns: type `enums::EmptyNonExhaustiveEnum` is non-empty + --> $DIR/enum.rs:7: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: `_` not covered - --> $DIR/enum.rs:9:11 + --> $DIR/enum.rs:16:11 | LL | match enum_unit { | ^^^^^^^^^ pattern `_` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms -error: aborting due to previous error +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/enum.rs:23:11 + | +LL | match enum_unit {}; + | ^^^^^^^^^ pattern `_` not covered + | + = 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/enum_same_crate_empty_match.rs b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs new file mode 100644 index 00000000000..afd6d996c15 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs @@ -0,0 +1,37 @@ +#![deny(unreachable_patterns)] + +#[non_exhaustive] +pub enum NonExhaustiveEnum { + Unit, + //~^ not covered + Tuple(u32), + //~^ not covered + Struct { field: u32 } + //~^ not covered +} + +pub enum NormalEnum { + Unit, + //~^ not covered + Tuple(u32), + //~^ not covered + Struct { field: u32 } + //~^ not covered +} + +#[non_exhaustive] +pub enum EmptyNonExhaustiveEnum {} + +fn empty_non_exhaustive(x: EmptyNonExhaustiveEnum) { + match x {} + match x { + _ => {} // not detected as unreachable + } +} + +fn main() { + match NonExhaustiveEnum::Unit {} + //~^ ERROR `Unit`, `Tuple(_)` and `Struct { .. }` not covered [E0004] + match NormalEnum::Unit {} + //~^ ERROR `Unit`, `Tuple(_)` and `Struct { .. }` not covered [E0004] +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr new file mode 100644 index 00000000000..a99a690bc9e --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr @@ -0,0 +1,45 @@ +error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered + --> $DIR/enum_same_crate_empty_match.rs:33:11 + | +LL | / pub enum NonExhaustiveEnum { +LL | | Unit, + | | ---- not covered +LL | | +LL | | Tuple(u32), + | | ----- not covered +LL | | +LL | | Struct { field: u32 } + | | ------ not covered +LL | | +LL | | } + | |_- `NonExhaustiveEnum` defined here +... +LL | match NonExhaustiveEnum::Unit {} + | ^^^^^^^^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered + --> $DIR/enum_same_crate_empty_match.rs:35:11 + | +LL | / pub enum NormalEnum { +LL | | Unit, + | | ---- not covered +LL | | +LL | | Tuple(u32), + | | ----- not covered +LL | | +LL | | Struct { field: u32 } + | | ------ not covered +LL | | +LL | | } + | |_- `NormalEnum` defined here +... +LL | match NormalEnum::Unit {} + | ^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 2 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.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr index b903e9b288e..0d669a9a4e9 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr @@ -1,4 +1,4 @@ -error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `uninhabited::IndirectUninhabitedEnum` is not handled +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedEnum` is non-empty --> $DIR/indirect_match.rs:18:11 | LL | match x {} @@ -6,7 +6,7 @@ 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 +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedStruct` is non-empty --> $DIR/indirect_match.rs:22:11 | LL | match x {} @@ -14,7 +14,7 @@ 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 +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedTupleStruct` is non-empty --> $DIR/indirect_match.rs:26:11 | LL | match x {} @@ -22,7 +22,7 @@ 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 +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedVariants` is non-empty --> $DIR/indirect_match.rs:32:11 | LL | match x {} 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 index f94616dc64b..41a37cf6a03 100644 --- 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 @@ -1,53 +1,41 @@ -error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `IndirectUninhabitedEnum` is not handled +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty --> $DIR/indirect_match_same_crate.rs:32:11 | LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum); - | ---------------------------------------------------- - | | | - | | variant not covered - | `IndirectUninhabitedEnum` defined here + | ---------------------------------------------------- `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 +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty --> $DIR/indirect_match_same_crate.rs:36:11 | LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct); - | -------------------------------------------------------- - | | | - | | variant not covered - | `IndirectUninhabitedStruct` defined here + | -------------------------------------------------------- `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 +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty --> $DIR/indirect_match_same_crate.rs:40:11 | LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); - | ------------------------------------------------------------------ - | | | - | | variant not covered - | `IndirectUninhabitedTupleStruct` defined here + | ------------------------------------------------------------------ `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 +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty --> $DIR/indirect_match_same_crate.rs:46:11 | LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants); - | ------------------------------------------------------------ - | | | - | | variant not covered - | `IndirectUninhabitedVariants` defined here + | ------------------------------------------------------------ `IndirectUninhabitedVariants` defined here ... LL | match x {} | ^ diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr index de3fa900cd6..10a456a5a87 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr @@ -6,7 +6,7 @@ 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 +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedStruct` is non-empty --> $DIR/match.rs:22:11 | LL | match x {} @@ -14,7 +14,7 @@ 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 +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedTupleStruct` is non-empty --> $DIR/match.rs:26:11 | LL | match x {} @@ -22,11 +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: multiple patterns of type `uninhabited::UninhabitedVariants` are not handled +error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered --> $DIR/match.rs:30:11 | LL | match x {} - | ^ + | ^ patterns `Tuple(_)` and `Struct { .. }` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms 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 index 3dd1a914d55..148af8c07b1 100644 --- 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 @@ -1,10 +1,7 @@ -error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `UninhabitedStruct` is not handled +error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty --> $DIR/match_same_crate.rs:28:11 | -LL | pub struct UninhabitedStruct { - | - ----------------- variant not covered - | _| - | | +LL | / pub struct UninhabitedStruct { LL | | _priv: !, LL | | } | |_- `UninhabitedStruct` defined here @@ -14,33 +11,30 @@ 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 +error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty --> $DIR/match_same_crate.rs:32:11 | LL | pub struct UninhabitedTupleStruct(!); - | ------------------------------------- - | | | - | | variant not covered - | `UninhabitedTupleStruct` defined here + | ------------------------------------- `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 +error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered --> $DIR/match_same_crate.rs:36:11 | LL | / pub enum UninhabitedVariants { LL | | #[non_exhaustive] Tuple(!), - | | ----- variant not covered + | | ----- not covered LL | | #[non_exhaustive] Struct { x: ! } - | | ------ variant not covered + | | ------ not covered LL | | } | |_- `UninhabitedVariants` defined here ... LL | match x {} - | ^ + | ^ patterns `Tuple(_)` and `Struct { .. }` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms 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 index 3b56c689071..2fc09c81ab0 100644 --- 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 @@ -22,11 +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::UninhabitedVariants` is non-empty +error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered --> $DIR/match_with_exhaustive_patterns.rs:33:11 | LL | match x {} - | ^ + | ^ patterns `Tuple(_)` and `Struct { .. }` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms diff --git a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr index 7af6075262c..18ffdccb9b2 100644 --- a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr +++ b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr @@ -9,6 +9,9 @@ LL | let _ = match x { error[E0004]: non-exhaustive patterns: type `&Void` is non-empty --> $DIR/uninhabited-matches-feature-gated.rs:12:19 | +LL | enum Void {} + | ------------ `Void` defined here +... LL | let _ = match x {}; | ^ | |
