diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_hir/src/hir.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/loops.rs | 50 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/messages.ftl | 2 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/errors.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/cx/expr.rs | 4 |
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 { |
