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.
This commit is contained in:
parent
a549711f6e
commit
1a267e3f40
3 changed files with 89 additions and 2 deletions
|
@ -177,6 +177,14 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) {
|
fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) {
|
||||||
|
fn has_let_expr(expr: &Expr<'_>) -> bool {
|
||||||
|
match &expr.kind {
|
||||||
|
hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
|
||||||
|
hir::ExprKind::Let(..) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let prev_cx = visitor.cx;
|
let prev_cx = visitor.cx;
|
||||||
|
|
||||||
visitor.terminating_scopes.insert(arm.hir_id.local_id);
|
visitor.terminating_scopes.insert(arm.hir_id.local_id);
|
||||||
|
@ -184,8 +192,9 @@ fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir
|
||||||
visitor.enter_node_scope_with_dtor(arm.hir_id.local_id);
|
visitor.enter_node_scope_with_dtor(arm.hir_id.local_id);
|
||||||
visitor.cx.var_parent = visitor.cx.parent;
|
visitor.cx.var_parent = visitor.cx.parent;
|
||||||
|
|
||||||
if let Some(expr) = arm.guard {
|
if let Some(expr) = arm.guard
|
||||||
// Check for if??
|
&& !has_let_expr(expr)
|
||||||
|
{
|
||||||
visitor.terminating_scopes.insert(expr.hir_id.local_id);
|
visitor.terminating_scopes.insert(expr.hir_id.local_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,12 @@ use std::borrow::Borrow;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
/// Lowers a condition in a way that ensures that variables bound in any let
|
||||||
|
/// expressions are definitely initialized in the if body.
|
||||||
|
///
|
||||||
|
/// If `declare_bindings` is false then variables created in `let`
|
||||||
|
/// expressions will not be declared. This is for if let guards on arms with
|
||||||
|
/// an or pattern, where the guard is lowered multiple times.
|
||||||
pub(crate) fn then_else_break(
|
pub(crate) fn then_else_break(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
|
|
72
tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs
Normal file
72
tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// Ensure that temporaries in if-let guards live for the arm
|
||||||
|
// regression test for #118593
|
||||||
|
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(if_let_guard)]
|
||||||
|
#![feature(let_chains)]
|
||||||
|
|
||||||
|
fn get_temp() -> Option<String> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn let_guard(num: u8) {
|
||||||
|
match num {
|
||||||
|
1 | 2 if let Some(ref a) = get_temp() => {
|
||||||
|
let _b = a;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
match num {
|
||||||
|
3 | 4 if let Some(ref mut c) = get_temp() => {
|
||||||
|
let _d = c;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn let_let_chain_guard(num: u8) {
|
||||||
|
match num {
|
||||||
|
5 | 6
|
||||||
|
if let Some(ref a) = get_temp()
|
||||||
|
&& let Some(ref b) = get_temp() =>
|
||||||
|
{
|
||||||
|
let _x = a;
|
||||||
|
let _y = b;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
match num {
|
||||||
|
7 | 8
|
||||||
|
if let Some(ref mut c) = get_temp()
|
||||||
|
&& let Some(ref mut d) = get_temp() =>
|
||||||
|
{
|
||||||
|
let _w = c;
|
||||||
|
let _z = d;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn let_cond_chain_guard(num: u8) {
|
||||||
|
match num {
|
||||||
|
9 | 10
|
||||||
|
if let Some(ref a) = get_temp()
|
||||||
|
&& true =>
|
||||||
|
{
|
||||||
|
let _x = a;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
match num {
|
||||||
|
11 | 12
|
||||||
|
if let Some(ref mut b) = get_temp()
|
||||||
|
&& true =>
|
||||||
|
{
|
||||||
|
let _w = b;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue