Don't depend on Allocation sizes for pattern length
This commit is contained in:
parent
3a75e80557
commit
a5a7fcbde3
2 changed files with 137 additions and 68 deletions
|
|
@ -178,11 +178,11 @@ use super::{PatternFoldable, PatternFolder, compare_const_vals};
|
|||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::RangeEnd;
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::ty::layout::{Integer, IntegerExt, VariantIdx};
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const};
|
||||
use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size};
|
||||
|
||||
use rustc::mir::Field;
|
||||
use rustc::mir::interpret::ConstValue;
|
||||
use rustc::mir::interpret::{ConstValue, Pointer, Scalar};
|
||||
use rustc::util::common::ErrorReported;
|
||||
|
||||
use syntax::attr::{SignedInt, UnsignedInt};
|
||||
|
|
@ -200,14 +200,54 @@ use std::u128;
|
|||
pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>)
|
||||
-> &'a Pattern<'tcx>
|
||||
{
|
||||
cx.pattern_arena.alloc(LiteralExpander.fold_pattern(&pat))
|
||||
cx.pattern_arena.alloc(LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat))
|
||||
}
|
||||
|
||||
struct LiteralExpander;
|
||||
impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
|
||||
struct LiteralExpander<'a, 'tcx> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LiteralExpander<'a, 'tcx> {
|
||||
/// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice
|
||||
fn fold_const_value_deref(
|
||||
&mut self,
|
||||
val: ConstValue<'tcx>,
|
||||
rty: Ty<'tcx>,
|
||||
crty: Ty<'tcx>,
|
||||
) -> ConstValue<'tcx> {
|
||||
match (val, &crty.sty, &rty.sty) {
|
||||
// the easy case, deref a reference
|
||||
(ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => ConstValue::ByRef(
|
||||
p.alloc_id,
|
||||
self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id),
|
||||
p.offset,
|
||||
),
|
||||
// unsize array to slice if pattern is array but match value or other patterns are slice
|
||||
(ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
|
||||
assert_eq!(t, u);
|
||||
ConstValue::ScalarPair(
|
||||
Scalar::Ptr(p),
|
||||
n.val.try_to_scalar().unwrap(),
|
||||
)
|
||||
},
|
||||
// fat pointers stay the same
|
||||
(ConstValue::ScalarPair(..), _, _) => val,
|
||||
// FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
|
||||
_ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> PatternFolder<'tcx> for LiteralExpander<'a, 'tcx> {
|
||||
fn fold_pattern(&mut self, pat: &Pattern<'tcx>) -> Pattern<'tcx> {
|
||||
match (&pat.ty.sty, &*pat.kind) {
|
||||
(&ty::Ref(_, rty, _), &PatternKind::Constant { ref value }) => {
|
||||
(
|
||||
&ty::Ref(_, rty, _),
|
||||
&PatternKind::Constant { value: Const {
|
||||
val,
|
||||
ty: ty::TyS { sty: ty::Ref(_, crty, _), .. },
|
||||
} },
|
||||
) => {
|
||||
Pattern {
|
||||
ty: pat.ty,
|
||||
span: pat.span,
|
||||
|
|
@ -215,7 +255,11 @@ impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
|
|||
subpattern: Pattern {
|
||||
ty: rty,
|
||||
span: pat.span,
|
||||
kind: box PatternKind::Constant { value: value.clone() },
|
||||
kind: box PatternKind::Constant { value: Const::from_const_value(
|
||||
self.tcx,
|
||||
self.fold_const_value_deref(*val, rty, crty),
|
||||
rty,
|
||||
) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -732,15 +776,16 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
|
|||
for row in patterns {
|
||||
match *row.kind {
|
||||
PatternKind::Constant { value } => {
|
||||
if let Some(ptr) = value.to_ptr() {
|
||||
let is_array_ptr = value.ty
|
||||
.builtin_deref(true)
|
||||
.and_then(|t| t.ty.builtin_index())
|
||||
.map_or(false, |t| t == cx.tcx.types.u8);
|
||||
if is_array_ptr {
|
||||
let alloc = cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
|
||||
max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
|
||||
}
|
||||
match (value.val, &value.ty.sty) {
|
||||
(_, ty::Array(_, n)) => max_fixed_len = cmp::max(
|
||||
max_fixed_len,
|
||||
n.unwrap_usize(cx.tcx),
|
||||
),
|
||||
(ConstValue::ScalarPair(_, n), ty::Slice(_)) => max_fixed_len = cmp::max(
|
||||
max_fixed_len,
|
||||
n.to_usize(&cx.tcx).unwrap(),
|
||||
),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
|
||||
|
|
@ -1358,18 +1403,44 @@ fn slice_pat_covered_by_constructor<'tcx>(
|
|||
) -> Result<bool, ErrorReported> {
|
||||
let data: &[u8] = match *ctor {
|
||||
ConstantValue(const_val) => {
|
||||
let val = match const_val.val {
|
||||
ConstValue::Unevaluated(..) |
|
||||
ConstValue::ByRef(..) => bug!("unexpected ConstValue: {:?}", const_val),
|
||||
ConstValue::Scalar(val) | ConstValue::ScalarPair(val, _) => val,
|
||||
};
|
||||
if let Ok(ptr) = val.to_ptr() {
|
||||
tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id).bytes.as_ref()
|
||||
} else {
|
||||
bug!("unexpected non-ptr ConstantValue")
|
||||
match (const_val.val, &const_val.ty.sty) {
|
||||
(ConstValue::ByRef(id, alloc, offset), ty::Array(t, n)) => {
|
||||
if *t != tcx.types.u8 {
|
||||
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
|
||||
// any sort of exhaustiveness/unreachable check yet
|
||||
return Ok(false);
|
||||
}
|
||||
let ptr = Pointer::new(id, offset);
|
||||
let n = n.assert_usize(tcx).unwrap();
|
||||
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
|
||||
},
|
||||
(ConstValue::ScalarPair(Scalar::Bits { .. }, n), ty::Slice(_)) => {
|
||||
assert_eq!(n.to_usize(&tcx).unwrap(), 0);
|
||||
&[]
|
||||
},
|
||||
(ConstValue::ScalarPair(Scalar::Ptr(ptr), n), ty::Slice(t)) => {
|
||||
if *t != tcx.types.u8 {
|
||||
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
|
||||
// any sort of exhaustiveness/unreachable check yet
|
||||
return Ok(false);
|
||||
}
|
||||
let n = n.to_usize(&tcx).unwrap();
|
||||
tcx.alloc_map
|
||||
.lock()
|
||||
.unwrap_memory(ptr.alloc_id)
|
||||
.get_bytes(&tcx, ptr, Size::from_bytes(n))
|
||||
.unwrap()
|
||||
},
|
||||
_ => bug!(
|
||||
"slice_pat_covered_by_constructor: {:#?}, {:#?}, {:#?}, {:#?}",
|
||||
ctor, prefix, slice, suffix,
|
||||
),
|
||||
}
|
||||
}
|
||||
_ => bug!()
|
||||
_ => bug!(
|
||||
"slice_pat_covered_by_constructor not ConstValue: {:#?}, {:#?}, {:#?}, {:#?}",
|
||||
ctor, prefix, slice, suffix,
|
||||
),
|
||||
};
|
||||
|
||||
let pat_len = prefix.len() + suffix.len();
|
||||
|
|
@ -1675,22 +1746,23 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
|||
// necessarily point to memory, they are usually just integers. The only time
|
||||
// they should be pointing to memory is when they are subslices of nonzero
|
||||
// slices
|
||||
let (opt_ptr, n, ty) = match value.ty.builtin_deref(false).unwrap().ty.sty {
|
||||
ty::TyKind::Array(t, n) => (value.to_ptr(), n.unwrap_usize(cx.tcx), t),
|
||||
ty::TyKind::Slice(t) => {
|
||||
match value.val {
|
||||
ConstValue::ScalarPair(ptr, n) => (
|
||||
ptr.to_ptr().ok(),
|
||||
n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64,
|
||||
t,
|
||||
),
|
||||
_ => span_bug!(
|
||||
pat.span,
|
||||
"slice pattern constant must be scalar pair but is {:?}",
|
||||
value,
|
||||
),
|
||||
}
|
||||
},
|
||||
let (opt_ptr, n, ty) = match (value.val, &value.ty.sty) {
|
||||
(ConstValue::ByRef(id, alloc, offset), ty::TyKind::Array(t, n)) => (
|
||||
Some((
|
||||
Pointer::new(id, offset),
|
||||
alloc,
|
||||
)),
|
||||
n.unwrap_usize(cx.tcx),
|
||||
t,
|
||||
),
|
||||
(ConstValue::ScalarPair(ptr, n), ty::TyKind::Slice(t)) => (
|
||||
ptr.to_ptr().ok().map(|ptr| (
|
||||
ptr,
|
||||
cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
|
||||
)),
|
||||
n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64,
|
||||
t,
|
||||
),
|
||||
_ => span_bug!(
|
||||
pat.span,
|
||||
"unexpected const-val {:?} with ctor {:?}",
|
||||
|
|
@ -1702,8 +1774,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
|||
// convert a constant slice/array pattern to a list of patterns.
|
||||
match (n, opt_ptr) {
|
||||
(0, _) => Some(SmallVec::new()),
|
||||
(_, Some(ptr)) => {
|
||||
let alloc = cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
|
||||
(_, Some((ptr, alloc))) => {
|
||||
let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
|
||||
(0..n).map(|i| {
|
||||
let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
|
||||
|
|
|
|||
|
|
@ -1259,34 +1259,32 @@ pub fn compare_const_vals<'a, 'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
if let ty::Ref(_, rty, _) = ty.value.sty {
|
||||
if let ty::Str = rty.sty {
|
||||
match (a.val, b.val) {
|
||||
(
|
||||
ConstValue::ScalarPair(
|
||||
Scalar::Ptr(ptr_a),
|
||||
len_a,
|
||||
),
|
||||
ConstValue::ScalarPair(
|
||||
Scalar::Ptr(ptr_b),
|
||||
len_b,
|
||||
),
|
||||
) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => {
|
||||
if let Ok(len_a) = len_a.to_bits(tcx.data_layout.pointer_size) {
|
||||
if let Ok(len_b) = len_b.to_bits(tcx.data_layout.pointer_size) {
|
||||
if len_a == len_b {
|
||||
let map = tcx.alloc_map.lock();
|
||||
let alloc_a = map.unwrap_memory(ptr_a.alloc_id);
|
||||
let alloc_b = map.unwrap_memory(ptr_b.alloc_id);
|
||||
if alloc_a.bytes.len() as u128 == len_a {
|
||||
return from_bool(alloc_a == alloc_b);
|
||||
}
|
||||
if let ty::Str = ty.value.sty {
|
||||
match (a.val, b.val) {
|
||||
(
|
||||
ConstValue::ScalarPair(
|
||||
Scalar::Ptr(ptr_a),
|
||||
len_a,
|
||||
),
|
||||
ConstValue::ScalarPair(
|
||||
Scalar::Ptr(ptr_b),
|
||||
len_b,
|
||||
),
|
||||
) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => {
|
||||
if let Ok(len_a) = len_a.to_bits(tcx.data_layout.pointer_size) {
|
||||
if let Ok(len_b) = len_b.to_bits(tcx.data_layout.pointer_size) {
|
||||
if len_a == len_b {
|
||||
let map = tcx.alloc_map.lock();
|
||||
let alloc_a = map.unwrap_memory(ptr_a.alloc_id);
|
||||
let alloc_b = map.unwrap_memory(ptr_b.alloc_id);
|
||||
if alloc_a.bytes.len() as u128 == len_a {
|
||||
return from_bool(alloc_a == alloc_b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue