diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index e87cf05713cd3..f0b3606b7cc66 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -48,6 +48,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) @@ -157,4 +162,4 @@ ast_lowering_underscore_expr_lhs_assign = in expressions, `_` can only be used on the left-hand side of an assignment .label = `_` not allowed here -ast_lowering_use_angle_brackets = use angle brackets instead +ast_lowering_use_angle_brackets = use angle brackets instead \ No newline at end of file diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 834409da6750a..c79cb90450efc 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -405,3 +405,13 @@ pub(crate) struct AsyncBoundOnlyForFnTraits { #[primary_span] pub span: Span, } + +#[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 9950db4784b9c..9c497de8642c9 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -8,6 +8,7 @@ use super::errors::{ }; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; +use crate::errors::ContinueLabeledBlock; use crate::{FnDeclKind, ImplTraitPosition}; use rustc_ast::ptr::P as AstP; use rustc_ast::*; @@ -283,7 +284,26 @@ 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 let Some(_) = opt_label { + if let Some((_, is_loop, block_span)) = self.resolver.get_label_res(e.id) { + if is_loop { + hir::ExprKind::Continue( + self.lower_jump_destination(e.id, *opt_label), + ) + } else { + 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)) + } + } 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)); @@ -1429,8 +1449,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 a5be91bb87209..885bc63f659b1 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -229,7 +229,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 30409e990e13c..1d37bd02f48c0 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -200,7 +200,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_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2f4da29133f1b..bb5782ac30e18 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -658,7 +658,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, @@ -2215,7 +2215,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() { @@ -4184,7 +4187,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { Ok(Some(result)) } - fn with_resolved_label(&mut self, label: Option