From 237576c51ca39eaf0c98814b223d2464b2271d9e Mon Sep 17 00:00:00 2001 From: Sarthak Singh Date: Tue, 27 Feb 2024 21:10:00 +0530 Subject: [PATCH] Continue inside a labeled block now lowers to a error when to lowering the ast --- compiler/rustc_ast_lowering/messages.ftl | 5 +++ compiler/rustc_ast_lowering/src/errors.rs | 10 +++++ compiler/rustc_ast_lowering/src/expr.rs | 26 +++++++++-- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 3 +- compiler/rustc_resolve/src/late.rs | 44 +++++++++++++------ .../rustc_resolve/src/late/diagnostics.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 3 +- .../cont-in-block/cont-in-fn-issue-113379.rs | 28 ++++++++++++ .../cont-in-fn-issue-113379.stderr | 31 +++++++++++++ .../cont-in-match-arm-issue-121623.rs | 8 ++++ .../cont-in-match-arm-issue-121623.stderr | 14 ++++++ 12 files changed, 156 insertions(+), 20 deletions(-) create mode 100644 tests/ui/lowering/cont-in-block/cont-in-fn-issue-113379.rs create mode 100644 tests/ui/lowering/cont-in-block/cont-in-fn-issue-113379.stderr create mode 100644 tests/ui/lowering/cont-in-block/cont-in-match-arm-issue-121623.rs create mode 100644 tests/ui/lowering/cont-in-block/cont-in-match-arm-issue-121623.stderr 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 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