diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index e87cf05713cd3..4005bf4bd7bf5 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) diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 570449513bf2a..4167f42ac78ea 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -404,3 +404,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 0b1cb12408003..0d51b4481c077 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::*; @@ -279,7 +280,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)); @@ -1425,8 +1435,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 087d240b0d50f..a783fbaea7e66 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 c6bb7032ace3a..da32f58310108 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_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index de6e121c79bbb..e6b94561555b5 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, @@ -2211,7 +2211,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() { @@ -4181,7 +4184,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { Ok(Some(result)) } - fn with_resolved_label(&mut self, label: Option