Skip to content

Commit ace794c

Browse files
committed
Always capture slice when pattern requires checking the length
1 parent 9d871b0 commit ace794c

File tree

3 files changed

+209
-91
lines changed

3 files changed

+209
-91
lines changed

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

+13-6
Original file line numberDiff line numberDiff line change
@@ -438,12 +438,19 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
438438
// to borrow discr.
439439
needs_to_be_read = true;
440440
}
441-
PatKind::Or(_)
442-
| PatKind::Box(_)
443-
| PatKind::Slice(..)
444-
| PatKind::Ref(..)
445-
| PatKind::Wild => {
446-
// If the PatKind is Or, Box, Slice or Ref, the decision is made later
441+
PatKind::Slice(lhs, wild, rhs) => {
442+
// We don't need to test the length if the pattern is `[..]`
443+
if matches!((lhs, wild, rhs), (&[], Some(_), &[]))
444+
// Arrays have a statically known size, so
445+
// there is no need to read their length
446+
|| discr_place.place.base_ty.is_array()
447+
{
448+
} else {
449+
needs_to_be_read = true;
450+
}
451+
}
452+
PatKind::Or(_) | PatKind::Box(_) | PatKind::Ref(..) | PatKind::Wild => {
453+
// If the PatKind is Or, Box, or Ref, the decision is made later
447454
// as these patterns contains subpatterns
448455
// If the PatKind is Wild, the decision is made based on the other patterns being
449456
// examined

tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs

+59-13
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
// edition:2021
22

33
#![feature(rustc_attrs)]
4+
#![feature(stmt_expr_attributes)]
45

56
// Should capture the discriminant since a variant of a multivariant enum is
67
// mentioned in the match arm; the discriminant is captured by the closure regardless
78
// of if it creates a binding
89
fn test_1_should_capture() {
910
let variant = Some(2229);
1011
let c = #[rustc_capture_analysis]
11-
//~^ ERROR: attributes on expressions are experimental
12-
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
13-
1412
|| {
1513
//~^ First Pass analysis includes:
1614
//~| Min Capture analysis includes:
@@ -29,8 +27,6 @@ fn test_1_should_capture() {
2927
fn test_2_should_not_capture() {
3028
let variant = Some(2229);
3129
let c = #[rustc_capture_analysis]
32-
//~^ ERROR: attributes on expressions are experimental
33-
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
3430
|| {
3531
//~^ First Pass analysis includes:
3632
match variant {
@@ -50,8 +46,6 @@ enum SingleVariant {
5046
fn test_3_should_not_capture_single_variant() {
5147
let variant = SingleVariant::Points(1);
5248
let c = #[rustc_capture_analysis]
53-
//~^ ERROR: attributes on expressions are experimental
54-
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
5549
|| {
5650
//~^ First Pass analysis includes:
5751
match variant {
@@ -66,8 +60,6 @@ fn test_3_should_not_capture_single_variant() {
6660
fn test_6_should_capture_single_variant() {
6761
let variant = SingleVariant::Points(1);
6862
let c = #[rustc_capture_analysis]
69-
//~^ ERROR: attributes on expressions are experimental
70-
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
7163
|| {
7264
//~^ First Pass analysis includes:
7365
//~| Min Capture analysis includes:
@@ -88,8 +80,6 @@ fn test_6_should_capture_single_variant() {
8880
fn test_4_should_not_capture_array() {
8981
let array: [i32; 3] = [0; 3];
9082
let c = #[rustc_capture_analysis]
91-
//~^ ERROR: attributes on expressions are experimental
92-
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
9383
|| {
9484
//~^ First Pass analysis includes:
9585
match array {
@@ -112,8 +102,6 @@ enum MVariant {
112102
fn test_5_should_capture_multi_variant() {
113103
let variant = MVariant::A;
114104
let c = #[rustc_capture_analysis]
115-
//~^ ERROR: attributes on expressions are experimental
116-
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
117105
|| {
118106
//~^ First Pass analysis includes:
119107
//~| Min Capture analysis includes:
@@ -127,11 +115,69 @@ fn test_5_should_capture_multi_variant() {
127115
c();
128116
}
129117

118+
// Even though all patterns are wild, we need to read the discriminant
119+
// in order to test the slice length
120+
fn test_7_should_capture_slice_len() {
121+
let slice: &[i32] = &[1, 2, 3];
122+
let c = #[rustc_capture_analysis]
123+
|| {
124+
//~^ First Pass analysis includes:
125+
//~| Min Capture analysis includes:
126+
match slice {
127+
//~^ NOTE: Capturing slice[] -> ImmBorrow
128+
//~| NOTE: Min Capture slice[] -> ImmBorrow
129+
[_,_,_] => {},
130+
_ => {}
131+
}
132+
};
133+
c();
134+
let c = #[rustc_capture_analysis]
135+
|| {
136+
//~^ First Pass analysis includes:
137+
//~| Min Capture analysis includes:
138+
match slice {
139+
//~^ NOTE: Capturing slice[] -> ImmBorrow
140+
//~| NOTE: Min Capture slice[] -> ImmBorrow
141+
[] => {},
142+
_ => {}
143+
}
144+
};
145+
c();
146+
let c = #[rustc_capture_analysis]
147+
|| {
148+
//~^ First Pass analysis includes:
149+
//~| Min Capture analysis includes:
150+
match slice {
151+
//~^ NOTE: Capturing slice[] -> ImmBorrow
152+
//~| NOTE: Min Capture slice[] -> ImmBorrow
153+
[_, .. ,_] => {},
154+
_ => {}
155+
}
156+
};
157+
c();
158+
}
159+
160+
// Wild pattern that doesn't bind, so no capture
161+
fn test_8_capture_slice_wild() {
162+
let slice: &[i32] = &[1, 2, 3];
163+
let c = #[rustc_capture_analysis]
164+
|| {
165+
//~^ First Pass analysis includes:
166+
match slice {
167+
[..] => {},
168+
_ => {}
169+
}
170+
};
171+
c();
172+
}
173+
130174
fn main() {
131175
test_1_should_capture();
132176
test_2_should_not_capture();
133177
test_3_should_not_capture_single_variant();
134178
test_6_should_capture_single_variant();
135179
test_4_should_not_capture_array();
136180
test_5_should_capture_multi_variant();
181+
test_7_should_capture_slice_len();
182+
test_8_capture_slice_wild();
137183
}

0 commit comments

Comments
 (0)