From a6a707169d42e3ef2ca8ef243a6023a2c7df988b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 24 Dec 2024 19:08:09 +0000 Subject: [PATCH] Consider arm to diverge if guard diverges --- compiler/rustc_hir_typeck/src/_match.rs | 12 ++++++++++-- tests/ui/reachable/expr_match.rs | 8 ++++++-- tests/ui/reachable/expr_match.stderr | 24 +++++++++++++++++++++++- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 243313ee8767a..87300f5bb83c6 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -77,12 +77,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut prior_non_diverging_arms = vec![]; // Used only for diagnostics. let mut prior_arm = None; for arm in arms { + self.diverges.set(Diverges::Maybe); + if let Some(e) = &arm.guard { - self.diverges.set(Diverges::Maybe); self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {}); + + // FIXME: If this is the first arm and the pattern is irrefutable, + // e.g. `_` or `x`, and the guard diverges, then the whole match + // may also be considered to diverge. We should warn on all subsequent + // arms, too, just like we do for diverging scrutinees above. } - self.diverges.set(Diverges::Maybe); + // N.B. We don't reset diverges here b/c we want to warn in the arm + // if the guard diverges, like: `x if { loop {} } => f()`, and we + // also want to consider the arm to diverge itself. let arm_ty = self.check_expr_with_expectation(arm.body, expected); all_arms_diverge &= self.diverges.get(); diff --git a/tests/ui/reachable/expr_match.rs b/tests/ui/reachable/expr_match.rs index 2fd26b54e15ee..1bae061c98421 100644 --- a/tests/ui/reachable/expr_match.rs +++ b/tests/ui/reachable/expr_match.rs @@ -21,9 +21,13 @@ fn d() { } fn e() { - // Here the compiler fails to figure out that the `println` is dead. - match () { () if return => (), () => return } + match () { + () if return => (), + //~^ ERROR unreachable expression + () => return, + } println!("I am dead"); + //~^ ERROR unreachable statement } fn f() { diff --git a/tests/ui/reachable/expr_match.stderr b/tests/ui/reachable/expr_match.stderr index d15208609cff8..ae202a6e0c34a 100644 --- a/tests/ui/reachable/expr_match.stderr +++ b/tests/ui/reachable/expr_match.stderr @@ -23,5 +23,27 @@ LL | println!("I am dead"); | = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: unreachable expression + --> $DIR/expr_match.rs:25:25 + | +LL | () if return => (), + | ------ ^^ unreachable expression + | | + | any code following this expression is unreachable + +error: unreachable statement + --> $DIR/expr_match.rs:29:5 + | +LL | / match () { +LL | | () if return => (), +LL | | +LL | | () => return, +LL | | } + | |_____- any code following this `match` expression is unreachable, as all arms diverge +LL | println!("I am dead"); + | ^^^^^^^^^^^^^^^^^^^^^ unreachable statement + | + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors