Skip to content

Commit 002a1c2

Browse files
committed
Destructure byte array constants to array patterns instead of keeping them opaque
1 parent 4e3eb52 commit 002a1c2

File tree

3 files changed

+13
-34
lines changed

3 files changed

+13
-34
lines changed

compiler/rustc_mir_build/src/thir/pattern/_match.rs

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -304,12 +304,11 @@ use std::iter::{FromIterator, IntoIterator};
304304
use std::ops::RangeInclusive;
305305

306306
crate fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> {
307-
LiteralExpander { tcx: cx.tcx, param_env: cx.param_env }.fold_pattern(&pat)
307+
LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat)
308308
}
309309

310310
struct LiteralExpander<'tcx> {
311311
tcx: TyCtxt<'tcx>,
312-
param_env: ty::ParamEnv<'tcx>,
313312
}
314313

315314
impl<'tcx> LiteralExpander<'tcx> {
@@ -328,40 +327,17 @@ impl<'tcx> LiteralExpander<'tcx> {
328327
) -> ConstValue<'tcx> {
329328
debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty);
330329
match (val, &crty.kind(), &rty.kind()) {
331-
// the easy case, deref a reference
332-
(ConstValue::Scalar(p), x, y) if x == y => {
333-
match p {
334-
Scalar::Ptr(p) => {
335-
let alloc = self.tcx.global_alloc(p.alloc_id).unwrap_memory();
336-
ConstValue::ByRef { alloc, offset: p.offset }
337-
}
338-
Scalar::Raw { .. } => {
339-
let layout = self.tcx.layout_of(self.param_env.and(rty)).unwrap();
340-
if layout.is_zst() {
341-
// Deref of a reference to a ZST is a nop.
342-
ConstValue::Scalar(Scalar::zst())
343-
} else {
344-
// FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;`
345-
bug!("cannot deref {:#?}, {} -> {}", val, crty, rty);
346-
}
347-
}
348-
}
349-
}
350330
// unsize array to slice if pattern is array but match value or other patterns are slice
351331
(ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
352332
assert_eq!(t, u);
333+
assert_eq!(p.offset, Size::ZERO);
353334
ConstValue::Slice {
354335
data: self.tcx.global_alloc(p.alloc_id).unwrap_memory(),
355-
start: p.offset.bytes().try_into().unwrap(),
336+
start: 0,
356337
end: n.eval_usize(self.tcx, ty::ParamEnv::empty()).try_into().unwrap(),
357338
}
358339
}
359-
// fat pointers stay the same
360-
(ConstValue::Slice { .. }, _, _)
361-
| (_, ty::Slice(_), ty::Slice(_))
362-
| (_, ty::Str, ty::Str) => val,
363-
// FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
364-
_ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
340+
_ => val,
365341
}
366342
}
367343
}

compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -390,11 +390,14 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
390390
ty::Slice(elem_ty) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv },
391391
// `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
392392
// matching against references, you can only use byte string literals.
393-
// FIXME: clean this up, likely by permitting array patterns when matching on slices
394-
ty::Array(elem_ty, _) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv },
393+
// The typechecker has a special case for byte string literals, by treating them
394+
// as slices. This means we turn `&[T; N]` constants into slice patterns, which
395+
// has no negative effects on pattern matching, even if we're actually matching on
396+
// arrays.
397+
ty::Array(..) |
395398
// Cannot merge this with the catch all branch below, because the `const_deref`
396-
// changes the type from slice to array, and slice patterns behave differently from
397-
// array patterns.
399+
// changes the type from slice to array, we need to keep the original type in the
400+
// pattern.
398401
ty::Slice(..) => {
399402
let old = self.behind_reference.replace(true);
400403
let array = tcx.deref_const(self.param_env.and(cv));

src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ LL | match buf {
77
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
88
= note: the matched value is of type `&[u8; 4]`
99

10-
error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
10+
error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
1111
--> $DIR/match-byte-array-patterns-2.rs:10:11
1212
|
1313
LL | match buf {
14-
| ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
14+
| ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
1515
|
1616
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
1717
= note: the matched value is of type `&[u8]`

0 commit comments

Comments
 (0)