ExprUseVisitor: remove maybe_read_scrutinee

The split between walk_pat and maybe_read_scrutinee has now become
redundant.

Due to this change, one testcase within the testsuite has become similar
enough to a known ICE to also break. I am leaving this as future work,
as it requires feature(type_alias_impl_trait)
This commit is contained in:
Maja Kądziołka 2025-03-26 20:59:50 +01:00
parent 9cb47c6e8e
commit e25803acea
No known key found for this signature in database
11 changed files with 152 additions and 262 deletions

View file

@ -7,9 +7,7 @@
use std::cell::{Ref, RefCell};
use std::ops::Deref;
use std::slice::from_ref;
use hir::Expr;
use hir::def::DefKind;
use hir::pat_util::EnumerateAndAdjustIterator as _;
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
@ -313,7 +311,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
let param_place = self.cat_rvalue(param.hir_id, param_ty);
self.walk_irrefutable_pat(&param_place, param.pat)?;
self.fake_read_scrutinee(&param_place, false)?;
self.walk_pat(&param_place, param.pat, false)?;
}
self.consume_expr(body.value)?;
@ -455,13 +454,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
hir::ExprKind::Match(discr, arms, _) => {
let discr_place = self.cat_expr(discr)?;
self.maybe_read_scrutinee(
discr,
discr_place.clone(),
arms.iter().map(|arm| arm.pat),
)?;
self.fake_read_scrutinee(&discr_place, true)?;
self.walk_expr(discr)?;
// treatment of the discriminant is handled while walking the arms.
for arm in arms {
self.walk_arm(&discr_place, arm)?;
}
@ -598,116 +593,25 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
Ok(())
}
fn maybe_read_scrutinee<'t>(
#[instrument(skip(self), level = "debug")]
fn fake_read_scrutinee(
&self,
discr: &Expr<'_>,
discr_place: PlaceWithHirId<'tcx>,
pats: impl Iterator<Item = &'t hir::Pat<'t>>,
discr_place: &PlaceWithHirId<'tcx>,
refutable: bool,
) -> Result<(), Cx::Error> {
// Matching should not always be considered a use of the place, hence
// discr does not necessarily need to be borrowed.
// We only want to borrow discr if the pattern contain something other
// than wildcards.
let mut needs_to_be_read = false;
for pat in pats {
self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
match &pat.kind {
PatKind::Missing => unreachable!(),
PatKind::Binding(.., opt_sub_pat) => {
// If the opt_sub_pat is None, then the binding does not count as
// a wildcard for the purpose of borrowing discr.
if opt_sub_pat.is_none() {
needs_to_be_read = true;
}
}
PatKind::Never => {
// A never pattern reads the value.
// FIXME(never_patterns): does this do what I expect?
needs_to_be_read = true;
}
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
// A `Path` pattern is just a name like `Foo`. This is either a
// named constant or else it refers to an ADT variant
let closure_def_id = match discr_place.place.base {
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
_ => None,
};
let res = self.cx.typeck_results().qpath_res(qpath, *hir_id);
match res {
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
// Named constants have to be equated with the value
// being matched, so that's a read of the value being matched.
//
// FIXME: We don't actually reads for ZSTs.
needs_to_be_read = true;
}
_ => {
// Otherwise, this is a struct/enum variant, and so it's
// only a read if we need to read the discriminant.
needs_to_be_read |=
self.is_multivariant_adt(place.place.ty(), *span);
}
}
}
PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => {
// For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
// against a multivariant enum or struct. In that case, we have to read
// the discriminant. Otherwise this kind of pattern doesn't actually
// read anything (we'll get invoked for the `...`, which may indeed
// perform some reads).
let place_ty = place.place.ty();
needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span);
}
PatKind::Expr(_) | PatKind::Range(..) => {
// If the PatKind is a Lit or a Range then we want
// to borrow discr.
needs_to_be_read = true;
}
PatKind::Slice(lhs, wild, rhs) => {
// We don't need to test the length if the pattern is `[..]`
if matches!((lhs, wild, rhs), (&[], Some(_), &[]))
// Arrays have a statically known size, so
// there is no need to read their length
|| place.place.ty().peel_refs().is_array()
{
} else {
needs_to_be_read = true;
}
}
PatKind::Or(_)
| PatKind::Box(_)
| PatKind::Deref(_)
| PatKind::Ref(..)
| PatKind::Guard(..)
| PatKind::Wild
| PatKind::Err(_) => {
// If the PatKind is Or, Box, or Ref, the decision is made later
// as these patterns contains subpatterns
// If the PatKind is Wild or Err, the decision is made based on the other patterns
// being examined
}
}
Ok(())
})?
}
if needs_to_be_read {
self.borrow_expr(discr, BorrowKind::Immutable)?;
let cause = if refutable {
FakeReadCause::ForMatchedPlace(closure_def_id)
} else {
let closure_def_id = match discr_place.place.base {
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
_ => None,
};
FakeReadCause::ForLet(closure_def_id)
};
self.delegate.borrow_mut().fake_read(
&discr_place,
FakeReadCause::ForMatchedPlace(closure_def_id),
discr_place.hir_id,
);
self.delegate.borrow_mut().fake_read(discr_place, cause, discr_place.hir_id);
// We always want to walk the discriminant. We want to make sure, for instance,
// that the discriminant has been initialized.
self.walk_expr(discr)?;
}
Ok(())
}
@ -724,12 +628,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
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 {
// borrowing because we need to test the discriminant
self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter())?;
self.walk_block(els)?;
}
self.walk_irrefutable_pat(&expr_place, pat)?;
Ok(())
}
@ -901,16 +804,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
discr_place: &PlaceWithHirId<'tcx>,
arm: &hir::Arm<'_>,
) -> Result<(), Cx::Error> {
let closure_def_id = match discr_place.place.base {
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
_ => None,
};
self.delegate.borrow_mut().fake_read(
discr_place,
FakeReadCause::ForMatchedPlace(closure_def_id),
discr_place.hir_id,
);
self.walk_pat(discr_place, arm.pat, arm.guard.is_some())?;
if let Some(ref e) = arm.guard {
@ -921,27 +814,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
Ok(())
}
/// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
/// let binding, and *not* a match arm or nested pat.)
fn walk_irrefutable_pat(
&self,
discr_place: &PlaceWithHirId<'tcx>,
pat: &hir::Pat<'_>,
) -> Result<(), Cx::Error> {
let closure_def_id = match discr_place.place.base {
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
_ => None,
};
self.delegate.borrow_mut().fake_read(
discr_place,
FakeReadCause::ForLet(closure_def_id),
discr_place.hir_id,
);
self.walk_pat(discr_place, pat, false)?;
Ok(())
}
/// The core driver for walking a pattern
///
/// This should mirror how pattern-matching gets lowered to MIR, as
@ -1984,6 +1856,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
/// Here, we cannot perform such an accurate checks, because querying
/// whether a type is inhabited requires that it has been fully inferred,
/// which cannot be guaranteed at this point.
#[instrument(skip(self, span), level = "debug")]
fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
if let ty::Adt(def, _) = self.cx.structurally_resolve_type(span, ty).kind() {
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need

15
tests/crashes/119786-2.rs Normal file
View file

@ -0,0 +1,15 @@
//@ known-bug: #119786
//@ edition:2021
fn enum_upvar() {
type T = impl Copy;
let foo: T = Some((1u32, 2u32));
let x = move || {
match foo {
None => (),
Some(_) => (),
}
};
}
pub fn main() {}

15
tests/crashes/119786-3.rs Normal file
View file

@ -0,0 +1,15 @@
//@ known-bug: #119786
//@ edition:2021
fn enum_upvar() {
type T = impl Copy;
let foo: T = Some((1u32, 2u32));
let x = move || {
match foo {
None => (),
Some((a, b)) => (),
}
};
}
pub fn main() {}

View file

@ -4,18 +4,16 @@ fn foo::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_fake
yields ()
{
debug _task_context => _2;
debug f => (*(_1.0: &&Foo));
debug f => (*(_1.0: &Foo));
let mut _0: ();
let mut _3: &Foo;
let mut _4: &&Foo;
let mut _5: &&&Foo;
let mut _6: isize;
let mut _7: bool;
let mut _5: isize;
let mut _6: bool;
bb0: {
PlaceMention((*(_1.0: &&Foo)));
_6 = discriminant((*(*(_1.0: &&Foo))));
switchInt(move _6) -> [0: bb2, otherwise: bb1];
_5 = discriminant((*(_1.0: &Foo)));
switchInt(move _5) -> [0: bb2, otherwise: bb1];
}
bb1: {
@ -32,17 +30,15 @@ yields ()
}
bb4: {
FakeRead(ForMatchedPlace(None), (*(_1.0: &&Foo)));
unreachable;
}
bb5: {
_3 = &fake shallow (*(*(_1.0: &&Foo)));
_4 = &fake shallow (*(_1.0: &&Foo));
_5 = &fake shallow (_1.0: &&Foo);
StorageLive(_7);
_7 = const true;
switchInt(move _7) -> [0: bb8, otherwise: bb7];
_3 = &fake shallow (*(_1.0: &Foo));
_4 = &fake shallow (_1.0: &Foo);
StorageLive(_6);
_6 = const true;
switchInt(move _6) -> [0: bb8, otherwise: bb7];
}
bb6: {
@ -50,10 +46,9 @@ yields ()
}
bb7: {
StorageDead(_7);
StorageDead(_6);
FakeRead(ForMatchGuard, _3);
FakeRead(ForMatchGuard, _4);
FakeRead(ForMatchGuard, _5);
_0 = const ();
goto -> bb10;
}
@ -63,7 +58,7 @@ yields ()
}
bb9: {
StorageDead(_7);
StorageDead(_6);
goto -> bb6;
}

View file

@ -4,18 +4,16 @@ fn foo::{closure#0}::{synthetic#0}(_1: {async closure body@$DIR/async_closure_fa
yields ()
{
debug _task_context => _2;
debug f => (_1.0: &Foo);
debug f => (*(_1.0: &Foo));
let mut _0: ();
let mut _3: &Foo;
let mut _4: &&Foo;
let mut _5: &&&Foo;
let mut _6: isize;
let mut _7: bool;
let mut _5: isize;
let mut _6: bool;
bb0: {
PlaceMention((_1.0: &Foo));
_6 = discriminant((*(_1.0: &Foo)));
switchInt(move _6) -> [0: bb2, otherwise: bb1];
_5 = discriminant((*(_1.0: &Foo)));
switchInt(move _5) -> [0: bb2, otherwise: bb1];
}
bb1: {
@ -29,24 +27,22 @@ yields ()
bb3: {
_3 = &fake shallow (*(_1.0: &Foo));
_4 = &fake shallow (_1.0: &Foo);
nop;
StorageLive(_7);
_7 = const true;
switchInt(move _7) -> [0: bb5, otherwise: bb4];
StorageLive(_6);
_6 = const true;
switchInt(move _6) -> [0: bb5, otherwise: bb4];
}
bb4: {
StorageDead(_7);
StorageDead(_6);
FakeRead(ForMatchGuard, _3);
FakeRead(ForMatchGuard, _4);
FakeRead(ForMatchGuard, _5);
_0 = const ();
goto -> bb6;
}
bb5: {
StorageDead(_7);
StorageDead(_6);
falseEdge -> [real: bb1, imaginary: bb1];
}

View file

@ -4,7 +4,7 @@ error[E0505]: cannot move out of `ts` because it is borrowed
LL | let _b = || { match ts {
| -- -- borrow occurs due to use in closure
| |
| borrow of `ts` occurs here
| borrow of `ts.x` occurs here
...
LL | let mut mut_ts = ts;
| ^^ move out of `ts` occurs here

View file

@ -14,7 +14,6 @@ fn test_1_should_capture() {
//~| ERROR Min Capture analysis includes:
match variant {
//~^ NOTE: Capturing variant[] -> Immutable
//~| NOTE: Capturing variant[] -> Immutable
//~| NOTE: Min Capture variant[] -> Immutable
Some(_) => {}
_ => {}
@ -65,9 +64,8 @@ fn test_6_should_capture_single_variant() {
//~^ ERROR First Pass analysis includes:
//~| ERROR Min Capture analysis includes:
match variant {
//~^ NOTE: Capturing variant[] -> Immutable
//~| NOTE: Capturing variant[(0, 0)] -> Immutable
//~| NOTE: Min Capture variant[] -> Immutable
//~^ NOTE: Capturing variant[(0, 0)] -> Immutable
//~| NOTE: Min Capture variant[(0, 0)] -> Immutable
SingleVariant::Points(a) => {
println!("{:?}", a);
}
@ -133,7 +131,6 @@ fn test_5_should_capture_multi_variant() {
//~| ERROR Min Capture analysis includes:
match variant {
//~^ NOTE: Capturing variant[] -> Immutable
//~| NOTE: Capturing variant[] -> Immutable
//~| NOTE: Min Capture variant[] -> Immutable
MVariant::A => {}
_ => {}
@ -151,9 +148,8 @@ fn test_7_should_capture_slice_len() {
//~^ ERROR First Pass analysis includes:
//~| ERROR Min Capture analysis includes:
match slice {
//~^ NOTE: Capturing slice[] -> Immutable
//~| NOTE: Capturing slice[Deref] -> Immutable
//~| NOTE: Min Capture slice[] -> Immutable
//~^ NOTE: Capturing slice[Deref] -> Immutable
//~| NOTE: Min Capture slice[Deref] -> Immutable
[_,_,_] => {},
_ => {}
}
@ -164,9 +160,8 @@ fn test_7_should_capture_slice_len() {
//~^ ERROR First Pass analysis includes:
//~| ERROR Min Capture analysis includes:
match slice {
//~^ NOTE: Capturing slice[] -> Immutable
//~| NOTE: Capturing slice[Deref] -> Immutable
//~| NOTE: Min Capture slice[] -> Immutable
//~^ NOTE: Capturing slice[Deref] -> Immutable
//~| NOTE: Min Capture slice[Deref] -> Immutable
[] => {},
_ => {}
}
@ -177,9 +172,8 @@ fn test_7_should_capture_slice_len() {
//~^ ERROR First Pass analysis includes:
//~| ERROR Min Capture analysis includes:
match slice {
//~^ NOTE: Capturing slice[] -> Immutable
//~| NOTE: Capturing slice[Deref] -> Immutable
//~| NOTE: Min Capture slice[] -> Immutable
//~^ NOTE: Capturing slice[Deref] -> Immutable
//~| NOTE: Min Capture slice[Deref] -> Immutable
[_, .. ,_] => {},
_ => {}
}

View file

@ -14,11 +14,6 @@ note: Capturing variant[] -> Immutable
|
LL | match variant {
| ^^^^^^^
note: Capturing variant[] -> Immutable
--> $DIR/patterns-capture-analysis.rs:15:15
|
LL | match variant {
| ^^^^^^^
error: Min Capture analysis includes:
--> $DIR/patterns-capture-analysis.rs:12:5
@ -38,7 +33,7 @@ LL | match variant {
| ^^^^^^^
error: First Pass analysis includes:
--> $DIR/patterns-capture-analysis.rs:31:5
--> $DIR/patterns-capture-analysis.rs:30:5
|
LL | / || {
LL | |
@ -49,7 +44,7 @@ LL | | };
| |_____^
error: First Pass analysis includes:
--> $DIR/patterns-capture-analysis.rs:50:5
--> $DIR/patterns-capture-analysis.rs:49:5
|
LL | / || {
LL | |
@ -60,7 +55,7 @@ LL | | };
| |_____^
error: First Pass analysis includes:
--> $DIR/patterns-capture-analysis.rs:64:5
--> $DIR/patterns-capture-analysis.rs:63:5
|
LL | / || {
LL | |
@ -70,19 +65,14 @@ LL | | match variant {
LL | | };
| |_____^
|
note: Capturing variant[] -> Immutable
--> $DIR/patterns-capture-analysis.rs:67:15
|
LL | match variant {
| ^^^^^^^
note: Capturing variant[(0, 0)] -> Immutable
--> $DIR/patterns-capture-analysis.rs:67:15
--> $DIR/patterns-capture-analysis.rs:66:15
|
LL | match variant {
| ^^^^^^^
error: Min Capture analysis includes:
--> $DIR/patterns-capture-analysis.rs:64:5
--> $DIR/patterns-capture-analysis.rs:63:5
|
LL | / || {
LL | |
@ -92,14 +82,14 @@ LL | | match variant {
LL | | };
| |_____^
|
note: Min Capture variant[] -> Immutable
--> $DIR/patterns-capture-analysis.rs:67:15
note: Min Capture variant[(0, 0)] -> Immutable
--> $DIR/patterns-capture-analysis.rs:66:15
|
LL | match variant {
| ^^^^^^^
error: First Pass analysis includes:
--> $DIR/patterns-capture-analysis.rs:84:5
--> $DIR/patterns-capture-analysis.rs:82:5
|
LL | / || {
LL | |
@ -110,7 +100,7 @@ LL | | };
| |_____^
error: First Pass analysis includes:
--> $DIR/patterns-capture-analysis.rs:96:5
--> $DIR/patterns-capture-analysis.rs:94:5
|
LL | / || {
LL | |
@ -121,7 +111,7 @@ LL | | };
| |_____^
error: First Pass analysis includes:
--> $DIR/patterns-capture-analysis.rs:109:5
--> $DIR/patterns-capture-analysis.rs:107:5
|
LL | / || {
LL | |
@ -132,7 +122,7 @@ LL | | };
| |_____^
error: First Pass analysis includes:
--> $DIR/patterns-capture-analysis.rs:131:5
--> $DIR/patterns-capture-analysis.rs:129:5
|
LL | / || {
LL | |
@ -143,18 +133,13 @@ LL | | };
| |_____^
|
note: Capturing variant[] -> Immutable
--> $DIR/patterns-capture-analysis.rs:134:15
|
LL | match variant {
| ^^^^^^^
note: Capturing variant[] -> Immutable
--> $DIR/patterns-capture-analysis.rs:134:15
--> $DIR/patterns-capture-analysis.rs:132:15
|
LL | match variant {
| ^^^^^^^
error: Min Capture analysis includes:
--> $DIR/patterns-capture-analysis.rs:131:5
--> $DIR/patterns-capture-analysis.rs:129:5
|
LL | / || {
LL | |
@ -165,13 +150,13 @@ LL | | };
| |_____^
|
note: Min Capture variant[] -> Immutable
--> $DIR/patterns-capture-analysis.rs:134:15
--> $DIR/patterns-capture-analysis.rs:132:15
|
LL | match variant {
| ^^^^^^^
error: First Pass analysis includes:
--> $DIR/patterns-capture-analysis.rs:150:5
--> $DIR/patterns-capture-analysis.rs:147:5
|
LL | / || {
LL | |
@ -181,19 +166,14 @@ LL | | match slice {
LL | | };
| |_____^
|
note: Capturing slice[] -> Immutable
--> $DIR/patterns-capture-analysis.rs:153:15
|
LL | match slice {
| ^^^^^
note: Capturing slice[Deref] -> Immutable
--> $DIR/patterns-capture-analysis.rs:153:15
--> $DIR/patterns-capture-analysis.rs:150:15
|
LL | match slice {
| ^^^^^
error: Min Capture analysis includes:
--> $DIR/patterns-capture-analysis.rs:150:5
--> $DIR/patterns-capture-analysis.rs:147:5
|
LL | / || {
LL | |
@ -203,14 +183,14 @@ LL | | match slice {
LL | | };
| |_____^
|
note: Min Capture slice[] -> Immutable
--> $DIR/patterns-capture-analysis.rs:153:15
note: Min Capture slice[Deref] -> Immutable
--> $DIR/patterns-capture-analysis.rs:150:15
|
LL | match slice {
| ^^^^^
error: First Pass analysis includes:
--> $DIR/patterns-capture-analysis.rs:163:5
--> $DIR/patterns-capture-analysis.rs:159:5
|
LL | / || {
LL | |
@ -220,19 +200,14 @@ LL | | match slice {
LL | | };
| |_____^
|
note: Capturing slice[] -> Immutable
--> $DIR/patterns-capture-analysis.rs:166:15
|
LL | match slice {
| ^^^^^
note: Capturing slice[Deref] -> Immutable
--> $DIR/patterns-capture-analysis.rs:166:15
--> $DIR/patterns-capture-analysis.rs:162:15
|
LL | match slice {
| ^^^^^
error: Min Capture analysis includes:
--> $DIR/patterns-capture-analysis.rs:163:5
--> $DIR/patterns-capture-analysis.rs:159:5
|
LL | / || {
LL | |
@ -242,14 +217,14 @@ LL | | match slice {
LL | | };
| |_____^
|
note: Min Capture slice[] -> Immutable
--> $DIR/patterns-capture-analysis.rs:166:15
note: Min Capture slice[Deref] -> Immutable
--> $DIR/patterns-capture-analysis.rs:162:15
|
LL | match slice {
| ^^^^^
error: First Pass analysis includes:
--> $DIR/patterns-capture-analysis.rs:176:5
--> $DIR/patterns-capture-analysis.rs:171:5
|
LL | / || {
LL | |
@ -259,19 +234,14 @@ LL | | match slice {
LL | | };
| |_____^
|
note: Capturing slice[] -> Immutable
--> $DIR/patterns-capture-analysis.rs:179:15
|
LL | match slice {
| ^^^^^
note: Capturing slice[Deref] -> Immutable
--> $DIR/patterns-capture-analysis.rs:179:15
--> $DIR/patterns-capture-analysis.rs:174:15
|
LL | match slice {
| ^^^^^
error: Min Capture analysis includes:
--> $DIR/patterns-capture-analysis.rs:176:5
--> $DIR/patterns-capture-analysis.rs:171:5
|
LL | / || {
LL | |
@ -281,14 +251,14 @@ LL | | match slice {
LL | | };
| |_____^
|
note: Min Capture slice[] -> Immutable
--> $DIR/patterns-capture-analysis.rs:179:15
note: Min Capture slice[Deref] -> Immutable
--> $DIR/patterns-capture-analysis.rs:174:15
|
LL | match slice {
| ^^^^^
error: First Pass analysis includes:
--> $DIR/patterns-capture-analysis.rs:194:5
--> $DIR/patterns-capture-analysis.rs:188:5
|
LL | / || {
LL | |

View file

@ -0,0 +1,41 @@
//@ edition:2024
//@ check-pass
// Background:
fn f1() {
let mut a = (21, 37);
// only captures a.0, example compiles fine
let mut f = || {
let (ref mut x, _) = a;
*x = 42;
};
a.1 = 69;
f();
}
// This used to error out:
fn f2() {
let mut a = (21, 37);
// used to capture all of a, now captures only a.0
let mut f = || {
match a {
(ref mut x, _) => *x = 42,
}
};
a.1 = 69;
f();
}
// This was inconsistent with the following:
fn main() {
let mut a = (21, 37);
// the useless @-pattern would cause it to capture only a.0. now the
// behavior is consistent with the case that doesn't use the @-pattern
let mut f = || {
match a {
(ref mut x @ _, _) => *x = 42,
}
};
a.1 = 69;
f();
}

View file

@ -23,15 +23,6 @@ fn upvar() {
};
}
fn enum_upvar() {
type T = impl Copy;
let foo: T = Some((1u32, 2u32));
let x = move || match foo {
None => (),
Some((a, b)) => (),
};
}
fn r#struct() {
#[derive(Copy, Clone)]
struct Foo((u32, u32));