Skip to content

Commit 7df1d9f

Browse files
committed
Allow constants of byte slice type as patterns
1 parent a49316d commit 7df1d9f

File tree

2 files changed

+68
-59
lines changed

2 files changed

+68
-59
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 57 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -330,47 +330,6 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
330330
})
331331
}
332332

333-
// convert a byte-string pattern to a list of u8 patterns.
334-
fn lower_byte_str_pattern<'p>(&mut self, pat: &'p Pattern<'tcx>) -> Vec<&'p Pattern<'tcx>>
335-
where 'a: 'p
336-
{
337-
let pattern_arena = &*self.pattern_arena;
338-
let tcx = self.tcx;
339-
self.byte_array_map.entry(pat).or_insert_with(|| {
340-
match pat.kind {
341-
box PatternKind::Constant {
342-
value: const_val
343-
} => {
344-
if let Some(ptr) = const_val.to_ptr() {
345-
let is_array_ptr = const_val.ty
346-
.builtin_deref(true)
347-
.and_then(|t| t.ty.builtin_index())
348-
.map_or(false, |t| t == tcx.types.u8);
349-
assert!(is_array_ptr);
350-
let alloc = tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
351-
assert_eq!(ptr.offset.bytes(), 0);
352-
// FIXME: check length
353-
alloc.bytes.iter().map(|b| {
354-
&*pattern_arena.alloc(Pattern {
355-
ty: tcx.types.u8,
356-
span: pat.span,
357-
kind: box PatternKind::Constant {
358-
value: ty::Const::from_bits(
359-
tcx,
360-
*b as u128,
361-
ty::ParamEnv::empty().and(tcx.types.u8))
362-
}
363-
})
364-
}).collect()
365-
} else {
366-
bug!("not a byte str: {:?}", const_val)
367-
}
368-
}
369-
_ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat)
370-
}
371-
}).clone()
372-
}
373-
374333
fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
375334
if self.tcx.features().exhaustive_patterns {
376335
self.tcx.is_ty_uninhabited_from(self.module, ty)
@@ -1705,26 +1664,65 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
17051664
PatternKind::Constant { value } => {
17061665
match *constructor {
17071666
Slice(..) => {
1708-
if let Some(ptr) = value.to_ptr() {
1709-
let is_array_ptr = value.ty
1710-
.builtin_deref(true)
1711-
.and_then(|t| t.ty.builtin_index())
1712-
.map_or(false, |t| t == cx.tcx.types.u8);
1713-
assert!(is_array_ptr);
1714-
let data_len = cx.tcx
1715-
.alloc_map
1716-
.lock()
1717-
.unwrap_memory(ptr.alloc_id)
1718-
.bytes
1719-
.len();
1720-
if wild_patterns.len() == data_len {
1721-
Some(cx.lower_byte_str_pattern(pat))
1722-
} else {
1723-
None
1667+
// we extract an `Option` for the pointer because slices of zero elements don't
1668+
// necessarily point to memory, they are usually just integers. The only time
1669+
// they should be pointing to memory is when they are subslices of nonzero
1670+
// slices
1671+
let (opt_ptr, data_len) = match value.ty.builtin_deref(false).unwrap().ty.sty {
1672+
ty::TyKind::Array(t, n) => {
1673+
assert!(t == cx.tcx.types.u8);
1674+
(value.to_ptr(), n.unwrap_usize(cx.tcx))
1675+
},
1676+
ty::TyKind::Slice(t) => {
1677+
assert!(t == cx.tcx.types.u8);
1678+
match value.val {
1679+
ConstValue::ScalarPair(ptr, n) => (
1680+
ptr.to_ptr().ok(),
1681+
n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64
1682+
),
1683+
_ => span_bug!(
1684+
pat.span,
1685+
"slice pattern constant must be scalar pair but is {:?}",
1686+
value,
1687+
),
1688+
}
1689+
},
1690+
_ => span_bug!(
1691+
pat.span,
1692+
"unexpected const-val {:?} with ctor {:?}",
1693+
value,
1694+
constructor,
1695+
),
1696+
};
1697+
if wild_patterns.len() as u64 == data_len {
1698+
// convert a byte-string pattern to a list of u8 patterns.
1699+
match (data_len, opt_ptr) {
1700+
(0, _) => Some(Vec::new()),
1701+
(_, Some(ptr)) => {
1702+
let alloc = cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
1703+
// FIXME: use `Allocation::read_bytes` once available
1704+
assert_eq!(ptr.offset.bytes(), 0);
1705+
Some(alloc.bytes.iter().map(|b| {
1706+
&*cx.pattern_arena.alloc(Pattern {
1707+
ty: cx.tcx.types.u8,
1708+
span: pat.span,
1709+
kind: box PatternKind::Constant {
1710+
value: ty::Const::from_bits(
1711+
cx.tcx,
1712+
*b as u128,
1713+
ty::ParamEnv::empty().and(cx.tcx.types.u8))
1714+
},
1715+
})
1716+
}).collect())
1717+
},
1718+
(_, None) => span_bug!(
1719+
pat.span,
1720+
"non zero length slice with const-val {:?}",
1721+
value,
1722+
),
17241723
}
17251724
} else {
1726-
span_bug!(pat.span,
1727-
"unexpected const-val {:?} with ctor {:?}", value, constructor)
1725+
None
17281726
}
17291727
}
17301728
_ => {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// compile-pass
2+
3+
fn main() {
4+
let s = &[0x00; 4][..]; //Slice of any value
5+
const MAGIC_TEST: &[u8] = b"TEST"; //Const slice to pattern match with
6+
match s {
7+
MAGIC_TEST => (),
8+
[0x00, 0x00, 0x00, 0x00] => (),
9+
_ => ()
10+
}
11+
}

0 commit comments

Comments
 (0)