Skip to content

Commit 58ba609

Browse files
Continue inside a labeled block now lowers to a error when to lowering the ast
1 parent 5a1e544 commit 58ba609

File tree

13 files changed

+152
-26
lines changed

13 files changed

+152
-26
lines changed

compiler/rustc_ast_lowering/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ ast_lowering_clobber_abi_not_supported =
4848
4949
ast_lowering_closure_cannot_be_static = closures cannot be static
5050
51+
ast_lowering_continue_labeled_block =
52+
`continue` pointing to a labeled block
53+
.label = labeled blocks cannot be `continue`'d
54+
.block_label = labeled block the `continue` points to
55+
5156
ast_lowering_coroutine_too_many_parameters =
5257
too many parameters for a coroutine (expected 0 or 1 parameters)
5358

compiler/rustc_ast_lowering/src/errors.rs

+10
Original file line numberDiff line numberDiff line change
@@ -404,3 +404,13 @@ pub(crate) struct AsyncBoundOnlyForFnTraits {
404404
#[primary_span]
405405
pub span: Span,
406406
}
407+
408+
#[derive(Diagnostic)]
409+
#[diag(ast_lowering_continue_labeled_block, code = E0696)]
410+
pub struct ContinueLabeledBlock {
411+
#[primary_span]
412+
#[label]
413+
pub span: Span,
414+
#[label(ast_lowering_block_label)]
415+
pub block_span: Span,
416+
}

