diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 9ed93d481e773..566915b85dfb4 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -54,6 +54,11 @@ ast_lowering_clobber_abi_not_supported = ast_lowering_closure_cannot_be_static = closures cannot be static +ast_lowering_continue_labeled_block = + `continue` pointing to a labeled block + .label = labeled blocks cannot be `continue`'d + .block_label = labeled block the `continue` points to + ast_lowering_coroutine_too_many_parameters = too many parameters for a coroutine (expected 0 or 1 parameters) diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 7a6c9d8d0d375..ea1139e972cb6 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -451,3 +451,13 @@ pub(crate) struct YieldInClosure { #[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")] pub suggestion: Option, } + +#[derive(Diagnostic)] +#[diag(ast_lowering_continue_labeled_block, code = E0696)] +pub struct ContinueLabeledBlock { + #[primary_span] + #[label] + pub span: Span, + #[label(ast_lowering_block_label)] + pub block_span: Span, +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 124fe6bd380d2..57107bbc49333 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -15,14 +15,13 @@ use thin_vec::{thin_vec, ThinVec}; use super::errors::{ AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, - ClosureCannotBeStatic, CoroutineTooManyParameters, + ClosureCannotBeStatic, ContinueLabeledBlock, CoroutineTooManyParameters, FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody, - NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign, + NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign, YieldInClosure, }; use super::{ ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs, ResolverAstLoweringExt, }; -use crate::errors::YieldInClosure; use crate::{FnDeclKind, ImplTraitPosition}; impl<'hir> LoweringContext<'_, 'hir> { @@ -291,7 +290,16 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Break(self.lower_jump_destination(e.id, *opt_label), opt_expr) } ExprKind::Continue(opt_label) => { - hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label)) + if opt_label.is_some() + && let Some((_, is_loop, block_span)) = self.resolver.get_label_res(e.id) + && !is_loop + { + hir::ExprKind::Err( + self.dcx().emit_err(ContinueLabeledBlock { span: e.span, block_span }), + ) + } else { + hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label)) + } } ExprKind::Ret(e) => { let e = e.as_ref().map(|x| self.lower_expr(x)); @@ -1470,8 +1478,8 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination { let target_id = match destination { Some((id, _)) => { - if let Some(loop_id) = self.resolver.get_label_res(id) { - Ok(self.lower_node_id(loop_id)) + if let Some((id, _is_loop, _)) = self.resolver.get_label_res(id) { + Ok(self.lower_node_id(id)) } else { Err(hir::LoopIdError::UnresolvedLabel) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 224787c335beb..e04b8af135842 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -252,7 +252,7 @@ impl ResolverAstLowering { } /// Obtains resolution for a label with the given `NodeId`. - fn get_label_res(&self, id: NodeId) -> Option { + fn get_label_res(&self, id: NodeId) -> Option<(NodeId, bool, Span)> { self.label_res_map.get(&id).copied() } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9736428e6f7c7..98aabc7b8072a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -203,7 +203,8 @@ pub struct ResolverAstLowering { /// Resolutions for import nodes, which have multiple resolutions in different namespaces. pub import_res_map: NodeMap>>>, /// Resolutions for labels (node IDs of their corresponding blocks or loops). - pub label_res_map: NodeMap, + /// The boolean stores if the node is loop. The span is the span of the node. + pub label_res_map: NodeMap<(ast::NodeId, bool, Span)>, /// Resolutions for lifetimes. pub lifetimes_res_map: NodeMap, /// Lifetime parameters that lowering will have to introduce. diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index bfe0d54e64521..a8c3a97e7679d 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -95,11 +95,6 @@ passes_collapse_debuginfo = passes_confusables = attribute should be applied to an inherent method .label = not an inherent method -passes_continue_labeled_block = - `continue` pointing to a labeled block - .label = labeled blocks cannot be `continue`'d - .block_label = labeled block the `continue` points to - passes_coverage_not_fn_or_closure = attribute should be applied to a function definition or closure .label = not a function or closure diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index ff85be109d460..6d20198682164 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1044,16 +1044,6 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'_, G> for BreakNonLoop<'a> { } } -#[derive(Diagnostic)] -#[diag(passes_continue_labeled_block, code = E0696)] -pub struct ContinueLabeledBlock { - #[primary_span] - #[label] - pub span: Span, - #[label(passes_block_label)] - pub block_span: Span, -} - #[derive(Diagnostic)] #[diag(passes_break_inside_closure, code = E0267)] pub struct BreakInsideClosure<'a> { diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 25115c5cafd89..8311ca39c2dd3 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -15,8 +15,8 @@ use rustc_span::{BytePos, Span}; use Context::*; use crate::errors::{ - BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, - OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, + BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, OutsideLoop, OutsideLoopSuggestion, + UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, }; #[derive(Clone, Copy, Debug, PartialEq)] @@ -266,13 +266,9 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.require_label_in_labeled_block(e.span, &destination, "continue"); match destination.target_id { - Ok(loop_id) => { - if let Node::Block(block) = self.tcx.hir_node(loop_id) { - self.sess.dcx().emit_err(ContinueLabeledBlock { - span: e.span, - block_span: block.span, - }); - } + Ok(_loop_id) => { + // We have already insured that the loop exists while lowering the ast. + // See `compiler/rustc_ast_lowering/src/expr.rs::LoweringContext::lower_expr_mut` } Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { self.sess.dcx().emit_err(UnlabeledCfInWhileCondition { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 7e5fd82b80cee..777ae128b79ef 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -672,7 +672,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { last_block_rib: Option>, /// The current set of local scopes, for labels. - label_ribs: Vec>, + label_ribs: Vec>, /// The current set of local scopes for lifetimes. lifetime_ribs: Vec, @@ -2316,7 +2316,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved /// label and reports an error if the label is not found or is unreachable. - fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'a>> { + fn resolve_label( + &mut self, + mut label: Ident, + ) -> Result<((NodeId, bool, Span), Span), ResolutionError<'a>> { let mut suggestion = None; for i in (0..self.label_ribs.len()).rev() { @@ -4333,7 +4336,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { Ok(Some(result)) } - fn with_resolved_label(&mut self, label: Option