Skip to content

Commit 244a754

Browse files
committed
accept macros inside the labeled block before the match
1 parent 2ea5bc8 commit 244a754

File tree

3 files changed

+57
-4
lines changed

3 files changed

+57
-4
lines changed

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

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

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

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

compiler/rustc_passes/src/loops.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,9 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
233233
if attrs.iter().any(|attr| attr.has_name(sym::const_continue)) {
234234
if let Some(break_label) = break_label.label {
235235
let is_target_label = |cx: &Context| match cx {
236-
Context::LoopMatch { labeled_block } => break_label == *labeled_block,
236+
Context::LoopMatch { labeled_block } => {
237+
break_label.ident.name == labeled_block.ident.name
238+
}
237239
_ => false,
238240
};
239241

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)