From 55650a293fdde121b7b766e403035a6f606bb522 Mon Sep 17 00:00:00 2001 From: Yukang Date: Thu, 13 Aug 2026 09:46:31 +0800 Subject: [PATCH 1/2] Add regression test for try block label suggestions --- .../invalid-label-suggestion-issue-160987.rs | 14 ++++++++++++++ .../invalid-label-suggestion-issue-160987.stderr | 15 +++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/ui/try-block/invalid-label-suggestion-issue-160987.rs create mode 100644 tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr diff --git a/tests/ui/try-block/invalid-label-suggestion-issue-160987.rs b/tests/ui/try-block/invalid-label-suggestion-issue-160987.rs new file mode 100644 index 0000000000000..01e03bc03e9e7 --- /dev/null +++ b/tests/ui/try-block/invalid-label-suggestion-issue-160987.rs @@ -0,0 +1,14 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/160987. +//! A label suggested for a try block must use valid syntax. + +//@ edition: 2024 + +#![feature(try_blocks)] + +fn main() { + try { + break; + //~^ ERROR `break` outside of a loop or labeled block + None?; + }; +} diff --git a/tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr b/tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr new file mode 100644 index 0000000000000..4d539e176a453 --- /dev/null +++ b/tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr @@ -0,0 +1,15 @@ +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/invalid-label-suggestion-issue-160987.rs:10:9 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL ~ try 'block: { +LL ~ break 'block; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0268`. From 54a639147e9700f9b4f3d4b0d8502f6771db8102 Mon Sep 17 00:00:00 2001 From: Yukang Date: Thu, 13 Aug 2026 10:20:09 +0800 Subject: [PATCH 2/2] Fix invalid suggestion from try unlabled block --- compiler/rustc_hir_typeck/src/diagnostics.rs | 5 +++- compiler/rustc_hir_typeck/src/loops.rs | 29 ++++++++++++++----- ...nvalid-label-suggestion-issue-160987.fixed | 16 ++++++++++ .../invalid-label-suggestion-issue-160987.rs | 2 ++ ...valid-label-suggestion-issue-160987.stderr | 7 +++-- 5 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 tests/ui/try-block/invalid-label-suggestion-issue-160987.fixed diff --git a/compiler/rustc_hir_typeck/src/diagnostics.rs b/compiler/rustc_hir_typeck/src/diagnostics.rs index 722dfb0794ec1..fd74693e7f9fb 100644 --- a/compiler/rustc_hir_typeck/src/diagnostics.rs +++ b/compiler/rustc_hir_typeck/src/diagnostics.rs @@ -819,10 +819,13 @@ pub(crate) struct OutsideLoop<'a> { applicability = "maybe-incorrect" )] pub(crate) struct OutsideLoopSuggestion { - #[suggestion_part(code = "'block: ")] + #[suggestion_part(code = "{block_prefix}")] pub block_span: Span, #[suggestion_part(code = " 'block")] pub break_spans: Vec, + #[suggestion_part(code = " }}")] + pub wrap_end: Option, + pub block_prefix: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_typeck/src/loops.rs b/compiler/rustc_hir_typeck/src/loops.rs index 21aad64f58d38..ea01744d5b64e 100644 --- a/compiler/rustc_hir_typeck/src/loops.rs +++ b/compiler/rustc_hir_typeck/src/loops.rs @@ -31,7 +31,10 @@ enum Context { kind: hir::CoroutineDesugaring, source: hir::CoroutineSource, }, - UnlabeledBlock(Span), + UnlabeledBlock { + label_span: Span, + wrap_end: Option, + }, UnlabeledIfBlock(Span), LabeledBlock, /// E.g. The labeled block inside `['_'; 'block: { break 'block 1 + 2; }]`. @@ -50,6 +53,7 @@ struct BlockInfo { name: String, spans: Vec, suggs: Vec, + wrap_end: Option, } #[derive(PartialEq)] @@ -118,7 +122,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { ck_loop.cx_stack.last(), Some(&Normal) | Some(&AnonConst) - | Some(&UnlabeledBlock(_)) + | Some(&UnlabeledBlock { .. }) | Some(&UnlabeledIfBlock(_)) ) { @@ -177,10 +181,16 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { None, ) if matches!( self.cx_stack.last(), - Some(&Normal) | Some(&AnonConst) | Some(&UnlabeledBlock(_)) + Some(&Normal) | Some(&AnonConst) | Some(&UnlabeledBlock { .. }) ) => { - self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b)); + // An unlabeled block targeted by `break` may comes from a `try` block. + // Since `try 'block: {}` is invalid, nest a labeled block inside its body. + let wrap_end = b.targeted_by_break.then(|| b.span.shrink_to_hi()); + self.with_context( + UnlabeledBlock { label_span: b.span.shrink_to_lo(), wrap_end }, + |v| v.visit_block(b), + ); } hir::ExprKind::Break(break_destination, ref opt_expr) => { if let Some(e) = opt_expr { @@ -365,13 +375,14 @@ impl<'hir> CheckLoopVisitor<'hir> { source, }); } - UnlabeledBlock(block_span) - if br_cx_kind == BreakContextKind::Break && block_span.eq_ctxt(break_span) => + UnlabeledBlock { label_span, wrap_end } + if br_cx_kind == BreakContextKind::Break && label_span.eq_ctxt(break_span) => { - let block = self.block_breaks.entry(block_span).or_insert_with(|| BlockInfo { + let block = self.block_breaks.entry(label_span).or_insert_with(|| BlockInfo { name: br_cx_kind.to_string(), spans: vec![], suggs: vec![], + wrap_end, }); block.spans.push(span); block.suggs.push(break_span); @@ -379,7 +390,7 @@ impl<'hir> CheckLoopVisitor<'hir> { UnlabeledIfBlock(_) if br_cx_kind == BreakContextKind::Break => { self.require_break_cx(br_cx_kind, span, break_span, cx_pos - 1); } - Normal | AnonConst | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) | ConstBlock => { + Normal | AnonConst | Fn | UnlabeledBlock { .. } | UnlabeledIfBlock(_) | ConstBlock => { self.tcx.dcx().emit_err(OutsideLoop { spans: vec![span], name: &br_cx_kind.to_string(), @@ -415,6 +426,8 @@ impl<'hir> CheckLoopVisitor<'hir> { suggestion: Some(OutsideLoopSuggestion { block_span: *s, break_spans: block.suggs.clone(), + block_prefix: if block.wrap_end.is_some() { "{ 'block: " } else { "'block: " }, + wrap_end: block.wrap_end, }), }); } diff --git a/tests/ui/try-block/invalid-label-suggestion-issue-160987.fixed b/tests/ui/try-block/invalid-label-suggestion-issue-160987.fixed new file mode 100644 index 0000000000000..c0b9eeb1189e9 --- /dev/null +++ b/tests/ui/try-block/invalid-label-suggestion-issue-160987.fixed @@ -0,0 +1,16 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/160987. +//! A label suggested for a try block must use valid syntax. + +//@ edition: 2024 +//@ run-rustfix + +#![feature(try_blocks)] +#![allow(unreachable_code)] + +fn main() { + try { 'block: { + break 'block; + //~^ ERROR `break` outside of a loop or labeled block + None?; + } }; +} diff --git a/tests/ui/try-block/invalid-label-suggestion-issue-160987.rs b/tests/ui/try-block/invalid-label-suggestion-issue-160987.rs index 01e03bc03e9e7..aab9c98313c91 100644 --- a/tests/ui/try-block/invalid-label-suggestion-issue-160987.rs +++ b/tests/ui/try-block/invalid-label-suggestion-issue-160987.rs @@ -2,8 +2,10 @@ //! A label suggested for a try block must use valid syntax. //@ edition: 2024 +//@ run-rustfix #![feature(try_blocks)] +#![allow(unreachable_code)] fn main() { try { diff --git a/tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr b/tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr index 4d539e176a453..55e57242ac686 100644 --- a/tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr +++ b/tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr @@ -1,13 +1,16 @@ error[E0268]: `break` outside of a loop or labeled block - --> $DIR/invalid-label-suggestion-issue-160987.rs:10:9 + --> $DIR/invalid-label-suggestion-issue-160987.rs:12:9 | LL | break; | ^^^^^ cannot `break` outside of a loop or labeled block | help: consider labeling this block to be able to break within it | -LL ~ try 'block: { +LL ~ try { 'block: { LL ~ break 'block; +LL | +LL | None?; +LL ~ } }; | error: aborting due to 1 previous error