diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 19ba4016be2e3..4f22c991080e2 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -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 }; diff --git a/tests/mir-opt/building/match/array-non-capture.rs b/tests/mir-opt/building/match/array-non-capture.rs new file mode 100644 index 0000000000000..afcceaafaa772 --- /dev/null +++ b/tests/mir-opt/building/match/array-non-capture.rs @@ -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() +} diff --git a/tests/mir-opt/building/match/array_non_capture.prefix_only-{closure#0}.built.after.mir b/tests/mir-opt/building/match/array_non_capture.prefix_only-{closure#0}.built.after.mir new file mode 100644 index 0000000000000..7ccd3e1c76d4c --- /dev/null +++ b/tests/mir-opt/building/match/array_non_capture.prefix_only-{closure#0}.built.after.mir @@ -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; + } +} diff --git a/tests/mir-opt/building/match/array_non_capture.prefix_slice_only-{closure#0}.built.after.mir b/tests/mir-opt/building/match/array_non_capture.prefix_slice_only-{closure#0}.built.after.mir new file mode 100644 index 0000000000000..2b31dcd3abd8a --- /dev/null +++ b/tests/mir-opt/building/match/array_non_capture.prefix_slice_only-{closure#0}.built.after.mir @@ -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; + } +} diff --git a/tests/mir-opt/building/match/array_non_capture.prefix_slice_suffix-{closure#0}.built.after.mir b/tests/mir-opt/building/match/array_non_capture.prefix_slice_suffix-{closure#0}.built.after.mir new file mode 100644 index 0000000000000..91b3cb206d67b --- /dev/null +++ b/tests/mir-opt/building/match/array_non_capture.prefix_slice_suffix-{closure#0}.built.after.mir @@ -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; + } +}