Skip to content

Commit

Permalink
Note an edge case in array/slice pattern handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Zalathar committed Jan 20, 2025
1 parent 824a040 commit 5bf1de1
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 0 deletions.
15 changes: 15 additions & 0 deletions compiler/rustc_mir_build/src/builder/matches/match_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
exact_size = false;
}

// Normally `exact_size` is true iff this is an array pattern, but there
// is at least one edge-case exception. Consider code like this:
//
// ```ignore (illustrative)
// let arr = [1, 2, 3];
// let closure = || match arr {
// [_, ..] => {}
// };
// ```
//
// Under Rust 2021 disjoint-capture rules, the array place isn't
// actually captured, because no part of it is actually read or bound
// by the match. So the above code can't resolve it, and falls back to
// `exact_size = false`. This appears to be benign, but keep it in mind.

match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
let elem =
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
Expand Down
43 changes: 43 additions & 0 deletions tests/mir-opt/building/match/array-non-capture.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//@ edition: 2021
// skip-filecheck

// Under the Rust 2021 disjoint capture rules, a "captured" place sometimes
// doesn't actually need to be captured, if it is only matched against
// irrefutable patterns that don't bind anything.
//
// When that happens, there is currently some MIR-building code
// (`Builder::prefix_slice_suffix`) that can no longer distinguish between
// array patterns and slice patterns, so it falls back to the code for dealing
// with slice patterns.
//
// That appears to be benign, but it's worth having a test that explicitly
// triggers the edge-case scenario. If someone makes a change that assumes the
// edge case can't happen, then hopefully this test will demand attention by
// either triggering an ICE, or needing its MIR to be re-blessed.

// EMIT_MIR array_non_capture.prefix_only-{closure#0}.built.after.mir
fn prefix_only() -> u32 {
let arr = [1, 2, 3];
let closure = || match arr {
[_, _, _] => 101u32,
};
closure()
}

// EMIT_MIR array_non_capture.prefix_slice_only-{closure#0}.built.after.mir
fn prefix_slice_only() -> u32 {
let arr = [1, 2, 3];
let closure = || match arr {
[_, ..] => 102u32,
};
closure()
}

// EMIT_MIR array_non_capture.prefix_slice_suffix-{closure#0}.built.after.mir
fn prefix_slice_suffix() -> u32 {
let arr = [1, 2, 3];
let closure = || match arr {
[_, .., _] => 103u32,
};
closure()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// MIR for `prefix_only::{closure#0}` after built

fn prefix_only::{closure#0}(_1: &{closure@$DIR/array-non-capture.rs:21:19: 21:21}) -> u32 {
let mut _0: u32;

bb0: {
_0 = const 101_u32;
goto -> bb2;
}

bb1: {
unreachable;
}

bb2: {
return;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// MIR for `prefix_slice_only::{closure#0}` after built

fn prefix_slice_only::{closure#0}(_1: &{closure@$DIR/array-non-capture.rs:30:19: 30:21}) -> u32 {
let mut _0: u32;

bb0: {
_0 = const 102_u32;
goto -> bb2;
}

bb1: {
unreachable;
}

bb2: {
return;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// MIR for `prefix_slice_suffix::{closure#0}` after built

fn prefix_slice_suffix::{closure#0}(_1: &{closure@$DIR/array-non-capture.rs:39:19: 39:21}) -> u32 {
let mut _0: u32;

bb0: {
_0 = const 103_u32;
goto -> bb2;
}

bb1: {
unreachable;
}

bb2: {
return;
}
}

0 comments on commit 5bf1de1

Please sign in to comment.