Skip to content

Commit f2e19d0

Browse files
Continue inside a labeled block now lowers to a error when to lowering the ast
1 parent 710ce90 commit f2e19d0

File tree

14 files changed

+153
-37
lines changed

14 files changed

+153
-37
lines changed

compiler/rustc_ast_lowering/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ ast_lowering_clobber_abi_not_supported =
5454
5555
ast_lowering_closure_cannot_be_static = closures cannot be static
5656
57+
ast_lowering_continue_labeled_block =
58+
`continue` pointing to a labeled block
59+
.label = labeled blocks cannot be `continue`'d
60+
.block_label = labeled block the `continue` points to
61+
5762
ast_lowering_coroutine_too_many_parameters =
5863
too many parameters for a coroutine (expected 0 or 1 parameters)
5964

compiler/rustc_ast_lowering/src/errors.rs

+10
Original file line numberDiff line numberDiff line change
@@ -451,3 +451,13 @@ pub(crate) struct YieldInClosure {
451451
#[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")]
452452
pub suggestion: Option<Span>,
453453
}
454+
455+
#[derive(Diagnostic)]
456+
#[diag(ast_lowering_continue_labeled_block, code = E0696)]
457+
pub struct ContinueLabeledBlock {
458+
#[primary_span]
459+
#[label]
460+
pub span: Span,
461+
#[label(ast_lowering_block_label)]
462+
pub block_span: Span,
463+
}

compiler/rustc_ast_lowering/src/expr.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,13 @@ use thin_vec::{thin_vec, ThinVec};
1515

1616
use super::errors::{
1717
AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
18-
ClosureCannotBeStatic, CoroutineTooManyParameters,
18+
ClosureCannotBeStatic, ContinueLabeledBlock, CoroutineTooManyParameters,
1919
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
20-
NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign,
20+
NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign, YieldInClosure,
2121
};
2222
use super::{
2323
ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs, ResolverAstLoweringExt,
2424
};
25-
use crate::errors::YieldInClosure;
2625
use crate::{FnDeclKind, ImplTraitPosition};
2726

