From 013c2f3d59630a45367a524644971fd0210519bd Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 16 May 2023 01:59:47 +0200 Subject: [PATCH 1/3] Add some tests --- .../omitted-patterns.rs | 32 +++++++++++++- .../omitted-patterns.stderr | 42 ++++++++++++------- 2 files changed, 59 insertions(+), 15 deletions(-) diff --git a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs index 3482af74752f8..bed3ca526c1b9 100644 --- a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs +++ b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs @@ -13,8 +13,8 @@ use enums::{ EmptyNonExhaustiveEnum, NestedNonExhaustive, NonExhaustiveEnum, NonExhaustiveSingleVariant, VariantNonExhaustive, }; -use unstable::{UnstableEnum, OnlyUnstableEnum, UnstableStruct, OnlyUnstableStruct}; use structs::{FunctionalRecord, MixedVisFields, NestedStruct, NormalStruct}; +use unstable::{OnlyUnstableEnum, OnlyUnstableStruct, UnstableEnum, UnstableStruct}; #[non_exhaustive] #[derive(Default)] @@ -127,11 +127,22 @@ fn main() { _ => {} } + // No variants are mentioned #[deny(non_exhaustive_omitted_patterns)] match NonExhaustiveSingleVariant::A(true) { _ => {} } //~^^ some variants are not matched explicitly + #[deny(non_exhaustive_omitted_patterns)] + match Some(NonExhaustiveSingleVariant::A(true)) { + Some(_) => {} + None => {} + } + #[deny(non_exhaustive_omitted_patterns)] + match Some(&NonExhaustiveSingleVariant::A(true)) { + Some(_) => {} + None => {} + } // Ok: we don't lint on `if let` expressions #[deny(non_exhaustive_omitted_patterns)] @@ -202,6 +213,25 @@ fn main() { _ => {} } //~^^ some variants are not matched explicitly + + #[deny(non_exhaustive_omitted_patterns)] + match (true, &non_enum) { + (true, NonExhaustiveEnum::Unit) => {} + _ => {} + } + + #[deny(non_exhaustive_omitted_patterns)] + match (&non_enum, true) { + (NonExhaustiveEnum::Unit, true) => {} + _ => {} + } + //~^^ some variants are not matched explicitly + + #[deny(non_exhaustive_omitted_patterns)] + match Some(&non_enum) { + Some(NonExhaustiveEnum::Unit | NonExhaustiveEnum::Tuple(_)) => {} + _ => {} + } } #[deny(non_exhaustive_omitted_patterns)] diff --git a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr index 923394474b262..b604646e88e63 100644 --- a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr +++ b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr @@ -50,7 +50,7 @@ LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested = note: the pattern is of type `NestedStruct` and the `non_exhaustive_omitted_patterns` attribute was found warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:173:9 + --> $DIR/omitted-patterns.rs:184:9 | LL | let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable2` not listed @@ -58,13 +58,13 @@ LL | let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `OnlyUnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:172:12 + --> $DIR/omitted-patterns.rs:183:12 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:181:9 + --> $DIR/omitted-patterns.rs:192:9 | LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable` not listed @@ -72,7 +72,7 @@ LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:180:12 + --> $DIR/omitted-patterns.rs:191:12 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -143,7 +143,7 @@ LL | _ => {} = note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:132:9 + --> $DIR/omitted-patterns.rs:133:9 | LL | _ => {} | ^ pattern `NonExhaustiveSingleVariant::A(_)` not covered @@ -151,13 +151,13 @@ LL | _ => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveSingleVariant` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:130:12 + --> $DIR/omitted-patterns.rs:131:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:144:9 + --> $DIR/omitted-patterns.rs:155:9 | LL | _ => {} | ^ pattern `UnstableEnum::Unstable` not covered @@ -165,13 +165,13 @@ LL | _ => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:143:16 + --> $DIR/omitted-patterns.rs:154:16 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:168:9 + --> $DIR/omitted-patterns.rs:179:9 | LL | _ => {} | ^ pattern `OnlyUnstableEnum::Unstable2` not covered @@ -179,13 +179,13 @@ LL | _ => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `OnlyUnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:165:12 + --> $DIR/omitted-patterns.rs:176:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0005]: refutable pattern in local binding - --> $DIR/omitted-patterns.rs:194:9 + --> $DIR/omitted-patterns.rs:205:9 | LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit; | ^^^^^^^^^^^^^^^ pattern `_` not covered @@ -199,7 +199,7 @@ LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit | ++++++++++++++++ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:202:9 + --> $DIR/omitted-patterns.rs:213:9 | LL | _ => {} | ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered @@ -207,11 +207,25 @@ LL | _ => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:198:12 + --> $DIR/omitted-patterns.rs:209:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 10 previous errors; 6 warnings emitted +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:226:9 + | +LL | _ => {} + | ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:223:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 11 previous errors; 6 warnings emitted For more information about this error, try `rustc --explain E0005`. From 38e7d422db677185f3474a39b77c8eff0a2802c4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 16 May 2023 14:21:58 +0200 Subject: [PATCH 2/3] Don't use per-arm lint levels This makes things unnecessarily complicated for now --- compiler/rustc_lint_defs/src/builtin.rs | 2 +- .../src/thir/pattern/deconstruct_pat.rs | 1 - .../src/thir/pattern/usefulness.rs | 2 +- .../omitted-patterns.rs | 50 ++----- .../omitted-patterns.stderr | 127 +++++------------- .../stable-omitted-patterns.rs | 6 +- .../stable-omitted-patterns.stderr | 6 +- 7 files changed, 51 insertions(+), 143 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a3d7bd3ef59a3..35d39d9be41eb 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3814,9 +3814,9 @@ declare_lint! { /// // in crate B /// #![feature(non_exhaustive_omitted_patterns_lint)] /// + /// #[warn(non_exhaustive_omitted_patterns)] /// match Bar::A { /// Bar::A => {}, - /// #[warn(non_exhaustive_omitted_patterns)] /// _ => {}, /// } /// ``` diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 9af1378131273..a3ec284473577 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1596,7 +1596,6 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { self.collect_unreachable_spans(&mut spans); spans } - fn collect_unreachable_spans(&self, spans: &mut Vec) { // We don't look at subpatterns if we already reported the whole pattern as unreachable. if !self.is_reachable() { diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index d8f66a1755b2b..39cb3613dc5c1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -973,7 +973,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( .map(|arm| { debug!(?arm); let v = PatStack::from_pattern(arm.pat); - is_useful(cx, &matrix, &v, RealArm, arm.hir_id, arm.has_guard, true); + is_useful(cx, &matrix, &v, RealArm, lint_root, arm.has_guard, true); if !arm.has_guard { matrix.push(v); } diff --git a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs index bed3ca526c1b9..87cfa3b868b06 100644 --- a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs +++ b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs @@ -1,6 +1,7 @@ // Test that the `non_exhaustive_omitted_patterns` lint is triggered correctly. #![feature(non_exhaustive_omitted_patterns_lint, unstable_test_feature)] +#![deny(unreachable_patterns)] // aux-build:enums.rs extern crate enums; @@ -31,6 +32,17 @@ pub enum Bar { C, } +fn no_lint() { + let non_enum = NonExhaustiveEnum::Unit; + // Ok: without the attribute + match non_enum { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + _ => {} + } +} + +#[warn(non_exhaustive_omitted_patterns)] fn main() { let enumeration = Bar::A; @@ -38,30 +50,20 @@ fn main() { match enumeration { Bar::A => {} Bar::B => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } let non_enum = NonExhaustiveEnum::Unit; - // Ok: without the attribute - match non_enum { - NonExhaustiveEnum::Unit => {} - NonExhaustiveEnum::Tuple(_) => {} - _ => {} - } - match non_enum { NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } //~^^ some variants are not matched explicitly match non_enum { NonExhaustiveEnum::Unit | NonExhaustiveEnum::Struct { .. } => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } //~^^ some variants are not matched explicitly @@ -71,22 +73,18 @@ fn main() { NonExhaustiveEnum::Unit if x > 10 => {} NonExhaustiveEnum::Tuple(_) => {} NonExhaustiveEnum::Struct { .. } => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } //~^^ some variants are not matched explicitly // Ok: all covered and not `unreachable-patterns` - #[deny(unreachable_patterns)] match non_enum { NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} NonExhaustiveEnum::Struct { .. } => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } - #[deny(non_exhaustive_omitted_patterns)] match NestedNonExhaustive::B { NestedNonExhaustive::A(NonExhaustiveEnum::Unit) => {} NestedNonExhaustive::A(_) => {} @@ -96,68 +94,56 @@ fn main() { //~^^ some variants are not matched explicitly //~^^^^^ some variants are not matched explicitly - #[warn(non_exhaustive_omitted_patterns)] match VariantNonExhaustive::Baz(1, 2) { VariantNonExhaustive::Baz(_, _) => {} VariantNonExhaustive::Bar { x, .. } => {} } //~^^ some fields are not explicitly listed - #[warn(non_exhaustive_omitted_patterns)] let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default(); //~^ some fields are not explicitly listed // Ok: this is local - #[warn(non_exhaustive_omitted_patterns)] let Foo { a, b, .. } = Foo::default(); - #[warn(non_exhaustive_omitted_patterns)] let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); //~^ some fields are not explicitly listed //~^^ some fields are not explicitly listed // Ok: this tests https://github.com/rust-lang/rust/issues/89382 - #[warn(non_exhaustive_omitted_patterns)] let MixedVisFields { a, b, .. } = MixedVisFields::default(); // Ok: because this only has 1 variant - #[deny(non_exhaustive_omitted_patterns)] match NonExhaustiveSingleVariant::A(true) { NonExhaustiveSingleVariant::A(true) => {} _ => {} } // No variants are mentioned - #[deny(non_exhaustive_omitted_patterns)] match NonExhaustiveSingleVariant::A(true) { _ => {} } //~^^ some variants are not matched explicitly - #[deny(non_exhaustive_omitted_patterns)] match Some(NonExhaustiveSingleVariant::A(true)) { Some(_) => {} None => {} } - #[deny(non_exhaustive_omitted_patterns)] match Some(&NonExhaustiveSingleVariant::A(true)) { Some(_) => {} None => {} } // Ok: we don't lint on `if let` expressions - #[deny(non_exhaustive_omitted_patterns)] if let NonExhaustiveEnum::Tuple(_) = non_enum {} match UnstableEnum::Stable { UnstableEnum::Stable => {} UnstableEnum::Stable2 => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } //~^^ some variants are not matched explicitly // Ok: the feature is on and all variants are matched - #[deny(non_exhaustive_omitted_patterns)] match UnstableEnum::Stable { UnstableEnum::Stable => {} UnstableEnum::Stable2 => {} @@ -166,47 +152,38 @@ fn main() { } // Ok: the feature is on and both variants are matched - #[deny(non_exhaustive_omitted_patterns)] match OnlyUnstableEnum::Unstable { OnlyUnstableEnum::Unstable => {} OnlyUnstableEnum::Unstable2 => {} _ => {} } - #[deny(non_exhaustive_omitted_patterns)] match OnlyUnstableEnum::Unstable { OnlyUnstableEnum::Unstable => {} _ => {} } //~^^ some variants are not matched explicitly - #[warn(non_exhaustive_omitted_patterns)] let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); //~^ some fields are not explicitly listed // OK: both unstable fields are matched with feature on - #[warn(non_exhaustive_omitted_patterns)] let OnlyUnstableStruct { unstable, unstable2, .. } = OnlyUnstableStruct::new(); - #[warn(non_exhaustive_omitted_patterns)] let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); //~^ some fields are not explicitly listed // OK: both unstable and stable fields are matched with feature on - #[warn(non_exhaustive_omitted_patterns)] let UnstableStruct { stable, stable2, unstable, .. } = UnstableStruct::default(); // Ok: local bindings are allowed - #[deny(non_exhaustive_omitted_patterns)] let local = NonExhaustiveEnum::Unit; // Ok: missing patterns will be blocked by the pattern being refutable - #[deny(non_exhaustive_omitted_patterns)] let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit; //~^ refutable pattern in local binding // Check that matching on a reference results in a correctly spanned diagnostic - #[deny(non_exhaustive_omitted_patterns)] match &non_enum { NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} @@ -214,20 +191,17 @@ fn main() { } //~^^ some variants are not matched explicitly - #[deny(non_exhaustive_omitted_patterns)] match (true, &non_enum) { (true, NonExhaustiveEnum::Unit) => {} _ => {} } - #[deny(non_exhaustive_omitted_patterns)] match (&non_enum, true) { (NonExhaustiveEnum::Unit, true) => {} _ => {} } //~^^ some variants are not matched explicitly - #[deny(non_exhaustive_omitted_patterns)] match Some(&non_enum) { Some(NonExhaustiveEnum::Unit | NonExhaustiveEnum::Tuple(_)) => {} _ => {} diff --git a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr index b604646e88e63..1b7b80cc0b006 100644 --- a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr +++ b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr @@ -1,5 +1,5 @@ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:102:9 + --> $DIR/omitted-patterns.rs:99:9 | LL | VariantNonExhaustive::Bar { x, .. } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `y` not listed @@ -7,41 +7,31 @@ LL | VariantNonExhaustive::Bar { x, .. } => {} = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `VariantNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:99:12 + --> $DIR/omitted-patterns.rs:45:8 | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:107:9 + --> $DIR/omitted-patterns.rs:103:9 | LL | let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `third_field` not listed | = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `FunctionalRecord` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:106:12 - | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:115:29 + --> $DIR/omitted-patterns.rs:109:29 | LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `second_field` not listed | = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `NormalStruct` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:114:12 - | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:115:9 + --> $DIR/omitted-patterns.rs:109:9 | LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `foo` not listed @@ -50,91 +40,61 @@ LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested = note: the pattern is of type `NestedStruct` and the `non_exhaustive_omitted_patterns` attribute was found warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:184:9 + --> $DIR/omitted-patterns.rs:167:9 | LL | let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable2` not listed | = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `OnlyUnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:183:12 - | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:192:9 + --> $DIR/omitted-patterns.rs:173:9 | LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable` not listed | = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:191:12 - | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:58:9 +warning: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:61:9 | LL | _ => {} | ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:57:16 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:65:9 +warning: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:67:9 | LL | _ => {} | ^ pattern `NonExhaustiveEnum::Tuple(_)` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:64:16 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:75:9 +warning: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:76:9 | LL | _ => {} | ^ pattern `NonExhaustiveEnum::Unit` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:74:16 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:92:32 +warning: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:90:32 | LL | NestedNonExhaustive::A(_) => {} | ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:89:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:94:9 +warning: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:92:9 | LL | _ => {} | ^ pattern `NestedNonExhaustive::C` not covered @@ -142,50 +102,35 @@ LL | _ => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:133:9 +warning: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:124:9 | LL | _ => {} | ^ pattern `NonExhaustiveSingleVariant::A(_)` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveSingleVariant` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:131:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:155:9 +warning: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:142:9 | LL | _ => {} | ^ pattern `UnstableEnum::Unstable` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:154:16 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:179:9 +warning: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:163:9 | LL | _ => {} | ^ pattern `OnlyUnstableEnum::Unstable2` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `OnlyUnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:176:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0005]: refutable pattern in local binding - --> $DIR/omitted-patterns.rs:205:9 + --> $DIR/omitted-patterns.rs:183:9 | LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit; | ^^^^^^^^^^^^^^^ pattern `_` not covered @@ -198,34 +143,24 @@ help: you might want to use `let else` to handle the variant that isn't matched LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit else { todo!() }; | ++++++++++++++++ -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:213:9 +warning: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:190:9 | LL | _ => {} | ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:209:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:226:9 +warning: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:201:9 | LL | _ => {} | ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:223:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors; 6 warnings emitted +error: aborting due to previous error; 16 warnings emitted For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs b/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs index 82ee68687ed00..20b51a5cf3f72 100644 --- a/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs +++ b/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs @@ -6,20 +6,20 @@ // aux-build:unstable.rs extern crate unstable; -use unstable::{UnstableEnum, OnlyUnstableEnum, UnstableStruct, OnlyUnstableStruct}; +use unstable::{OnlyUnstableEnum, OnlyUnstableStruct, UnstableEnum, UnstableStruct}; fn main() { // OK: this matches all the stable variants + #[deny(non_exhaustive_omitted_patterns)] match UnstableEnum::Stable { UnstableEnum::Stable => {} UnstableEnum::Stable2 => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } + #[deny(non_exhaustive_omitted_patterns)] match UnstableEnum::Stable { UnstableEnum::Stable => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } //~^^ some variants are not matched explicitly diff --git a/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr b/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr index f38368590fb1c..5b75cfb69fe0c 100644 --- a/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr +++ b/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr @@ -21,10 +21,10 @@ LL | _ => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/stable-omitted-patterns.rs:22:16 + --> $DIR/stable-omitted-patterns.rs:20:12 | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error; 1 warning emitted From d5edcb14374f0a50fbec0fc5c7c42001815d2693 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 16 May 2023 20:00:51 +0200 Subject: [PATCH 3/3] Implement lint as a separate columns-wise pass --- compiler/rustc_lint_defs/src/builtin.rs | 21 +- .../src/thir/pattern/check_match.rs | 7 +- .../src/thir/pattern/deconstruct_pat.rs | 45 +++-- .../src/thir/pattern/usefulness.rs | 183 ++++++++++++------ ...te-non_exhaustive_omitted_patterns_lint.rs | 25 ++- ...on_exhaustive_omitted_patterns_lint.stderr | 111 ++++++++--- .../omitted-patterns.rs | 27 +-- .../omitted-patterns.stderr | 107 +++++----- .../stable-omitted-patterns.rs | 2 +- .../stable-omitted-patterns.stderr | 6 +- 10 files changed, 334 insertions(+), 200 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 35d39d9be41eb..b3ce8db6229c5 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3798,8 +3798,10 @@ declare_lint! { } declare_lint! { - /// The `non_exhaustive_omitted_patterns` lint detects when a wildcard (`_` or `..`) in a - /// pattern for a `#[non_exhaustive]` struct or enum is reachable. + /// The `non_exhaustive_omitted_patterns` lint detects when some variants or fields of a + /// `#[non_exhaustive]` struct or enum are not mentioned explicitly in a pattern. This allows + /// downstream crates to be warned when new variants or fields are added to the upstream struct + /// or enum. /// /// ### Example /// @@ -3827,8 +3829,8 @@ declare_lint! { /// warning: reachable patterns not covered of non exhaustive enum /// --> $DIR/reachable-patterns.rs:70:9 /// | - /// LL | _ => {} - /// | ^ pattern `B` not covered + /// LL | match Bar::A { + /// | ^ pattern `Bar::B` not covered /// | /// note: the lint level is defined here /// --> $DIR/reachable-patterns.rs:69:16 @@ -3841,12 +3843,11 @@ declare_lint! { /// /// ### Explanation /// - /// Structs and enums tagged with `#[non_exhaustive]` force the user to add a - /// (potentially redundant) wildcard when pattern-matching, to allow for future - /// addition of fields or variants. The `non_exhaustive_omitted_patterns` lint - /// detects when such a wildcard happens to actually catch some fields/variants. - /// In other words, when the match without the wildcard would not be exhaustive. - /// This lets the user be informed if new fields/variants were added. + /// Structs and enums tagged with `#[non_exhaustive]` force the user to add a (potentially + /// redundant) wildcard when pattern-matching, to allow for future addition of fields or + /// variants. The `non_exhaustive_omitted_patterns` lint detects when such a wildcard happens to + /// actually catch some fields/variants. This lets the user be informed if new fields/variants + /// were added. pub NON_EXHAUSTIVE_OMITTED_PATTERNS, Allow, "detect when patterns of types marked `non_exhaustive` are missed", diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 2b52d70af2a44..b268074bdb5da 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -250,7 +250,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let scrut = &self.thir[scrut]; let scrut_ty = scrut.ty; - let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty); + let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty, scrut.span); match source { // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }` @@ -415,7 +415,8 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let pattern = self.lower_pattern(&mut cx, pat); let pattern_ty = pattern.ty(); let arm = MatchArm { pat: pattern, hir_id: self.lint_level, has_guard: false }; - let report = compute_match_usefulness(&cx, &[arm], self.lint_level, pattern_ty); + let report = + compute_match_usefulness(&cx, &[arm], self.lint_level, pattern_ty, pattern.span()); // Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We // only care about exhaustiveness here. @@ -583,7 +584,7 @@ fn is_let_irrefutable<'p, 'tcx>( pat: &'p DeconstructedPat<'p, 'tcx>, ) -> bool { let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }]; - let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty()); + let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty(), pat.span()); // Report if the pattern is unreachable, which can only occur when the type is uninhabited. // This also reports unreachable sub-patterns though, so we can't just replace it with an diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index a3ec284473577..eaa94ab8bb80b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -643,9 +643,8 @@ pub(super) enum Constructor<'tcx> { /// for those types for which we cannot list constructors explicitly, like `f64` and `str`. NonExhaustive, /// Stands for constructors that are not seen in the matrix, as explained in the documentation - /// for [`SplitWildcard`]. The carried `bool` is used for the `non_exhaustive_omitted_patterns` - /// lint. - Missing { nonexhaustive_enum_missing_real_variants: bool }, + /// for [`SplitWildcard`]. + Missing, /// Wildcard pattern. Wildcard, /// Or-pattern. @@ -1053,6 +1052,16 @@ impl<'tcx> SplitWildcard<'tcx> { self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.matrix_ctors)) } + /// Iterate over the constructors for this type that are present in the matrix. This has the + /// effect of deduplicating present constructors. + /// WARNING: this omits special constructors like `Wildcard` and `Opaque`. + pub(super) fn iter_present<'a, 'p>( + &'a self, + pcx: &'a PatCtxt<'a, 'p, 'tcx>, + ) -> impl Iterator> + Captures<'p> { + self.all_ctors.iter().filter(move |ctor| ctor.is_covered_by_any(pcx, &self.matrix_ctors)) + } + /// Return the set of constructors resulting from splitting the wildcard. As explained at the /// top of the file, if any constructors are missing we can ignore the present ones. fn into_ctors(self, pcx: &PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> { @@ -1086,15 +1095,7 @@ impl<'tcx> SplitWildcard<'tcx> { // sometimes prefer reporting the list of constructors instead of just `_`. let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty); let ctor = if !self.matrix_ctors.is_empty() || report_when_all_missing { - if pcx.is_non_exhaustive { - Missing { - nonexhaustive_enum_missing_real_variants: self - .iter_missing(pcx) - .any(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))), - } - } else { - Missing { nonexhaustive_enum_missing_real_variants: false } - } + Missing } else { Wildcard }; @@ -1240,9 +1241,10 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { /// Values and patterns can be represented as a constructor applied to some fields. This represents /// a pattern in this form. -/// This also keeps track of whether the pattern has been found reachable during analysis. For this -/// reason we should be careful not to clone patterns for which we care about that. Use -/// `clone_and_forget_reachability` if you're sure. +/// This also uses interior mutability to keep track of whether the pattern has been found reachable +/// during analysis. For this reason we should be careful not to clone patterns for which we care +/// about that. +#[derive(Clone)] pub(crate) struct DeconstructedPat<'p, 'tcx> { ctor: Constructor<'tcx>, fields: Fields<'p, 'tcx>, @@ -1273,12 +1275,6 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { DeconstructedPat::new(ctor, fields, pcx.ty, pcx.span) } - /// Clone this value. This method emphasizes that cloning loses reachability information and - /// should be done carefully. - pub(super) fn clone_and_forget_reachability(&self) -> Self { - DeconstructedPat::new(self.ctor.clone(), self.fields, self.ty, self.span) - } - pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self { let mkpat = |pat| DeconstructedPat::from_pat(cx, pat); let ctor; @@ -1522,6 +1518,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { pub(super) fn is_or_pat(&self) -> bool { matches!(self.ctor, Or) } + pub(super) fn flatten_or_pat(&'p self) -> SmallVec<[&'p Self; 1]> { + if self.is_or_pat() { + self.iter_fields().flat_map(|p| p.flatten_or_pat()).collect() + } else { + smallvec![self] + } + } pub(super) fn ctor(&self) -> &Constructor<'tcx> { &self.ctor diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 39cb3613dc5c1..21c7a4b8e5ec9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -642,14 +642,7 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> { .into_iter() .flat_map(|witness| { new_patterns.iter().map(move |pat| { - Witness( - witness - .0 - .iter() - .chain(once(pat)) - .map(DeconstructedPat::clone_and_forget_reachability) - .collect(), - ) + Witness(witness.0.iter().chain(once(pat)).cloned().collect()) }) }) .collect() @@ -843,7 +836,6 @@ fn is_useful<'p, 'tcx>( } // We split the head constructor of `v`. let split_ctors = v_ctor.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); - let is_non_exhaustive_and_wild = is_non_exhaustive && v_ctor.is_wildcard(); // For each constructor, we compute whether there's a value that starts with it that would // witness the usefulness of `v`. let start_matrix = &matrix; @@ -864,56 +856,6 @@ fn is_useful<'p, 'tcx>( ) }); let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor); - - // When all the conditions are met we have a match with a `non_exhaustive` enum - // that has the potential to trigger the `non_exhaustive_omitted_patterns` lint. - // To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors` - if is_non_exhaustive_and_wild - // Only emit a lint on refutable patterns. - && cx.refutable - // We check that the match has a wildcard pattern and that wildcard is useful, - // meaning there are variants that are covered by the wildcard. Without the check - // for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}` - && usefulness.is_useful() && matches!(witness_preference, RealArm) - && matches!( - &ctor, - Constructor::Missing { nonexhaustive_enum_missing_real_variants: true } - ) - { - let patterns = { - let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); - // Construct for each missing constructor a "wild" version of this - // constructor, that matches everything that can be built with - // it. For example, if `ctor` is a `Constructor::Variant` for - // `Option::Some`, we get the pattern `Some(_)`. - split_wildcard - .iter_missing(pcx) - // Filter out the `NonExhaustive` because we want to list only real - // variants. Also remove any unstable feature gated variants. - // Because of how we computed `nonexhaustive_enum_missing_real_variants`, - // this will not return an empty `Vec`. - .filter(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))) - .cloned() - .map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor)) - .collect::>() - }; - - // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` - // is not exhaustive enough. - // - // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`. - cx.tcx.emit_spanned_lint( - NON_EXHAUSTIVE_OMITTED_PATTERNS, - lint_root, - pcx.span, - NonExhaustiveOmittedPattern { - scrut_ty: pcx.ty, - uncovered: Uncovered::new(pcx.span, pcx.cx, patterns), - }, - ); - } - ret.extend(usefulness); } } @@ -925,6 +867,96 @@ fn is_useful<'p, 'tcx>( ret } +/// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned +/// in a given column. This traverses patterns column-by-column, where a column is the intuitive +/// notion of "subpatterns that inspect the same subvalue". +/// Despite similarities with `is_useful`, this traversal is different. Notably this is linear in the +/// depth of patterns, whereas `is_useful` is worst-case exponential (exhaustiveness is NP-complete). +fn collect_nonexhaustive_missing_variants<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, + column: &[&DeconstructedPat<'p, 'tcx>], +) -> Vec> { + let mut witnesses = Vec::new(); + // If the column is all wildcards, we don't want to collect anything and we can't recurse + // further. + let is_all_wildcards = column.iter().all(|p| p.ctor().is_wildcard()); + if column.is_empty() || is_all_wildcards { + return witnesses; + } + + let ty = column[0].ty(); + let span = column[0].span(); + let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); + let pcx = &PatCtxt { cx, ty, span, is_top_level: false, is_non_exhaustive }; + + let mut split_wildcard = SplitWildcard::new(pcx); + split_wildcard.split(pcx, column.iter().map(|p| p.ctor())); + + if is_non_exhaustive { + witnesses.extend( + split_wildcard + .iter_missing(pcx) + // Filter out the `NonExhaustive` ctor because we want to list only real variants. + // Also remove any unstable feature gated variants. + .filter(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))) + .cloned() + .map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor)), + ) + } + + // Recurse into the fields. + for ctor in split_wildcard.iter_present(pcx) { + let arity = ctor.arity(pcx); + if arity == 0 { + continue; + } + + // We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These + // columns may not have the same length in the presence of or-patterns (this is why we can't + // reuse what `Matrix` does). + let mut specialized_columns: Vec> = (0..arity).map(|_| Vec::new()).collect(); + let relevant_patterns = column.iter().filter(|pat| ctor.is_covered_by(pcx, pat.ctor())); + for pat in relevant_patterns { + let specialized = pat.specialize(pcx, &ctor); + for (subpat, sub_column) in specialized.iter().zip(&mut specialized_columns) { + if subpat.is_or_pat() { + sub_column.extend(subpat.iter_fields()) + } else { + sub_column.push(subpat) + } + } + } + assert!( + !specialized_columns[0].is_empty(), + "ctor {ctor:?} was listed as present but isn't" + ); + + for (i, col_i) in specialized_columns.iter().enumerate() { + // Compute witnesses for each column. + let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i.as_slice()); + if wits_for_col_i.is_empty() { + continue; + } + // For each witness, we build a new pattern in the shape of `ctor(_, _, wit, _, _)`, + // adding enough wildcards to match `arity`. + let fields = Fields::wildcards(pcx, &ctor); + for wit in wits_for_col_i { + let fields_with_wit = Fields::from_iter( + cx, + fields + .iter_patterns() + .enumerate() + .map(|(j, wild)| if i == j { &wit } else { wild }) + .cloned(), + ); + let pat = DeconstructedPat::new(ctor.clone(), fields_with_wit, ty, DUMMY_SP); + witnesses.push(pat); + } + } + } + witnesses +} + /// The arm of a match expression. #[derive(Clone, Copy, Debug)] pub(crate) struct MatchArm<'p, 'tcx> { @@ -965,6 +997,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( arms: &[MatchArm<'p, 'tcx>], lint_root: HirId, scrut_ty: Ty<'tcx>, + scrut_span: Span, ) -> UsefulnessReport<'p, 'tcx> { let mut matrix = Matrix::empty(); let arm_usefulness: Vec<_> = arms @@ -989,9 +1022,39 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP)); let v = PatStack::from_pattern(wild_pattern); let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, lint_root, false, true); - let non_exhaustiveness_witnesses = match usefulness { + let non_exhaustiveness_witnesses: Vec<_> = match usefulness { WithWitnesses(pats) => pats.into_iter().map(|w| w.single_pattern()).collect(), NoWitnesses { .. } => bug!(), }; + + // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hittin + // `if let`s. Only run if the match is exhaustive otherwise the error is redundant. + if cx.refutable + && non_exhaustiveness_witnesses.is_empty() + && !matches!( + cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, lint_root).0, + rustc_session::lint::Level::Allow + ) + { + let pat_column = arms.iter().flat_map(|arm| arm.pat.flatten_or_pat()).collect::>(); + let witnesses = collect_nonexhaustive_missing_variants(cx, &pat_column); + + if !witnesses.is_empty() { + // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` + // is not exhaustive enough. + // + // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`. + cx.tcx.emit_spanned_lint( + NON_EXHAUSTIVE_OMITTED_PATTERNS, + lint_root, + scrut_span, + NonExhaustiveOmittedPattern { + scrut_ty, + uncovered: Uncovered::new(scrut_span, cx, witnesses), + }, + ); + } + } + UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses } } diff --git a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs index 9b646060adfd9..c14fa88507746 100644 --- a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs +++ b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs @@ -3,13 +3,17 @@ #![deny(non_exhaustive_omitted_patterns)] //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` +//~| WARNING unknown lint: `non_exhaustive_omitted_patterns` #![allow(non_exhaustive_omitted_patterns)] //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` +//~| WARNING unknown lint: `non_exhaustive_omitted_patterns` fn main() { enum Foo { - A, B, C, + A, + B, + C, } #[allow(non_exhaustive_omitted_patterns)] @@ -17,18 +21,21 @@ fn main() { //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` + //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` match Foo::A { - Foo::A => {} - Foo::B => {} + _ => {} } - //~^^^^ ERROR non-exhaustive patterns: `Foo::C` not covered + #[warn(non_exhaustive_omitted_patterns)] + //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns` + //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` + //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` + //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` + //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` match Foo::A { - Foo::A => {} - Foo::B => {} - #[warn(non_exhaustive_omitted_patterns)] _ => {} } - //~^^^ WARNING unknown lint: `non_exhaustive_omitted_patterns` - //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` + + match Foo::A {} + //~^ ERROR non-exhaustive patterns } diff --git a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr index fb39c404c207e..b17e9a1a25d6e 100644 --- a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr +++ b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr @@ -10,7 +10,7 @@ LL | #![deny(non_exhaustive_omitted_patterns)] = note: `#[warn(unknown_lints)]` on by default warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1 | LL | #![allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | #![allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,10 +40,20 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:5 | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `non_exhaustive_omitted_patterns` lint is unstable + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +warning: unknown lint: `non_exhaustive_omitted_patterns` + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:5 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the `non_exhaustive_omitted_patterns` lint is unstable = note: see issue #89554 for more information @@ -60,7 +70,7 @@ LL | #![deny(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1 | LL | #![allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -70,7 +80,7 @@ LL | #![allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +90,57 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5 + | +LL | #[allow(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `non_exhaustive_omitted_patterns` lint is unstable + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +warning: unknown lint: `non_exhaustive_omitted_patterns` + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:5 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `non_exhaustive_omitted_patterns` lint is unstable + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +warning: unknown lint: `non_exhaustive_omitted_patterns` + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:5 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `non_exhaustive_omitted_patterns` lint is unstable + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +warning: unknown lint: `non_exhaustive_omitted_patterns` + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1 + | +LL | #![deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `non_exhaustive_omitted_patterns` lint is unstable + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +warning: unknown lint: `non_exhaustive_omitted_patterns` + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1 + | +LL | #![allow(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `non_exhaustive_omitted_patterns` lint is unstable + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +warning: unknown lint: `non_exhaustive_omitted_patterns` + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,35 +150,40 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:5 | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the `non_exhaustive_omitted_patterns` lint is unstable = note: see issue #89554 for more information = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable -error[E0004]: non-exhaustive patterns: `Foo::C` not covered - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:20:11 +error[E0004]: non-exhaustive patterns: `Foo::A`, `Foo::B` and `Foo::C` not covered + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:39:11 | -LL | match Foo::A { - | ^^^^^^ pattern `Foo::C` not covered +LL | match Foo::A {} + | ^^^^^^ patterns `Foo::A`, `Foo::B` and `Foo::C` not covered | note: `Foo` defined here - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:12:15 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:14:9 | LL | enum Foo { | --- -LL | A, B, C, - | ^ not covered +LL | A, + | ^ not covered +LL | B, + | ^ not covered +LL | C, + | ^ not covered = note: the matched value is of type `Foo` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ Foo::B => {}, -LL + Foo::C => todo!() +LL ~ match Foo::A { +LL + Foo::A | Foo::B | Foo::C => todo!(), +LL + } | -error: aborting due to previous error; 10 warnings emitted +error: aborting due to previous error; 16 warnings emitted For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs index 87cfa3b868b06..17e1b3363c567 100644 --- a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs +++ b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs @@ -56,17 +56,17 @@ fn main() { let non_enum = NonExhaustiveEnum::Unit; match non_enum { + //~^ some variants are not matched explicitly NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} _ => {} } - //~^^ some variants are not matched explicitly match non_enum { + //~^ some variants are not matched explicitly NonExhaustiveEnum::Unit | NonExhaustiveEnum::Struct { .. } => {} _ => {} } - //~^^ some variants are not matched explicitly let x = 5; match non_enum { @@ -75,7 +75,6 @@ fn main() { NonExhaustiveEnum::Struct { .. } => {} _ => {} } - //~^^ some variants are not matched explicitly // Ok: all covered and not `unreachable-patterns` match non_enum { @@ -86,13 +85,12 @@ fn main() { } match NestedNonExhaustive::B { + //~^ some variants are not matched explicitly NestedNonExhaustive::A(NonExhaustiveEnum::Unit) => {} NestedNonExhaustive::A(_) => {} NestedNonExhaustive::B => {} _ => {} } - //~^^ some variants are not matched explicitly - //~^^^^^ some variants are not matched explicitly match VariantNonExhaustive::Baz(1, 2) { VariantNonExhaustive::Baz(_, _) => {} @@ -119,11 +117,10 @@ fn main() { _ => {} } - // No variants are mentioned + // Don't lint if no variant is mentioned, because we can't do it consistently. match NonExhaustiveSingleVariant::A(true) { _ => {} } - //~^^ some variants are not matched explicitly match Some(NonExhaustiveSingleVariant::A(true)) { Some(_) => {} None => {} @@ -137,11 +134,11 @@ fn main() { if let NonExhaustiveEnum::Tuple(_) = non_enum {} match UnstableEnum::Stable { + //~^ some variants are not matched explicitly UnstableEnum::Stable => {} UnstableEnum::Stable2 => {} _ => {} } - //~^^ some variants are not matched explicitly // Ok: the feature is on and all variants are matched match UnstableEnum::Stable { @@ -159,10 +156,10 @@ fn main() { } match OnlyUnstableEnum::Unstable { + //~^ some variants are not matched explicitly OnlyUnstableEnum::Unstable => {} _ => {} } - //~^^ some variants are not matched explicitly let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); //~^ some fields are not explicitly listed @@ -183,26 +180,32 @@ fn main() { let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit; //~^ refutable pattern in local binding - // Check that matching on a reference results in a correctly spanned diagnostic + // Check that matching on a reference results in a correct diagnostic match &non_enum { + //~^ some variants are not matched explicitly + //~| pattern `&NonExhaustiveEnum::Struct { .. }` not covered NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} _ => {} } - //~^^ some variants are not matched explicitly match (true, &non_enum) { + //~^ some variants are not matched explicitly + //~| patterns `(_, &NonExhaustiveEnum::Tuple(_))` and `(_, &NonExhaustiveEnum::Struct { .. })` not covered (true, NonExhaustiveEnum::Unit) => {} _ => {} } match (&non_enum, true) { + //~^ some variants are not matched explicitly + //~| patterns `(&NonExhaustiveEnum::Tuple(_), _)` and `(&NonExhaustiveEnum::Struct { .. }, _)` not covered (NonExhaustiveEnum::Unit, true) => {} _ => {} } - //~^^ some variants are not matched explicitly match Some(&non_enum) { + //~^ some variants are not matched explicitly + //~| pattern `Some(&NonExhaustiveEnum::Struct { .. })` not covered Some(NonExhaustiveEnum::Unit | NonExhaustiveEnum::Tuple(_)) => {} _ => {} } diff --git a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr index 1b7b80cc0b006..3bdad4a360620 100644 --- a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr +++ b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr @@ -1,5 +1,5 @@ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:99:9 + --> $DIR/omitted-patterns.rs:97:9 | LL | VariantNonExhaustive::Bar { x, .. } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `y` not listed @@ -13,7 +13,7 @@ LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:103:9 + --> $DIR/omitted-patterns.rs:101:9 | LL | let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `third_field` not listed @@ -22,7 +22,7 @@ LL | let FunctionalRecord { first_field, second_field, .. } = FunctionalReco = note: the pattern is of type `FunctionalRecord` and the `non_exhaustive_omitted_patterns` attribute was found warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:109:29 + --> $DIR/omitted-patterns.rs:107:29 | LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `second_field` not listed @@ -31,7 +31,7 @@ LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested = note: the pattern is of type `NormalStruct` and the `non_exhaustive_omitted_patterns` attribute was found warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:109:9 + --> $DIR/omitted-patterns.rs:107:9 | LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `foo` not listed @@ -40,7 +40,7 @@ LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested = note: the pattern is of type `NestedStruct` and the `non_exhaustive_omitted_patterns` attribute was found warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:167:9 + --> $DIR/omitted-patterns.rs:164:9 | LL | let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable2` not listed @@ -49,7 +49,7 @@ LL | let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); = note: the pattern is of type `OnlyUnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:173:9 + --> $DIR/omitted-patterns.rs:170:9 | LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable` not listed @@ -58,79 +58,52 @@ LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); = note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found warning: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:61:9 + --> $DIR/omitted-patterns.rs:58:11 | -LL | _ => {} - | ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered +LL | match non_enum { + | ^^^^^^^^ pattern `NonExhaustiveEnum::Struct { .. }` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found warning: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:67:9 + --> $DIR/omitted-patterns.rs:65:11 | -LL | _ => {} - | ^ pattern `NonExhaustiveEnum::Tuple(_)` not covered +LL | match non_enum { + | ^^^^^^^^ pattern `NonExhaustiveEnum::Tuple(_)` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found warning: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:76:9 + --> $DIR/omitted-patterns.rs:87:11 | -LL | _ => {} - | ^ pattern `NonExhaustiveEnum::Unit` not covered - | - = help: ensure that all variants are matched explicitly by adding the suggested match arms - = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found - -warning: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:90:32 - | -LL | NestedNonExhaustive::A(_) => {} - | ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered - | - = help: ensure that all variants are matched explicitly by adding the suggested match arms - = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found - -warning: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:92:9 - | -LL | _ => {} - | ^ pattern `NestedNonExhaustive::C` not covered +LL | match NestedNonExhaustive::B { + | ^^^^^^^^^^^^^^^^^^^^^^ patterns `NestedNonExhaustive::C`, `NestedNonExhaustive::A(NonExhaustiveEnum::Tuple(_))` and `NestedNonExhaustive::A(NonExhaustiveEnum::Struct { .. })` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found warning: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:124:9 + --> $DIR/omitted-patterns.rs:136:11 | -LL | _ => {} - | ^ pattern `NonExhaustiveSingleVariant::A(_)` not covered - | - = help: ensure that all variants are matched explicitly by adding the suggested match arms - = note: the matched value is of type `NonExhaustiveSingleVariant` and the `non_exhaustive_omitted_patterns` attribute was found - -warning: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:142:9 - | -LL | _ => {} - | ^ pattern `UnstableEnum::Unstable` not covered +LL | match UnstableEnum::Stable { + | ^^^^^^^^^^^^^^^^^^^^ pattern `UnstableEnum::Unstable` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found warning: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:163:9 + --> $DIR/omitted-patterns.rs:158:11 | -LL | _ => {} - | ^ pattern `OnlyUnstableEnum::Unstable2` not covered +LL | match OnlyUnstableEnum::Unstable { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `OnlyUnstableEnum::Unstable2` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `OnlyUnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found error[E0005]: refutable pattern in local binding - --> $DIR/omitted-patterns.rs:183:9 + --> $DIR/omitted-patterns.rs:180:9 | LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit; | ^^^^^^^^^^^^^^^ pattern `_` not covered @@ -144,23 +117,41 @@ LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit | ++++++++++++++++ warning: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:190:9 + --> $DIR/omitted-patterns.rs:184:11 | -LL | _ => {} - | ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered +LL | match &non_enum { + | ^^^^^^^^^ pattern `&NonExhaustiveEnum::Struct { .. }` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms - = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + = note: the matched value is of type `&NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found warning: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:201:9 + --> $DIR/omitted-patterns.rs:192:11 | -LL | _ => {} - | ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered +LL | match (true, &non_enum) { + | ^^^^^^^^^^^^^^^^^ patterns `(_, &NonExhaustiveEnum::Tuple(_))` and `(_, &NonExhaustiveEnum::Struct { .. })` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms - = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + = note: the matched value is of type `(bool, &NonExhaustiveEnum)` and the `non_exhaustive_omitted_patterns` attribute was found + +warning: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:199:11 + | +LL | match (&non_enum, true) { + | ^^^^^^^^^^^^^^^^^ patterns `(&NonExhaustiveEnum::Tuple(_), _)` and `(&NonExhaustiveEnum::Struct { .. }, _)` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `(&NonExhaustiveEnum, bool)` and the `non_exhaustive_omitted_patterns` attribute was found + +warning: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:206:11 + | +LL | match Some(&non_enum) { + | ^^^^^^^^^^^^^^^ pattern `Some(&NonExhaustiveEnum::Struct { .. })` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `Option<&NonExhaustiveEnum>` and the `non_exhaustive_omitted_patterns` attribute was found -error: aborting due to previous error; 16 warnings emitted +error: aborting due to previous error; 15 warnings emitted For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs b/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs index 20b51a5cf3f72..1828fdef90139 100644 --- a/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs +++ b/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs @@ -19,10 +19,10 @@ fn main() { #[deny(non_exhaustive_omitted_patterns)] match UnstableEnum::Stable { + //~^ some variants are not matched explicitly UnstableEnum::Stable => {} _ => {} } - //~^^ some variants are not matched explicitly // Ok: although this is a bit odd, we don't have anything to report // since there is no stable variants and the feature is off diff --git a/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr b/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr index 5b75cfb69fe0c..27939176f75ed 100644 --- a/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr +++ b/tests/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr @@ -13,10 +13,10 @@ LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/stable-omitted-patterns.rs:23:9 + --> $DIR/stable-omitted-patterns.rs:21:11 | -LL | _ => {} - | ^ pattern `UnstableEnum::Stable2` not covered +LL | match UnstableEnum::Stable { + | ^^^^^^^^^^^^^^^^^^^^ pattern `UnstableEnum::Stable2` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found