compiler/rustc_ast_lowering/src/expr.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use super::errors::{
88
};
99
use super::ResolverAstLoweringExt;
1010
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
11+
use crate::errors::ContinueLabeledBlock;
1112
use crate::{FnDeclKind, ImplTraitPosition};
1213
use rustc_ast::ptr::P as AstP;
1314
use rustc_ast::*;
@@ -279,7 +280,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
279280
hir::ExprKind::Break(self.lower_jump_destination(e.id, *opt_label), opt_expr)
280281
}
281282
ExprKind::Continue(opt_label) => {
282-
hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label))
283+
if opt_label.is_some()
284+
&& let Some((_, is_loop, block_span)) = self.resolver.get_label_res(e.id)
285+
&& !is_loop
286+
{
287+
hir::ExprKind::Err(
288+
self.dcx().emit_err(ContinueLabeledBlock { span: e.span, block_span }),
289+
)
290+
} else {
291+
hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label))
292+
}
283293
}
284294
ExprKind::Ret(e) => {
285295
let e = e.as_ref().map(|x| self.lower_expr(x));
@@ -1425,8 +1435,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
14251435
fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
14261436
let target_id = match destination {
14271437
Some((id, _)) => {
1428-
if let Some(loop_id) = self.resolver.get_label_res(id) {
1429-
Ok(self.lower_node_id(loop_id))
1438+
if let Some((id, _is_loop, _)) = self.resolver.get_label_res(id) {
1439+
Ok(self.lower_node_id(id))
14301440
} else {
14311441
Err(hir::LoopIdError::UnresolvedLabel)
14321442
}

compiler/rustc_ast_lowering/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ impl ResolverAstLowering {
229229
}
230230

231231
/// Obtains resolution for a label with the given `NodeId`.
232-
fn get_label_res(&self, id: NodeId) -> Option<NodeId> {
232+
fn get_label_res(&self, id: NodeId) -> Option<(NodeId, bool, Span)> {
233233
self.label_res_map.get(&id).copied()
234234
}
235235

compiler/rustc_middle/src/ty/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,8 @@ pub struct ResolverAstLowering {
203203
/// Resolutions for import nodes, which have multiple resolutions in different namespaces.
204204
pub import_res_map: NodeMap<hir::def::PerNS<Option<Res<ast::NodeId>>>>,
205205
/// Resolutions for labels (node IDs of their corresponding blocks or loops).
206-
pub label_res_map: NodeMap<ast::NodeId>,
206+
/// The boolean stores if the node is loop. The span is the span of the node.
207+
pub label_res_map: NodeMap<(ast::NodeId, bool, Span)>,
207208
/// Resolutions for lifetimes.
208209
pub lifetimes_res_map: NodeMap<LifetimeRes>,
209210
/// Lifetime parameters that lowering will have to introduce.

compiler/rustc_resolve/src/late.rs

+31-13
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
658658
last_block_rib: Option<Rib<'a>>,
659659

660660
/// The current set of local scopes, for labels.
661-
label_ribs: Vec<Rib<'a, NodeId>>,
661+
label_ribs: Vec<Rib<'a, (NodeId, bool, Span)>>,
662662

663663
/// The current set of local scopes for lifetimes.
664664
lifetime_ribs: Vec<LifetimeRib>,
@@ -2211,7 +2211,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
22112211

22122212
/// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
22132213
/// label and reports an error if the label is not found or is unreachable.
2214-
fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'a>> {
2214+
fn resolve_label(
2215+
&mut self,
2216+
mut label: Ident,
2217+
) -> Result<((NodeId, bool, Span), Span), ResolutionError<'a>> {
22152218
let mut suggestion = None;
22162219

22172220
for i in (0..self.label_ribs.len()).rev() {
@@ -4181,7 +4184,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
41814184
Ok(Some(result))
41824185
}
41834186

4184-
fn with_resolved_label(&mut self, label: Option<Label>, id: NodeId, f: impl FnOnce(&mut Self)) {
4187+
fn with_resolved_label(
4188+
&mut self,
4189+
label: Option<Label>,
4190+
id: NodeId,
4191+
is_loop: bool,
4192+
span: Span,
4193+
f: impl FnOnce(&mut Self),
4194+
) {
41854195
if let Some(label) = label {
41864196
if label.ident.as_str().as_bytes()[1] != b'_' {
41874197
self.diag_metadata.unused_labels.insert(id, label.ident.span);
@@ -4193,16 +4203,22 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
41934203

41944204
self.with_label_rib(RibKind::Normal, |this| {
41954205
let ident = label.ident.normalize_to_macro_rules();
4196-
this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
4206+
this.label_ribs.last_mut().unwrap().bindings.insert(ident, (id, is_loop, span));
41974207
f(this);
41984208
});
41994209
} else {
42004210
f(self);
42014211
}
42024212
}
42034213

4204-
fn resolve_labeled_block(&mut self, label: Option<Label>, id: NodeId, block: &'ast Block) {
4205-
self.with_resolved_label(label, id, |this| this.visit_block(block));
4214+
fn resolve_labeled_block(
4215+
&mut self,
4216+
label: Option<Label>,
4217+
id: NodeId,
4218+
block: &'ast Block,
4219+
is_loop: bool,
4220+
) {
4221+
self.with_resolved_label(label, id, is_loop, block.span, |this| this.visit_block(block));
42064222
}
42074223

42084224
fn resolve_block(&mut self, block: &'ast Block) {
@@ -4345,10 +4361,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
43454361

43464362
ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
43474363
match self.resolve_label(label.ident) {
4348-
Ok((node_id, _)) => {
4364+
Ok((node, _)) => {
43494365
// Since this res is a label, it is never read.
4350-
self.r.label_res_map.insert(expr.id, node_id);
4351-
self.diag_metadata.unused_labels.remove(&node_id);
4366+
self.r.label_res_map.insert(expr.id, node);
4367+
self.diag_metadata.unused_labels.remove(&node.0);
43524368
}
43534369
Err(error) => {
43544370
self.report_error(label.ident.span, error);
@@ -4383,11 +4399,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
43834399
}
43844400

43854401
ExprKind::Loop(ref block, label, _) => {
4386-
self.resolve_labeled_block(label, expr.id, block)
4402+
self.resolve_labeled_block(label, expr.id, block, true)
43874403
}
43884404

43894405
ExprKind::While(ref cond, ref block, label) => {
4390-
self.with_resolved_label(label, expr.id, |this| {
4406+
self.with_resolved_label(label, expr.id, true, block.span, |this| {
43914407
this.with_rib(ValueNS, RibKind::Normal, |this| {
43924408
let old = this.diag_metadata.in_if_condition.replace(cond);
43934409
this.visit_expr(cond);
@@ -4401,11 +4417,13 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
44014417
self.visit_expr(iter);
44024418
self.with_rib(ValueNS, RibKind::Normal, |this| {
44034419
this.resolve_pattern_top(pat, PatternSource::For);
4404-
this.resolve_labeled_block(label, expr.id, body);
4420+
this.resolve_labeled_block(label, expr.id, body, true);
44054421
});
44064422
}
44074423

4408-
ExprKind::Block(ref block, label) => self.resolve_labeled_block(label, block.id, block),
4424+
ExprKind::Block(ref block, label) => {
4425+
self.resolve_labeled_block(label, block.id, block, false)
4426+
}
44094427

44104428
// Equivalent to `visit::walk_expr` + passing some context to children.
44114429
ExprKind::Field(ref subexpression, _) => {

compiler/rustc_resolve/src/late/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -946,7 +946,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
946946
if let Some(err_code) = err.code {
947947
if err_code == E0425 {
948948
for label_rib in &self.label_ribs {
949-
for (label_ident, node_id) in &label_rib.bindings {
949+
for (label_ident, (node_id, _, _)) in &label_rib.bindings {
950950
let ident = path.last().unwrap().ident;
951951
if format!("'{ident}") == label_ident.to_string() {
952952
err.span_label(label_ident.span, "a label with a similar name exists");

compiler/rustc_resolve/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,8 @@ pub struct Resolver<'a, 'tcx> {
999999
/// Resolutions for import nodes, which have multiple resolutions in different namespaces.
10001000
import_res_map: NodeMap<PerNS<Option<Res>>>,
10011001
/// Resolutions for labels (node IDs of their corresponding blocks or loops).
1002-
label_res_map: NodeMap<NodeId>,
1002+
/// The boolean stores if the node is loop. The span is the span of the node.
1003+
label_res_map: NodeMap<(NodeId, bool, Span)>,
10031004
/// Resolutions for lifetimes.
10041005
lifetimes_res_map: NodeMap<LifetimeRes>,
10051006
/// Lifetime parameters that lowering will have to introduce.

tests/ui/label/label_break_value_continue.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
error[E0695]: unlabeled `continue` inside of a labeled block
2-
--> $DIR/label_break_value_continue.rs:6:9
3-
|
4-
LL | continue;
5-
| ^^^^^^^^ `continue` statements that would diverge to or through a labeled block need to bear a label
6-
71
error[E0696]: `continue` pointing to a labeled block
82
--> $DIR/label_break_value_continue.rs:13:9
93
|
@@ -13,6 +7,12 @@ LL | | continue 'b;
137
LL | | }
148
| |_____- labeled block the `continue` points to
159

10+
error[E0695]: unlabeled `continue` inside of a labeled block
11+
--> $DIR/label_break_value_continue.rs:6:9
12+
|
13+
LL | continue;
14+
| ^^^^^^^^ `continue` statements that would diverge to or through a labeled block need to bear a label
15+
1616
error[E0695]: unlabeled `continue` inside of a labeled block
1717
--> $DIR/label_break_value_continue.rs:21:13
1818
|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#![allow(incomplete_features)]
2+
#![feature(adt_const_params)]
3+
4+
trait Trait<const S: &'static str> {}
5+
6+
struct Bug<T>
7+
where
8+
T: Trait<
9+
{
10+
'b: { //~ ERROR [E0308]
11+
continue 'b; //~ ERROR [E0696]
12+
}
13+
},
14+
>,
15+
{
16+
t: T,
17+
}
18+
19+
fn f() -> impl Sized {
20+
'b: {
21+
continue 'b;
22+
//~^ ERROR [E0696]
23+
}
24+
}
25+
26+
fn main() {
27+
f();
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error[E0696]: `continue` pointing to a labeled block
2+
--> $DIR/cont-in-fn-issue-113379.rs:11:17
3+
|
4+
LL | / 'b: {
5+
LL | | continue 'b;
6+
| | ^^^^^^^^^^^ labeled blocks cannot be `continue`'d
7+
LL | | }
8+
| |_____________- labeled block the `continue` points to
9+
10+
error[E0696]: `continue` pointing to a labeled block
11+
--> $DIR/cont-in-fn-issue-113379.rs:21:9
12+
|
13+
LL | / 'b: {
14+
LL | | continue 'b;
15+
| | ^^^^^^^^^^^ labeled blocks cannot be `continue`'d
16+
LL | |
17+
LL | | }
18+
| |_____- labeled block the `continue` points to
19+
20+
error[E0308]: mismatched types
21+
--> $DIR/cont-in-fn-issue-113379.rs:10:13
22+
|
23+
LL | / 'b: {
24+
LL | | continue 'b;
25+
LL | | }
26+
| |_____________^ expected `&str`, found `()`
27+
28+
error: aborting due to 3 previous errors
29+
30+
Some errors have detailed explanations: E0308, E0696.
31+
For more information about an error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn main() {
2+
match () {
3+
_ => 'b: {
4+
continue 'b;
5+
//~^ ERROR [E0696]
6+
}
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0696]: `continue` pointing to a labeled block
2+
--> $DIR/cont-in-match-arm-issue-121623.rs:4:13
3+
|
4+
LL | _ => 'b: {
5+
| ______________-
6+
LL | | continue 'b;
7+
| | ^^^^^^^^^^^ labeled blocks cannot be `continue`'d
8+
LL | |
9+
LL | | }
10+
| |_________- labeled block the `continue` points to
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0696`.

0 commit comments

Comments
 (0)