Skip to content

Commit 5d84fca

Browse files
committed
accept macros inside the labeled block before the match
1 parent d6cb6b6 commit 5d84fca

File tree

3 files changed

+57
-4
lines changed

3 files changed

+57
-4
lines changed

compiler/rustc_hir_typeck/src/loops.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,9 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
214214
if attrs.iter().any(|attr| attr.has_name(sym::const_continue)) {
215215
if let Some(break_label) = break_label.label {
216216
let is_target_label = |cx: &Context| match cx {
217-
Context::LoopMatch { labeled_block } => break_label == *labeled_block,
217+
Context::LoopMatch { labeled_block } => {
218+
break_label.ident.name == labeled_block.ident.name
219+
}
218220
_ => false,
219221
};
220222

compiler/rustc_mir_build/src/thir/cx/expr.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -898,9 +898,12 @@ impl<'tcx> ThirBuildCx<'tcx> {
898898
dcx.emit_fatal(LoopMatchBadRhs { span: rhs_expr.span })
899899
};
900900

901-
if let Some(first) = block_body.stmts.first() {
902-
let span = first.span.to(block_body.stmts.last().unwrap().span);
903-
dcx.emit_fatal(LoopMatchBadStatements { span })
901+
// The labeled block should contain one match expression, but defining items is
902+
// allowed.
903+
for stmt in block_body.stmts {
904+
if !matches!(stmt.kind, rustc_hir::StmtKind::Item(_)) {
905+
dcx.emit_fatal(LoopMatchBadStatements { span: stmt.span })
906+
}
904907
}
905908

906909
let Some(block_body_expr) = block_body.expr else {

tests/ui/loop-match/macro.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Test that macros can be defined in the labeled block. This should not trigger an error about
2+
// statements not being allowed in that position, and should of course work as expected.
3+
4+
//@ run-pass
5+
6+
#![allow(incomplete_features)]
7+
#![feature(loop_match)]
8+
9+
enum State {
10+
A,
11+
B,
12+
C,
13+
}
14+
15+
fn main() {
16+
let mut state = State::A;
17+
#[loop_match]
18+
'a: loop {
19+
state = 'blk: {
20+
macro_rules! const_continue {
21+
($e:expr) => {
22+
#[const_continue]
23+
break 'blk $e;
24+
};
25+
}
26+
match state {
27+
State::A => {
28+
const_continue!(State::B);
29+
}
30+
State::B => {
31+
// Without special logic, the compiler believes this is a
32+
// reassignment to an immutable variable because of the
33+
// `loop`. So this tests that local variables work.
34+
let _a = 0;
35+
36+
if true {
37+
const_continue!(State::C);
38+
} else {
39+
const_continue!(State::A);
40+
}
41+
}
42+
State::C => break 'a,
43+
}
44+
};
45+
}
46+
47+
assert!(matches!(state, State::C))
48+
}

0 commit comments

Comments
 (0)