From aa7cc5d2f453853a4025cf029f3e42625c7e1e18 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 1 Jul 2025 15:29:09 +0200 Subject: [PATCH 1/2] loop match: run exhaustiveness check --- compiler/rustc_middle/src/thir.rs | 14 +- compiler/rustc_middle/src/thir/visit.rs | 4 +- .../rustc_mir_build/src/builder/expr/into.rs | 12 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 7 +- .../src/thir/pattern/check_match.rs | 8 +- compiler/rustc_mir_build/src/thir/print.rs | 19 +- tests/ui/loop-match/invalid.rs | 13 + tests/ui/loop-match/invalid.stderr | 28 +- .../ui/thir-print/thir-tree-loop-match.stdout | 290 ++++++++++-------- 9 files changed, 242 insertions(+), 153 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index bda8dcadbced8..730c1147684b4 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -380,11 +380,11 @@ pub enum ExprKind<'tcx> { }, /// A `#[loop_match] loop { state = 'blk: { match state { ... } } }` expression. LoopMatch { - /// The state variable that is updated, and also the scrutinee of the match. + /// The state variable that is updated. + /// The `match_data.scrutinee` is the same variable, but with a different span. state: ExprId, region_scope: region::Scope, - arms: Box<[ArmId]>, - match_span: Span, + match_data: Box, }, /// Special expression representing the `let` part of an `if let` or similar construct /// (including `if let` guards in match arms, and let-chains formed by `&&`). @@ -599,6 +599,14 @@ pub struct Arm<'tcx> { pub span: Span, } +/// The `match` part of a `#[loop_match]` +#[derive(Clone, Debug, HashStable)] +pub struct LoopMatchMatchData { + pub scrutinee: ExprId, + pub arms: Box<[ArmId]>, + pub span: Span, +} + #[derive(Copy, Clone, Debug, HashStable)] pub enum LogicalOp { /// The `&&` operator. diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index c9ef723aea43a..dcfa6c4db3274 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -2,6 +2,7 @@ use super::{ AdtExpr, AdtExprBase, Arm, Block, ClosureExpr, Expr, ExprKind, InlineAsmExpr, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir, }; +use crate::thir::LoopMatchMatchData; /// Every `walk_*` method uses deconstruction to access fields of structs and /// enums. This will result in a compile error if a field is added, which makes @@ -83,7 +84,8 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor.visit_pat(pat); } Loop { body } => visitor.visit_expr(&visitor.thir()[body]), - LoopMatch { state: scrutinee, ref arms, .. } | Match { scrutinee, ref arms, .. } => { + LoopMatch { match_data: box LoopMatchMatchData { scrutinee, ref arms, .. }, .. } + | Match { scrutinee, ref arms, .. } => { visitor.visit_expr(&visitor.thir()[scrutinee]); for &arm in &**arms { visitor.visit_arm(&visitor.thir()[arm]); diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index fe3d072fa88e2..82b883a99a11c 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -245,7 +245,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None }) } - ExprKind::LoopMatch { state, region_scope, match_span, ref arms } => { + ExprKind::LoopMatch { + state, + region_scope, + match_data: box LoopMatchMatchData { box ref arms, span: match_span, scrutinee }, + } => { // Intuitively, this is a combination of a loop containing a labeled block // containing a match. // @@ -292,8 +296,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Logic for `match`. let scrutinee_place_builder = - unpack!(body_block = this.as_place_builder(body_block, state)); - let scrutinee_span = this.thir.exprs[state].span; + unpack!(body_block = this.as_place_builder(body_block, scrutinee)); + let scrutinee_span = this.thir.exprs[scrutinee].span; let match_start_span = match_span.shrink_to_lo().to(scrutinee_span); let mut patterns = Vec::with_capacity(arms.len()); @@ -335,7 +339,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { move |this| { this.in_breakable_scope(None, state_place, expr_span, |this| { Some(this.in_const_continuable_scope( - arms.clone(), + Box::from(arms), built_tree.clone(), state_place, expr_span, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 5197e93fda73a..b694409f327bd 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -983,8 +983,11 @@ impl<'tcx> ThirBuildCx<'tcx> { data: region::ScopeData::Node, }, - arms: arms.iter().map(|a| self.convert_arm(a)).collect(), - match_span: block_body_expr.span, + match_data: Box::new(LoopMatchMatchData { + scrutinee: self.mirror_expr(scrutinee), + arms: arms.iter().map(|a| self.convert_arm(a)).collect(), + span: block_body_expr.span, + }), } } else { let block_ty = self.typeck_results.node_type(body.hir_id); 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 41fbabc253930..b7b160c738d22 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -6,7 +6,7 @@ use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_err}; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; -use rustc_hir::{self as hir, BindingMode, ByRef, HirId}; +use rustc_hir::{self as hir, BindingMode, ByRef, HirId, MatchSource}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::Level; use rustc_middle::bug; @@ -154,6 +154,12 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { ExprKind::Match { scrutinee, box ref arms, match_source } => { self.check_match(scrutinee, arms, match_source, ex.span); } + ExprKind::LoopMatch { + match_data: box LoopMatchMatchData { scrutinee, box ref arms, span }, + .. + } => { + self.check_match(scrutinee, arms, MatchSource::Normal, span); + } ExprKind::Let { box ref pat, expr } => { self.check_let(pat, Some(expr), ex.span); } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 1507b6b8c068a..5efc4be2de2df 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -318,18 +318,23 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_expr(*body, depth_lvl + 2); print_indented!(self, ")", depth_lvl); } - LoopMatch { state, region_scope, match_span, arms } => { + LoopMatch { state, region_scope, match_data } => { print_indented!(self, "LoopMatch {", depth_lvl); print_indented!(self, "state:", depth_lvl + 1); self.print_expr(*state, depth_lvl + 2); print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1); - print_indented!(self, format!("match_span: {:?}", match_span), depth_lvl + 1); - - print_indented!(self, "arms: [", depth_lvl + 1); - for arm_id in arms.iter() { - self.print_arm(*arm_id, depth_lvl + 2); + print_indented!(self, "match_data:", depth_lvl + 1); + print_indented!(self, "LoopMatchMatchData {", depth_lvl + 2); + print_indented!(self, format!("span: {:?}", match_data.span), depth_lvl + 3); + print_indented!(self, "scrutinee:", depth_lvl + 3); + self.print_expr(match_data.scrutinee, depth_lvl + 4); + + print_indented!(self, "arms: [", depth_lvl + 3); + for arm_id in match_data.arms.iter() { + self.print_arm(*arm_id, depth_lvl + 4); } - print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "]", depth_lvl + 3); + print_indented!(self, "}", depth_lvl + 2); print_indented!(self, "}", depth_lvl); } Let { expr, pat } => { diff --git a/tests/ui/loop-match/invalid.rs b/tests/ui/loop-match/invalid.rs index 2ddc19f4fc62a..2f3b0a00f1f9f 100644 --- a/tests/ui/loop-match/invalid.rs +++ b/tests/ui/loop-match/invalid.rs @@ -159,3 +159,16 @@ fn arm_has_guard(cond: bool) { } } } + +fn non_exhaustive() { + let mut state = State::A; + #[loop_match] + loop { + state = 'blk: { + match state { + //~^ ERROR non-exhaustive patterns: `State::B` and `State::C` not covered + State::A => State::B, + } + } + } +} diff --git a/tests/ui/loop-match/invalid.stderr b/tests/ui/loop-match/invalid.stderr index 51fdd024c6fa9..0444c713d920f 100644 --- a/tests/ui/loop-match/invalid.stderr +++ b/tests/ui/loop-match/invalid.stderr @@ -86,6 +86,30 @@ error: match arms that are part of a `#[loop_match]` cannot have guards LL | State::B if cond => break 'a, | ^^^^ -error: aborting due to 12 previous errors +error[E0004]: non-exhaustive patterns: `State::B` and `State::C` not covered + --> $DIR/invalid.rs:168:19 + | +LL | match state { + | ^^^^^ patterns `State::B` and `State::C` not covered + | +note: `State` defined here + --> $DIR/invalid.rs:7:6 + | +LL | enum State { + | ^^^^^ +LL | A, +LL | B, + | - not covered +LL | C, + | - not covered + = note: the matched value is of type `State` +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 ~ State::A => State::B, +LL ~ State::B | State::C => todo!(), + | + +error: aborting due to 13 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0004, E0308. +For more information about an error, try `rustc --explain E0004`. diff --git a/tests/ui/thir-print/thir-tree-loop-match.stdout b/tests/ui/thir-print/thir-tree-loop-match.stdout index 828b93da6beb5..5c4c50cb15623 100644 --- a/tests/ui/thir-print/thir-tree-loop-match.stdout +++ b/tests/ui/thir-print/thir-tree-loop-match.stdout @@ -89,158 +89,182 @@ body: } } region_scope: Node(10) - match_span: $DIR/thir-tree-loop-match.rs:11:13: 17:14 (#0) - arms: [ - Arm { - pattern: - Pat: { - ty: bool - span: $DIR/thir-tree-loop-match.rs:12:17: 12:21 (#0) - kind: PatKind { - Constant { - value: Ty(bool, true) - } - } - } - guard: None - body: + match_data: + LoopMatchMatchData { + span: $DIR/thir-tree-loop-match.rs:11:13: 17:14 (#0) + scrutinee: Expr { ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(5)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:11:19: 11:24 (#0) kind: Scope { - region_scope: Node(17) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).17)) + region_scope: Node(12) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).12)) value: Expr { ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(5)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:11:19: 11:24 (#0) kind: - NeverToAny { - source: - Expr { - ty: ! - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0) - kind: - Block { - targeted_by_break: false + VarRef { + id: LocalVarId(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).2)) + } + } + } + } + arms: [ + Arm { + pattern: + Pat: { + ty: bool + span: $DIR/thir-tree-loop-match.rs:12:17: 12:21 (#0) + kind: PatKind { + Constant { + value: Ty(bool, true) + } + } + } + guard: None + body: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0) + kind: + Scope { + region_scope: Node(17) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).17)) + value: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0) + kind: + NeverToAny { + source: + Expr { + ty: ! + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None } span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0) - region_scope: Node(18) - safety_mode: Safe - stmts: [ - Stmt { - kind: Expr { - scope: Node(21) - expr: - Expr { - ty: ! - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:14:21: 14:37 (#0) - kind: - Scope { - region_scope: Node(19) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).19)) - value: - Expr { - ty: ! - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:14:21: 14:37 (#0) - kind: - ConstContinue ( - label: Node(10) - value: - Expr { - ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0) - kind: - Scope { - region_scope: Node(20) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).20)) - value: - Expr { - ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0) - kind: - Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0) }, neg: false) + kind: + Block { + targeted_by_break: false + span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0) + region_scope: Node(18) + safety_mode: Safe + stmts: [ + Stmt { + kind: Expr { + scope: Node(21) + expr: + Expr { + ty: ! + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:14:21: 14:37 (#0) + kind: + Scope { + region_scope: Node(19) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).19)) + value: + Expr { + ty: ! + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:14:21: 14:37 (#0) + kind: + ConstContinue ( + label: Node(10) + value: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0) + kind: + Scope { + region_scope: Node(20) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).20)) + value: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0) + kind: + Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0) }, neg: false) + } } } - } - ) + ) + } } } } - } + } + ] + expr: [] } - ] - expr: [] } } } } } + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).16)) + scope: Node(16) + span: $DIR/thir-tree-loop-match.rs:12:17: 15:18 (#0) } - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).16)) - scope: Node(16) - span: $DIR/thir-tree-loop-match.rs:12:17: 15:18 (#0) - } - Arm { - pattern: - Pat: { - ty: bool - span: $DIR/thir-tree-loop-match.rs:16:17: 16:22 (#0) - kind: PatKind { - Constant { - value: Ty(bool, false) + Arm { + pattern: + Pat: { + ty: bool + span: $DIR/thir-tree-loop-match.rs:16:17: 16:22 (#0) + kind: PatKind { + Constant { + value: Ty(bool, false) + } + } } - } - } - guard: None - body: - Expr { - ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0) - kind: - Scope { - region_scope: Node(25) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).25)) - value: - Expr { - ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0) - kind: - NeverToAny { - source: - Expr { - ty: ! - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0) - kind: - Return { - value: - Expr { - ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:16:33: 16:38 (#0) - kind: - Scope { - region_scope: Node(26) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).26)) - value: - Expr { - ty: bool - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } - span: $DIR/thir-tree-loop-match.rs:16:33: 16:38 (#0) - kind: - VarRef { - id: LocalVarId(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).2)) + guard: None + body: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0) + kind: + Scope { + region_scope: Node(25) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).25)) + value: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0) + kind: + NeverToAny { + source: + Expr { + ty: ! + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0) + kind: + Return { + value: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:16:33: 16:38 (#0) + kind: + Scope { + region_scope: Node(26) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).26)) + value: + Expr { + ty: bool + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } + span: $DIR/thir-tree-loop-match.rs:16:33: 16:38 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).2)) + } } } } @@ -250,12 +274,12 @@ body: } } } + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).24)) + scope: Node(24) + span: $DIR/thir-tree-loop-match.rs:16:17: 16:38 (#0) } - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).24)) - scope: Node(24) - span: $DIR/thir-tree-loop-match.rs:16:17: 16:38 (#0) + ] } - ] } } } From 8fdf0ef0ae32369a6fe82b2ef69b1f5e5dc68be1 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 1 Jul 2025 11:48:42 +0200 Subject: [PATCH 2/2] loop match: handle opaque patterns fixes issue 143203 --- .../rustc_mir_build/src/builder/matches/mod.rs | 6 ++++-- compiler/rustc_mir_build/src/errors.rs | 1 - tests/ui/loop-match/invalid.rs | 18 ++++++++++++++++++ tests/ui/loop-match/invalid.stderr | 10 ++++++++-- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 9600067a85fe3..2c29b8628417f 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -2970,6 +2970,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } Constructor::Wildcard => true, + // Opaque patterns must not be matched on structurally. + Constructor::Opaque(_) => false, + // These we may eventually support: Constructor::Struct | Constructor::Ref @@ -2980,8 +2983,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | Constructor::Str(_) => bug!("unsupported pattern constructor {:?}", pat.ctor()), // These should never occur here: - Constructor::Opaque(_) - | Constructor::Never + Constructor::Never | Constructor::NonExhaustive | Constructor::Hidden | Constructor::Missing diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 20e836f6bf208..16b49bf384c52 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1230,7 +1230,6 @@ pub(crate) struct ConstContinueMissingValue { #[derive(Diagnostic)] #[diag(mir_build_const_continue_unknown_jump_target)] -#[note] pub(crate) struct ConstContinueUnknownJumpTarget { #[primary_span] pub span: Span, diff --git a/tests/ui/loop-match/invalid.rs b/tests/ui/loop-match/invalid.rs index 2f3b0a00f1f9f..0c47b1e0057ae 100644 --- a/tests/ui/loop-match/invalid.rs +++ b/tests/ui/loop-match/invalid.rs @@ -172,3 +172,21 @@ fn non_exhaustive() { } } } + +fn invalid_range_pattern(state: f32) { + #[loop_match] + loop { + state = 'blk: { + match state { + 1.0 => { + #[const_continue] + break 'blk 2.5; + } + 4.0..3.0 => { + //~^ ERROR lower range bound must be less than upper + todo!() + } + } + } + } +} diff --git a/tests/ui/loop-match/invalid.stderr b/tests/ui/loop-match/invalid.stderr index 0444c713d920f..70f246caa9c2d 100644 --- a/tests/ui/loop-match/invalid.stderr +++ b/tests/ui/loop-match/invalid.stderr @@ -109,7 +109,13 @@ LL ~ State::A => State::B, LL ~ State::B | State::C => todo!(), | -error: aborting due to 13 previous errors +error[E0579]: lower range bound must be less than upper + --> $DIR/invalid.rs:185:17 + | +LL | 4.0..3.0 => { + | ^^^^^^^^ + +error: aborting due to 14 previous errors -Some errors have detailed explanations: E0004, E0308. +Some errors have detailed explanations: E0004, E0308, E0579. For more information about an error, try `rustc --explain E0004`.