Make `ConstValue::Slice` solely take `[u8]` and `str`
This commit is contained in:
parent
af6ac1fa14
commit
fa17654f79
|
@ -260,7 +260,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
ConstValue::Param(_) |
|
ConstValue::Param(_) |
|
||||||
ConstValue::Scalar(_) |
|
ConstValue::Scalar(_) |
|
||||||
ConstValue::Slice(..) |
|
ConstValue::Slice { .. } |
|
||||||
ConstValue::ByRef(..) |
|
ConstValue::ByRef(..) |
|
||||||
ConstValue::Unevaluated(..) => {}
|
ConstValue::Unevaluated(..) => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,14 +35,12 @@ pub enum ConstValue<'tcx> {
|
||||||
/// Not using the enum `Value` to encode that this must not be `Undef`.
|
/// Not using the enum `Value` to encode that this must not be `Undef`.
|
||||||
Scalar(Scalar),
|
Scalar(Scalar),
|
||||||
|
|
||||||
/// Used only for slices and strings (`&[T]`, `&str`, `*const [T]`, `*mut str`, `Box<str>`,
|
/// Used only for `&[u8]` and `&str`
|
||||||
/// etc.).
|
Slice {
|
||||||
///
|
data: &'tcx Allocation,
|
||||||
/// Empty slices don't necessarily have an address backed by an `AllocId`, thus we also need to
|
start: usize,
|
||||||
/// enable integer pointers. The `Scalar` type covers exactly those two cases. While we could
|
end: usize,
|
||||||
/// create dummy-`AllocId`s, the additional code effort for the conversions doesn't seem worth
|
},
|
||||||
/// it.
|
|
||||||
Slice(Scalar, u64),
|
|
||||||
|
|
||||||
/// An allocation together with a pointer into the allocation.
|
/// An allocation together with a pointer into the allocation.
|
||||||
/// Invariant: the pointer's `AllocId` resolves to the allocation.
|
/// Invariant: the pointer's `AllocId` resolves to the allocation.
|
||||||
|
@ -54,7 +52,7 @@ pub enum ConstValue<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
static_assert_size!(ConstValue<'_>, 40);
|
static_assert_size!(ConstValue<'_>, 32);
|
||||||
|
|
||||||
impl<'tcx> ConstValue<'tcx> {
|
impl<'tcx> ConstValue<'tcx> {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -65,7 +63,7 @@ impl<'tcx> ConstValue<'tcx> {
|
||||||
ConstValue::Placeholder(_) |
|
ConstValue::Placeholder(_) |
|
||||||
ConstValue::ByRef(..) |
|
ConstValue::ByRef(..) |
|
||||||
ConstValue::Unevaluated(..) |
|
ConstValue::Unevaluated(..) |
|
||||||
ConstValue::Slice(..) => None,
|
ConstValue::Slice { .. } => None,
|
||||||
ConstValue::Scalar(val) => Some(val),
|
ConstValue::Scalar(val) => Some(val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,14 +77,6 @@ impl<'tcx> ConstValue<'tcx> {
|
||||||
pub fn try_to_ptr(&self) -> Option<Pointer> {
|
pub fn try_to_ptr(&self) -> Option<Pointer> {
|
||||||
self.try_to_scalar()?.to_ptr().ok()
|
self.try_to_scalar()?.to_ptr().ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn new_slice(
|
|
||||||
val: Scalar,
|
|
||||||
len: u64,
|
|
||||||
) -> Self {
|
|
||||||
ConstValue::Slice(val, len)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A `Scalar` represents an immediate, primitive value existing outside of a
|
/// A `Scalar` represents an immediate, primitive value existing outside of a
|
||||||
|
|
|
@ -1567,21 +1567,27 @@ define_print_and_forward_display! {
|
||||||
=> p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap())),
|
=> p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap())),
|
||||||
(_, ty::FnDef(did, _)) => p!(write("{}", cx.tcx().def_path_str(*did))),
|
(_, ty::FnDef(did, _)) => p!(write("{}", cx.tcx().def_path_str(*did))),
|
||||||
(
|
(
|
||||||
ConstValue::Slice(place, len),
|
ConstValue::Slice { data, start, end },
|
||||||
ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _),
|
ty::Ref(_, slice_ty, _),
|
||||||
) => {
|
) => {
|
||||||
match (place, len) {
|
let slice = &data.bytes[start..end];
|
||||||
(_, 0) => "",
|
match slice_ty.sty {
|
||||||
(Scalar::Ptr(ptr), len) => {
|
ty::Str => {
|
||||||
let alloc = cx.tcx().alloc_map.lock().unwrap_memory(ptr.alloc_id);
|
let s = ::std::str::from_utf8(slice)
|
||||||
assert_eq!(len as usize as u64, len);
|
.expect("non utf8 str from miri");
|
||||||
let slice =
|
|
||||||
&alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];
|
|
||||||
let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
|
|
||||||
p!(write("{:?}", s))
|
p!(write("{:?}", s))
|
||||||
},
|
},
|
||||||
|
ty::Slice(elem) if elem == cx.tcx().types.u8 => {
|
||||||
|
p!(write("b\""));
|
||||||
|
for &c in slice {
|
||||||
|
for e in std::ascii::escape_default(c) {
|
||||||
|
p!(write("{}", e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p!(write("\""));
|
||||||
|
},
|
||||||
_ => bug!("invalid slice: {:#?}", self),
|
_ => bug!("invalid slice: {:#?}", self),
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
_ => p!(write("{:?} : ", self.val), print(self.ty)),
|
_ => p!(write("{:?} : ", self.val), print(self.ty)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1345,7 +1345,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
|
||||||
ConstValue::Param(p) => ConstValue::Param(p.fold_with(folder)),
|
ConstValue::Param(p) => ConstValue::Param(p.fold_with(folder)),
|
||||||
ConstValue::Placeholder(p) => ConstValue::Placeholder(p),
|
ConstValue::Placeholder(p) => ConstValue::Placeholder(p),
|
||||||
ConstValue::Scalar(a) => ConstValue::Scalar(a),
|
ConstValue::Scalar(a) => ConstValue::Scalar(a),
|
||||||
ConstValue::Slice(a, b) => ConstValue::Slice(a, b),
|
ConstValue::Slice { data, start, end } => ConstValue::Slice { data, start, end },
|
||||||
ConstValue::Unevaluated(did, substs)
|
ConstValue::Unevaluated(did, substs)
|
||||||
=> ConstValue::Unevaluated(did, substs.fold_with(folder)),
|
=> ConstValue::Unevaluated(did, substs.fold_with(folder)),
|
||||||
}
|
}
|
||||||
|
@ -1358,7 +1358,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
|
||||||
ConstValue::Param(p) => p.visit_with(visitor),
|
ConstValue::Param(p) => p.visit_with(visitor),
|
||||||
ConstValue::Placeholder(_) => false,
|
ConstValue::Placeholder(_) => false,
|
||||||
ConstValue::Scalar(_) => false,
|
ConstValue::Scalar(_) => false,
|
||||||
ConstValue::Slice(..) => false,
|
ConstValue::Slice { .. } => false,
|
||||||
ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor),
|
ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2207,7 +2207,7 @@ pub struct Const<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
static_assert_size!(Const<'_>, 48);
|
static_assert_size!(Const<'_>, 40);
|
||||||
|
|
||||||
impl<'tcx> Const<'tcx> {
|
impl<'tcx> Const<'tcx> {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use rustc::mir::interpret::{ConstValue, ErrorHandled};
|
use rustc::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar};
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
|
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, Size};
|
||||||
|
|
||||||
use crate::base;
|
use crate::base;
|
||||||
use crate::MemFlags;
|
use crate::MemFlags;
|
||||||
|
@ -92,17 +92,21 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
|
||||||
);
|
);
|
||||||
OperandValue::Immediate(llval)
|
OperandValue::Immediate(llval)
|
||||||
},
|
},
|
||||||
ConstValue::Slice(a, b) => {
|
ConstValue::Slice { data, start, end } => {
|
||||||
let a_scalar = match layout.abi {
|
let a_scalar = match layout.abi {
|
||||||
layout::Abi::ScalarPair(ref a, _) => a,
|
layout::Abi::ScalarPair(ref a, _) => a,
|
||||||
_ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout)
|
_ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout)
|
||||||
};
|
};
|
||||||
|
let a = Scalar::from(Pointer::new(
|
||||||
|
bx.tcx().alloc_map.lock().allocate(data),
|
||||||
|
Size::from_bytes(start as u64),
|
||||||
|
)).into();
|
||||||
let a_llval = bx.scalar_to_backend(
|
let a_llval = bx.scalar_to_backend(
|
||||||
a,
|
a,
|
||||||
a_scalar,
|
a_scalar,
|
||||||
bx.scalar_pair_element_backend_type(layout, 0, true),
|
bx.scalar_pair_element_backend_type(layout, 0, true),
|
||||||
);
|
);
|
||||||
let b_llval = bx.const_usize(b);
|
let b_llval = bx.const_usize((end - start) as u64);
|
||||||
OperandValue::Pair(a_llval, b_llval)
|
OperandValue::Pair(a_llval, b_llval)
|
||||||
},
|
},
|
||||||
ConstValue::ByRef(ptr, alloc) => {
|
ConstValue::ByRef(ptr, alloc) => {
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::error::Error;
|
||||||
use std::borrow::{Borrow, Cow};
|
use std::borrow::{Borrow, Cow};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
use rustc::hir::def::DefKind;
|
use rustc::hir::def::DefKind;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
|
@ -89,7 +90,14 @@ fn op_to_const<'tcx>(
|
||||||
// We do not normalize just any data. Only non-union scalars and slices.
|
// We do not normalize just any data. Only non-union scalars and slices.
|
||||||
let normalize = match op.layout.abi {
|
let normalize = match op.layout.abi {
|
||||||
layout::Abi::Scalar(..) => op.layout.ty.ty_adt_def().map_or(true, |adt| !adt.is_union()),
|
layout::Abi::Scalar(..) => op.layout.ty.ty_adt_def().map_or(true, |adt| !adt.is_union()),
|
||||||
layout::Abi::ScalarPair(..) => op.layout.ty.is_slice(),
|
layout::Abi::ScalarPair(..) => match op.layout.ty.sty {
|
||||||
|
ty::Ref(_, inner, _) => match inner.sty {
|
||||||
|
ty::Slice(elem) => elem == ecx.tcx.types.u8,
|
||||||
|
ty::Str => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
let normalized_op = if normalize {
|
let normalized_op = if normalize {
|
||||||
|
@ -101,8 +109,26 @@ fn op_to_const<'tcx>(
|
||||||
Ok(mplace) => return mplace_to_const(ecx, mplace),
|
Ok(mplace) => return mplace_to_const(ecx, mplace),
|
||||||
Err(Immediate::Scalar(x)) =>
|
Err(Immediate::Scalar(x)) =>
|
||||||
ConstValue::Scalar(x.not_undef().unwrap()),
|
ConstValue::Scalar(x.not_undef().unwrap()),
|
||||||
Err(Immediate::ScalarPair(a, b)) =>
|
Err(Immediate::ScalarPair(a, b)) => {
|
||||||
ConstValue::Slice(a.not_undef().unwrap(), b.to_usize(ecx).unwrap()),
|
let (data, start) = match a.not_undef().unwrap() {
|
||||||
|
Scalar::Ptr(ptr) => (
|
||||||
|
ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
|
||||||
|
ptr.offset.bytes(),
|
||||||
|
),
|
||||||
|
Scalar::Bits { .. } => (
|
||||||
|
ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(b"", ())),
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let len = b.to_usize(&ecx.tcx.tcx).unwrap();
|
||||||
|
let start = start.try_into().unwrap();
|
||||||
|
let len: usize = len.try_into().unwrap();
|
||||||
|
ConstValue::Slice {
|
||||||
|
data,
|
||||||
|
start,
|
||||||
|
end: start + len,
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
ecx.tcx.mk_const(ty::Const { val, ty: op.layout.ty })
|
ecx.tcx.mk_const(ty::Const { val, ty: op.layout.ty })
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,14 +33,16 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>(
|
||||||
let lit = match *lit {
|
let lit = match *lit {
|
||||||
LitKind::Str(ref s, _) => {
|
LitKind::Str(ref s, _) => {
|
||||||
let s = s.as_str();
|
let s = s.as_str();
|
||||||
let id = tcx.allocate_bytes(s.as_bytes());
|
let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes(), ());
|
||||||
ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64)
|
let allocation = tcx.intern_const_alloc(allocation);
|
||||||
|
ConstValue::Slice { data: allocation, start: 0, end: s.len() }
|
||||||
},
|
},
|
||||||
LitKind::Err(ref s) => {
|
LitKind::Err(ref s) => {
|
||||||
let s = s.as_str();
|
let s = s.as_str();
|
||||||
let id = tcx.allocate_bytes(s.as_bytes());
|
let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes(), ());
|
||||||
|
let allocation = tcx.intern_const_alloc(allocation);
|
||||||
return Ok(tcx.mk_const(ty::Const {
|
return Ok(tcx.mk_const(ty::Const {
|
||||||
val: ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64),
|
val: ConstValue::Slice{ data: allocation, start: 0, end: s.len() },
|
||||||
ty: tcx.types.err,
|
ty: tcx.types.err,
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
|
@ -172,7 +172,7 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const};
|
||||||
use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size};
|
use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size};
|
||||||
|
|
||||||
use rustc::mir::Field;
|
use rustc::mir::Field;
|
||||||
use rustc::mir::interpret::{ConstValue, Scalar, truncate};
|
use rustc::mir::interpret::{ConstValue, Scalar, truncate, AllocId, Pointer};
|
||||||
use rustc::util::common::ErrorReported;
|
use rustc::util::common::ErrorReported;
|
||||||
|
|
||||||
use syntax::attr::{SignedInt, UnsignedInt};
|
use syntax::attr::{SignedInt, UnsignedInt};
|
||||||
|
@ -186,6 +186,7 @@ use std::fmt;
|
||||||
use std::iter::{FromIterator, IntoIterator};
|
use std::iter::{FromIterator, IntoIterator};
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
use std::u128;
|
use std::u128;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>)
|
pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>)
|
||||||
-> &'a Pattern<'tcx>
|
-> &'a Pattern<'tcx>
|
||||||
|
@ -221,16 +222,17 @@ impl<'a, 'tcx> LiteralExpander<'a, 'tcx> {
|
||||||
// unsize array to slice if pattern is array but match value or other patterns are slice
|
// 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)) => {
|
(ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
|
||||||
assert_eq!(t, u);
|
assert_eq!(t, u);
|
||||||
ConstValue::Slice(
|
ConstValue::Slice {
|
||||||
Scalar::Ptr(p),
|
data: self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id),
|
||||||
n.val.try_to_scalar()
|
start: p.offset.bytes().try_into().unwrap(),
|
||||||
.unwrap()
|
end: n.unwrap_usize(self.tcx).try_into().unwrap(),
|
||||||
.to_usize(&self.tcx)
|
}
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
// fat pointers stay the same
|
// fat pointers stay the same
|
||||||
(ConstValue::Slice(..), _, _) => val,
|
| (ConstValue::Slice { .. }, _, _)
|
||||||
|
| (_, ty::Slice(_), ty::Slice(_))
|
||||||
|
| (_, ty::Str, ty::Str)
|
||||||
|
=> val,
|
||||||
// FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
|
// FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
|
||||||
_ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
|
_ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
|
||||||
}
|
}
|
||||||
|
@ -786,9 +788,9 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
|
||||||
max_fixed_len,
|
max_fixed_len,
|
||||||
n.unwrap_usize(cx.tcx),
|
n.unwrap_usize(cx.tcx),
|
||||||
),
|
),
|
||||||
(ConstValue::Slice(_, n), ty::Slice(_)) => max_fixed_len = cmp::max(
|
(ConstValue::Slice{ start, end, .. }, ty::Slice(_)) => max_fixed_len = cmp::max(
|
||||||
max_fixed_len,
|
max_fixed_len,
|
||||||
n,
|
(end - start) as u64,
|
||||||
),
|
),
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
@ -1431,42 +1433,17 @@ fn slice_pat_covered_by_const<'tcx>(
|
||||||
) -> Result<bool, ErrorReported> {
|
) -> Result<bool, ErrorReported> {
|
||||||
let data: &[u8] = match (const_val.val, &const_val.ty.sty) {
|
let data: &[u8] = match (const_val.val, &const_val.ty.sty) {
|
||||||
(ConstValue::ByRef(ptr, alloc), ty::Array(t, n)) => {
|
(ConstValue::ByRef(ptr, alloc), ty::Array(t, n)) => {
|
||||||
if *t != tcx.types.u8 {
|
assert_eq!(*t, tcx.types.u8);
|
||||||
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
|
|
||||||
// any sort of exhaustiveness/unreachable check yet
|
|
||||||
// This solely means that we don't lint about unreachable patterns, even if some
|
|
||||||
// are definitely unreachable.
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
let n = n.assert_usize(tcx).unwrap();
|
let n = n.assert_usize(tcx).unwrap();
|
||||||
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
|
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
|
||||||
},
|
},
|
||||||
// a slice fat pointer to a zero length slice
|
(ConstValue::Slice { data, start, end }, ty::Slice(t)) => {
|
||||||
(ConstValue::Slice(Scalar::Bits { .. }, 0), ty::Slice(t)) => {
|
assert_eq!(*t, tcx.types.u8);
|
||||||
if *t != tcx.types.u8 {
|
let ptr = Pointer::new(AllocId(0), Size::from_bytes(start as u64));
|
||||||
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
|
data.get_bytes(&tcx, ptr, Size::from_bytes((end - start) as u64)).unwrap()
|
||||||
// any sort of exhaustiveness/unreachable check yet
|
|
||||||
// This solely means that we don't lint about unreachable patterns, even if some
|
|
||||||
// are definitely unreachable.
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
&[]
|
|
||||||
},
|
|
||||||
//
|
|
||||||
(ConstValue::Slice(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
|
|
||||||
// This solely means that we don't lint about unreachable patterns, even if some
|
|
||||||
// are definitely unreachable.
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
tcx.alloc_map
|
|
||||||
.lock()
|
|
||||||
.unwrap_memory(ptr.alloc_id)
|
|
||||||
.get_bytes(&tcx, ptr, Size::from_bytes(n))
|
|
||||||
.unwrap()
|
|
||||||
},
|
},
|
||||||
|
// FIXME(oli-obk): create a way to extract fat pointers from ByRef
|
||||||
|
(_, ty::Slice(_)) => return Ok(false),
|
||||||
_ => bug!(
|
_ => bug!(
|
||||||
"slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
|
"slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
|
||||||
const_val, prefix, slice, suffix,
|
const_val, prefix, slice, suffix,
|
||||||
|
@ -1774,11 +1751,12 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
||||||
// necessarily point to memory, they are usually just integers. The only time
|
// 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
|
// they should be pointing to memory is when they are subslices of nonzero
|
||||||
// slices
|
// slices
|
||||||
let (opt_ptr, n, ty) = match value.ty.sty {
|
let (alloc, offset, n, ty) = match value.ty.sty {
|
||||||
ty::Array(t, n) => {
|
ty::Array(t, n) => {
|
||||||
match value.val {
|
match value.val {
|
||||||
ConstValue::ByRef(ptr, alloc) => (
|
ConstValue::ByRef(ptr, alloc) => (
|
||||||
Some((ptr, alloc)),
|
alloc,
|
||||||
|
ptr.offset,
|
||||||
n.unwrap_usize(cx.tcx),
|
n.unwrap_usize(cx.tcx),
|
||||||
t,
|
t,
|
||||||
),
|
),
|
||||||
|
@ -1790,14 +1768,16 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
||||||
},
|
},
|
||||||
ty::Slice(t) => {
|
ty::Slice(t) => {
|
||||||
match value.val {
|
match value.val {
|
||||||
ConstValue::Slice(ptr, n) => (
|
ConstValue::Slice { data, start, end } => (
|
||||||
ptr.to_ptr().ok().map(|ptr| (
|
data,
|
||||||
ptr,
|
Size::from_bytes(start as u64),
|
||||||
cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
|
(end - start) as u64,
|
||||||
)),
|
|
||||||
n,
|
|
||||||
t,
|
t,
|
||||||
),
|
),
|
||||||
|
ConstValue::ByRef(..) => {
|
||||||
|
// FIXME(oli-obk): implement `deref` for `ConstValue`
|
||||||
|
return None;
|
||||||
|
},
|
||||||
_ => span_bug!(
|
_ => span_bug!(
|
||||||
pat.span,
|
pat.span,
|
||||||
"slice pattern constant must be scalar pair but is {:?}",
|
"slice pattern constant must be scalar pair but is {:?}",
|
||||||
|
@ -1814,31 +1794,22 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
||||||
};
|
};
|
||||||
if wild_patterns.len() as u64 == n {
|
if wild_patterns.len() as u64 == n {
|
||||||
// convert a constant slice/array pattern to a list of patterns.
|
// convert a constant slice/array pattern to a list of patterns.
|
||||||
match (n, opt_ptr) {
|
let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
|
||||||
(0, _) => Some(SmallVec::new()),
|
let ptr = Pointer::new(AllocId(0), offset);
|
||||||
(_, Some((ptr, alloc))) => {
|
(0..n).map(|i| {
|
||||||
let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
|
let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
|
||||||
(0..n).map(|i| {
|
let scalar = alloc.read_scalar(
|
||||||
let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
|
&cx.tcx, ptr, layout.size,
|
||||||
let scalar = alloc.read_scalar(
|
).ok()?;
|
||||||
&cx.tcx, ptr, layout.size,
|
let scalar = scalar.not_undef().ok()?;
|
||||||
).ok()?;
|
let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
|
||||||
let scalar = scalar.not_undef().ok()?;
|
let pattern = Pattern {
|
||||||
let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
|
ty,
|
||||||
let pattern = Pattern {
|
span: pat.span,
|
||||||
ty,
|
kind: box PatternKind::Constant { value },
|
||||||
span: pat.span,
|
};
|
||||||
kind: box PatternKind::Constant { value },
|
Some(&*cx.pattern_arena.alloc(pattern))
|
||||||
};
|
}).collect()
|
||||||
Some(&*cx.pattern_arena.alloc(pattern))
|
|
||||||
}).collect()
|
|
||||||
},
|
|
||||||
(_, None) => span_bug!(
|
|
||||||
pat.span,
|
|
||||||
"non zero length slice with const-val {:?}",
|
|
||||||
value,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,11 @@ use crate::hair::constant::*;
|
||||||
|
|
||||||
use rustc::mir::{Field, BorrowKind, Mutability};
|
use rustc::mir::{Field, BorrowKind, Mutability};
|
||||||
use rustc::mir::{UserTypeProjection};
|
use rustc::mir::{UserTypeProjection};
|
||||||
use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
|
use rustc::mir::interpret::{GlobalId, ConstValue, sign_extend, AllocId, Pointer};
|
||||||
use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, UserType, DefIdTree};
|
use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, UserType, DefIdTree};
|
||||||
use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations};
|
use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations};
|
||||||
use rustc::ty::subst::{SubstsRef, Kind};
|
use rustc::ty::subst::{SubstsRef, Kind};
|
||||||
use rustc::ty::layout::VariantIdx;
|
use rustc::ty::layout::{VariantIdx, Size};
|
||||||
use rustc::hir::{self, PatKind, RangeEnd};
|
use rustc::hir::{self, PatKind, RangeEnd};
|
||||||
use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind};
|
use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind};
|
||||||
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
|
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
|
||||||
|
@ -1293,22 +1293,25 @@ pub fn compare_const_vals<'a, 'gcx, 'tcx>(
|
||||||
if let ty::Str = ty.value.sty {
|
if let ty::Str = ty.value.sty {
|
||||||
match (a.val, b.val) {
|
match (a.val, b.val) {
|
||||||
(
|
(
|
||||||
ConstValue::Slice(
|
ConstValue::Slice { data: alloc_a, start: offset_a, end: end_a },
|
||||||
Scalar::Ptr(ptr_a),
|
ConstValue::Slice { data: alloc_b, start: offset_b, end: end_b },
|
||||||
len_a,
|
) => {
|
||||||
),
|
let len_a = end_a - offset_a;
|
||||||
ConstValue::Slice(
|
let len_b = end_b - offset_b;
|
||||||
Scalar::Ptr(ptr_b),
|
let a = alloc_a.get_bytes(
|
||||||
len_b,
|
&tcx,
|
||||||
),
|
// invent a pointer, only the offset is relevant anyway
|
||||||
) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => {
|
Pointer::new(AllocId(0), Size::from_bytes(offset_a as u64)),
|
||||||
if len_a == len_b {
|
Size::from_bytes(len_a as u64),
|
||||||
let map = tcx.alloc_map.lock();
|
);
|
||||||
let alloc_a = map.unwrap_memory(ptr_a.alloc_id);
|
let b = alloc_b.get_bytes(
|
||||||
let alloc_b = map.unwrap_memory(ptr_b.alloc_id);
|
&tcx,
|
||||||
if alloc_a.bytes.len() as u64 == len_a {
|
// invent a pointer, only the offset is relevant anyway
|
||||||
return from_bool(alloc_a == alloc_b);
|
Pointer::new(AllocId(0), Size::from_bytes(offset_b as u64)),
|
||||||
}
|
Size::from_bytes(len_b as u64),
|
||||||
|
);
|
||||||
|
if let (Ok(a), Ok(b)) = (a, b) {
|
||||||
|
return from_bool(a == b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|
|
@ -533,11 +533,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||||
MemPlace::from_ptr(ptr.with_default_tag(), alloc.align)
|
MemPlace::from_ptr(ptr.with_default_tag(), alloc.align)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
ConstValue::Slice(a, b) =>
|
ConstValue::Slice { data, start, end } =>
|
||||||
Operand::Immediate(Immediate::ScalarPair(
|
Operand::Immediate(Immediate::ScalarPair(
|
||||||
a.with_default_tag().into(),
|
Scalar::from(Pointer::new(
|
||||||
Scalar::from_uint(b, self.tcx.data_layout.pointer_size)
|
self.tcx.alloc_map.lock().allocate(data),
|
||||||
.with_default_tag().into(),
|
Size::from_bytes(start as u64),
|
||||||
|
)).with_default_tag().into(),
|
||||||
|
Scalar::from_uint(
|
||||||
|
(end - start) as u64,
|
||||||
|
self.tcx.data_layout.pointer_size,
|
||||||
|
).with_default_tag().into(),
|
||||||
)),
|
)),
|
||||||
ConstValue::Scalar(x) =>
|
ConstValue::Scalar(x) =>
|
||||||
Operand::Immediate(Immediate::Scalar(x.with_default_tag().into())),
|
Operand::Immediate(Immediate::Scalar(x.with_default_tag().into())),
|
||||||
|
|
|
@ -1255,10 +1255,10 @@ fn collect_const<'a, 'tcx>(
|
||||||
debug!("visiting const {:?}", constant);
|
debug!("visiting const {:?}", constant);
|
||||||
|
|
||||||
match constant.val {
|
match constant.val {
|
||||||
ConstValue::Slice(Scalar::Ptr(ptr), _) |
|
|
||||||
ConstValue::Scalar(Scalar::Ptr(ptr)) =>
|
ConstValue::Scalar(Scalar::Ptr(ptr)) =>
|
||||||
collect_miri(tcx, ptr.alloc_id, output),
|
collect_miri(tcx, ptr.alloc_id, output),
|
||||||
ConstValue::ByRef(_ptr, alloc) => {
|
ConstValue::Slice { data: alloc, start: _, end: _ } |
|
||||||
|
ConstValue::ByRef(_, alloc) => {
|
||||||
for &((), id) in alloc.relocations.values() {
|
for &((), id) in alloc.relocations.values() {
|
||||||
collect_miri(tcx, id, output);
|
collect_miri(tcx, id, output);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,13 @@ fn main() {
|
||||||
match s {
|
match s {
|
||||||
MAGIC_TEST => (),
|
MAGIC_TEST => (),
|
||||||
[0x00, 0x00, 0x00, 0x00] => (),
|
[0x00, 0x00, 0x00, 0x00] => (),
|
||||||
[4, 5, 6, 7] => (), //~ ERROR unreachable pattern
|
[4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
match s {
|
match s {
|
||||||
[0x00, 0x00, 0x00, 0x00] => (),
|
[0x00, 0x00, 0x00, 0x00] => (),
|
||||||
MAGIC_TEST => (),
|
MAGIC_TEST => (),
|
||||||
[4, 5, 6, 7] => (), //~ ERROR unreachable pattern
|
[4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
match s {
|
match s {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: unreachable pattern
|
error: unreachable pattern
|
||||||
--> $DIR/slice-pattern-const-2.rs:9:9
|
--> $DIR/slice-pattern-const-2.rs:28:9
|
||||||
|
|
|
|
||||||
LL | [4, 5, 6, 7] => (),
|
LL | FOO => (),
|
||||||
| ^^^^^^^^^^^^
|
| ^^^
|
||||||
|
|
|
|
||||||
note: lint level defined here
|
note: lint level defined here
|
||||||
--> $DIR/slice-pattern-const-2.rs:1:9
|
--> $DIR/slice-pattern-const-2.rs:1:9
|
||||||
|
@ -10,17 +10,5 @@ note: lint level defined here
|
||||||
LL | #![deny(unreachable_patterns)]
|
LL | #![deny(unreachable_patterns)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: unreachable pattern
|
error: aborting due to previous error
|
||||||
--> $DIR/slice-pattern-const-2.rs:15:9
|
|
||||||
|
|
|
||||||
LL | [4, 5, 6, 7] => (),
|
|
||||||
| ^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: unreachable pattern
|
|
||||||
--> $DIR/slice-pattern-const-2.rs:28:9
|
|
||||||
|
|
|
||||||
LL | FOO => (),
|
|
||||||
| ^^^
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue