Skip to content

Commit 1a267e3

Browse files
committed
Restore if let guard temporary scoping difference
Match guards with an if let guard or an if let chain guard should have a temporary scope of the whole arm. This is to allow ref bindings to temporaries to borrow check.
1 parent a549711 commit 1a267e3

File tree

3 files changed

+89
-2
lines changed

3 files changed

+89
-2
lines changed

compiler/rustc_hir_analysis/src/check/region.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -177,15 +177,24 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
177177
}
178178

179179
fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) {
180+
fn has_let_expr(expr: &Expr<'_>) -> bool {
181+
match &expr.kind {
182+
hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
183+
hir::ExprKind::Let(..) => true,
184+
_ => false,
185+
}
186+
}
187+
180188
let prev_cx = visitor.cx;
181189

182190
visitor.terminating_scopes.insert(arm.hir_id.local_id);
183191

184192
visitor.enter_node_scope_with_dtor(arm.hir_id.local_id);
185193
visitor.cx.var_parent = visitor.cx.parent;
186194

187-
if let Some(expr) = arm.guard {
188-
// Check for if??
195+
if let Some(expr) = arm.guard
196+
&& !has_let_expr(expr)
197+
{
189198
visitor.terminating_scopes.insert(expr.hir_id.local_id);
190199
}
191200

compiler/rustc_mir_build/src/build/matches/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ use std::borrow::Borrow;
3333
use std::mem;
3434

3535
impl<'a, 'tcx> Builder<'a, 'tcx> {
36+
/// Lowers a condition in a way that ensures that variables bound in any let
37+
/// expressions are definitely initialized in the if body.
38+
///
39+
/// If `declare_bindings` is false then variables created in `let`
40+
/// expressions will not be declared. This is for if let guards on arms with
41+
/// an or pattern, where the guard is lowered multiple times.
3642
pub(crate) fn then_else_break(
3743
&mut self,
3844
mut block: BasicBlock,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Ensure that temporaries in if-let guards live for the arm
2+
// regression test for #118593
3+
4+
// check-pass
5+
6+
#![feature(if_let_guard)]
7+
#![feature(let_chains)]
8+
9+
fn get_temp() -> Option<String> {
10+
None
11+
}
12+
13+
fn let_guard(num: u8) {
14+
match num {
15+
1 | 2 if let Some(ref a) = get_temp() => {
16+
let _b = a;
17+
}
18+
_ => {}
19+
}
20+
match num {
21+
3 | 4 if let Some(ref mut c) = get_temp() => {
22+
let _d = c;
23+
}
24+
_ => {}
25+
}
26+
}
27+
28+
fn let_let_chain_guard(num: u8) {
29+
match num {
30+
5 | 6
31+
if let Some(ref a) = get_temp()
32+
&& let Some(ref b) = get_temp() =>
33+
{
34+
let _x = a;
35+
let _y = b;
36+
}
37+
_ => {}
38+
}
39+
match num {
40+
7 | 8
41+
if let Some(ref mut c) = get_temp()
42+
&& let Some(ref mut d) = get_temp() =>
43+
{
44+
let _w = c;
45+
let _z = d;
46+
}
47+
_ => {}
48+
}
49+
}
50+
51+
fn let_cond_chain_guard(num: u8) {
52+
match num {
53+
9 | 10
54+
if let Some(ref a) = get_temp()
55+
&& true =>
56+
{
57+
let _x = a;
58+
}
59+
_ => {}
60+
}
61+
match num {
62+
11 | 12
63+
if let Some(ref mut b) = get_temp()
64+
&& true =>
65+
{
66+
let _w = b;
67+
}
68+
_ => {}
69+
}
70+
}
71+
72+
fn main() {}

0 commit comments

Comments
 (0)