2827
impl<'hir> LoweringContext<'_, 'hir> {
@@ -291,7 +290,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
291290
hir::ExprKind::Break(self.lower_jump_destination(e.id, *opt_label), opt_expr)
292291
}
293292
ExprKind::Continue(opt_label) => {
294-
hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label))
293+
if opt_label.is_some()
294+
&& let Some((_, is_loop, block_span)) = self.resolver.get_label_res(e.id)
295+
&& !is_loop
296+
{
297+
hir::ExprKind::Err(
298+
self.dcx().emit_err(ContinueLabeledBlock { span: e.span, block_span }),
299+
)
300+
} else {
301+
hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label))
302+
}
295303
}
296304
ExprKind::Ret(e) => {
297305
let e = e.as_ref().map(|x| self.lower_expr(x));
@@ -1470,8 +1478,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
14701478
fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
14711479
let target_id = match destination {
14721480
Some((id, _)) => {
1473-
if let Some(loop_id) = self.resolver.get_label_res(id) {
1474-
Ok(self.lower_node_id(loop_id))
1481+
if let Some((id, _is_loop, _)) = self.resolver.get_label_res(id) {
1482+
Ok(self.lower_node_id(id))
14751483
} else {
14761484
Err(hir::LoopIdError::UnresolvedLabel)
14771485
}

compiler/rustc_ast_lowering/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ impl ResolverAstLowering {
252252
}
253253

254254
/// Obtains resolution for a label with the given `NodeId`.
255-
fn get_label_res(&self, id: NodeId) -> Option<NodeId> {
255+
fn get_label_res(&self, id: NodeId) -> Option<(NodeId, bool, Span)> {
256256
self.label_res_map.get(&id).copied()
257257
}
258258

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
@@ -672,7 +672,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
672672
last_block_rib: Option<Rib<'a>>,
673673

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

677677
/// The current set of local scopes for lifetimes.
678678
lifetime_ribs: Vec<LifetimeRib>,
@@ -2316,7 +2316,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
23162316

23172317
/// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
23182318
/// label and reports an error if the label is not found or is unreachable.
2319-
fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'a>> {
2319+
fn resolve_label(
2320+
&mut self,
2321+
mut label: Ident,
2322+
) -> Result<((NodeId, bool, Span), Span), ResolutionError<'a>> {
23202323
let mut suggestion = None;
23212324

23222325
for i in (0..self.label_ribs.len()).rev() {
@@ -4333,7 +4336,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
43334336
Ok(Some(result))
43344337
}
43354338

4336-
fn with_resolved_label(&mut self, label: Option<Label>, id: NodeId, f: impl FnOnce(&mut Self)) {
4339+
fn with_resolved_label(
4340+
&mut self,
4341+
label: Option<Label>,
4342+
id: NodeId,
4343+
is_loop: bool,
4344+
span: Span,
4345+
f: impl FnOnce(&mut Self),
4346+
) {
43374347
if let Some(label) = label {
43384348
if label.ident.as_str().as_bytes()[1] != b'_' {
43394349
self.diag_metadata.unused_labels.insert(id, label.ident.span);
@@ -4345,16 +4355,22 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
43454355

43464356
self.with_label_rib(RibKind::Normal, |this| {
43474357
let ident = label.ident.normalize_to_macro_rules();
4348-
this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
4358+
this.label_ribs.last_mut().unwrap().bindings.insert(ident, (id, is_loop, span));
43494359
f(this);
43504360
});
43514361
} else {
43524362
f(self);
43534363
}
43544364
}
43554365

4356-
fn resolve_labeled_block(&mut self, label: Option<Label>, id: NodeId, block: &'ast Block) {
4357-
self.with_resolved_label(label, id, |this| this.visit_block(block));
4366+
fn resolve_labeled_block(
4367+
&mut self,
4368+
label: Option<Label>,
4369+
id: NodeId,
4370+
block: &'ast Block,
4371+
is_loop: bool,
4372+
) {
4373+
self.with_resolved_label(label, id, is_loop, block.span, |this| this.visit_block(block));
43584374
}
43594375

43604376
fn resolve_block(&mut self, block: &'ast Block) {
@@ -4497,10 +4513,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
44974513

44984514
ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
44994515
match self.resolve_label(label.ident) {
4500-
Ok((node_id, _)) => {
4516+
Ok((node, _)) => {
45014517
// Since this res is a label, it is never read.
4502-
self.r.label_res_map.insert(expr.id, node_id);
4503-
self.diag_metadata.unused_labels.remove(&node_id);
4518+
self.r.label_res_map.insert(expr.id, node);
4519+
self.diag_metadata.unused_labels.remove(&node.0);
45044520
}
45054521
Err(error) => {
45064522
self.report_error(label.ident.span, error);
@@ -4535,11 +4551,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
45354551
}
45364552

45374553
ExprKind::Loop(ref block, label, _) => {
4538-
self.resolve_labeled_block(label, expr.id, block)
4554+
self.resolve_labeled_block(label, expr.id, block, true)
45394555
}
45404556

45414557
ExprKind::While(ref cond, ref block, label) => {
4542-
self.with_resolved_label(label, expr.id, |this| {
4558+
self.with_resolved_label(label, expr.id, true, block.span, |this| {
45434559
this.with_rib(ValueNS, RibKind::Normal, |this| {
45444560
let old = this.diag_metadata.in_if_condition.replace(cond);
45454561
this.visit_expr(cond);
@@ -4553,11 +4569,13 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
45534569
self.visit_expr(iter);
45544570
self.with_rib(ValueNS, RibKind::Normal, |this| {
45554571
this.resolve_pattern_top(pat, PatternSource::For);
4556-
this.resolve_labeled_block(label, expr.id, body);
4572+
this.resolve_labeled_block(label, expr.id, body, true);
45574573
});
45584574
}
45594575

4560-
ExprKind::Block(ref block, label) => self.resolve_labeled_block(label, block.id, block),
4576+
ExprKind::Block(ref block, label) => {
4577+
self.resolve_labeled_block(label, block.id, block, false)
4578+
}
45614579

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

compiler/rustc_resolve/src/late/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -935,7 +935,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
935935
if let Some(err_code) = err.code {
936936
if err_code == E0425 {
937937
for label_rib in &self.label_ribs {
938-
for (label_ident, node_id) in &label_rib.bindings {
938+
for (label_ident, (node_id, _, _)) in &label_rib.bindings {
939939
let ident = path.last().unwrap().ident;
940940
if format!("'{ident}") == label_ident.to_string() {
941941
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
@@ -1017,7 +1017,8 @@ pub struct Resolver<'a, 'tcx> {
10171017
/// Resolutions for import nodes, which have multiple resolutions in different namespaces.
10181018
import_res_map: NodeMap<PerNS<Option<Res>>>,
10191019
/// Resolutions for labels (node IDs of their corresponding blocks or loops).
1020-
label_res_map: NodeMap<NodeId>,
1020+
/// The boolean stores if the node is loop. The span is the span of the node.
1021+
label_res_map: NodeMap<(NodeId, bool, Span)>,
10211022
/// Resolutions for lifetimes.
10221023
lifetimes_res_map: NodeMap<LifetimeRes>,
10231024
/// Lifetime parameters that lowering will have to introduce.

tests/crashes/113379.rs

-7
This file was deleted.

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,31 @@
1+
// Fixes: #113379
2+
3+
#![allow(incomplete_features)]
4+
#![feature(adt_const_params)]
5+
6+
trait Trait<const S: usize> {}
7+
8+
struct Bug<T>
9+
where
10+
T: Trait<
11+
{
12+
'b: {
13+
//~^ ERROR [E0308]
14+
continue 'b; //~ ERROR [E0696]
15+
}
16+
},
17+
>,
18+
{
19+
t: T,
20+
}
21+
22+
fn f() -> impl Sized {
23+
'b: {
24+
continue 'b;
25+
//~^ ERROR [E0696]
26+
}
27+
}
28+
29+
fn main() {
30+
f();
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error[E0696]: `continue` pointing to a labeled block
2+
--> $DIR/cont-in-fn-issue-113379.rs:12:17
3+
|
4+
LL | / 'b: {
5+
LL | |
6+
LL | | continue 'b;
7+
| | ^^^^^^^^^^^ labeled blocks cannot be `continue`'d
8+
LL | | }
9+
| |_____________- labeled block the `continue` points to
10+
11+
error[E0696]: `continue` pointing to a labeled block
12+
--> $DIR/cont-in-fn-issue-113379.rs:22:9
13+
|
14+
LL | / 'b: {
15+
LL | | continue 'b;
16+
| | ^^^^^^^^^^^ labeled blocks cannot be `continue`'d
17+
LL | |
18+
LL | | }
19+
| |_____- labeled block the `continue` points to
20+
21+
error[E0308]: mismatched types
22+
--> $DIR/cont-in-fn-issue-113379.rs:10:13
23+
|
24+
LL | / 'b: {
25+
LL | |
26+
LL | | continue 'b;
27+
LL | | }
28+
| |_____________^ expected `usize`, found `()`
29+
30+
error: aborting due to 3 previous errors
31+
32+
Some errors have detailed explanations: E0308, E0696.
33+
For more information about an error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
//@ known-bug: #121623
1+
// Fixes: #121623
2+
23
fn main() {
34
match () {
45
_ => 'b: {
56
continue 'b;
7+
//~^ ERROR [E0696]
68
}
79
}
810
}
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)