Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 4 additions & 9 deletions compiler/rustc_hir_typeck/src/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
}

hir::ExprKind::Let(hir::LetExpr { pat, init, .. }) => {
self.walk_local(init, pat, None, || self.borrow_expr(init, BorrowKind::Immutable))?;
self.walk_local(init, pat, None)?;
}

hir::ExprKind::Match(discr, arms, _) => {
Expand Down Expand Up @@ -577,7 +577,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
fn walk_stmt(&self, stmt: &hir::Stmt<'_>) -> Result<(), Cx::Error> {
match stmt.kind {
hir::StmtKind::Let(hir::LetStmt { pat, init: Some(expr), els, .. }) => {
self.walk_local(expr, pat, *els, || Ok(()))?;
self.walk_local(expr, pat, *els)?;
}

hir::StmtKind::Let(_) => {}
Expand Down Expand Up @@ -617,19 +617,14 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
Ok(())
}

fn walk_local<F>(
fn walk_local(
&self,
expr: &hir::Expr<'_>,
pat: &hir::Pat<'_>,
els: Option<&hir::Block<'_>>,
mut f: F,
) -> Result<(), Cx::Error>
where
F: FnMut() -> Result<(), Cx::Error>,
{
) -> Result<(), Cx::Error> {
self.walk_expr(expr)?;
let expr_place = self.cat_expr(expr)?;
f()?;
self.fake_read_scrutinee(&expr_place, els.is_some())?;
self.walk_pat(&expr_place, pat, false)?;
if let Some(els) = els {
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/closures/2229_closure_analysis/capture-enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@ fn multi_variant_enum() {
//~| ERROR Min Capture analysis includes:
if let Info::Point(_, _, str) = point {
//~^ NOTE: Capturing point[] -> Immutable
//~| NOTE: Capturing point[] -> Immutable
//~| NOTE: Capturing point[(2, 0)] -> ByValue
//~| NOTE: Min Capture point[] -> ByValue
println!("{}", str);
}

if let Info::Meta(_, v) = meta {
//~^ NOTE: Capturing meta[] -> Immutable
//~| NOTE: Capturing meta[] -> Immutable
//~| NOTE: Capturing meta[(1, 1)] -> ByValue
//~| NOTE: Min Capture meta[] -> ByValue
println!("{:?}", v);
Expand Down
24 changes: 7 additions & 17 deletions tests/ui/closures/2229_closure_analysis/capture-enums.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,18 @@ note: Capturing point[] -> Immutable
|
LL | if let Info::Point(_, _, str) = point {
| ^^^^^
note: Capturing point[] -> Immutable
--> $DIR/capture-enums.rs:21:41
|
LL | if let Info::Point(_, _, str) = point {
| ^^^^^
note: Capturing point[(2, 0)] -> ByValue
--> $DIR/capture-enums.rs:21:41
|
LL | if let Info::Point(_, _, str) = point {
| ^^^^^
note: Capturing meta[] -> Immutable
--> $DIR/capture-enums.rs:29:35
|
LL | if let Info::Meta(_, v) = meta {
| ^^^^
note: Capturing meta[] -> Immutable
--> $DIR/capture-enums.rs:29:35
--> $DIR/capture-enums.rs:28:35
|
LL | if let Info::Meta(_, v) = meta {
| ^^^^
note: Capturing meta[(1, 1)] -> ByValue
--> $DIR/capture-enums.rs:29:35
--> $DIR/capture-enums.rs:28:35
|
LL | if let Info::Meta(_, v) = meta {
| ^^^^
Expand All @@ -57,13 +47,13 @@ note: Min Capture point[] -> ByValue
LL | if let Info::Point(_, _, str) = point {
| ^^^^^
note: Min Capture meta[] -> ByValue
--> $DIR/capture-enums.rs:29:35
--> $DIR/capture-enums.rs:28:35
|
LL | if let Info::Meta(_, v) = meta {
| ^^^^

error: First Pass analysis includes:
--> $DIR/capture-enums.rs:49:5
--> $DIR/capture-enums.rs:47:5
|
LL | / || {
LL | |
Expand All @@ -75,13 +65,13 @@ LL | | };
| |_____^
|
note: Capturing point[(2, 0)] -> ByValue
--> $DIR/capture-enums.rs:52:47
--> $DIR/capture-enums.rs:50:47
|
LL | let SingleVariant::Point(_, _, str) = point;
| ^^^^^

error: Min Capture analysis includes:
--> $DIR/capture-enums.rs:49:5
--> $DIR/capture-enums.rs:47:5
|
LL | / || {
LL | |
Expand All @@ -93,7 +83,7 @@ LL | | };
| |_____^
|
note: Min Capture point[(2, 0)] -> ByValue
--> $DIR/capture-enums.rs:52:47
--> $DIR/capture-enums.rs:50:47
|
LL | let SingleVariant::Point(_, _, str) = point;
| ^^^^^
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//@ edition:2021

#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
#![allow(irrefutable_let_patterns)]

enum SingleVariant {
Pair(i32, String),
}

fn if_let_closure() {
let variant = SingleVariant::Pair(1, "hello".into());

let c = #[rustc_capture_analysis]
|| {
//~^ ERROR First Pass analysis includes:
//~| ERROR Min Capture analysis includes:
if let SingleVariant::Pair(ref n, s) = variant {
//~^ NOTE: Capturing variant[(0, 0)] -> Immutable
//~| NOTE: Capturing variant[(1, 0)] -> ByValue
//~| NOTE: Min Capture variant[(0, 0)] -> Immutable
//~| NOTE: Min Capture variant[(1, 0)] -> ByValue
let _ = (n, s);
}
};

c();
}

fn match_closure() {
let variant = SingleVariant::Pair(1, "hello".into());

let c = #[rustc_capture_analysis]
|| {
//~^ ERROR First Pass analysis includes:
//~| ERROR Min Capture analysis includes:
match variant {
//~^ NOTE: Capturing variant[(0, 0)] -> Immutable
//~| NOTE: Capturing variant[(1, 0)] -> ByValue
//~| NOTE: Min Capture variant[(0, 0)] -> Immutable
//~| NOTE: Min Capture variant[(1, 0)] -> ByValue
SingleVariant::Pair(ref n, s) => {
let _ = (n, s);
}
}
};

c();
}

fn main() {
if_let_closure();
match_closure();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
error: First Pass analysis includes:
--> $DIR/if-let-patterns-capture-analysis.rs:15:5
|
LL | / || {
LL | |
LL | |
LL | | if let SingleVariant::Pair(ref n, s) = variant {
... |
LL | | };
| |_____^
|
note: Capturing variant[(0, 0)] -> Immutable
--> $DIR/if-let-patterns-capture-analysis.rs:18:48
|
LL | if let SingleVariant::Pair(ref n, s) = variant {
| ^^^^^^^
note: Capturing variant[(1, 0)] -> ByValue
--> $DIR/if-let-patterns-capture-analysis.rs:18:48
|
LL | if let SingleVariant::Pair(ref n, s) = variant {
| ^^^^^^^

error: Min Capture analysis includes:
--> $DIR/if-let-patterns-capture-analysis.rs:15:5
|
LL | / || {
LL | |
LL | |
LL | | if let SingleVariant::Pair(ref n, s) = variant {
... |
LL | | };
| |_____^
|
note: Min Capture variant[(0, 0)] -> Immutable
--> $DIR/if-let-patterns-capture-analysis.rs:18:48
|
LL | if let SingleVariant::Pair(ref n, s) = variant {
| ^^^^^^^
note: Min Capture variant[(1, 0)] -> ByValue
--> $DIR/if-let-patterns-capture-analysis.rs:18:48
|
LL | if let SingleVariant::Pair(ref n, s) = variant {
| ^^^^^^^

error: First Pass analysis includes:
--> $DIR/if-let-patterns-capture-analysis.rs:34:5
|
LL | / || {
LL | |
LL | |
LL | | match variant {
... |
LL | | };
| |_____^
|
note: Capturing variant[(0, 0)] -> Immutable
--> $DIR/if-let-patterns-capture-analysis.rs:37:15
|
LL | match variant {
| ^^^^^^^
note: Capturing variant[(1, 0)] -> ByValue
--> $DIR/if-let-patterns-capture-analysis.rs:37:15
|
LL | match variant {
| ^^^^^^^

error: Min Capture analysis includes:
--> $DIR/if-let-patterns-capture-analysis.rs:34:5
|
LL | / || {
LL | |
LL | |
LL | | match variant {
... |
LL | | };
| |_____^
|
note: Min Capture variant[(0, 0)] -> Immutable
--> $DIR/if-let-patterns-capture-analysis.rs:37:15
|
LL | match variant {
| ^^^^^^^
note: Min Capture variant[(1, 0)] -> ByValue
--> $DIR/if-let-patterns-capture-analysis.rs:37:15
|
LL | match variant {
| ^^^^^^^

error: aborting due to 4 previous errors

51 changes: 51 additions & 0 deletions tests/ui/closures/2229_closure_analysis/run_pass/if-let-capture.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//@ edition:2021
//@ run-pass

// Regression test for #153982: `if let` in a closure should capture only the
// moved field, matching `match` and plain `let` destructuring.

#![allow(dead_code, irrefutable_let_patterns)]

use std::mem::{size_of, size_of_val};

struct Thing(String, String);

fn if_let_capture_size(x: Thing) -> usize {
let closure = || {
if let Thing(_a, _) = x {}
};

size_of_val(&closure)
}

fn match_capture_size(x: Thing) -> usize {
let closure = || {
match x {
Thing(_a, _) => {}
}
};

size_of_val(&closure)
}

fn let_capture_size(x: Thing) -> usize {
let closure = || {
let Thing(_a, _) = x;
};

size_of_val(&closure)
}

fn main() {
let if_let_size = if_let_capture_size(Thing(String::from("a"), String::from("b")));
let match_size = match_capture_size(Thing(String::from("a"), String::from("b")));
let let_size = let_capture_size(Thing(String::from("a"), String::from("b")));

assert_eq!(if_let_size, size_of::<String>());
assert_eq!(match_size, size_of::<String>());
assert_eq!(let_size, size_of::<String>());

assert_eq!(if_let_size, match_size);
assert_eq!(if_let_size, let_size);
assert_ne!(if_let_size, size_of::<Thing>());
}
Loading