Skip to content

Commit 5bf1de1

Browse files
committed
Note an edge case in array/slice pattern handling
1 parent 824a040 commit 5bf1de1

5 files changed

+112
-0
lines changed

compiler/rustc_mir_build/src/builder/matches/match_pair.rs

+15
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6060
exact_size = false;
6161
}
6262

63+
// Normally `exact_size` is true iff this is an array pattern, but there
64+
// is at least one edge-case exception. Consider code like this:
65+
//
66+
// ```ignore (illustrative)
67+
// let arr = [1, 2, 3];
68+
// let closure = || match arr {
69+
// [_, ..] => {}
70+
// };
71+
// ```
72+
//
73+
// Under Rust 2021 disjoint-capture rules, the array place isn't
74+
// actually captured, because no part of it is actually read or bound
75+
// by the match. So the above code can't resolve it, and falls back to
76+
// `exact_size = false`. This appears to be benign, but keep it in mind.
77+
6378
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
6479
let elem =
6580
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//@ edition: 2021
2+
// skip-filecheck
3+
4+
// Under the Rust 2021 disjoint capture rules, a "captured" place sometimes
5+
// doesn't actually need to be captured, if it is only matched against
6+
// irrefutable patterns that don't bind anything.
7+
//
8+
// When that happens, there is currently some MIR-building code
9+
// (`Builder::prefix_slice_suffix`) that can no longer distinguish between
10+
// array patterns and slice patterns, so it falls back to the code for dealing
11+
// with slice patterns.
12+
//
13+
// That appears to be benign, but it's worth having a test that explicitly
14+
// triggers the edge-case scenario. If someone makes a change that assumes the
15+
// edge case can't happen, then hopefully this test will demand attention by
16+
// either triggering an ICE, or needing its MIR to be re-blessed.
17+
18+
// EMIT_MIR array_non_capture.prefix_only-{closure#0}.built.after.mir
19+
fn prefix_only() -> u32 {
20+
let arr = [1, 2, 3];
21+
let closure = || match arr {
22+
[_, _, _] => 101u32,
23+
};
24+
closure()
25+
}
26+
27+
// EMIT_MIR array_non_capture.prefix_slice_only-{closure#0}.built.after.mir
28+
fn prefix_slice_only() -> u32 {
29+
let arr = [1, 2, 3];
30+
let closure = || match arr {
31+
[_, ..] => 102u32,
32+
};
33+
closure()
34+
}
35+
36+
// EMIT_MIR array_non_capture.prefix_slice_suffix-{closure#0}.built.after.mir
37+
fn prefix_slice_suffix() -> u32 {
38+
let arr = [1, 2, 3];
39+
let closure = || match arr {
40+
[_, .., _] => 103u32,
41+
};
42+
closure()
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// MIR for `prefix_only::{closure#0}` after built
2+
3+
fn prefix_only::{closure#0}(_1: &{closure@$DIR/array-non-capture.rs:21:19: 21:21}) -> u32 {
4+
let mut _0: u32;
5+
6+
bb0: {
7+
_0 = const 101_u32;
8+
goto -> bb2;
9+
}
10+
11+
bb1: {
12+
unreachable;
13+
}
14+
15+
bb2: {
16+
return;
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// MIR for `prefix_slice_only::{closure#0}` after built
2+
3+
fn prefix_slice_only::{closure#0}(_1: &{closure@$DIR/array-non-capture.rs:30:19: 30:21}) -> u32 {
4+
let mut _0: u32;
5+
6+
bb0: {
7+
_0 = const 102_u32;
8+
goto -> bb2;
9+
}
10+
11+
bb1: {
12+
unreachable;
13+
}
14+
15+
bb2: {
16+
return;
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// MIR for `prefix_slice_suffix::{closure#0}` after built
2+
3+
fn prefix_slice_suffix::{closure#0}(_1: &{closure@$DIR/array-non-capture.rs:39:19: 39:21}) -> u32 {
4+
let mut _0: u32;
5+
6+
bb0: {
7+
_0 = const 103_u32;
8+
goto -> bb2;
9+
}
10+
11+
bb1: {
12+
unreachable;
13+
}
14+
15+
bb2: {
16+
return;
17+
}
18+
}

0 commit comments

Comments
 (0)