about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/loops.rs50
-rw-r--r--compiler/rustc_mir_build/messages.ftl2
-rw-r--r--compiler/rustc_mir_build/src/errors.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs4
5 files changed, 34 insertions, 28 deletions
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 1b1b3ced44d..08361718108 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -3016,7 +3016,7 @@ impl fmt::Display for LoopIdError {
     }
 }
 
-#[derive(Copy, Clone, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Debug, PartialEq, HashStable_Generic)]
 pub struct Destination {
     /// This is `Some(_)` iff there is an explicit user-specified 'label
     pub label: Option<Label>,
diff --git a/compiler/rustc_hir_typeck/src/loops.rs b/compiler/rustc_hir_typeck/src/loops.rs
index d47a3246964..acfa5c473aa 100644
--- a/compiler/rustc_hir_typeck/src/loops.rs
+++ b/compiler/rustc_hir_typeck/src/loops.rs
@@ -2,7 +2,6 @@ use std::collections::BTreeMap;
 use std::fmt;
 
 use Context::*;
-use rustc_ast::Label;
 use rustc_hir as hir;
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::DefKind;
@@ -42,8 +41,8 @@ enum Context {
     ConstBlock,
     /// E.g. `#[loop_match] loop { state = 'label: { /* ... */ } }`.
     LoopMatch {
-        /// The label of the labeled block (not of the loop itself).
-        labeled_block: Label,
+        /// The destination pointing to the labeled block (not to the loop itself).
+        labeled_block: Destination,
     },
 }
 
@@ -186,18 +185,18 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
             {
                 self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b));
             }
-            hir::ExprKind::Break(break_label, ref opt_expr) => {
+            hir::ExprKind::Break(break_destination, ref opt_expr) => {
                 if let Some(e) = opt_expr {
                     self.visit_expr(e);
                 }
 
-                if self.require_label_in_labeled_block(e.span, &break_label, "break") {
+                if self.require_label_in_labeled_block(e.span, &break_destination, "break") {
                     // If we emitted an error about an unlabeled break in a labeled
                     // block, we don't need any further checking for this break any more
                     return;
                 }
 
-                let loop_id = match break_label.target_id {
+                let loop_id = match break_destination.target_id {
                     Ok(loop_id) => Some(loop_id),
                     Err(hir::LoopIdError::OutsideLoopScope) => None,
                     Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
@@ -212,18 +211,25 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
 
                 // A `#[const_continue]` must break to a block in a `#[loop_match]`.
                 if find_attr!(self.tcx.hir_attrs(e.hir_id), AttributeKind::ConstContinue(_)) {
-                    if let Some(break_label) = break_label.label {
-                        let is_target_label = |cx: &Context| match cx {
-                            Context::LoopMatch { labeled_block } => {
-                                break_label.ident.name == labeled_block.ident.name
-                            }
-                            _ => false,
-                        };
+                    let Some(label) = break_destination.label else {
+                        let span = e.span;
+                        self.tcx.dcx().emit_fatal(ConstContinueBadLabel { span });
+                    };
 
-                        if !self.cx_stack.iter().rev().any(is_target_label) {
-                            let span = break_label.ident.span;
-                            self.tcx.dcx().emit_fatal(ConstContinueBadLabel { span });
+                    let is_target_label = |cx: &Context| match cx {
+                        Context::LoopMatch { labeled_block } => {
+                            // NOTE: with macro expansion, the label's span might be different here
+                            // even though it does still refer to the same HIR node. A block
+                            // can't have two labels, so the hir_id is a unique identifier.
+                            assert!(labeled_block.target_id.is_ok()); // see `is_loop_match`.
+                            break_destination.target_id == labeled_block.target_id
                         }
+                        _ => false,
+                    };
+
+                    if !self.cx_stack.iter().rev().any(is_target_label) {
+                        let span = label.ident.span;
+                        self.tcx.dcx().emit_fatal(ConstContinueBadLabel { span });
                     }
                 }
 
@@ -249,7 +255,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
                         Some(kind) => {
                             let suggestion = format!(
                                 "break{}",
-                                break_label
+                                break_destination
                                     .label
                                     .map_or_else(String::new, |l| format!(" {}", l.ident))
                             );
@@ -259,7 +265,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
                                 kind: kind.name(),
                                 suggestion,
                                 loop_label,
-                                break_label: break_label.label,
+                                break_label: break_destination.label,
                                 break_expr_kind: &break_expr.kind,
                                 break_expr_span: break_expr.span,
                             });
@@ -268,7 +274,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
                 }
 
                 let sp_lo = e.span.with_lo(e.span.lo() + BytePos("break".len() as u32));
-                let label_sp = match break_label.label {
+                let label_sp = match break_destination.label {
                     Some(label) => sp_lo.with_hi(label.ident.span.hi()),
                     None => sp_lo.shrink_to_lo(),
                 };
@@ -416,7 +422,7 @@ impl<'hir> CheckLoopVisitor<'hir> {
         &self,
         e: &'hir hir::Expr<'hir>,
         body: &'hir hir::Block<'hir>,
-    ) -> Option<Label> {
+    ) -> Option<Destination> {
         if !find_attr!(self.tcx.hir_attrs(e.hir_id), AttributeKind::LoopMatch(_)) {
             return None;
         }
@@ -438,8 +444,8 @@ impl<'hir> CheckLoopVisitor<'hir> {
 
         let hir::ExprKind::Assign(_, rhs_expr, _) = loop_body_expr.kind else { return None };
 
-        let hir::ExprKind::Block(_, label) = rhs_expr.kind else { return None };
+        let hir::ExprKind::Block(block, label) = rhs_expr.kind else { return None };
 
-        label
+        Some(Destination { label, target_id: Ok(block.hir_id) })
     }
 }
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index abfe8eb66dd..287639de663 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -87,7 +87,7 @@ mir_build_confused = missing patterns are not covered because `{$variable}` is i
 mir_build_const_continue_bad_const = could not determine the target branch for this `#[const_continue]`
     .label = this value is too generic
 
-mir_build_const_continue_missing_value = a `#[const_continue]` must break to a label with a value
+mir_build_const_continue_missing_label_or_value = a `#[const_continue]` must break to a label with a value
 
 mir_build_const_continue_not_const = could not determine the target branch for this `#[const_continue]`
     .help = try extracting the expression into a `const` item
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index f1fbd5c4a49..1a52c6c85cb 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1254,8 +1254,8 @@ pub(crate) struct ConstContinueBadConst {
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_build_const_continue_missing_value)]
-pub(crate) struct ConstContinueMissingValue {
+#[diag(mir_build_const_continue_missing_label_or_value)]
+pub(crate) struct ConstContinueMissingLabelOrValue {
     #[primary_span]
     pub span: Span,
 }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index a0d3913c159..81b0e21a5f5 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -852,9 +852,9 @@ impl<'tcx> ThirBuildCx<'tcx> {
                 if find_attr!(self.tcx.hir_attrs(expr.hir_id), AttributeKind::ConstContinue(_)) {
                     match dest.target_id {
                         Ok(target_id) => {
-                            let Some(value) = value else {
+                            let (Some(value), Some(_)) = (value, dest.label) else {
                                 let span = expr.span;
-                                self.tcx.dcx().emit_fatal(ConstContinueMissingValue { span })
+                                self.tcx.dcx().emit_fatal(ConstContinueMissingLabelOrValue { span })
                             };
 
                             ExprKind::ConstContinue {