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 87ccbed842fc..b0ccf1f85181 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -532,6 +532,18 @@ fn check_match( | hir::MatchSource::AwaitDesugar | hir::MatchSource::FormatArgs => None, }; + + // Check if the match would be exhaustive if all guards were removed. + // If so, we leave a note that guards don't count towards exhaustivity. + let would_be_exhaustive_without_guards = { + let any_arm_has_guard = tarms.iter().any(|arm| arm.has_guard); + any_arm_has_guard && { + let guardless_arms: Vec<_> = + tarms.iter().map(|arm| MatchArm { has_guard: false, ..*arm }).collect(); + rustc_pattern_analysis::rustc::analyze_match(&cx, &guardless_arms, scrut.ty) + .is_ok_and(|report| report.non_exhaustiveness_witnesses.is_empty()) + } + }; self.error = Err(report_non_exhaustive_match( &cx, self.thir, @@ -540,6 +552,7 @@ fn check_match( witnesses, arms, braces_span, + would_be_exhaustive_without_guards, )); } } @@ -1153,6 +1166,7 @@ fn report_non_exhaustive_match<'p, 'tcx>( witnesses: Vec>, arms: &[ArmId], braces_span: Option, + would_be_exhaustive_without_guards: bool, ) -> ErrorGuaranteed { let is_empty_match = arms.is_empty(); let non_empty_enum = match scrut_ty.kind() { @@ -1363,8 +1377,7 @@ fn report_non_exhaustive_match<'p, 'tcx>( }, ); - let all_arms_have_guards = arms.iter().all(|arm_id| thir[*arm_id].guard.is_some()); - if !is_empty_match && all_arms_have_guards { + if would_be_exhaustive_without_guards { err.subdiagnostic(NonExhaustiveMatchAllArmsGuarded); } if let Some((span, sugg)) = suggestion { diff --git a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr index 046c0d5f6588..68a1bebf6b13 100644 --- a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr +++ b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr @@ -569,6 +569,7 @@ note: `Result` defined here = note: not covered = note: the matched value is of type `Result` = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required + = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Err(_) => {}, diff --git a/tests/ui/pattern/usefulness/empty-types.normal.stderr b/tests/ui/pattern/usefulness/empty-types.normal.stderr index ba158c1176b3..320959534e52 100644 --- a/tests/ui/pattern/usefulness/empty-types.normal.stderr +++ b/tests/ui/pattern/usefulness/empty-types.normal.stderr @@ -569,6 +569,7 @@ note: `Result` defined here = note: not covered = note: the matched value is of type `Result` = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required + = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Err(_) => {}, diff --git a/tests/ui/pattern/usefulness/guards.stderr b/tests/ui/pattern/usefulness/guards.stderr index 82ed2a93c55f..8907fd155f5d 100644 --- a/tests/ui/pattern/usefulness/guards.stderr +++ b/tests/ui/pattern/usefulness/guards.stderr @@ -5,6 +5,7 @@ LL | match 0u8 { | ^^^ pattern `128_u8..=u8::MAX` not covered | = note: the matched value is of type `u8` + = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ 128 ..= 255 if true => {}, diff --git a/tests/ui/pattern/usefulness/issue-30240.stderr b/tests/ui/pattern/usefulness/issue-30240.stderr index da8bbdffbf6d..d592d3110adb 100644 --- a/tests/ui/pattern/usefulness/issue-30240.stderr +++ b/tests/ui/pattern/usefulness/issue-30240.stderr @@ -20,6 +20,7 @@ LL | match "world" { | = note: the matched value is of type `&str` = note: `&str` cannot be matched exhaustively, so a wildcard `_` is necessary + = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ "hello" => {}, diff --git a/tests/ui/pattern/usefulness/issue-72377.rs b/tests/ui/pattern/usefulness/issue-72377.rs index 782a9963f2e5..61a74fa68f90 100644 --- a/tests/ui/pattern/usefulness/issue-72377.rs +++ b/tests/ui/pattern/usefulness/issue-72377.rs @@ -9,6 +9,7 @@ fn main() { //~^ ERROR non-exhaustive patterns: `(X::A, Some(X::A))`, `(X::A, Some(X::B))`, `(X::B, Some(X::B))` and 2 //~| NOTE more not covered //~| NOTE the matched value is of type `(X, Option)` + //~| NOTE match arms with guards don't count towards exhaustivity (_, None) => false, (v, Some(w)) if v == w => true, (X::B, Some(X::C)) => false, diff --git a/tests/ui/pattern/usefulness/issue-72377.stderr b/tests/ui/pattern/usefulness/issue-72377.stderr index 1eaee1bd3521..ec42caa49d3e 100644 --- a/tests/ui/pattern/usefulness/issue-72377.stderr +++ b/tests/ui/pattern/usefulness/issue-72377.stderr @@ -5,6 +5,7 @@ LL | match (x, y) { | ^^^^^^ patterns `(X::A, Some(X::A))`, `(X::A, Some(X::B))`, `(X::B, Some(X::B))` and 2 more not covered | = note: the matched value is of type `(X, Option)` + = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | LL ~ (X::A, Some(X::C)) | (X::C, Some(X::A)) => false, diff --git a/tests/ui/pattern/usefulness/match-non-exhaustive.rs b/tests/ui/pattern/usefulness/match-non-exhaustive.rs index 62c185d04b35..3b210a115d21 100644 --- a/tests/ui/pattern/usefulness/match-non-exhaustive.rs +++ b/tests/ui/pattern/usefulness/match-non-exhaustive.rs @@ -1,5 +1,4 @@ fn main() { match 0 { 1 => () } //~ ERROR non-exhaustive patterns match 0 { 0 if false => () } //~ ERROR non-exhaustive patterns - //-| NOTE match arms with guards don't count towards exhaustivity } diff --git a/tests/ui/pattern/usefulness/match-non-exhaustive.stderr b/tests/ui/pattern/usefulness/match-non-exhaustive.stderr index 1a0cc58f35df..f226bdf80646 100644 --- a/tests/ui/pattern/usefulness/match-non-exhaustive.stderr +++ b/tests/ui/pattern/usefulness/match-non-exhaustive.stderr @@ -17,7 +17,6 @@ LL | match 0 { 0 if false => () } | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered | = note: the matched value is of type `i32` - = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL | match 0 { 0 if false => (), i32::MIN..=-1_i32 | 1_i32..=i32::MAX => todo!() } diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr index 4622ea59b547..81e0df15a6e1 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr @@ -44,6 +44,7 @@ note: `Option` defined here = note: not covered = note: the matched value is of type `&Option` = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required + = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ None => {}, @@ -63,6 +64,7 @@ note: `Option` defined here = note: not covered = note: the matched value is of type `&Option` = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required + = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ None => {}, diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.stderr index ca92aa491d70..4ff7194542bf 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.stderr +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.stderr @@ -10,6 +10,7 @@ note: `Option` defined here | = note: not covered = note: the matched value is of type `Option` + = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ None if let y = x => {},