Skip to content

Commit c489979

Browse files
committed
fix: Reject upvar scrutinees for loop_match
1 parent b56aaec commit c489979

File tree

3 files changed

+115
-8
lines changed

3 files changed

+115
-8
lines changed

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

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -955,21 +955,26 @@ impl<'tcx> ThirBuildCx<'tcx> {
955955
dcx.emit_fatal(LoopMatchBadRhs { span: block_body_expr.span })
956956
};
957957

958-
fn local(expr: &rustc_hir::Expr<'_>) -> Option<hir::HirId> {
958+
fn local(
959+
cx: &mut ThirBuildCx<'_>,
960+
expr: &rustc_hir::Expr<'_>,
961+
) -> Option<hir::HirId> {
959962
if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind {
960-
if let Res::Local(hir_id) = path.res {
963+
if let Res::Local(hir_id) = path.res
964+
&& !cx.is_upvar(hir_id)
965+
{
961966
return Some(hir_id);
962967
}
963968
}
964969

965970
None
966971
}
967972

968-
let Some(scrutinee_hir_id) = local(scrutinee) else {
973+
let Some(scrutinee_hir_id) = local(self, scrutinee) else {
969974
dcx.emit_fatal(LoopMatchInvalidMatch { span: scrutinee.span })
970975
};
971976

972-
if local(state) != Some(scrutinee_hir_id) {
977+
if local(self, state) != Some(scrutinee_hir_id) {
973978
dcx.emit_fatal(LoopMatchInvalidUpdate {
974979
scrutinee: scrutinee.span,
975980
lhs: state.span,
@@ -1260,10 +1265,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
12601265
fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'tcx> {
12611266
// We want upvars here not captures.
12621267
// Captures will be handled in MIR.
1263-
let is_upvar = self
1264-
.tcx
1265-
.upvars_mentioned(self.body_owner)
1266-
.is_some_and(|upvars| upvars.contains_key(&var_hir_id));
1268+
let is_upvar = self.is_upvar(var_hir_id);
12671269

12681270
debug!(
12691271
"convert_var({:?}): is_upvar={}, body_owner={:?}",
@@ -1443,6 +1445,12 @@ impl<'tcx> ThirBuildCx<'tcx> {
14431445
}
14441446
}
14451447

1448+
fn is_upvar(&mut self, var_hir_id: hir::HirId) -> bool {
1449+
self.tcx
1450+
.upvars_mentioned(self.body_owner)
1451+
.is_some_and(|upvars| upvars.contains_key(&var_hir_id))
1452+
}
1453+
14461454
/// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExpr.
14471455
fn field_refs(&mut self, fields: &'tcx [hir::ExprField<'tcx>]) -> Box<[FieldExpr]> {
14481456
fields
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#![allow(incomplete_features)]
2+
#![feature(loop_match)]
3+
4+
#[derive(Clone, Copy)]
5+
enum State {
6+
A,
7+
B,
8+
}
9+
10+
fn main() {
11+
let mut state = State::A;
12+
13+
#[loop_match]
14+
loop {
15+
state = 'blk: {
16+
match state {
17+
State::A => {
18+
#[const_continue]
19+
break 'blk State::B;
20+
}
21+
State::B => {
22+
return;
23+
}
24+
}
25+
}
26+
}
27+
28+
|| {
29+
#[loop_match]
30+
loop {
31+
state = 'blk: {
32+
match state {
33+
//~^ ERROR invalid match on `#[loop_match]` state
34+
State::A => {
35+
#[const_continue]
36+
break 'blk State::B;
37+
}
38+
State::B => {
39+
return;
40+
}
41+
}
42+
}
43+
}
44+
};
45+
46+
|| {
47+
let mut state = state;
48+
#[loop_match]
49+
loop {
50+
state = 'blk: {
51+
match state {
52+
State::A => {
53+
#[const_continue]
54+
break 'blk State::B;
55+
}
56+
State::B => {
57+
return;
58+
}
59+
}
60+
}
61+
}
62+
};
63+
64+
move || {
65+
#[loop_match]
66+
loop {
67+
state = 'blk: {
68+
match state {
69+
//~^ ERROR invalid match on `#[loop_match]` state
70+
State::A => {
71+
#[const_continue]
72+
break 'blk State::B;
73+
}
74+
State::B => {
75+
return;
76+
}
77+
}
78+
}
79+
}
80+
};
81+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: invalid match on `#[loop_match]` state
2+
--> $DIR/upvar_scrutinee.rs:32:23
3+
|
4+
LL | match state {
5+
| ^^^^^
6+
|
7+
= note: a local variable must be the scrutinee within a `#[loop_match]`
8+
9+
error: invalid match on `#[loop_match]` state
10+
--> $DIR/upvar_scrutinee.rs:68:23
11+
|
12+
LL | match state {
13+
| ^^^^^
14+
|
15+
= note: a local variable must be the scrutinee within a `#[loop_match]`
16+
17+
error: aborting due to 2 previous errors
18+

0 commit comments

Comments
 (0)