Auto merge of #50249 - Zoxc:allocation-const, r=oli-obk
Introduce ConstValue and use it instead of miri's Value for constant values r? @oli-obk
This commit is contained in:
commit
c705877b1d
58 changed files with 1104 additions and 767 deletions
|
@ -60,7 +60,7 @@
|
||||||
//! user of the `DepNode` API of having to know how to compute the expected
|
//! user of the `DepNode` API of having to know how to compute the expected
|
||||||
//! fingerprint for a given set of node parameters.
|
//! fingerprint for a given set of node parameters.
|
||||||
|
|
||||||
use mir::interpret::{GlobalId};
|
use mir::interpret::{GlobalId, ConstValue};
|
||||||
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
|
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
|
||||||
use hir::map::DefPathHash;
|
use hir::map::DefPathHash;
|
||||||
use hir::{HirId, ItemLocalId};
|
use hir::{HirId, ItemLocalId};
|
||||||
|
@ -621,13 +621,14 @@ define_dep_nodes!( <'tcx>
|
||||||
[input] UsedCrateSource(CrateNum),
|
[input] UsedCrateSource(CrateNum),
|
||||||
[input] PostorderCnums,
|
[input] PostorderCnums,
|
||||||
|
|
||||||
// This query is not expected to have inputs -- as a result, it's
|
// These queries are not expected to have inputs -- as a result, they
|
||||||
// not a good candidate for "replay" because it's essentially a
|
// are not good candidates for "replay" because they are essentially
|
||||||
// pure function of its input (and hence the expectation is that
|
// pure functions of their input (and hence the expectation is that
|
||||||
// no caller would be green **apart** from just this
|
// no caller would be green **apart** from just these
|
||||||
// query). Making it anonymous avoids hashing the result, which
|
// queries). Making them anonymous avoids hashing the result, which
|
||||||
// may save a bit of time.
|
// may save a bit of time.
|
||||||
[anon] EraseRegionsTy { ty: Ty<'tcx> },
|
[anon] EraseRegionsTy { ty: Ty<'tcx> },
|
||||||
|
[anon] ConstValueToAllocation { val: ConstValue<'tcx>, ty: Ty<'tcx> },
|
||||||
|
|
||||||
[input] Freevars(DefId),
|
[input] Freevars(DefId),
|
||||||
[input] MaybeUnusedTraitImport(DefId),
|
[input] MaybeUnusedTraitImport(DefId),
|
||||||
|
|
|
@ -384,6 +384,30 @@ for ::middle::const_val::ConstVal<'gcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||||
|
for ::mir::interpret::ConstValue<'gcx> {
|
||||||
|
fn hash_stable<W: StableHasherResult>(&self,
|
||||||
|
hcx: &mut StableHashingContext<'a>,
|
||||||
|
hasher: &mut StableHasher<W>) {
|
||||||
|
use mir::interpret::ConstValue::*;
|
||||||
|
|
||||||
|
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||||
|
|
||||||
|
match *self {
|
||||||
|
ByVal(val) => {
|
||||||
|
val.hash_stable(hcx, hasher);
|
||||||
|
}
|
||||||
|
ByValPair(a, b) => {
|
||||||
|
a.hash_stable(hcx, hasher);
|
||||||
|
b.hash_stable(hcx, hasher);
|
||||||
|
}
|
||||||
|
ByRef(alloc) => {
|
||||||
|
alloc.hash_stable(hcx, hasher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl_stable_hash_for!(enum mir::interpret::Value {
|
impl_stable_hash_for!(enum mir::interpret::Value {
|
||||||
ByVal(v),
|
ByVal(v),
|
||||||
ByValPair(a, b),
|
ByValPair(a, b),
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use ty::{self, TyCtxt, layout};
|
use ty::{self, TyCtxt, layout};
|
||||||
use ty::subst::Substs;
|
use ty::subst::Substs;
|
||||||
use mir::interpret::{Value, PrimVal};
|
use mir::interpret::ConstValue;
|
||||||
use errors::DiagnosticBuilder;
|
use errors::DiagnosticBuilder;
|
||||||
|
|
||||||
use graphviz::IntoCow;
|
use graphviz::IntoCow;
|
||||||
|
@ -25,27 +25,7 @@ pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>;
|
||||||
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
|
||||||
pub enum ConstVal<'tcx> {
|
pub enum ConstVal<'tcx> {
|
||||||
Unevaluated(DefId, &'tcx Substs<'tcx>),
|
Unevaluated(DefId, &'tcx Substs<'tcx>),
|
||||||
Value(Value),
|
Value(ConstValue<'tcx>),
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> ConstVal<'tcx> {
|
|
||||||
pub fn to_raw_bits(&self) -> Option<u128> {
|
|
||||||
match *self {
|
|
||||||
ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
|
|
||||||
Some(b)
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn unwrap_u64(&self) -> u64 {
|
|
||||||
match self.to_raw_bits() {
|
|
||||||
Some(val) => {
|
|
||||||
assert_eq!(val as u64 as u128, val);
|
|
||||||
val as u64
|
|
||||||
},
|
|
||||||
None => bug!("expected constant u64, got {:#?}", self),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
|
@ -945,7 +945,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
// Always promote `[T; 0]` (even when e.g. borrowed mutably).
|
// Always promote `[T; 0]` (even when e.g. borrowed mutably).
|
||||||
let promotable = match expr_ty.sty {
|
let promotable = match expr_ty.sty {
|
||||||
ty::TyArray(_, len) if len.val.to_raw_bits() == Some(0) => true,
|
ty::TyArray(_, len) if len.assert_usize(self.tcx) == Some(0) => true,
|
||||||
_ => promotable,
|
_ => promotable,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ mod value;
|
||||||
|
|
||||||
pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage};
|
pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage};
|
||||||
|
|
||||||
pub use self::value::{PrimVal, PrimValKind, Value, Pointer};
|
pub use self::value::{PrimVal, PrimValKind, Value, Pointer, ConstValue};
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -20,8 +20,10 @@ use ty::{self, TyCtxt};
|
||||||
use ty::layout::{self, Align, HasDataLayout};
|
use ty::layout::{self, Align, HasDataLayout};
|
||||||
use middle::region;
|
use middle::region;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
use std::io;
|
||||||
use syntax::ast::Mutability;
|
use syntax::ast::Mutability;
|
||||||
use rustc_serialize::{Encoder, Decoder, Decodable, Encodable};
|
use rustc_serialize::{Encoder, Decoder, Decodable, Encodable};
|
||||||
|
use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
|
||||||
pub enum Lock {
|
pub enum Lock {
|
||||||
|
@ -235,7 +237,7 @@ impl fmt::Display for AllocId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
|
||||||
pub struct Allocation {
|
pub struct Allocation {
|
||||||
/// The actual bytes of the allocation.
|
/// The actual bytes of the allocation.
|
||||||
/// Note that the bytes of a pointer represent the offset of the pointer
|
/// Note that the bytes of a pointer represent the offset of the pointer
|
||||||
|
@ -254,17 +256,69 @@ pub struct Allocation {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Allocation {
|
impl Allocation {
|
||||||
pub fn from_bytes(slice: &[u8]) -> Self {
|
pub fn from_bytes(slice: &[u8], align: Align) -> Self {
|
||||||
let mut undef_mask = UndefMask::new(0);
|
let mut undef_mask = UndefMask::new(0);
|
||||||
undef_mask.grow(slice.len() as u64, true);
|
undef_mask.grow(slice.len() as u64, true);
|
||||||
Self {
|
Self {
|
||||||
bytes: slice.to_owned(),
|
bytes: slice.to_owned(),
|
||||||
relocations: BTreeMap::new(),
|
relocations: BTreeMap::new(),
|
||||||
undef_mask,
|
undef_mask,
|
||||||
align: Align::from_bytes(1, 1).unwrap(),
|
align,
|
||||||
runtime_mutability: Mutability::Immutable,
|
runtime_mutability: Mutability::Immutable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_byte_aligned_bytes(slice: &[u8]) -> Self {
|
||||||
|
Allocation::from_bytes(slice, Align::from_bytes(1, 1).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn undef(size: u64, align: Align) -> Self {
|
||||||
|
assert_eq!(size as usize as u64, size);
|
||||||
|
Allocation {
|
||||||
|
bytes: vec![0; size as usize],
|
||||||
|
relocations: BTreeMap::new(),
|
||||||
|
undef_mask: UndefMask::new(size),
|
||||||
|
align,
|
||||||
|
runtime_mutability: Mutability::Immutable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Methods to access integers in the target endianness
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
pub fn write_target_uint(
|
||||||
|
endianness: layout::Endian,
|
||||||
|
mut target: &mut [u8],
|
||||||
|
data: u128,
|
||||||
|
) -> Result<(), io::Error> {
|
||||||
|
let len = target.len();
|
||||||
|
match endianness {
|
||||||
|
layout::Endian::Little => target.write_uint128::<LittleEndian>(data, len),
|
||||||
|
layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_target_int(
|
||||||
|
endianness: layout::Endian,
|
||||||
|
mut target: &mut [u8],
|
||||||
|
data: i128,
|
||||||
|
) -> Result<(), io::Error> {
|
||||||
|
let len = target.len();
|
||||||
|
match endianness {
|
||||||
|
layout::Endian::Little => target.write_int128::<LittleEndian>(data, len),
|
||||||
|
layout::Endian::Big => target.write_int128::<BigEndian>(data, len),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
|
||||||
|
match endianness {
|
||||||
|
layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
|
||||||
|
layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -3,7 +3,69 @@
|
||||||
use ty::layout::{Align, HasDataLayout};
|
use ty::layout::{Align, HasDataLayout};
|
||||||
use ty;
|
use ty;
|
||||||
|
|
||||||
use super::{EvalResult, MemoryPointer, PointerArithmetic};
|
use super::{EvalResult, MemoryPointer, PointerArithmetic, Allocation};
|
||||||
|
|
||||||
|
/// Represents a constant value in Rust. ByVal and ByValPair are optimizations which
|
||||||
|
/// matches Value's optimizations for easy conversions between these two types
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
|
||||||
|
pub enum ConstValue<'tcx> {
|
||||||
|
// Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef
|
||||||
|
ByVal(PrimVal),
|
||||||
|
// Used only for types with layout::abi::ScalarPair
|
||||||
|
ByValPair(PrimVal, PrimVal),
|
||||||
|
// Used only for the remaining cases
|
||||||
|
ByRef(&'tcx Allocation),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> ConstValue<'tcx> {
|
||||||
|
#[inline]
|
||||||
|
pub fn from_byval_value(val: Value) -> Self {
|
||||||
|
match val {
|
||||||
|
Value::ByRef(..) => bug!(),
|
||||||
|
Value::ByValPair(a, b) => ConstValue::ByValPair(a, b),
|
||||||
|
Value::ByVal(val) => ConstValue::ByVal(val),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_byval_value(&self) -> Option<Value> {
|
||||||
|
match *self {
|
||||||
|
ConstValue::ByRef(..) => None,
|
||||||
|
ConstValue::ByValPair(a, b) => Some(Value::ByValPair(a, b)),
|
||||||
|
ConstValue::ByVal(val) => Some(Value::ByVal(val)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_primval(val: PrimVal) -> Self {
|
||||||
|
ConstValue::ByVal(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_primval(&self) -> Option<PrimVal> {
|
||||||
|
match *self {
|
||||||
|
ConstValue::ByRef(..) => None,
|
||||||
|
ConstValue::ByValPair(..) => None,
|
||||||
|
ConstValue::ByVal(val) => Some(val),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_bits(&self) -> Option<u128> {
|
||||||
|
match self.to_primval() {
|
||||||
|
Some(PrimVal::Bytes(val)) => Some(val),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_ptr(&self) -> Option<MemoryPointer> {
|
||||||
|
match self.to_primval() {
|
||||||
|
Some(PrimVal::Ptr(ptr)) => Some(ptr),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A `Value` represents a single self-contained Rust value.
|
/// A `Value` represents a single self-contained Rust value.
|
||||||
///
|
///
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir.html
|
//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir.html
|
||||||
|
|
||||||
use graphviz::IntoCow;
|
use graphviz::IntoCow;
|
||||||
use middle::const_val::ConstVal;
|
|
||||||
use middle::region;
|
use middle::region;
|
||||||
use rustc_data_structures::sync::{Lrc};
|
use rustc_data_structures::sync::{Lrc};
|
||||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||||
|
@ -1549,11 +1548,7 @@ impl<'tcx> Operand<'tcx> {
|
||||||
span,
|
span,
|
||||||
ty,
|
ty,
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: tcx.mk_const(ty::Const {
|
value: ty::Const::zero_sized(tcx, ty),
|
||||||
// ZST function type
|
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
|
|
||||||
ty
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1881,11 +1876,17 @@ impl<'tcx> Debug for Literal<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
|
/// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
|
||||||
fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
|
pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
|
||||||
use middle::const_val::ConstVal::*;
|
use middle::const_val::ConstVal;
|
||||||
match const_val.val {
|
match const_val.val {
|
||||||
Unevaluated(..) => write!(fmt, "{:?}", const_val),
|
ConstVal::Unevaluated(..) => write!(fmt, "{:?}", const_val),
|
||||||
Value(val) => print_miri_value(val, const_val.ty, fmt),
|
ConstVal::Value(val) => {
|
||||||
|
if let Some(value) = val.to_byval_value() {
|
||||||
|
print_miri_value(value, const_val.ty, fmt)
|
||||||
|
} else {
|
||||||
|
write!(fmt, "{:?}:{}", val, const_val.ty)
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
|
||||||
PlaceTy::Ty {
|
PlaceTy::Ty {
|
||||||
ty: match ty.sty {
|
ty: match ty.sty {
|
||||||
ty::TyArray(inner, size) => {
|
ty::TyArray(inner, size) => {
|
||||||
let size = size.val.unwrap_u64();
|
let size = size.unwrap_usize(tcx);
|
||||||
let len = size - (from as u64) - (to as u64);
|
let len = size - (from as u64) - (to as u64);
|
||||||
tcx.mk_array(inner, len)
|
tcx.mk_array(inner, len)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ use std::hash::Hash;
|
||||||
use std::intrinsics;
|
use std::intrinsics;
|
||||||
use ty::{self, Ty, TyCtxt};
|
use ty::{self, Ty, TyCtxt};
|
||||||
use ty::subst::Substs;
|
use ty::subst::Substs;
|
||||||
|
use mir::interpret::Allocation;
|
||||||
|
|
||||||
/// The shorthand encoding uses an enum's variant index `usize`
|
/// The shorthand encoding uses an enum's variant index `usize`
|
||||||
/// and is offset by this value so it never matches a real variant.
|
/// and is offset by this value so it never matches a real variant.
|
||||||
|
@ -262,6 +263,15 @@ pub fn decode_const<'a, 'tcx, D>(decoder: &mut D)
|
||||||
Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?))
|
Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn decode_allocation<'a, 'tcx, D>(decoder: &mut D)
|
||||||
|
-> Result<&'tcx Allocation, D::Error>
|
||||||
|
where D: TyDecoder<'a, 'tcx>,
|
||||||
|
'tcx: 'a,
|
||||||
|
{
|
||||||
|
Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?))
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! __impl_decoder_methods {
|
macro_rules! __impl_decoder_methods {
|
||||||
($($name:ident -> $ty:ty;)*) => {
|
($($name:ident -> $ty:ty;)*) => {
|
||||||
|
@ -393,6 +403,15 @@ macro_rules! implement_ty_decoder {
|
||||||
decode_const(self)
|
decode_const(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::mir::interpret::Allocation>
|
||||||
|
for $DecoderName<$($typaram),*> {
|
||||||
|
fn specialized_decode(
|
||||||
|
&mut self
|
||||||
|
) -> Result<&'tcx $crate::mir::interpret::Allocation, Self::Error> {
|
||||||
|
decode_allocation(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,14 +26,12 @@ use lint::{self, Lint};
|
||||||
use ich::{StableHashingContext, NodeIdHashingMode};
|
use ich::{StableHashingContext, NodeIdHashingMode};
|
||||||
use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
|
use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
|
||||||
use infer::outlives::free_region_map::FreeRegionMap;
|
use infer::outlives::free_region_map::FreeRegionMap;
|
||||||
use middle::const_val::ConstVal;
|
|
||||||
use middle::cstore::{CrateStore, LinkMeta};
|
use middle::cstore::{CrateStore, LinkMeta};
|
||||||
use middle::cstore::EncodedMetadata;
|
use middle::cstore::EncodedMetadata;
|
||||||
use middle::lang_items;
|
use middle::lang_items;
|
||||||
use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
|
use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
|
||||||
use middle::stability;
|
use middle::stability;
|
||||||
use mir::{self, Mir, interpret};
|
use mir::{self, Mir, interpret};
|
||||||
use mir::interpret::{Value, PrimVal};
|
|
||||||
use ty::subst::{Kind, Substs, Subst};
|
use ty::subst::{Kind, Substs, Subst};
|
||||||
use ty::ReprOptions;
|
use ty::ReprOptions;
|
||||||
use ty::Instance;
|
use ty::Instance;
|
||||||
|
@ -1131,7 +1129,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
return alloc_id;
|
return alloc_id;
|
||||||
}
|
}
|
||||||
// create an allocation that just contains these bytes
|
// create an allocation that just contains these bytes
|
||||||
let alloc = interpret::Allocation::from_bytes(bytes);
|
let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes);
|
||||||
let alloc = self.intern_const_alloc(alloc);
|
let alloc = self.intern_const_alloc(alloc);
|
||||||
|
|
||||||
// the next unique id
|
// the next unique id
|
||||||
|
@ -2366,10 +2364,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
|
pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
|
||||||
self.mk_ty(TyArray(ty, self.mk_const(ty::Const {
|
self.mk_ty(TyArray(ty, ty::Const::from_usize(self, n)))
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.into()))),
|
|
||||||
ty: self.types.usize
|
|
||||||
})))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
|
|
@ -182,7 +182,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
|
||||||
ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
|
ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
|
||||||
ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)),
|
ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)),
|
||||||
ty::TyArray(_, n) => {
|
ty::TyArray(_, n) => {
|
||||||
match n.val.to_raw_bits() {
|
match n.assert_usize(tcx) {
|
||||||
Some(n) => format!("array of {} elements", n),
|
Some(n) => format!("array of {} elements", n),
|
||||||
None => "array".to_string(),
|
None => "array".to_string(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,7 +262,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
TyArray(ty, len) => {
|
TyArray(ty, len) => {
|
||||||
match len.val.to_raw_bits() {
|
match len.assert_usize(tcx) {
|
||||||
// If the array is definitely non-empty, it's uninhabited if
|
// If the array is definitely non-empty, it's uninhabited if
|
||||||
// the type of its elements is uninhabited.
|
// the type of its elements is uninhabited.
|
||||||
Some(n) if n != 0 => ty.uninhabited_from(visited, tcx),
|
Some(n) if n != 0 => ty.uninhabited_from(visited, tcx),
|
||||||
|
|
|
@ -543,7 +543,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let element = self.layout_of(element)?;
|
let element = self.layout_of(element)?;
|
||||||
let count = count.val.unwrap_u64();
|
let count = count.unwrap_usize(tcx);
|
||||||
let size = element.size.checked_mul(count, dl)
|
let size = element.size.checked_mul(count, dl)
|
||||||
.ok_or(LayoutError::SizeOverflow(ty))?;
|
.ok_or(LayoutError::SizeOverflow(ty))?;
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
use dep_graph::SerializedDepNodeIndex;
|
use dep_graph::SerializedDepNodeIndex;
|
||||||
use dep_graph::DepNode;
|
use dep_graph::DepNode;
|
||||||
use hir::def_id::{CrateNum, DefId, DefIndex};
|
use hir::def_id::{CrateNum, DefId, DefIndex};
|
||||||
use mir::interpret::{GlobalId};
|
use mir::interpret::{GlobalId, ConstValue};
|
||||||
use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal};
|
use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal};
|
||||||
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
|
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
|
||||||
use ty::subst::Substs;
|
use ty::subst::Substs;
|
||||||
|
@ -137,6 +137,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::super_predicates_of<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> QueryDescription<'tcx> for queries::const_value_to_allocation<'tcx> {
|
||||||
|
fn describe(_tcx: TyCtxt, (val, ty): (ConstValue<'tcx>, Ty<'tcx>)) -> String {
|
||||||
|
format!("converting value `{:?}` ({}) to an allocation", val, ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> QueryDescription<'tcx> for queries::erase_regions_ty<'tcx> {
|
impl<'tcx> QueryDescription<'tcx> for queries::erase_regions_ty<'tcx> {
|
||||||
fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String {
|
fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String {
|
||||||
format!("erasing regions from `{:?}`", ty)
|
format!("erasing regions from `{:?}`", ty)
|
||||||
|
|
|
@ -145,6 +145,15 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx>{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Key for (mir::interpret::ConstValue<'tcx>, Ty<'tcx>) {
|
||||||
|
fn map_crate(&self) -> CrateNum {
|
||||||
|
LOCAL_CRATE
|
||||||
|
}
|
||||||
|
fn default_span(&self, _: TyCtxt) -> Span {
|
||||||
|
DUMMY_SP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> Key for Ty<'tcx> {
|
impl<'tcx> Key for Ty<'tcx> {
|
||||||
fn map_crate(&self) -> CrateNum {
|
fn map_crate(&self) -> CrateNum {
|
||||||
LOCAL_CRATE
|
LOCAL_CRATE
|
||||||
|
|
|
@ -28,7 +28,7 @@ use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol};
|
||||||
use middle::const_val::EvalResult;
|
use middle::const_val::EvalResult;
|
||||||
use mir::mono::{CodegenUnit, Stats};
|
use mir::mono::{CodegenUnit, Stats};
|
||||||
use mir;
|
use mir;
|
||||||
use mir::interpret::{GlobalId};
|
use mir::interpret::{GlobalId, Allocation, ConstValue};
|
||||||
use session::{CompileResult, CrateDisambiguator};
|
use session::{CompileResult, CrateDisambiguator};
|
||||||
use session::config::OutputFilenames;
|
use session::config::OutputFilenames;
|
||||||
use traits::{self, Vtable};
|
use traits::{self, Vtable};
|
||||||
|
@ -228,6 +228,11 @@ define_maps! { <'tcx>
|
||||||
[] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
|
[] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
|
||||||
-> EvalResult<'tcx>,
|
-> EvalResult<'tcx>,
|
||||||
|
|
||||||
|
/// Converts a constant value to an constant allocation
|
||||||
|
[] fn const_value_to_allocation: const_value_to_allocation(
|
||||||
|
(ConstValue<'tcx>, Ty<'tcx>)
|
||||||
|
) -> &'tcx Allocation,
|
||||||
|
|
||||||
[] fn check_match: CheckMatch(DefId)
|
[] fn check_match: CheckMatch(DefId)
|
||||||
-> Result<(), ErrorReported>,
|
-> Result<(), ErrorReported>,
|
||||||
|
|
||||||
|
@ -478,6 +483,12 @@ fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> {
|
||||||
DepConstructor::EraseRegionsTy { ty }
|
DepConstructor::EraseRegionsTy { ty }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn const_value_to_allocation<'tcx>(
|
||||||
|
(val, ty): (ConstValue<'tcx>, Ty<'tcx>)
|
||||||
|
) -> DepConstructor<'tcx> {
|
||||||
|
DepConstructor::ConstValueToAllocation { val, ty }
|
||||||
|
}
|
||||||
|
|
||||||
fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
|
fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
|
||||||
DepConstructor::TypeParamPredicates {
|
DepConstructor::TypeParamPredicates {
|
||||||
item_id,
|
item_id,
|
||||||
|
|
|
@ -956,6 +956,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
|
||||||
DepKind::FulfillObligation |
|
DepKind::FulfillObligation |
|
||||||
DepKind::VtableMethods |
|
DepKind::VtableMethods |
|
||||||
DepKind::EraseRegionsTy |
|
DepKind::EraseRegionsTy |
|
||||||
|
DepKind::ConstValueToAllocation |
|
||||||
DepKind::NormalizeProjectionTy |
|
DepKind::NormalizeProjectionTy |
|
||||||
DepKind::NormalizeTyAfterErasingRegions |
|
DepKind::NormalizeTyAfterErasingRegions |
|
||||||
DepKind::DropckOutlives |
|
DepKind::DropckOutlives |
|
||||||
|
|
|
@ -22,12 +22,11 @@ use hir::svh::Svh;
|
||||||
use ich::Fingerprint;
|
use ich::Fingerprint;
|
||||||
use ich::StableHashingContext;
|
use ich::StableHashingContext;
|
||||||
use infer::canonical::{Canonical, Canonicalize};
|
use infer::canonical::{Canonical, Canonicalize};
|
||||||
use middle::const_val::ConstVal;
|
|
||||||
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
|
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
|
||||||
use middle::privacy::AccessLevels;
|
use middle::privacy::AccessLevels;
|
||||||
use middle::resolve_lifetime::ObjectLifetimeDefault;
|
use middle::resolve_lifetime::ObjectLifetimeDefault;
|
||||||
use mir::Mir;
|
use mir::Mir;
|
||||||
use mir::interpret::{GlobalId, Value, PrimVal};
|
use mir::interpret::GlobalId;
|
||||||
use mir::GeneratorLayout;
|
use mir::GeneratorLayout;
|
||||||
use session::CrateDisambiguator;
|
use session::CrateDisambiguator;
|
||||||
use traits::{self, Reveal};
|
use traits::{self, Reveal};
|
||||||
|
@ -1933,27 +1932,23 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||||
promoted: None
|
promoted: None
|
||||||
};
|
};
|
||||||
match tcx.const_eval(param_env.and(cid)) {
|
match tcx.const_eval(param_env.and(cid)) {
|
||||||
Ok(&ty::Const {
|
Ok(val) => {
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
|
// FIXME: Find the right type and use it instead of `val.ty` here
|
||||||
ty,
|
if let Some(b) = val.assert_bits(val.ty) {
|
||||||
}) => {
|
trace!("discriminants: {} ({:?})", b, repr_type);
|
||||||
trace!("discriminants: {} ({:?})", b, repr_type);
|
Some(Discr {
|
||||||
Some(Discr {
|
val: b,
|
||||||
val: b,
|
ty: val.ty,
|
||||||
ty,
|
})
|
||||||
})
|
} else {
|
||||||
},
|
info!("invalid enum discriminant: {:#?}", val);
|
||||||
Ok(&ty::Const {
|
::middle::const_val::struct_error(
|
||||||
val: ConstVal::Value(other),
|
tcx,
|
||||||
..
|
tcx.def_span(expr_did),
|
||||||
}) => {
|
"constant evaluation of enum discriminant resulted in non-integer",
|
||||||
info!("invalid enum discriminant: {:#?}", other);
|
).emit();
|
||||||
::middle::const_val::struct_error(
|
None
|
||||||
tcx,
|
}
|
||||||
tcx.def_span(expr_did),
|
|
||||||
"constant evaluation of enum discriminant resulted in non-integer",
|
|
||||||
).emit();
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
err.report(tcx, tcx.def_span(expr_did), "enum discriminant");
|
err.report(tcx, tcx.def_span(expr_did), "enum discriminant");
|
||||||
|
@ -1964,7 +1959,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
_ => span_bug!(tcx.def_span(expr_did), "const eval "),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ use middle::const_val::ConstVal;
|
||||||
use ty::subst::{Kind, UnpackedKind, Substs};
|
use ty::subst::{Kind, UnpackedKind, Substs};
|
||||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||||
use ty::error::{ExpectedFound, TypeError};
|
use ty::error::{ExpectedFound, TypeError};
|
||||||
use mir::interpret::{GlobalId, Value, PrimVal};
|
use mir::interpret::GlobalId;
|
||||||
use util::common::ErrorReported;
|
use util::common::ErrorReported;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
@ -469,8 +469,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
||||||
assert_eq!(sz_a.ty, tcx.types.usize);
|
assert_eq!(sz_a.ty, tcx.types.usize);
|
||||||
assert_eq!(sz_b.ty, tcx.types.usize);
|
assert_eq!(sz_b.ty, tcx.types.usize);
|
||||||
let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> {
|
let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> {
|
||||||
|
if let Some(s) = x.assert_usize(tcx) {
|
||||||
|
return Ok(s);
|
||||||
|
}
|
||||||
match x.val {
|
match x.val {
|
||||||
ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()),
|
|
||||||
ConstVal::Unevaluated(def_id, substs) => {
|
ConstVal::Unevaluated(def_id, substs) => {
|
||||||
// FIXME(eddyb) get the right param_env.
|
// FIXME(eddyb) get the right param_env.
|
||||||
let param_env = ty::ParamEnv::empty();
|
let param_env = ty::ParamEnv::empty();
|
||||||
|
@ -487,15 +489,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
||||||
instance,
|
instance,
|
||||||
promoted: None
|
promoted: None
|
||||||
};
|
};
|
||||||
match tcx.const_eval(param_env.and(cid)) {
|
if let Some(s) = tcx.const_eval(param_env.and(cid))
|
||||||
Ok(&ty::Const {
|
.ok()
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
|
.map(|c| c.unwrap_usize(tcx)) {
|
||||||
..
|
return Ok(s)
|
||||||
}) => {
|
|
||||||
assert_eq!(b as u64 as u128, b);
|
|
||||||
return Ok(b as u64);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,6 +19,7 @@ use ty::subst::{Substs, Subst, Kind, UnpackedKind};
|
||||||
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
|
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
|
||||||
use ty::{Slice, TyS};
|
use ty::{Slice, TyS};
|
||||||
use util::captures::Captures;
|
use util::captures::Captures;
|
||||||
|
use mir::interpret::{Allocation, PrimVal, MemoryPointer, Value, ConstValue};
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
@ -1730,4 +1731,156 @@ pub struct Const<'tcx> {
|
||||||
pub val: ConstVal<'tcx>,
|
pub val: ConstVal<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Const<'tcx> {
|
||||||
|
pub fn unevaluated(
|
||||||
|
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||||
|
def_id: DefId,
|
||||||
|
substs: &'tcx Substs<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> &'tcx Self {
|
||||||
|
tcx.mk_const(Const {
|
||||||
|
val: ConstVal::Unevaluated(def_id, substs),
|
||||||
|
ty,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_const_val(
|
||||||
|
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||||
|
val: ConstVal<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> &'tcx Self {
|
||||||
|
tcx.mk_const(Const {
|
||||||
|
val,
|
||||||
|
ty,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_const_value(
|
||||||
|
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||||
|
val: ConstValue<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> &'tcx Self {
|
||||||
|
Self::from_const_val(tcx, ConstVal::Value(val), ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_alloc(
|
||||||
|
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||||
|
alloc: &'tcx Allocation,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> &'tcx Self {
|
||||||
|
Self::from_const_value(tcx, ConstValue::ByRef(alloc), ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_byval_value(
|
||||||
|
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||||
|
val: Value,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> &'tcx Self {
|
||||||
|
Self::from_const_value(tcx, ConstValue::from_byval_value(val), ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_primval(
|
||||||
|
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||||
|
val: PrimVal,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> &'tcx Self {
|
||||||
|
Self::from_const_value(tcx, ConstValue::from_primval(val), ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_bits(
|
||||||
|
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||||
|
val: u128,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> &'tcx Self {
|
||||||
|
Self::from_primval(tcx, PrimVal::Bytes(val), ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
|
||||||
|
Self::from_primval(tcx, PrimVal::Undef, ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> &'tcx Self {
|
||||||
|
Self::from_bits(tcx, v as u128, tcx.types.bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self {
|
||||||
|
Self::from_bits(tcx, n as u128, tcx.types.usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_bits(&self, ty: Ty<'_>) -> Option<u128> {
|
||||||
|
if self.ty != ty {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
match self.val {
|
||||||
|
ConstVal::Value(val) => val.to_bits(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_ptr(&self) -> Option<MemoryPointer> {
|
||||||
|
match self.val {
|
||||||
|
ConstVal::Value(val) => val.to_ptr(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_primval(&self) -> Option<PrimVal> {
|
||||||
|
match self.val {
|
||||||
|
ConstVal::Value(val) => val.to_primval(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn assert_bits(&self, ty: Ty<'_>) -> Option<u128> {
|
||||||
|
assert_eq!(self.ty, ty);
|
||||||
|
match self.val {
|
||||||
|
ConstVal::Value(val) => val.to_bits(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn assert_bool(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<bool> {
|
||||||
|
self.assert_bits(tcx.types.bool).and_then(|v| match v {
|
||||||
|
0 => Some(false),
|
||||||
|
1 => Some(true),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn assert_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<u64> {
|
||||||
|
self.assert_bits(tcx.types.usize).map(|v| v as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn unwrap_bits(&self, ty: Ty<'_>) -> u128 {
|
||||||
|
match self.assert_bits(ty) {
|
||||||
|
Some(val) => val,
|
||||||
|
None => bug!("expected bits of {}, got {:#?}", ty, self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn unwrap_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> u64 {
|
||||||
|
match self.assert_usize(tcx) {
|
||||||
|
Some(val) => val,
|
||||||
|
None => bug!("expected constant usize, got {:#?}", self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {}
|
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {}
|
||||||
|
|
|
@ -25,7 +25,6 @@ use ty::TypeVariants::*;
|
||||||
use ty::layout::{Integer, IntegerExt};
|
use ty::layout::{Integer, IntegerExt};
|
||||||
use util::common::ErrorReported;
|
use util::common::ErrorReported;
|
||||||
use middle::lang_items;
|
use middle::lang_items;
|
||||||
use mir::interpret::{Value, PrimVal};
|
|
||||||
|
|
||||||
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
|
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
|
||||||
HashStable};
|
HashStable};
|
||||||
|
@ -659,9 +658,8 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
|
||||||
TyArray(_, n) => {
|
TyArray(_, n) => {
|
||||||
self.hash_discriminant_u8(&n.val);
|
self.hash_discriminant_u8(&n.val);
|
||||||
match n.val {
|
match n.val {
|
||||||
ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b),
|
ConstVal::Value(alloc) => self.hash(alloc),
|
||||||
ConstVal::Unevaluated(def_id, _) => self.def_id(def_id),
|
ConstVal::Unevaluated(def_id, _) => self.def_id(def_id),
|
||||||
_ => bug!("arrays should not have {:?} as length", n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TyRawPtr(m) => self.hash(m.mutbl),
|
TyRawPtr(m) => self.hash(m.mutbl),
|
||||||
|
|
|
@ -21,7 +21,6 @@ use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, Ty
|
||||||
use ty::{TyDynamic, TyInt, TyUint, TyInfer};
|
use ty::{TyDynamic, TyInt, TyUint, TyInfer};
|
||||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||||
use util::nodemap::FxHashSet;
|
use util::nodemap::FxHashSet;
|
||||||
use mir::interpret::{Value, PrimVal};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -1183,15 +1182,12 @@ define_print! {
|
||||||
TyArray(ty, sz) => {
|
TyArray(ty, sz) => {
|
||||||
print!(f, cx, write("["), print(ty), write("; "))?;
|
print!(f, cx, write("["), print(ty), write("; "))?;
|
||||||
match sz.val {
|
match sz.val {
|
||||||
ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => {
|
ConstVal::Value(..) => ty::tls::with(|tcx| {
|
||||||
write!(f, "{}", sz)?;
|
write!(f, "{}", sz.unwrap_usize(tcx))
|
||||||
}
|
})?,
|
||||||
ConstVal::Unevaluated(_def_id, _substs) => {
|
ConstVal::Unevaluated(_def_id, _substs) => {
|
||||||
write!(f, "_")?;
|
write!(f, "_")?;
|
||||||
}
|
}
|
||||||
_ => {
|
|
||||||
write!(f, "{:?}", sz)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
write!(f, "]")
|
write!(f, "]")
|
||||||
}
|
}
|
||||||
|
|
|
@ -425,7 +425,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
||||||
ProjectionElem::Subslice { from, to } => PlaceTy::Ty {
|
ProjectionElem::Subslice { from, to } => PlaceTy::Ty {
|
||||||
ty: match base_ty.sty {
|
ty: match base_ty.sty {
|
||||||
ty::TyArray(inner, size) => {
|
ty::TyArray(inner, size) => {
|
||||||
let size = size.val.unwrap_u64();
|
let size = size.unwrap_usize(tcx);
|
||||||
let min_size = (from as u64) + (to as u64);
|
let min_size = (from as u64) + (to as u64);
|
||||||
if let Some(rest_size) = size.checked_sub(min_size) {
|
if let Some(rest_size) = size.checked_sub(min_size) {
|
||||||
tcx.mk_array(inner, rest_size)
|
tcx.mk_array(inner, rest_size)
|
||||||
|
|
|
@ -16,11 +16,10 @@ use rustc_data_structures::indexed_vec::Idx;
|
||||||
use build::{BlockAnd, BlockAndExtension, Builder};
|
use build::{BlockAnd, BlockAndExtension, Builder};
|
||||||
use build::expr::category::{Category, RvalueFunc};
|
use build::expr::category::{Category, RvalueFunc};
|
||||||
use hair::*;
|
use hair::*;
|
||||||
use rustc::middle::const_val::ConstVal;
|
|
||||||
use rustc::middle::region;
|
use rustc::middle::region;
|
||||||
use rustc::ty::{self, Ty, UpvarSubsts};
|
use rustc::ty::{self, Ty, UpvarSubsts};
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::mir::interpret::{Value, PrimVal, EvalErrorKind};
|
use rustc::mir::interpret::EvalErrorKind;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
|
@ -200,10 +199,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
span: expr_span,
|
span: expr_span,
|
||||||
ty: this.hir.tcx().types.u32,
|
ty: this.hir.tcx().types.u32,
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: this.hir.tcx().mk_const(ty::Const {
|
value: ty::Const::from_bits(
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
|
this.hir.tcx(),
|
||||||
ty: this.hir.tcx().types.u32
|
0,
|
||||||
}),
|
this.hir.tcx().types.u32),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
box AggregateKind::Generator(closure_id, substs, movability)
|
box AggregateKind::Generator(closure_id, substs, movability)
|
||||||
|
@ -378,10 +377,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
let bits = self.hir.integer_bit_width(ty);
|
let bits = self.hir.integer_bit_width(ty);
|
||||||
let n = (!0u128) >> (128 - bits);
|
let n = (!0u128) >> (128 - bits);
|
||||||
let literal = Literal::Value {
|
let literal = Literal::Value {
|
||||||
value: self.hir.tcx().mk_const(ty::Const {
|
value: ty::Const::from_bits(self.hir.tcx(), n, ty)
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
|
|
||||||
ty
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.literal_operand(span, ty, literal)
|
self.literal_operand(span, ty, literal)
|
||||||
|
@ -393,10 +389,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
let bits = self.hir.integer_bit_width(ty);
|
let bits = self.hir.integer_bit_width(ty);
|
||||||
let n = 1 << (bits - 1);
|
let n = 1 << (bits - 1);
|
||||||
let literal = Literal::Value {
|
let literal = Literal::Value {
|
||||||
value: self.hir.tcx().mk_const(ty::Const {
|
value: ty::Const::from_bits(self.hir.tcx(), n, ty)
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
|
|
||||||
ty
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.literal_operand(span, ty, literal)
|
self.literal_operand(span, ty, literal)
|
||||||
|
|
|
@ -122,12 +122,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
match *match_pair.pattern.kind {
|
match *match_pair.pattern.kind {
|
||||||
PatternKind::Constant { value } => {
|
PatternKind::Constant { value } => {
|
||||||
// if the places match, the type should match
|
|
||||||
assert_eq!(match_pair.pattern.ty, switch_ty);
|
|
||||||
|
|
||||||
indices.entry(value)
|
indices.entry(value)
|
||||||
.or_insert_with(|| {
|
.or_insert_with(|| {
|
||||||
options.push(value.val.to_raw_bits().expect("switching on int"));
|
options.push(value.unwrap_bits(switch_ty));
|
||||||
options.len() - 1
|
options.len() - 1
|
||||||
});
|
});
|
||||||
true
|
true
|
||||||
|
|
|
@ -13,9 +13,7 @@
|
||||||
|
|
||||||
use build::Builder;
|
use build::Builder;
|
||||||
|
|
||||||
use rustc::middle::const_val::ConstVal;
|
|
||||||
use rustc::ty::{self, Ty};
|
use rustc::ty::{self, Ty};
|
||||||
use rustc::mir::interpret::{Value, PrimVal};
|
|
||||||
|
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use syntax_pos::{Span, DUMMY_SP};
|
use syntax_pos::{Span, DUMMY_SP};
|
||||||
|
@ -64,10 +62,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let literal = Literal::Value {
|
let literal = Literal::Value {
|
||||||
value: self.hir.tcx().mk_const(ty::Const {
|
value: ty::Const::from_bits(self.hir.tcx(), 0, ty)
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
|
|
||||||
ty
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.literal_operand(span, ty, literal)
|
self.literal_operand(span, ty, literal)
|
||||||
|
|
|
@ -14,8 +14,7 @@ use hair::cx::Cx;
|
||||||
use hair::cx::block;
|
use hair::cx::block;
|
||||||
use hair::cx::to_ref::ToRef;
|
use hair::cx::to_ref::ToRef;
|
||||||
use rustc::hir::def::{Def, CtorKind};
|
use rustc::hir::def::{Def, CtorKind};
|
||||||
use rustc::middle::const_val::ConstVal;
|
use rustc::mir::interpret::GlobalId;
|
||||||
use rustc::mir::interpret::{GlobalId, Value, PrimVal};
|
|
||||||
use rustc::ty::{self, AdtKind, Ty};
|
use rustc::ty::{self, AdtKind, Ty};
|
||||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
|
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
|
||||||
use rustc::ty::cast::CastKind as TyCastKind;
|
use rustc::ty::cast::CastKind as TyCastKind;
|
||||||
|
@ -522,7 +521,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||||
promoted: None
|
promoted: None
|
||||||
};
|
};
|
||||||
let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) {
|
let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) {
|
||||||
Ok(cv) => cv.val.unwrap_u64(),
|
Ok(cv) => cv.unwrap_usize(cx.tcx),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
e.report(cx.tcx, cx.tcx.def_span(def_id), "array length");
|
e.report(cx.tcx, cx.tcx.def_span(def_id), "array length");
|
||||||
0
|
0
|
||||||
|
@ -635,22 +634,17 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||||
span: expr.span,
|
span: expr.span,
|
||||||
kind: ExprKind::Literal {
|
kind: ExprKind::Literal {
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: cx.tcx().mk_const(ty::Const {
|
value: val,
|
||||||
val,
|
|
||||||
ty,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}.to_ref();
|
}.to_ref();
|
||||||
let offset = mk_const(
|
let offset = mk_const(ty::Const::from_bits(cx.tcx, offset as u128, ty));
|
||||||
ConstVal::Value(Value::ByVal(PrimVal::Bytes(offset as u128))),
|
|
||||||
);
|
|
||||||
match did {
|
match did {
|
||||||
Some(did) => {
|
Some(did) => {
|
||||||
// in case we are offsetting from a computed discriminant
|
// in case we are offsetting from a computed discriminant
|
||||||
// and not the beginning of discriminants (which is always `0`)
|
// and not the beginning of discriminants (which is always `0`)
|
||||||
let substs = Substs::identity_for_item(cx.tcx(), did);
|
let substs = Substs::identity_for_item(cx.tcx(), did);
|
||||||
let lhs = mk_const(ConstVal::Unevaluated(did, substs));
|
let lhs = mk_const(ty::Const::unevaluated(cx.tcx(), did, substs, ty));
|
||||||
let bin = ExprKind::Binary {
|
let bin = ExprKind::Binary {
|
||||||
op: BinOp::Add,
|
op: BinOp::Add,
|
||||||
lhs,
|
lhs,
|
||||||
|
@ -707,10 +701,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||||
span: expr.span,
|
span: expr.span,
|
||||||
kind: ExprKind::Literal {
|
kind: ExprKind::Literal {
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: cx.tcx().mk_const(ty::Const {
|
value: ty::Const::zero_sized(cx.tcx(), ty),
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
|
|
||||||
ty
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -764,20 +755,20 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||||
Def::StructCtor(_, CtorKind::Fn) |
|
Def::StructCtor(_, CtorKind::Fn) |
|
||||||
Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal {
|
Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal {
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: cx.tcx.mk_const(ty::Const {
|
value: ty::Const::zero_sized(
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
|
cx.tcx,
|
||||||
ty: cx.tables().node_id_to_type(expr.hir_id)
|
cx.tables().node_id_to_type(expr.hir_id)),
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
Def::Const(def_id) |
|
Def::Const(def_id) |
|
||||||
Def::AssociatedConst(def_id) => ExprKind::Literal {
|
Def::AssociatedConst(def_id) => ExprKind::Literal {
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: cx.tcx.mk_const(ty::Const {
|
value: ty::Const::unevaluated(
|
||||||
val: ConstVal::Unevaluated(def_id, substs),
|
cx.tcx,
|
||||||
ty: cx.tables().node_id_to_type(expr.hir_id)
|
def_id,
|
||||||
}),
|
substs,
|
||||||
|
cx.tables().node_id_to_type(expr.hir_id))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
use hair::*;
|
use hair::*;
|
||||||
|
|
||||||
use rustc::middle::const_val::ConstVal;
|
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc::hir::map::blocks::FnLikeNode;
|
use rustc::hir::map::blocks::FnLikeNode;
|
||||||
|
@ -31,7 +30,6 @@ use syntax::attr;
|
||||||
use syntax::symbol::Symbol;
|
use syntax::symbol::Symbol;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc::mir::interpret::{Value, PrimVal};
|
|
||||||
use hair::pattern::parse_float;
|
use hair::pattern::parse_float;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -117,10 +115,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
|
pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
|
||||||
Literal::Value {
|
Literal::Value {
|
||||||
value: self.tcx.mk_const(ty::Const {
|
value: ty::Const::from_usize(self.tcx, value),
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))),
|
|
||||||
ty: self.tcx.types.usize
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,19 +129,13 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
pub fn true_literal(&mut self) -> Literal<'tcx> {
|
pub fn true_literal(&mut self) -> Literal<'tcx> {
|
||||||
Literal::Value {
|
Literal::Value {
|
||||||
value: self.tcx.mk_const(ty::Const {
|
value: ty::Const::from_bool(self.tcx, true),
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))),
|
|
||||||
ty: self.tcx.types.bool
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn false_literal(&mut self) -> Literal<'tcx> {
|
pub fn false_literal(&mut self) -> Literal<'tcx> {
|
||||||
Literal::Value {
|
Literal::Value {
|
||||||
value: self.tcx.mk_const(ty::Const {
|
value: ty::Const::from_bool(self.tcx, false),
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
|
|
||||||
ty: self.tcx.types.bool
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +151,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||||
layout::Integer::from_attr(self.tcx, ty).size().bits()
|
layout::Integer::from_attr(self.tcx, ty).size().bits()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Combine with rustc_mir::hair::pattern::lit_to_const
|
||||||
pub fn const_eval_literal(
|
pub fn const_eval_literal(
|
||||||
&mut self,
|
&mut self,
|
||||||
lit: &'tcx ast::LitKind,
|
lit: &'tcx ast::LitKind,
|
||||||
|
@ -171,7 +161,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||||
) -> Literal<'tcx> {
|
) -> Literal<'tcx> {
|
||||||
trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
|
trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
|
||||||
|
|
||||||
let parse_float = |num, fty| -> Value {
|
let parse_float = |num, fty| -> ConstValue<'tcx> {
|
||||||
parse_float(num, fty, neg).unwrap_or_else(|_| {
|
parse_float(num, fty, neg).unwrap_or_else(|_| {
|
||||||
// FIXME(#31407) this is only necessary because float parsing is buggy
|
// FIXME(#31407) this is only necessary because float parsing is buggy
|
||||||
self.tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)");
|
self.tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)");
|
||||||
|
@ -193,7 +183,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||||
let s = s.as_str();
|
let s = s.as_str();
|
||||||
let id = self.tcx.allocate_cached(s.as_bytes());
|
let id = self.tcx.allocate_cached(s.as_bytes());
|
||||||
let ptr = MemoryPointer::new(id, 0);
|
let ptr = MemoryPointer::new(id, 0);
|
||||||
Value::ByValPair(
|
ConstValue::ByValPair(
|
||||||
PrimVal::Ptr(ptr),
|
PrimVal::Ptr(ptr),
|
||||||
PrimVal::from_u128(s.len() as u128),
|
PrimVal::from_u128(s.len() as u128),
|
||||||
)
|
)
|
||||||
|
@ -201,16 +191,16 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||||
LitKind::ByteStr(ref data) => {
|
LitKind::ByteStr(ref data) => {
|
||||||
let id = self.tcx.allocate_cached(data);
|
let id = self.tcx.allocate_cached(data);
|
||||||
let ptr = MemoryPointer::new(id, 0);
|
let ptr = MemoryPointer::new(id, 0);
|
||||||
Value::ByVal(PrimVal::Ptr(ptr))
|
ConstValue::ByVal(PrimVal::Ptr(ptr))
|
||||||
},
|
},
|
||||||
LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
|
LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)),
|
||||||
LitKind::Int(n, _) if neg => {
|
LitKind::Int(n, _) if neg => {
|
||||||
let n = n as i128;
|
let n = n as i128;
|
||||||
let n = n.overflowing_neg().0;
|
let n = n.overflowing_neg().0;
|
||||||
let n = clamp(n as u128);
|
let n = clamp(n as u128);
|
||||||
Value::ByVal(PrimVal::Bytes(n))
|
ConstValue::ByVal(PrimVal::Bytes(n))
|
||||||
},
|
},
|
||||||
LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(clamp(n))),
|
LitKind::Int(n, _) => ConstValue::ByVal(PrimVal::Bytes(clamp(n))),
|
||||||
LitKind::Float(n, fty) => {
|
LitKind::Float(n, fty) => {
|
||||||
parse_float(n, fty)
|
parse_float(n, fty)
|
||||||
}
|
}
|
||||||
|
@ -221,14 +211,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||||
};
|
};
|
||||||
parse_float(n, fty)
|
parse_float(n, fty)
|
||||||
}
|
}
|
||||||
LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
|
LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)),
|
||||||
LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
|
LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)),
|
||||||
};
|
};
|
||||||
Literal::Value {
|
Literal::Value {
|
||||||
value: self.tcx.mk_const(ty::Const {
|
value: ty::Const::from_const_value(self.tcx, lit, ty)
|
||||||
val: ConstVal::Value(lit),
|
|
||||||
ty,
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,11 +245,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||||
let method_ty = method_ty.subst(self.tcx, substs);
|
let method_ty = method_ty.subst(self.tcx, substs);
|
||||||
return (method_ty,
|
return (method_ty,
|
||||||
Literal::Value {
|
Literal::Value {
|
||||||
value: self.tcx.mk_const(ty::Const {
|
value: ty::Const::zero_sized(self.tcx, method_ty)
|
||||||
// ZST function type
|
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
|
|
||||||
ty: method_ty
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ use rustc::hir::RangeEnd;
|
||||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||||
|
|
||||||
use rustc::mir::Field;
|
use rustc::mir::Field;
|
||||||
use rustc::mir::interpret::{Value, PrimVal};
|
|
||||||
use rustc::util::common::ErrorReported;
|
use rustc::util::common::ErrorReported;
|
||||||
|
|
||||||
use syntax_pos::{Span, DUMMY_SP};
|
use syntax_pos::{Span, DUMMY_SP};
|
||||||
|
@ -180,37 +179,34 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
|
||||||
self.byte_array_map.entry(pat).or_insert_with(|| {
|
self.byte_array_map.entry(pat).or_insert_with(|| {
|
||||||
match pat.kind {
|
match pat.kind {
|
||||||
box PatternKind::Constant {
|
box PatternKind::Constant {
|
||||||
value: &ty::Const { val: ConstVal::Value(b), ty }
|
value: const_val
|
||||||
} => {
|
} => {
|
||||||
match b {
|
if let Some(ptr) = const_val.to_ptr() {
|
||||||
Value::ByVal(PrimVal::Ptr(ptr)) => {
|
let is_array_ptr = const_val.ty
|
||||||
let is_array_ptr = ty
|
.builtin_deref(true)
|
||||||
.builtin_deref(true)
|
.and_then(|t| t.ty.builtin_index())
|
||||||
.and_then(|t| t.ty.builtin_index())
|
.map_or(false, |t| t == tcx.types.u8);
|
||||||
.map_or(false, |t| t == tcx.types.u8);
|
assert!(is_array_ptr);
|
||||||
assert!(is_array_ptr);
|
let alloc = tcx
|
||||||
let alloc = tcx
|
.interpret_interner
|
||||||
.interpret_interner
|
.get_alloc(ptr.alloc_id)
|
||||||
.get_alloc(ptr.alloc_id)
|
.unwrap();
|
||||||
.unwrap();
|
assert_eq!(ptr.offset, 0);
|
||||||
assert_eq!(ptr.offset, 0);
|
// FIXME: check length
|
||||||
// FIXME: check length
|
alloc.bytes.iter().map(|b| {
|
||||||
alloc.bytes.iter().map(|b| {
|
&*pattern_arena.alloc(Pattern {
|
||||||
&*pattern_arena.alloc(Pattern {
|
ty: tcx.types.u8,
|
||||||
ty: tcx.types.u8,
|
span: pat.span,
|
||||||
span: pat.span,
|
kind: box PatternKind::Constant {
|
||||||
kind: box PatternKind::Constant {
|
value: ty::Const::from_bits(
|
||||||
value: tcx.mk_const(ty::Const {
|
tcx,
|
||||||
val: ConstVal::Value(Value::ByVal(
|
*b as u128,
|
||||||
PrimVal::Bytes(*b as u128),
|
tcx.types.u8)
|
||||||
)),
|
}
|
||||||
ty: tcx.types.u8
|
})
|
||||||
})
|
}).collect()
|
||||||
}
|
} else {
|
||||||
})
|
bug!("not a byte str: {:?}", const_val)
|
||||||
}).collect()
|
|
||||||
},
|
|
||||||
_ => bug!("not a byte str: {:?}", b),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat)
|
_ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat)
|
||||||
|
@ -439,14 +435,11 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||||
match pcx.ty.sty {
|
match pcx.ty.sty {
|
||||||
ty::TyBool => {
|
ty::TyBool => {
|
||||||
[true, false].iter().map(|&b| {
|
[true, false].iter().map(|&b| {
|
||||||
ConstantValue(cx.tcx.mk_const(ty::Const {
|
ConstantValue(ty::Const::from_bool(cx.tcx, b))
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))),
|
|
||||||
ty: cx.tcx.types.bool
|
|
||||||
}))
|
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
ty::TyArray(ref sub_ty, len) if len.val.to_raw_bits().is_some() => {
|
ty::TyArray(ref sub_ty, len) if len.assert_usize(cx.tcx).is_some() => {
|
||||||
let len = len.val.unwrap_u64();
|
let len = len.unwrap_usize(cx.tcx);
|
||||||
if len != 0 && cx.is_uninhabited(sub_ty) {
|
if len != 0 && cx.is_uninhabited(sub_ty) {
|
||||||
vec![]
|
vec![]
|
||||||
} else {
|
} else {
|
||||||
|
@ -554,21 +547,23 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
|
||||||
for row in patterns {
|
for row in patterns {
|
||||||
match *row.kind {
|
match *row.kind {
|
||||||
PatternKind::Constant {
|
PatternKind::Constant {
|
||||||
value: &ty::Const {
|
value: const_val @ &ty::Const {
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))),
|
val: ConstVal::Value(..),
|
||||||
ty,
|
..
|
||||||
}
|
}
|
||||||
} => {
|
} => {
|
||||||
let is_array_ptr = ty
|
if let Some(ptr) = const_val.to_ptr() {
|
||||||
.builtin_deref(true)
|
let is_array_ptr = const_val.ty
|
||||||
.and_then(|t| t.ty.builtin_index())
|
.builtin_deref(true)
|
||||||
.map_or(false, |t| t == cx.tcx.types.u8);
|
.and_then(|t| t.ty.builtin_index())
|
||||||
if is_array_ptr {
|
.map_or(false, |t| t == cx.tcx.types.u8);
|
||||||
let alloc = cx.tcx
|
if is_array_ptr {
|
||||||
.interpret_interner
|
let alloc = cx.tcx
|
||||||
.get_alloc(ptr.alloc_id)
|
.interpret_interner
|
||||||
.unwrap();
|
.get_alloc(ptr.alloc_id)
|
||||||
max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
|
.unwrap();
|
||||||
|
max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
|
PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
|
||||||
|
@ -836,7 +831,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
|
||||||
/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
|
/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
|
||||||
///
|
///
|
||||||
/// Returns None in case of a catch-all, which can't be specialized.
|
/// Returns None in case of a catch-all, which can't be specialized.
|
||||||
fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
|
fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt,
|
||||||
pat: &Pattern<'tcx>,
|
pat: &Pattern<'tcx>,
|
||||||
pcx: PatternContext)
|
pcx: PatternContext)
|
||||||
-> Option<Vec<Constructor<'tcx>>>
|
-> Option<Vec<Constructor<'tcx>>>
|
||||||
|
@ -854,7 +849,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
|
||||||
Some(vec![ConstantRange(lo, hi, end)]),
|
Some(vec![ConstantRange(lo, hi, end)]),
|
||||||
PatternKind::Array { .. } => match pcx.ty.sty {
|
PatternKind::Array { .. } => match pcx.ty.sty {
|
||||||
ty::TyArray(_, length) => Some(vec![
|
ty::TyArray(_, length) => Some(vec![
|
||||||
Slice(length.val.unwrap_u64())
|
Slice(length.unwrap_usize(cx.tcx))
|
||||||
]),
|
]),
|
||||||
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
|
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
|
||||||
},
|
},
|
||||||
|
@ -934,27 +929,31 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
|
fn slice_pat_covered_by_constructor<'tcx>(
|
||||||
ctor: &Constructor,
|
tcx: TyCtxt<'_, 'tcx, '_>,
|
||||||
prefix: &[Pattern],
|
_span: Span,
|
||||||
slice: &Option<Pattern>,
|
ctor: &Constructor,
|
||||||
suffix: &[Pattern])
|
prefix: &[Pattern<'tcx>],
|
||||||
-> Result<bool, ErrorReported> {
|
slice: &Option<Pattern<'tcx>>,
|
||||||
|
suffix: &[Pattern<'tcx>]
|
||||||
|
) -> Result<bool, ErrorReported> {
|
||||||
let data: &[u8] = match *ctor {
|
let data: &[u8] = match *ctor {
|
||||||
ConstantValue(&ty::Const { val: ConstVal::Value(
|
ConstantValue(const_val @ &ty::Const { val: ConstVal::Value(..), .. }) => {
|
||||||
Value::ByVal(PrimVal::Ptr(ptr))
|
if let Some(ptr) = const_val.to_ptr() {
|
||||||
), ty }) => {
|
let is_array_ptr = const_val.ty
|
||||||
let is_array_ptr = ty
|
.builtin_deref(true)
|
||||||
.builtin_deref(true)
|
.and_then(|t| t.ty.builtin_index())
|
||||||
.and_then(|t| t.ty.builtin_index())
|
.map_or(false, |t| t == tcx.types.u8);
|
||||||
.map_or(false, |t| t == tcx.types.u8);
|
assert!(is_array_ptr);
|
||||||
assert!(is_array_ptr);
|
tcx
|
||||||
tcx
|
.interpret_interner
|
||||||
.interpret_interner
|
.get_alloc(ptr.alloc_id)
|
||||||
.get_alloc(ptr.alloc_id)
|
.unwrap()
|
||||||
.unwrap()
|
.bytes
|
||||||
.bytes
|
.as_ref()
|
||||||
.as_ref()
|
} else {
|
||||||
|
bug!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => bug!()
|
_ => bug!()
|
||||||
};
|
};
|
||||||
|
@ -969,15 +968,13 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
|
||||||
data[data.len()-suffix.len()..].iter().zip(suffix))
|
data[data.len()-suffix.len()..].iter().zip(suffix))
|
||||||
{
|
{
|
||||||
match pat.kind {
|
match pat.kind {
|
||||||
box PatternKind::Constant { value } => match value.val {
|
box PatternKind::Constant { value } => {
|
||||||
ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
|
let b = value.unwrap_bits(pat.ty);
|
||||||
assert_eq!(b as u8 as u128, b);
|
assert_eq!(b as u8 as u128, b);
|
||||||
if b as u8 != *ch {
|
if b as u8 != *ch {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => span_bug!(pat.span, "bad const u8 {:?}", value)
|
}
|
||||||
},
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -987,8 +984,8 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
|
||||||
|
|
||||||
fn constructor_covered_by_range<'a, 'tcx>(
|
fn constructor_covered_by_range<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
ctor: &Constructor,
|
ctor: &Constructor<'tcx>,
|
||||||
from: &ConstVal, to: &ConstVal,
|
from: &'tcx ty::Const<'tcx>, to: &'tcx ty::Const<'tcx>,
|
||||||
end: RangeEnd,
|
end: RangeEnd,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Result<bool, ErrorReported> {
|
) -> Result<bool, ErrorReported> {
|
||||||
|
@ -1006,22 +1003,22 @@ fn constructor_covered_by_range<'a, 'tcx>(
|
||||||
}
|
}
|
||||||
match *ctor {
|
match *ctor {
|
||||||
ConstantValue(value) => {
|
ConstantValue(value) => {
|
||||||
let to = some_or_ok!(cmp_to(&value.val));
|
let to = some_or_ok!(cmp_to(value));
|
||||||
let end = (to == Ordering::Less) ||
|
let end = (to == Ordering::Less) ||
|
||||||
(end == RangeEnd::Included && to == Ordering::Equal);
|
(end == RangeEnd::Included && to == Ordering::Equal);
|
||||||
Ok(some_or_ok!(cmp_from(&value.val)) && end)
|
Ok(some_or_ok!(cmp_from(value)) && end)
|
||||||
},
|
},
|
||||||
ConstantRange(from, to, RangeEnd::Included) => {
|
ConstantRange(from, to, RangeEnd::Included) => {
|
||||||
let to = some_or_ok!(cmp_to(&to.val));
|
let to = some_or_ok!(cmp_to(to));
|
||||||
let end = (to == Ordering::Less) ||
|
let end = (to == Ordering::Less) ||
|
||||||
(end == RangeEnd::Included && to == Ordering::Equal);
|
(end == RangeEnd::Included && to == Ordering::Equal);
|
||||||
Ok(some_or_ok!(cmp_from(&from.val)) && end)
|
Ok(some_or_ok!(cmp_from(from)) && end)
|
||||||
},
|
},
|
||||||
ConstantRange(from, to, RangeEnd::Excluded) => {
|
ConstantRange(from, to, RangeEnd::Excluded) => {
|
||||||
let to = some_or_ok!(cmp_to(&to.val));
|
let to = some_or_ok!(cmp_to(to));
|
||||||
let end = (to == Ordering::Less) ||
|
let end = (to == Ordering::Less) ||
|
||||||
(end == RangeEnd::Excluded && to == Ordering::Equal);
|
(end == RangeEnd::Excluded && to == Ordering::Equal);
|
||||||
Ok(some_or_ok!(cmp_from(&from.val)) && end)
|
Ok(some_or_ok!(cmp_from(from)) && end)
|
||||||
}
|
}
|
||||||
Single => Ok(true),
|
Single => Ok(true),
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
|
@ -1083,8 +1080,8 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
||||||
|
|
||||||
PatternKind::Constant { value } => {
|
PatternKind::Constant { value } => {
|
||||||
match *constructor {
|
match *constructor {
|
||||||
Slice(..) => match value.val {
|
Slice(..) => {
|
||||||
ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => {
|
if let Some(ptr) = value.to_ptr() {
|
||||||
let is_array_ptr = value.ty
|
let is_array_ptr = value.ty
|
||||||
.builtin_deref(true)
|
.builtin_deref(true)
|
||||||
.and_then(|t| t.ty.builtin_index())
|
.and_then(|t| t.ty.builtin_index())
|
||||||
|
@ -1101,14 +1098,15 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
_ => span_bug!(pat.span,
|
span_bug!(pat.span,
|
||||||
"unexpected const-val {:?} with ctor {:?}", value, constructor)
|
"unexpected const-val {:?} with ctor {:?}", value, constructor)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
match constructor_covered_by_range(
|
match constructor_covered_by_range(
|
||||||
cx.tcx,
|
cx.tcx,
|
||||||
constructor, &value.val, &value.val, RangeEnd::Included,
|
constructor, value, value, RangeEnd::Included,
|
||||||
value.ty,
|
value.ty,
|
||||||
) {
|
) {
|
||||||
Ok(true) => Some(vec![]),
|
Ok(true) => Some(vec![]),
|
||||||
|
@ -1122,7 +1120,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
||||||
PatternKind::Range { lo, hi, ref end } => {
|
PatternKind::Range { lo, hi, ref end } => {
|
||||||
match constructor_covered_by_range(
|
match constructor_covered_by_range(
|
||||||
cx.tcx,
|
cx.tcx,
|
||||||
constructor, &lo.val, &hi.val, end.clone(), lo.ty,
|
constructor, lo, hi, end.clone(), lo.ty,
|
||||||
) {
|
) {
|
||||||
Ok(true) => Some(vec![]),
|
Ok(true) => Some(vec![]),
|
||||||
Ok(false) => None,
|
Ok(false) => None,
|
||||||
|
|
|
@ -19,8 +19,8 @@ pub(crate) use self::check_match::check_match;
|
||||||
use interpret::{const_val_field, const_variant_index, self};
|
use interpret::{const_val_field, const_variant_index, self};
|
||||||
|
|
||||||
use rustc::middle::const_val::ConstVal;
|
use rustc::middle::const_val::ConstVal;
|
||||||
use rustc::mir::{Field, BorrowKind, Mutability};
|
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
|
||||||
use rustc::mir::interpret::{GlobalId, Value, PrimVal};
|
use rustc::mir::interpret::{PrimVal, GlobalId, ConstValue};
|
||||||
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
|
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
|
||||||
use rustc::ty::subst::{Substs, Kind};
|
use rustc::ty::subst::{Substs, Kind};
|
||||||
use rustc::hir::{self, PatKind, RangeEnd};
|
use rustc::hir::{self, PatKind, RangeEnd};
|
||||||
|
@ -124,24 +124,11 @@ pub enum PatternKind<'tcx> {
|
||||||
|
|
||||||
fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result {
|
fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match value.val {
|
match value.val {
|
||||||
ConstVal::Value(v) => print_miri_value(v, value.ty, f),
|
ConstVal::Value(..) => fmt_const_val(f, value),
|
||||||
ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
|
ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
use rustc::ty::TypeVariants::*;
|
|
||||||
match (value, &ty.sty) {
|
|
||||||
(Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"),
|
|
||||||
(Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"),
|
|
||||||
(Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n),
|
|
||||||
(Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128),
|
|
||||||
(Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
|
|
||||||
write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
|
|
||||||
_ => bug!("{:?}: {} not printable in a pattern", value, ty),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> fmt::Display for Pattern<'tcx> {
|
impl<'tcx> fmt::Display for Pattern<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self.kind {
|
match *self.kind {
|
||||||
|
@ -372,7 +359,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
(PatternKind::Constant { value: lo },
|
(PatternKind::Constant { value: lo },
|
||||||
PatternKind::Constant { value: hi }) => {
|
PatternKind::Constant { value: hi }) => {
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
match (end, compare_const_vals(self.tcx, &lo.val, &hi.val, ty).unwrap()) {
|
match (end, compare_const_vals(self.tcx, lo, hi, ty).unwrap()) {
|
||||||
(RangeEnd::Excluded, Ordering::Less) =>
|
(RangeEnd::Excluded, Ordering::Less) =>
|
||||||
PatternKind::Range { lo, hi, end },
|
PatternKind::Range { lo, hi, end },
|
||||||
(RangeEnd::Excluded, _) => {
|
(RangeEnd::Excluded, _) => {
|
||||||
|
@ -616,7 +603,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
|
|
||||||
ty::TyArray(_, len) => {
|
ty::TyArray(_, len) => {
|
||||||
// fixed-length array
|
// fixed-length array
|
||||||
let len = len.val.unwrap_u64();
|
let len = len.unwrap_usize(self.tcx);
|
||||||
assert!(len >= prefix.len() as u64 + suffix.len() as u64);
|
assert!(len >= prefix.len() as u64 + suffix.len() as u64);
|
||||||
PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
|
PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
|
||||||
}
|
}
|
||||||
|
@ -740,8 +727,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
self.tables.local_id_root.expect("literal outside any scope"),
|
self.tables.local_id_root.expect("literal outside any scope"),
|
||||||
self.substs,
|
self.substs,
|
||||||
);
|
);
|
||||||
let cv = self.tcx.mk_const(ty::Const { val, ty });
|
*self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
|
||||||
*self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
|
|
||||||
},
|
},
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
self.errors.push(PatternError::FloatBug);
|
self.errors.push(PatternError::FloatBug);
|
||||||
|
@ -762,8 +748,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
self.tables.local_id_root.expect("literal outside any scope"),
|
self.tables.local_id_root.expect("literal outside any scope"),
|
||||||
self.substs,
|
self.substs,
|
||||||
);
|
);
|
||||||
let cv = self.tcx.mk_const(ty::Const { val, ty });
|
*self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
|
||||||
*self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
|
|
||||||
},
|
},
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
self.errors.push(PatternError::FloatBug);
|
self.errors.push(PatternError::FloatBug);
|
||||||
|
@ -866,7 +851,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
ty::TyArray(_, n) => {
|
ty::TyArray(_, n) => {
|
||||||
PatternKind::Array {
|
PatternKind::Array {
|
||||||
prefix: (0..n.val.unwrap_u64())
|
prefix: (0..n.unwrap_usize(self.tcx))
|
||||||
.map(|i| adt_subpattern(i as usize, None))
|
.map(|i| adt_subpattern(i as usize, None))
|
||||||
.collect(),
|
.collect(),
|
||||||
slice: None,
|
slice: None,
|
||||||
|
@ -1049,45 +1034,48 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
|
||||||
|
|
||||||
pub fn compare_const_vals<'a, 'tcx>(
|
pub fn compare_const_vals<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
a: &ConstVal,
|
a: &'tcx ty::Const<'tcx>,
|
||||||
b: &ConstVal,
|
b: &'tcx ty::Const<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Option<Ordering> {
|
) -> Option<Ordering> {
|
||||||
trace!("compare_const_vals: {:?}, {:?}", a, b);
|
trace!("compare_const_vals: {:?}, {:?}", a, b);
|
||||||
use rustc::mir::interpret::{Value, PrimVal};
|
// FIXME: This should use assert_bits(ty) instead of use_bits
|
||||||
match (a, b) {
|
// but triggers possibly bugs due to mismatching of arrays and slices
|
||||||
(&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))),
|
if let (Some(a), Some(b)) = (a.to_bits(ty), b.to_bits(ty)) {
|
||||||
&ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => {
|
use ::rustc_apfloat::Float;
|
||||||
use ::rustc_apfloat::Float;
|
match ty.sty {
|
||||||
match ty.sty {
|
ty::TyFloat(ast::FloatTy::F32) => {
|
||||||
ty::TyFloat(ast::FloatTy::F32) => {
|
let l = ::rustc_apfloat::ieee::Single::from_bits(a);
|
||||||
let l = ::rustc_apfloat::ieee::Single::from_bits(a);
|
let r = ::rustc_apfloat::ieee::Single::from_bits(b);
|
||||||
let r = ::rustc_apfloat::ieee::Single::from_bits(b);
|
l.partial_cmp(&r)
|
||||||
l.partial_cmp(&r)
|
},
|
||||||
},
|
ty::TyFloat(ast::FloatTy::F64) => {
|
||||||
ty::TyFloat(ast::FloatTy::F64) => {
|
let l = ::rustc_apfloat::ieee::Double::from_bits(a);
|
||||||
let l = ::rustc_apfloat::ieee::Double::from_bits(a);
|
let r = ::rustc_apfloat::ieee::Double::from_bits(b);
|
||||||
let r = ::rustc_apfloat::ieee::Double::from_bits(b);
|
l.partial_cmp(&r)
|
||||||
l.partial_cmp(&r)
|
},
|
||||||
},
|
ty::TyInt(_) => {
|
||||||
ty::TyInt(_) => {
|
let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt");
|
||||||
let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt");
|
let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt");
|
||||||
let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt");
|
Some((a as i128).cmp(&(b as i128)))
|
||||||
Some((a as i128).cmp(&(b as i128)))
|
},
|
||||||
},
|
_ => Some(a.cmp(&b)),
|
||||||
_ => Some(a.cmp(&b)),
|
}
|
||||||
}
|
} else {
|
||||||
},
|
if a == b {
|
||||||
_ if a == b => Some(Ordering::Equal),
|
Some(Ordering::Equal)
|
||||||
_ => None,
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Combine with rustc_mir::hair::cx::const_eval_literal
|
||||||
fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
neg: bool)
|
neg: bool)
|
||||||
-> Result<ConstVal<'tcx>, ()> {
|
-> Result<&'tcx ty::Const<'tcx>, ()> {
|
||||||
use syntax::ast::*;
|
use syntax::ast::*;
|
||||||
|
|
||||||
use rustc::mir::interpret::*;
|
use rustc::mir::interpret::*;
|
||||||
|
@ -1096,7 +1084,7 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
||||||
let s = s.as_str();
|
let s = s.as_str();
|
||||||
let id = tcx.allocate_cached(s.as_bytes());
|
let id = tcx.allocate_cached(s.as_bytes());
|
||||||
let ptr = MemoryPointer::new(id, 0);
|
let ptr = MemoryPointer::new(id, 0);
|
||||||
Value::ByValPair(
|
ConstValue::ByValPair(
|
||||||
PrimVal::Ptr(ptr),
|
PrimVal::Ptr(ptr),
|
||||||
PrimVal::from_u128(s.len() as u128),
|
PrimVal::from_u128(s.len() as u128),
|
||||||
)
|
)
|
||||||
|
@ -1104,9 +1092,9 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
||||||
LitKind::ByteStr(ref data) => {
|
LitKind::ByteStr(ref data) => {
|
||||||
let id = tcx.allocate_cached(data);
|
let id = tcx.allocate_cached(data);
|
||||||
let ptr = MemoryPointer::new(id, 0);
|
let ptr = MemoryPointer::new(id, 0);
|
||||||
Value::ByVal(PrimVal::Ptr(ptr))
|
ConstValue::ByVal(PrimVal::Ptr(ptr))
|
||||||
},
|
},
|
||||||
LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
|
LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)),
|
||||||
LitKind::Int(n, _) => {
|
LitKind::Int(n, _) => {
|
||||||
enum Int {
|
enum Int {
|
||||||
Signed(IntTy),
|
Signed(IntTy),
|
||||||
|
@ -1119,31 +1107,28 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
||||||
ty::TyUint(other) => Int::Unsigned(other),
|
ty::TyUint(other) => Int::Unsigned(other),
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
|
// This converts from LitKind::Int (which is sign extended) to
|
||||||
|
// PrimVal::Bytes (which is zero extended)
|
||||||
let n = match ty {
|
let n = match ty {
|
||||||
// FIXME(oli-obk): are these casts correct?
|
// FIXME(oli-obk): are these casts correct?
|
||||||
Int::Signed(IntTy::I8) if neg =>
|
Int::Signed(IntTy::I8) if neg =>
|
||||||
(n as i128 as i8).overflowing_neg().0 as i128 as u128,
|
(n as i8).overflowing_neg().0 as u8 as u128,
|
||||||
Int::Signed(IntTy::I16) if neg =>
|
Int::Signed(IntTy::I16) if neg =>
|
||||||
(n as i128 as i16).overflowing_neg().0 as i128 as u128,
|
(n as i16).overflowing_neg().0 as u16 as u128,
|
||||||
Int::Signed(IntTy::I32) if neg =>
|
Int::Signed(IntTy::I32) if neg =>
|
||||||
(n as i128 as i32).overflowing_neg().0 as i128 as u128,
|
(n as i32).overflowing_neg().0 as u32 as u128,
|
||||||
Int::Signed(IntTy::I64) if neg =>
|
Int::Signed(IntTy::I64) if neg =>
|
||||||
(n as i128 as i64).overflowing_neg().0 as i128 as u128,
|
(n as i64).overflowing_neg().0 as u64 as u128,
|
||||||
Int::Signed(IntTy::I128) if neg =>
|
Int::Signed(IntTy::I128) if neg =>
|
||||||
(n as i128).overflowing_neg().0 as u128,
|
(n as i128).overflowing_neg().0 as u128,
|
||||||
Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128,
|
Int::Signed(IntTy::I8) | Int::Unsigned(UintTy::U8) => n as u8 as u128,
|
||||||
Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128,
|
Int::Signed(IntTy::I16) | Int::Unsigned(UintTy::U16) => n as u16 as u128,
|
||||||
Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128,
|
Int::Signed(IntTy::I32) | Int::Unsigned(UintTy::U32) => n as u32 as u128,
|
||||||
Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128,
|
Int::Signed(IntTy::I64) | Int::Unsigned(UintTy::U64) => n as u64 as u128,
|
||||||
Int::Signed(IntTy::I128) => n,
|
Int::Signed(IntTy::I128)| Int::Unsigned(UintTy::U128) => n,
|
||||||
Int::Unsigned(UintTy::U8) => n as u8 as u128,
|
|
||||||
Int::Unsigned(UintTy::U16) => n as u16 as u128,
|
|
||||||
Int::Unsigned(UintTy::U32) => n as u32 as u128,
|
|
||||||
Int::Unsigned(UintTy::U64) => n as u64 as u128,
|
|
||||||
Int::Unsigned(UintTy::U128) => n,
|
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
Value::ByVal(PrimVal::Bytes(n))
|
ConstValue::ByVal(PrimVal::Bytes(n))
|
||||||
},
|
},
|
||||||
LitKind::Float(n, fty) => {
|
LitKind::Float(n, fty) => {
|
||||||
parse_float(n, fty, neg)?
|
parse_float(n, fty, neg)?
|
||||||
|
@ -1155,17 +1140,17 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
||||||
};
|
};
|
||||||
parse_float(n, fty, neg)?
|
parse_float(n, fty, neg)?
|
||||||
}
|
}
|
||||||
LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
|
LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)),
|
||||||
LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
|
LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)),
|
||||||
};
|
};
|
||||||
Ok(ConstVal::Value(lit))
|
Ok(ty::Const::from_const_value(tcx, lit, ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_float(
|
pub fn parse_float<'tcx>(
|
||||||
num: Symbol,
|
num: Symbol,
|
||||||
fty: ast::FloatTy,
|
fty: ast::FloatTy,
|
||||||
neg: bool,
|
neg: bool,
|
||||||
) -> Result<Value, ()> {
|
) -> Result<ConstValue<'tcx>, ()> {
|
||||||
let num = num.as_str();
|
let num = num.as_str();
|
||||||
use rustc_apfloat::ieee::{Single, Double};
|
use rustc_apfloat::ieee::{Single, Double};
|
||||||
use rustc_apfloat::Float;
|
use rustc_apfloat::Float;
|
||||||
|
@ -1192,5 +1177,5 @@ pub fn parse_float(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Value::ByVal(PrimVal::Bytes(bits)))
|
Ok(ConstValue::ByVal(PrimVal::Bytes(bits)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
|
use rustc::middle::const_val::{ConstEvalErr, ErrKind};
|
||||||
use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError};
|
use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError};
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::ty::{self, TyCtxt, Ty, Instance};
|
use rustc::ty::{self, TyCtxt, Ty, Instance};
|
||||||
|
@ -8,9 +8,13 @@ use rustc::ty::subst::Subst;
|
||||||
|
|
||||||
use syntax::ast::Mutability;
|
use syntax::ast::Mutability;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
|
use syntax::codemap::DUMMY_SP;
|
||||||
|
|
||||||
use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal, AllocId};
|
use rustc::mir::interpret::{
|
||||||
use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory};
|
EvalResult, EvalError, EvalErrorKind, GlobalId,
|
||||||
|
Value, Pointer, PrimVal, AllocId, Allocation, ConstValue,
|
||||||
|
};
|
||||||
|
use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory, MemoryKind};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
@ -57,19 +61,21 @@ pub fn mk_eval_cx<'a, 'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_promoted<'a, 'mir, 'tcx>(
|
pub fn eval_promoted<'a, 'mir, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
|
||||||
cid: GlobalId<'tcx>,
|
cid: GlobalId<'tcx>,
|
||||||
mir: &'mir mir::Mir<'tcx>,
|
mir: &'mir mir::Mir<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> Option<(Value, Pointer, Ty<'tcx>)> {
|
) -> Option<(Value, Pointer, Ty<'tcx>)> {
|
||||||
let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env);
|
ecx.with_fresh_body(|ecx| {
|
||||||
match res {
|
let res = eval_body_using_ecx(ecx, cid, Some(mir), param_env);
|
||||||
Ok(val) => Some(val),
|
match res {
|
||||||
Err(mut err) => {
|
Ok(val) => Some(val),
|
||||||
ecx.report(&mut err, false, None);
|
Err(mut err) => {
|
||||||
None
|
ecx.report(&mut err, false, None);
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_body<'a, 'tcx>(
|
pub fn eval_body<'a, 'tcx>(
|
||||||
|
@ -87,19 +93,76 @@ pub fn eval_body<'a, 'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn value_to_const_value<'a, 'tcx>(
|
||||||
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
val: Value,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> &'tcx ty::Const<'tcx> {
|
||||||
|
let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
|
||||||
|
|
||||||
|
if layout.is_zst() {
|
||||||
|
return ty::Const::from_const_value(
|
||||||
|
tcx,
|
||||||
|
ConstValue::ByVal(PrimVal::Undef),
|
||||||
|
ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
let val = match layout.abi {
|
||||||
|
layout::Abi::Scalar(..) => {
|
||||||
|
if let Value::ByVal(val) = val {
|
||||||
|
ConstValue::ByVal(val)
|
||||||
|
} else {
|
||||||
|
bug!("expected ByVal value, got {:?}", val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layout::Abi::ScalarPair(..) => {
|
||||||
|
if let Value::ByValPair(a, b) = val {
|
||||||
|
ConstValue::ByValPair(a, b)
|
||||||
|
} else {
|
||||||
|
bug!("expected ByValPair value, got {:?}", val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if let Value::ByRef(ptr, align) = val {
|
||||||
|
let ptr = ptr.primval.to_ptr().unwrap();
|
||||||
|
assert_eq!(ptr.offset, 0);
|
||||||
|
let alloc = tcx.interpret_interner
|
||||||
|
.get_alloc(ptr.alloc_id)
|
||||||
|
.expect("miri allocation never successfully created");
|
||||||
|
assert_eq!(align, alloc.align);
|
||||||
|
ConstValue::ByRef(alloc)
|
||||||
|
} else {
|
||||||
|
bug!("expected ByRef value, got {:?}", val);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ty::Const::from_const_value(tcx, val, ty)
|
||||||
|
}
|
||||||
|
|
||||||
fn eval_body_and_ecx<'a, 'mir, 'tcx>(
|
fn eval_body_and_ecx<'a, 'mir, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
cid: GlobalId<'tcx>,
|
cid: GlobalId<'tcx>,
|
||||||
mir: Option<&'mir mir::Mir<'tcx>>,
|
mir: Option<&'mir mir::Mir<'tcx>>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
|
) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
|
||||||
debug!("eval_body: {:?}, {:?}", cid, param_env);
|
debug!("eval_body_and_ecx: {:?}, {:?}", cid, param_env);
|
||||||
// we start out with the best span we have
|
// we start out with the best span we have
|
||||||
// and try improving it down the road when more information is available
|
// and try improving it down the road when more information is available
|
||||||
let span = tcx.def_span(cid.instance.def_id());
|
let span = tcx.def_span(cid.instance.def_id());
|
||||||
let mut span = mir.map(|mir| mir.span).unwrap_or(span);
|
let span = mir.map(|mir| mir.span).unwrap_or(span);
|
||||||
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
|
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
|
||||||
let res = (|| {
|
let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env);
|
||||||
|
(r, ecx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_body_using_ecx<'a, 'mir, 'tcx>(
|
||||||
|
ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
|
||||||
|
cid: GlobalId<'tcx>,
|
||||||
|
mir: Option<&'mir mir::Mir<'tcx>>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> {
|
||||||
|
debug!("eval_body: {:?}, {:?}", cid, param_env);
|
||||||
|
let tcx = ecx.tcx.tcx;
|
||||||
let mut mir = match mir {
|
let mut mir = match mir {
|
||||||
Some(mir) => mir,
|
Some(mir) => mir,
|
||||||
None => ecx.load_mir(cid.instance.def)?,
|
None => ecx.load_mir(cid.instance.def)?,
|
||||||
|
@ -107,7 +170,6 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
|
||||||
if let Some(index) = cid.promoted {
|
if let Some(index) = cid.promoted {
|
||||||
mir = &mir.promoted[index];
|
mir = &mir.promoted[index];
|
||||||
}
|
}
|
||||||
span = mir.span;
|
|
||||||
let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
|
let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
|
||||||
assert!(!layout.is_unsized());
|
assert!(!layout.is_unsized());
|
||||||
let ptr = ecx.memory.allocate(
|
let ptr = ecx.memory.allocate(
|
||||||
|
@ -139,14 +201,11 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
|
||||||
let ptr = ptr.into();
|
let ptr = ptr.into();
|
||||||
// always try to read the value and report errors
|
// always try to read the value and report errors
|
||||||
let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? {
|
let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? {
|
||||||
// if it's a constant (so it needs no address, directly compute its value)
|
Some(val) => val,
|
||||||
Some(val) if tcx.is_static(cid.instance.def_id()).is_none() => val,
|
|
||||||
// point at the allocation
|
// point at the allocation
|
||||||
_ => Value::ByRef(ptr, layout.align),
|
_ => Value::ByRef(ptr, layout.align),
|
||||||
};
|
};
|
||||||
Ok((value, ptr, layout.ty))
|
Ok((value, ptr, layout.ty))
|
||||||
})();
|
|
||||||
(res, ecx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CompileTimeEvaluator;
|
pub struct CompileTimeEvaluator;
|
||||||
|
@ -357,14 +416,16 @@ pub fn const_val_field<'a, 'tcx>(
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
variant: Option<usize>,
|
variant: Option<usize>,
|
||||||
field: mir::Field,
|
field: mir::Field,
|
||||||
value: Value,
|
value: ConstValue<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> ::rustc::middle::const_val::EvalResult<'tcx> {
|
) -> ::rustc::middle::const_val::EvalResult<'tcx> {
|
||||||
trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
|
trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
|
||||||
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
|
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
|
||||||
let result = (|| {
|
let result = (|| {
|
||||||
|
let value = ecx.const_value_to_value(value, ty)?;
|
||||||
let (mut field, ty) = match value {
|
let (mut field, ty) = match value {
|
||||||
Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
|
Value::ByValPair(..) | Value::ByVal(_) =>
|
||||||
|
ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
|
||||||
Value::ByRef(ptr, align) => {
|
Value::ByRef(ptr, align) => {
|
||||||
let place = Place::Ptr {
|
let place = Place::Ptr {
|
||||||
ptr,
|
ptr,
|
||||||
|
@ -385,10 +446,7 @@ pub fn const_val_field<'a, 'tcx>(
|
||||||
Ok((field, ty))
|
Ok((field, ty))
|
||||||
})();
|
})();
|
||||||
match result {
|
match result {
|
||||||
Ok((field, ty)) => Ok(tcx.mk_const(ty::Const {
|
Ok((field, ty)) => Ok(value_to_const_value(tcx, field, ty)),
|
||||||
val: ConstVal::Value(field),
|
|
||||||
ty,
|
|
||||||
})),
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let (trace, span) = ecx.generate_stacktrace(None);
|
let (trace, span) = ecx.generate_stacktrace(None);
|
||||||
let err = ErrKind::Miri(err, trace);
|
let err = ErrKind::Miri(err, trace);
|
||||||
|
@ -404,15 +462,15 @@ pub fn const_variant_index<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
value: Value,
|
val: ConstValue<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> EvalResult<'tcx, usize> {
|
) -> EvalResult<'tcx, usize> {
|
||||||
trace!("const_variant_index: {:?}, {:?}, {:?}", instance, value, ty);
|
trace!("const_variant_index: {:?}, {:?}, {:?}", instance, val, ty);
|
||||||
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
|
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
|
||||||
|
let value = ecx.const_value_to_value(val, ty)?;
|
||||||
let (ptr, align) = match value {
|
let (ptr, align) = match value {
|
||||||
Value::ByValPair(..) | Value::ByVal(_) => {
|
Value::ByValPair(..) | Value::ByVal(_) => {
|
||||||
let layout = ecx.layout_of(ty)?;
|
let layout = ecx.layout_of(ty)?;
|
||||||
use super::MemoryKind;
|
|
||||||
let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
|
let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
|
||||||
let ptr: Pointer = ptr.into();
|
let ptr: Pointer = ptr.into();
|
||||||
ecx.write_value_to_ptr(value, ptr, layout.align, ty)?;
|
ecx.write_value_to_ptr(value, ptr, layout.align, ty)?;
|
||||||
|
@ -424,6 +482,30 @@ pub fn const_variant_index<'a, 'tcx>(
|
||||||
ecx.read_discriminant_as_variant_index(place, ty)
|
ecx.read_discriminant_as_variant_index(place, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn const_value_to_allocation_provider<'a, 'tcx>(
|
||||||
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
(val, ty): (ConstValue<'tcx>, Ty<'tcx>),
|
||||||
|
) -> &'tcx Allocation {
|
||||||
|
match val {
|
||||||
|
ConstValue::ByRef(alloc) => return alloc,
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
let result = || -> EvalResult<'tcx, &'tcx Allocation> {
|
||||||
|
let mut ecx = EvalContext::new(
|
||||||
|
tcx.at(DUMMY_SP),
|
||||||
|
ty::ParamEnv::reveal_all(),
|
||||||
|
CompileTimeEvaluator,
|
||||||
|
());
|
||||||
|
let value = ecx.const_value_to_value(val, ty)?;
|
||||||
|
let layout = ecx.layout_of(ty)?;
|
||||||
|
let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
|
||||||
|
ecx.write_value_to_ptr(value, ptr.into(), layout.align, ty)?;
|
||||||
|
let alloc = ecx.memory.get(ptr.alloc_id)?;
|
||||||
|
Ok(tcx.intern_const_alloc(alloc.clone()))
|
||||||
|
};
|
||||||
|
result().expect("unable to convert ConstVal to Allocation")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn const_eval_provider<'a, 'tcx>(
|
pub fn const_eval_provider<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
|
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
|
||||||
|
@ -432,17 +514,6 @@ pub fn const_eval_provider<'a, 'tcx>(
|
||||||
let cid = key.value;
|
let cid = key.value;
|
||||||
let def_id = cid.instance.def.def_id();
|
let def_id = cid.instance.def.def_id();
|
||||||
|
|
||||||
if tcx.is_foreign_item(def_id) {
|
|
||||||
let id = tcx.interpret_interner.cache_static(def_id);
|
|
||||||
let ty = tcx.type_of(def_id);
|
|
||||||
let layout = tcx.layout_of(key.param_env.and(ty)).unwrap();
|
|
||||||
let ptr = MemoryPointer::new(id, 0);
|
|
||||||
return Ok(tcx.mk_const(ty::Const {
|
|
||||||
val: ConstVal::Value(Value::ByRef(ptr.into(), layout.align)),
|
|
||||||
ty,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(id) = tcx.hir.as_local_node_id(def_id) {
|
if let Some(id) = tcx.hir.as_local_node_id(def_id) {
|
||||||
let tables = tcx.typeck_tables_of(def_id);
|
let tables = tcx.typeck_tables_of(def_id);
|
||||||
let span = tcx.def_span(def_id);
|
let span = tcx.def_span(def_id);
|
||||||
|
@ -469,11 +540,8 @@ pub fn const_eval_provider<'a, 'tcx>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
|
let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
|
||||||
res.map(|(miri_value, _, miri_ty)| {
|
res.map(|(val, _, miri_ty)| {
|
||||||
tcx.mk_const(ty::Const {
|
value_to_const_value(tcx, val, miri_ty)
|
||||||
val: ConstVal::Value(miri_value),
|
|
||||||
ty: miri_ty,
|
|
||||||
})
|
|
||||||
}).map_err(|mut err| {
|
}).map_err(|mut err| {
|
||||||
if tcx.is_static(def_id).is_some() {
|
if tcx.is_static(def_id).is_some() {
|
||||||
ecx.report(&mut err, true, None);
|
ecx.report(&mut err, true, None);
|
||||||
|
|
|
@ -15,7 +15,7 @@ use syntax::codemap::{self, Span};
|
||||||
use syntax::ast::Mutability;
|
use syntax::ast::Mutability;
|
||||||
use rustc::mir::interpret::{
|
use rustc::mir::interpret::{
|
||||||
GlobalId, Value, Pointer, PrimVal, PrimValKind,
|
GlobalId, Value, Pointer, PrimVal, PrimValKind,
|
||||||
EvalError, EvalResult, EvalErrorKind, MemoryPointer,
|
EvalError, EvalResult, EvalErrorKind, MemoryPointer, ConstValue,
|
||||||
};
|
};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
@ -116,15 +116,6 @@ pub struct ValTy<'tcx> {
|
||||||
pub ty: Ty<'tcx>,
|
pub ty: Ty<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ValTy<'tcx> {
|
|
||||||
pub fn from(val: &ty::Const<'tcx>) -> Option<Self> {
|
|
||||||
match val.val {
|
|
||||||
ConstVal::Value(value) => Some(ValTy { value, ty: val.ty }),
|
|
||||||
ConstVal::Unevaluated { .. } => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
|
impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
|
||||||
type Target = Value;
|
type Target = Value;
|
||||||
fn deref(&self) -> &Value {
|
fn deref(&self) -> &Value {
|
||||||
|
@ -183,6 +174,8 @@ impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MAX_TERMINATORS: usize = 1_000_000;
|
||||||
|
|
||||||
impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
|
||||||
|
@ -197,10 +190,19 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
||||||
memory: Memory::new(tcx, memory_data),
|
memory: Memory::new(tcx, memory_data),
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
stack_limit: tcx.sess.const_eval_stack_frame_limit,
|
stack_limit: tcx.sess.const_eval_stack_frame_limit,
|
||||||
terminators_remaining: 1_000_000,
|
terminators_remaining: MAX_TERMINATORS,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn with_fresh_body<F: FnOnce(&mut Self) -> R, R>(&mut self, f: F) -> R {
|
||||||
|
let stack = mem::replace(&mut self.stack, Vec::new());
|
||||||
|
let terminators_remaining = mem::replace(&mut self.terminators_remaining, MAX_TERMINATORS);
|
||||||
|
let r = f(self);
|
||||||
|
self.stack = stack;
|
||||||
|
self.terminators_remaining = terminators_remaining;
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, MemoryPointer> {
|
pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, MemoryPointer> {
|
||||||
let layout = self.layout_of(ty)?;
|
let layout = self.layout_of(ty)?;
|
||||||
assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
|
assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
|
||||||
|
@ -235,7 +237,27 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn const_to_value(&self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
|
pub fn const_value_to_value(
|
||||||
|
&mut self,
|
||||||
|
val: ConstValue<'tcx>,
|
||||||
|
_ty: Ty<'tcx>,
|
||||||
|
) -> EvalResult<'tcx, Value> {
|
||||||
|
match val {
|
||||||
|
ConstValue::ByRef(alloc) => {
|
||||||
|
// FIXME: Allocate new AllocId for all constants inside
|
||||||
|
let id = self.memory.allocate_value(alloc.clone(), Some(MemoryKind::Stack))?;
|
||||||
|
Ok(Value::ByRef(MemoryPointer::new(id, 0).into(), alloc.align))
|
||||||
|
},
|
||||||
|
ConstValue::ByValPair(a, b) => Ok(Value::ByValPair(a, b)),
|
||||||
|
ConstValue::ByVal(val) => Ok(Value::ByVal(val)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn const_to_value(
|
||||||
|
&mut self,
|
||||||
|
const_val: &ConstVal<'tcx>,
|
||||||
|
ty: Ty<'tcx>
|
||||||
|
) -> EvalResult<'tcx, Value> {
|
||||||
match *const_val {
|
match *const_val {
|
||||||
ConstVal::Unevaluated(def_id, substs) => {
|
ConstVal::Unevaluated(def_id, substs) => {
|
||||||
let instance = self.resolve(def_id, substs)?;
|
let instance = self.resolve(def_id, substs)?;
|
||||||
|
@ -244,7 +266,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
||||||
promoted: None,
|
promoted: None,
|
||||||
}, ty)
|
}, ty)
|
||||||
}
|
}
|
||||||
ConstVal::Value(val) => Ok(val),
|
ConstVal::Value(val) => self.const_value_to_value(val, ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,7 +590,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
||||||
|
|
||||||
Repeat(ref operand, _) => {
|
Repeat(ref operand, _) => {
|
||||||
let (elem_ty, length) = match dest_ty.sty {
|
let (elem_ty, length) = match dest_ty.sty {
|
||||||
ty::TyArray(elem_ty, n) => (elem_ty, n.val.unwrap_u64()),
|
ty::TyArray(elem_ty, n) => (elem_ty, n.unwrap_usize(self.tcx.tcx)),
|
||||||
_ => {
|
_ => {
|
||||||
bug!(
|
bug!(
|
||||||
"tried to assign array-repeat to non-array type {:?}",
|
"tried to assign array-repeat to non-array type {:?}",
|
||||||
|
@ -592,7 +614,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
||||||
// FIXME(CTFE): don't allow computing the length of arrays in const eval
|
// FIXME(CTFE): don't allow computing the length of arrays in const eval
|
||||||
let src = self.eval_place(place)?;
|
let src = self.eval_place(place)?;
|
||||||
let ty = self.place_ty(place);
|
let ty = self.place_ty(place);
|
||||||
let (_, len) = src.elem_ty_and_len(ty);
|
let (_, len) = src.elem_ty_and_len(ty, self.tcx.tcx);
|
||||||
self.write_primval(
|
self.write_primval(
|
||||||
dest,
|
dest,
|
||||||
PrimVal::from_u128(len as u128),
|
PrimVal::from_u128(len as u128),
|
||||||
|
@ -822,8 +844,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
||||||
Literal::Value { ref value } => self.const_to_value(&value.val, ty)?,
|
Literal::Value { ref value } => self.const_to_value(&value.val, ty)?,
|
||||||
|
|
||||||
Literal::Promoted { index } => {
|
Literal::Promoted { index } => {
|
||||||
|
let instance = self.frame().instance;
|
||||||
self.read_global_as_value(GlobalId {
|
self.read_global_as_value(GlobalId {
|
||||||
instance: self.frame().instance,
|
instance,
|
||||||
promoted: Some(index),
|
promoted: Some(index),
|
||||||
}, ty)?
|
}, ty)?
|
||||||
}
|
}
|
||||||
|
@ -997,7 +1020,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_global_as_value(&self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
|
pub fn read_global_as_value(&mut self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
|
||||||
if self.tcx.is_static(gid.instance.def_id()).is_some() {
|
if self.tcx.is_static(gid.instance.def_id()).is_some() {
|
||||||
let alloc_id = self
|
let alloc_id = self
|
||||||
.tcx
|
.tcx
|
||||||
|
@ -1341,9 +1364,55 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
|
pub fn validate_ptr_target(
|
||||||
use syntax::ast::FloatTy;
|
&self,
|
||||||
|
ptr: MemoryPointer,
|
||||||
|
ptr_align: Align,
|
||||||
|
ty: Ty<'tcx>
|
||||||
|
) -> EvalResult<'tcx> {
|
||||||
|
match ty.sty {
|
||||||
|
ty::TyBool => {
|
||||||
|
let val = self.memory.read_primval(ptr, ptr_align, 1)?;
|
||||||
|
match val {
|
||||||
|
PrimVal::Bytes(0) | PrimVal::Bytes(1) => (),
|
||||||
|
// TODO: This seems a little overeager, should reading at bool type already be insta-UB?
|
||||||
|
_ => return err!(InvalidBool),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::TyChar => {
|
||||||
|
let c = self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()? as u32;
|
||||||
|
match ::std::char::from_u32(c) {
|
||||||
|
Some(..) => (),
|
||||||
|
None => return err!(InvalidChar(c as u128)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::TyFnPtr(_) => {
|
||||||
|
self.memory.read_ptr_sized(ptr, ptr_align)?;
|
||||||
|
},
|
||||||
|
ty::TyRef(_, rty, _) |
|
||||||
|
ty::TyRawPtr(ty::TypeAndMut { ty: rty, .. }) => {
|
||||||
|
self.read_ptr(ptr, ptr_align, rty)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::TyAdt(def, _) => {
|
||||||
|
if def.is_box() {
|
||||||
|
self.read_ptr(ptr, ptr_align, ty.boxed_ty())?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi {
|
||||||
|
let size = scalar.value.size(self).bytes();
|
||||||
|
self.memory.read_primval(ptr, ptr_align, size)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
|
||||||
let layout = self.layout_of(ty)?;
|
let layout = self.layout_of(ty)?;
|
||||||
self.memory.check_align(ptr, ptr_align)?;
|
self.memory.check_align(ptr, ptr_align)?;
|
||||||
|
|
||||||
|
@ -1352,81 +1421,27 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
||||||
}
|
}
|
||||||
|
|
||||||
let ptr = ptr.to_ptr()?;
|
let ptr = ptr.to_ptr()?;
|
||||||
let val = match ty.sty {
|
|
||||||
ty::TyBool => {
|
|
||||||
let val = self.memory.read_primval(ptr, ptr_align, 1)?;
|
|
||||||
let val = match val {
|
|
||||||
PrimVal::Bytes(0) => false,
|
|
||||||
PrimVal::Bytes(1) => true,
|
|
||||||
// TODO: This seems a little overeager, should reading at bool type already be insta-UB?
|
|
||||||
_ => return err!(InvalidBool),
|
|
||||||
};
|
|
||||||
PrimVal::from_bool(val)
|
|
||||||
}
|
|
||||||
ty::TyChar => {
|
|
||||||
let c = self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()? as u32;
|
|
||||||
match ::std::char::from_u32(c) {
|
|
||||||
Some(ch) => PrimVal::from_char(ch),
|
|
||||||
None => return err!(InvalidChar(c as u128)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::TyInt(int_ty) => {
|
// Not the right place to do this
|
||||||
use syntax::ast::IntTy::*;
|
//self.validate_ptr_target(ptr, ptr_align, ty)?;
|
||||||
let size = match int_ty {
|
|
||||||
I8 => 1,
|
match layout.abi {
|
||||||
I16 => 2,
|
layout::Abi::Scalar(..) => {
|
||||||
I32 => 4,
|
let primval = self.memory.read_primval(ptr, ptr_align, layout.size.bytes())?;
|
||||||
I64 => 8,
|
Ok(Some(Value::ByVal(primval)))
|
||||||
I128 => 16,
|
|
||||||
Isize => self.memory.pointer_size(),
|
|
||||||
};
|
|
||||||
self.memory.read_primval(ptr, ptr_align, size)?
|
|
||||||
}
|
}
|
||||||
|
layout::Abi::ScalarPair(ref a, ref b) => {
|
||||||
ty::TyUint(uint_ty) => {
|
let (a, b) = (&a.value, &b.value);
|
||||||
use syntax::ast::UintTy::*;
|
let (a_size, b_size) = (a.size(self), b.size(self));
|
||||||
let size = match uint_ty {
|
let a_ptr = ptr;
|
||||||
U8 => 1,
|
let b_offset = a_size.abi_align(b.align(self));
|
||||||
U16 => 2,
|
let b_ptr = ptr.offset(b_offset.bytes(), self)?.into();
|
||||||
U32 => 4,
|
let a_val = self.memory.read_primval(a_ptr, ptr_align, a_size.bytes())?;
|
||||||
U64 => 8,
|
let b_val = self.memory.read_primval(b_ptr, ptr_align, b_size.bytes())?;
|
||||||
U128 => 16,
|
Ok(Some(Value::ByValPair(a_val, b_val)))
|
||||||
Usize => self.memory.pointer_size(),
|
|
||||||
};
|
|
||||||
self.memory.read_primval(ptr, ptr_align, size)?
|
|
||||||
}
|
}
|
||||||
|
_ => Ok(None),
|
||||||
ty::TyFloat(FloatTy::F32) => {
|
}
|
||||||
PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()?)
|
|
||||||
}
|
|
||||||
ty::TyFloat(FloatTy::F64) => {
|
|
||||||
PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 8)?.to_bytes()?)
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::TyFnPtr(_) => self.memory.read_ptr_sized(ptr, ptr_align)?,
|
|
||||||
ty::TyRef(_, rty, _) |
|
|
||||||
ty::TyRawPtr(ty::TypeAndMut { ty: rty, .. }) => {
|
|
||||||
return self.read_ptr(ptr, ptr_align, rty).map(Some)
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::TyAdt(def, _) => {
|
|
||||||
if def.is_box() {
|
|
||||||
return self.read_ptr(ptr, ptr_align, ty.boxed_ty()).map(Some);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi {
|
|
||||||
let size = scalar.value.size(self).bytes();
|
|
||||||
self.memory.read_primval(ptr, ptr_align, size)?
|
|
||||||
} else {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => return Ok(None),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Some(Value::ByVal(val)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame(&self) -> &Frame<'mir, 'tcx> {
|
pub fn frame(&self) -> &Frame<'mir, 'tcx> {
|
||||||
|
@ -1466,7 +1481,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
||||||
let ptr = self.into_ptr(src)?;
|
let ptr = self.into_ptr(src)?;
|
||||||
// u64 cast is from usize to u64, which is always good
|
// u64 cast is from usize to u64, which is always good
|
||||||
let valty = ValTy {
|
let valty = ValTy {
|
||||||
value: ptr.to_value_with_len(length.val.unwrap_u64() ),
|
value: ptr.to_value_with_len(length.unwrap_usize(self.tcx.tcx)),
|
||||||
ty: dest_ty,
|
ty: dest_ty,
|
||||||
};
|
};
|
||||||
self.write_value(valty, dest)
|
self.write_value(valty, dest)
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian};
|
use std::collections::{btree_map, VecDeque};
|
||||||
use std::collections::{btree_map, BTreeMap, VecDeque};
|
use std::ptr;
|
||||||
use std::{ptr, io};
|
|
||||||
|
|
||||||
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::ty::Instance;
|
use rustc::ty::Instance;
|
||||||
|
use rustc::ty::ParamEnv;
|
||||||
use rustc::ty::maps::TyCtxtAt;
|
use rustc::ty::maps::TyCtxtAt;
|
||||||
use rustc::ty::layout::{self, Align, TargetDataLayout};
|
use rustc::ty::layout::{self, Align, TargetDataLayout};
|
||||||
use syntax::ast::Mutability;
|
use syntax::ast::Mutability;
|
||||||
|
use rustc::middle::const_val::{ConstVal, ErrKind};
|
||||||
|
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
|
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
|
||||||
use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, UndefMask, Value, Pointer,
|
use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, Value, Pointer,
|
||||||
EvalResult, PrimVal, EvalErrorKind};
|
EvalResult, PrimVal, EvalErrorKind, GlobalId};
|
||||||
|
pub use rustc::mir::interpret::{write_target_uint, write_target_int, read_target_uint};
|
||||||
|
|
||||||
use super::{EvalContext, Machine};
|
use super::{EvalContext, Machine};
|
||||||
|
|
||||||
|
@ -79,20 +82,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// kind is `None` for statics
|
/// kind is `None` for statics
|
||||||
pub fn allocate(
|
pub fn allocate_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
size: u64,
|
alloc: Allocation,
|
||||||
align: Align,
|
|
||||||
kind: Option<MemoryKind<M::MemoryKinds>>,
|
kind: Option<MemoryKind<M::MemoryKinds>>,
|
||||||
) -> EvalResult<'tcx, MemoryPointer> {
|
) -> EvalResult<'tcx, AllocId> {
|
||||||
assert_eq!(size as usize as u64, size);
|
|
||||||
let alloc = Allocation {
|
|
||||||
bytes: vec![0; size as usize],
|
|
||||||
relocations: BTreeMap::new(),
|
|
||||||
undef_mask: UndefMask::new(size),
|
|
||||||
align,
|
|
||||||
runtime_mutability: Mutability::Immutable,
|
|
||||||
};
|
|
||||||
let id = self.tcx.interpret_interner.reserve();
|
let id = self.tcx.interpret_interner.reserve();
|
||||||
M::add_lock(self, id);
|
M::add_lock(self, id);
|
||||||
match kind {
|
match kind {
|
||||||
|
@ -105,6 +99,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
||||||
self.uninitialized_statics.insert(id, alloc);
|
self.uninitialized_statics.insert(id, alloc);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// kind is `None` for statics
|
||||||
|
pub fn allocate(
|
||||||
|
&mut self,
|
||||||
|
size: u64,
|
||||||
|
align: Align,
|
||||||
|
kind: Option<MemoryKind<M::MemoryKinds>>,
|
||||||
|
) -> EvalResult<'tcx, MemoryPointer> {
|
||||||
|
let id = self.allocate_value(Allocation::undef(size, align), kind)?;
|
||||||
Ok(MemoryPointer::new(id, 0))
|
Ok(MemoryPointer::new(id, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,6 +277,31 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
||||||
|
|
||||||
/// Allocation accessors
|
/// Allocation accessors
|
||||||
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
||||||
|
fn const_eval_static(&self, def_id: DefId) -> EvalResult<'tcx, &'tcx Allocation> {
|
||||||
|
let instance = Instance::mono(self.tcx.tcx, def_id);
|
||||||
|
let gid = GlobalId {
|
||||||
|
instance,
|
||||||
|
promoted: None,
|
||||||
|
};
|
||||||
|
self.tcx.const_eval(ParamEnv::reveal_all().and(gid)).map_err(|err| {
|
||||||
|
match *err.kind {
|
||||||
|
ErrKind::Miri(ref err, _) => match err.kind {
|
||||||
|
EvalErrorKind::TypeckError |
|
||||||
|
EvalErrorKind::Layout(_) => EvalErrorKind::TypeckError.into(),
|
||||||
|
_ => EvalErrorKind::ReferencedConstant.into(),
|
||||||
|
},
|
||||||
|
ErrKind::TypeckError => EvalErrorKind::TypeckError.into(),
|
||||||
|
ref other => bug!("const eval returned {:?}", other),
|
||||||
|
}
|
||||||
|
}).map(|val| {
|
||||||
|
let const_val = match val.val {
|
||||||
|
ConstVal::Value(val) => val,
|
||||||
|
ConstVal::Unevaluated(..) => bug!("should be evaluated"),
|
||||||
|
};
|
||||||
|
self.tcx.const_value_to_allocation((const_val, val.ty))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
|
pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
|
||||||
// normal alloc?
|
// normal alloc?
|
||||||
match self.alloc_map.get(&id) {
|
match self.alloc_map.get(&id) {
|
||||||
|
@ -281,13 +311,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
||||||
Some(alloc) => Ok(alloc),
|
Some(alloc) => Ok(alloc),
|
||||||
None => {
|
None => {
|
||||||
// static alloc?
|
// static alloc?
|
||||||
self.tcx.interpret_interner.get_alloc(id)
|
if let Some(a) = self.tcx.interpret_interner.get_alloc(id) {
|
||||||
// no alloc? produce an error
|
return Ok(a);
|
||||||
.ok_or_else(|| if self.tcx.interpret_interner.get_fn(id).is_some() {
|
}
|
||||||
EvalErrorKind::DerefFunctionPointer.into()
|
// static variable?
|
||||||
} else {
|
if let Some(did) = self.tcx.interpret_interner.get_static(id) {
|
||||||
EvalErrorKind::DanglingPointerDeref.into()
|
return self.const_eval_static(did);
|
||||||
})
|
}
|
||||||
|
// otherwise return an error
|
||||||
|
Err(if self.tcx.interpret_interner.get_fn(id).is_some() {
|
||||||
|
EvalErrorKind::DerefFunctionPointer.into()
|
||||||
|
} else {
|
||||||
|
EvalErrorKind::DanglingPointerDeref.into()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -873,41 +909,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Methods to access integers in the target endianness
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
pub fn write_target_uint(
|
|
||||||
endianness: layout::Endian,
|
|
||||||
mut target: &mut [u8],
|
|
||||||
data: u128,
|
|
||||||
) -> Result<(), io::Error> {
|
|
||||||
let len = target.len();
|
|
||||||
match endianness {
|
|
||||||
layout::Endian::Little => target.write_uint128::<LittleEndian>(data, len),
|
|
||||||
layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_target_int(
|
|
||||||
endianness: layout::Endian,
|
|
||||||
mut target: &mut [u8],
|
|
||||||
data: i128,
|
|
||||||
) -> Result<(), io::Error> {
|
|
||||||
let len = target.len();
|
|
||||||
match endianness {
|
|
||||||
layout::Endian::Little => target.write_int128::<LittleEndian>(data, len),
|
|
||||||
layout::Endian::Big => target.write_int128::<BigEndian>(data, len),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
|
|
||||||
match endianness {
|
|
||||||
layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
|
|
||||||
layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Unaligned accesses
|
// Unaligned accesses
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -23,9 +23,11 @@ pub use self::const_eval::{
|
||||||
mk_borrowck_eval_cx,
|
mk_borrowck_eval_cx,
|
||||||
eval_body,
|
eval_body,
|
||||||
CompileTimeEvaluator,
|
CompileTimeEvaluator,
|
||||||
|
const_value_to_allocation_provider,
|
||||||
const_eval_provider,
|
const_eval_provider,
|
||||||
const_val_field,
|
const_val_field,
|
||||||
const_variant_index,
|
const_variant_index,
|
||||||
|
value_to_const_value,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use self::machine::Machine;
|
pub use self::machine::Machine;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::ty::{self, Ty};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
|
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
|
|
||||||
|
@ -69,9 +69,13 @@ impl<'tcx> Place {
|
||||||
self.to_ptr_align().0.to_ptr()
|
self.to_ptr_align().0.to_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) {
|
pub(super) fn elem_ty_and_len(
|
||||||
|
self,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
tcx: TyCtxt<'_, 'tcx, '_>
|
||||||
|
) -> (Ty<'tcx>, u64) {
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::TyArray(elem, n) => (elem, n.val.unwrap_u64() as u64),
|
ty::TyArray(elem, n) => (elem, n.unwrap_usize(tcx)),
|
||||||
|
|
||||||
ty::TySlice(elem) => {
|
ty::TySlice(elem) => {
|
||||||
match self {
|
match self {
|
||||||
|
@ -320,7 +324,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
let base = self.force_allocation(base)?;
|
let base = self.force_allocation(base)?;
|
||||||
let (base_ptr, align) = base.to_ptr_align();
|
let (base_ptr, align) = base.to_ptr_align();
|
||||||
|
|
||||||
let (elem_ty, len) = base.elem_ty_and_len(outer_ty);
|
let (elem_ty, len) = base.elem_ty_and_len(outer_ty, self.tcx.tcx);
|
||||||
let elem_size = self.layout_of(elem_ty)?.size.bytes();
|
let elem_size = self.layout_of(elem_ty)?.size.bytes();
|
||||||
assert!(
|
assert!(
|
||||||
n < len,
|
n < len,
|
||||||
|
@ -396,7 +400,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
let base = self.force_allocation(base)?;
|
let base = self.force_allocation(base)?;
|
||||||
let (base_ptr, align) = base.to_ptr_align();
|
let (base_ptr, align) = base.to_ptr_align();
|
||||||
|
|
||||||
let (elem_ty, n) = base.elem_ty_and_len(base_ty);
|
let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx);
|
||||||
let elem_size = self.layout_of(elem_ty)?.size.bytes();
|
let elem_size = self.layout_of(elem_ty)?.size.bytes();
|
||||||
assert!(n >= min_length as u64);
|
assert!(n >= min_length as u64);
|
||||||
|
|
||||||
|
@ -415,7 +419,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
let base = self.force_allocation(base)?;
|
let base = self.force_allocation(base)?;
|
||||||
let (base_ptr, align) = base.to_ptr_align();
|
let (base_ptr, align) = base.to_ptr_align();
|
||||||
|
|
||||||
let (elem_ty, n) = base.elem_ty_and_len(base_ty);
|
let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx);
|
||||||
let elem_size = self.layout_of(elem_ty)?.size.bytes();
|
let elem_size = self.layout_of(elem_ty)?.size.bytes();
|
||||||
assert!(u64::from(from) <= n - u64::from(to));
|
assert!(u64::from(from) <= n - u64::from(to));
|
||||||
let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?;
|
let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?;
|
||||||
|
|
|
@ -85,6 +85,7 @@ pub fn provide(providers: &mut Providers) {
|
||||||
shim::provide(providers);
|
shim::provide(providers);
|
||||||
transform::provide(providers);
|
transform::provide(providers);
|
||||||
providers.const_eval = interpret::const_eval_provider;
|
providers.const_eval = interpret::const_eval_provider;
|
||||||
|
providers.const_value_to_allocation = interpret::const_value_to_allocation_provider;
|
||||||
providers.check_match = hair::pattern::check_match;
|
providers.check_match = hair::pattern::check_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||||
use rustc::hir::map as hir_map;
|
use rustc::hir::map as hir_map;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::middle::const_val::ConstVal;
|
use rustc::middle::const_val::ConstVal;
|
||||||
use rustc::mir::interpret::{Value, PrimVal, AllocId, Pointer};
|
use rustc::mir::interpret::{AllocId, ConstValue};
|
||||||
use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
|
use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
|
||||||
use rustc::ty::subst::{Substs, Kind};
|
use rustc::ty::subst::{Substs, Kind};
|
||||||
use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
|
use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
|
||||||
|
@ -203,7 +203,7 @@ use rustc::session::config;
|
||||||
use rustc::mir::{self, Location, Promoted};
|
use rustc::mir::{self, Location, Promoted};
|
||||||
use rustc::mir::visit::Visitor as MirVisitor;
|
use rustc::mir::visit::Visitor as MirVisitor;
|
||||||
use rustc::mir::mono::MonoItem;
|
use rustc::mir::mono::MonoItem;
|
||||||
use rustc::mir::interpret::GlobalId;
|
use rustc::mir::interpret::{PrimVal, GlobalId};
|
||||||
|
|
||||||
use monomorphize::{self, Instance};
|
use monomorphize::{self, Instance};
|
||||||
use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
|
use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
|
||||||
|
@ -1237,22 +1237,17 @@ fn collect_const<'a, 'tcx>(
|
||||||
};
|
};
|
||||||
match val {
|
match val {
|
||||||
ConstVal::Unevaluated(..) => bug!("const eval yielded unevaluated const"),
|
ConstVal::Unevaluated(..) => bug!("const eval yielded unevaluated const"),
|
||||||
ConstVal::Value(Value::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => {
|
ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => {
|
||||||
collect_miri(tcx, a.alloc_id, output);
|
collect_miri(tcx, a.alloc_id, output);
|
||||||
collect_miri(tcx, b.alloc_id, output);
|
collect_miri(tcx, b.alloc_id, output);
|
||||||
}
|
}
|
||||||
ConstVal::Value(Value::ByValPair(_, PrimVal::Ptr(ptr))) |
|
ConstVal::Value(ConstValue::ByValPair(_, PrimVal::Ptr(ptr))) |
|
||||||
ConstVal::Value(Value::ByValPair(PrimVal::Ptr(ptr), _)) |
|
ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(ptr), _)) |
|
||||||
ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) =>
|
ConstVal::Value(ConstValue::ByVal(PrimVal::Ptr(ptr))) =>
|
||||||
collect_miri(tcx, ptr.alloc_id, output),
|
collect_miri(tcx, ptr.alloc_id, output),
|
||||||
ConstVal::Value(Value::ByRef(Pointer { primval: PrimVal::Ptr(ptr) }, _)) => {
|
ConstVal::Value(ConstValue::ByRef(alloc)) => {
|
||||||
// by ref should only collect the inner allocation, not the value itself
|
for &id in alloc.relocations.values() {
|
||||||
let alloc = tcx
|
collect_miri(tcx, id, output);
|
||||||
.interpret_interner
|
|
||||||
.get_alloc(ptr.alloc_id)
|
|
||||||
.expect("ByRef to extern static is not allowed");
|
|
||||||
for &inner in alloc.relocations.values() {
|
|
||||||
collect_miri(tcx, inner, output);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {},
|
_ => {},
|
||||||
|
|
|
@ -313,8 +313,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||||
ty::TyArray(inner_type, len) => {
|
ty::TyArray(inner_type, len) => {
|
||||||
output.push('[');
|
output.push('[');
|
||||||
self.push_type_name(inner_type, output);
|
self.push_type_name(inner_type, output);
|
||||||
write!(output, "; {}",
|
write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
|
||||||
len.val.unwrap_u64()).unwrap();
|
|
||||||
output.push(']');
|
output.push(']');
|
||||||
},
|
},
|
||||||
ty::TySlice(inner_type) => {
|
ty::TySlice(inner_type) => {
|
||||||
|
|
|
@ -11,12 +11,10 @@
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::infer;
|
use rustc::infer;
|
||||||
use rustc::middle::const_val::ConstVal;
|
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc::ty::subst::{Kind, Subst, Substs};
|
use rustc::ty::subst::{Kind, Subst, Substs};
|
||||||
use rustc::ty::maps::Providers;
|
use rustc::ty::maps::Providers;
|
||||||
use rustc::mir::interpret::{Value, PrimVal};
|
|
||||||
|
|
||||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||||
|
|
||||||
|
@ -303,7 +301,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
match self_ty.sty {
|
match self_ty.sty {
|
||||||
_ if is_copy => builder.copy_shim(),
|
_ if is_copy => builder.copy_shim(),
|
||||||
ty::TyArray(ty, len) => {
|
ty::TyArray(ty, len) => {
|
||||||
let len = len.val.unwrap_u64();
|
let len = len.unwrap_usize(tcx);
|
||||||
builder.array_shim(dest, src, ty, len)
|
builder.array_shim(dest, src, ty, len)
|
||||||
}
|
}
|
||||||
ty::TyClosure(def_id, substs) => {
|
ty::TyClosure(def_id, substs) => {
|
||||||
|
@ -442,11 +440,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||||
span: self.span,
|
span: self.span,
|
||||||
ty: func_ty,
|
ty: func_ty,
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: tcx.mk_const(ty::Const {
|
value: ty::Const::zero_sized(self.tcx, func_ty)
|
||||||
// ZST function type
|
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
|
|
||||||
ty: func_ty
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -506,10 +500,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||||
span: self.span,
|
span: self.span,
|
||||||
ty: self.tcx.types.usize,
|
ty: self.tcx.types.usize,
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: self.tcx.mk_const(ty::Const {
|
value: ty::Const::from_usize(self.tcx, value),
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))),
|
|
||||||
ty: self.tcx.types.usize,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -738,11 +729,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
span,
|
span,
|
||||||
ty,
|
ty,
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: tcx.mk_const(ty::Const {
|
value: ty::Const::zero_sized(tcx, ty)
|
||||||
// ZST function type
|
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
|
|
||||||
ty
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
vec![rcvr])
|
vec![rcvr])
|
||||||
|
|
|
@ -19,15 +19,17 @@ use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionE
|
||||||
use rustc::mir::visit::{Visitor, PlaceContext};
|
use rustc::mir::visit::{Visitor, PlaceContext};
|
||||||
use rustc::middle::const_val::ConstVal;
|
use rustc::middle::const_val::ConstVal;
|
||||||
use rustc::ty::{TyCtxt, self, Instance};
|
use rustc::ty::{TyCtxt, self, Instance};
|
||||||
use rustc::mir::interpret::{Value, PrimVal, GlobalId};
|
use rustc::mir::interpret::{Value, PrimVal, GlobalId, EvalResult};
|
||||||
|
use interpret::EvalContext;
|
||||||
|
use interpret::CompileTimeEvaluator;
|
||||||
use interpret::{eval_promoted, mk_borrowck_eval_cx, ValTy};
|
use interpret::{eval_promoted, mk_borrowck_eval_cx, ValTy};
|
||||||
use transform::{MirPass, MirSource};
|
use transform::{MirPass, MirSource};
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::{Span, DUMMY_SP};
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
use rustc_data_structures::indexed_vec::IndexVec;
|
use rustc_data_structures::indexed_vec::IndexVec;
|
||||||
use rustc::ty::ParamEnv;
|
use rustc::ty::ParamEnv;
|
||||||
use rustc::ty::layout::{
|
use rustc::ty::layout::{
|
||||||
LayoutOf, TyLayout, LayoutError,
|
LayoutOf, TyLayout, LayoutError, LayoutCx,
|
||||||
HasTyCtxt, TargetDataLayout, HasDataLayout,
|
HasTyCtxt, TargetDataLayout, HasDataLayout,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -64,6 +66,7 @@ type Const<'tcx> = (Value, ty::Ty<'tcx>, Span);
|
||||||
|
|
||||||
/// Finds optimization opportunities on the MIR.
|
/// Finds optimization opportunities on the MIR.
|
||||||
struct ConstPropagator<'b, 'a, 'tcx:'a+'b> {
|
struct ConstPropagator<'b, 'a, 'tcx:'a+'b> {
|
||||||
|
ecx: EvalContext<'a, 'b, 'tcx, CompileTimeEvaluator>,
|
||||||
mir: &'b Mir<'tcx>,
|
mir: &'b Mir<'tcx>,
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
source: MirSource,
|
source: MirSource,
|
||||||
|
@ -102,7 +105,11 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
source: MirSource,
|
source: MirSource,
|
||||||
) -> ConstPropagator<'b, 'a, 'tcx> {
|
) -> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
let param_env = tcx.param_env(source.def_id);
|
let param_env = tcx.param_env(source.def_id);
|
||||||
|
let substs = Substs::identity_for_item(tcx, source.def_id);
|
||||||
|
let instance = Instance::new(source.def_id, substs);
|
||||||
|
let ecx = mk_borrowck_eval_cx(tcx, instance, mir, DUMMY_SP).unwrap();
|
||||||
ConstPropagator {
|
ConstPropagator {
|
||||||
|
ecx,
|
||||||
mir,
|
mir,
|
||||||
tcx,
|
tcx,
|
||||||
source,
|
source,
|
||||||
|
@ -112,7 +119,27 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
|
fn use_ecx<F, T>(
|
||||||
|
&mut self,
|
||||||
|
span: Span,
|
||||||
|
f: F
|
||||||
|
) -> Option<T>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut Self) -> EvalResult<'tcx, T>,
|
||||||
|
{
|
||||||
|
self.ecx.tcx.span = span;
|
||||||
|
let r = match f(self) {
|
||||||
|
Ok(val) => Some(val),
|
||||||
|
Err(mut err) => {
|
||||||
|
self.ecx.report(&mut err, false, Some(span));
|
||||||
|
None
|
||||||
|
},
|
||||||
|
};
|
||||||
|
self.ecx.tcx.span = DUMMY_SP;
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
fn const_eval(&mut self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
|
||||||
let value = match self.tcx.const_eval(self.param_env.and(cid)) {
|
let value = match self.tcx.const_eval(self.param_env.and(cid)) {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@ -121,7 +148,9 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let val = match value.val {
|
let val = match value.val {
|
||||||
ConstVal::Value(v) => v,
|
ConstVal::Value(v) => {
|
||||||
|
self.use_ecx(span, |this| this.ecx.const_value_to_value(v, value.ty))?
|
||||||
|
},
|
||||||
_ => bug!("eval produced: {:?}", value),
|
_ => bug!("eval produced: {:?}", value),
|
||||||
};
|
};
|
||||||
let val = (val, value.ty, span);
|
let val = (val, value.ty, span);
|
||||||
|
@ -132,7 +161,12 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
|
fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
|
||||||
match c.literal {
|
match c.literal {
|
||||||
Literal::Value { value } => match value.val {
|
Literal::Value { value } => match value.val {
|
||||||
ConstVal::Value(v) => Some((v, value.ty, c.span)),
|
ConstVal::Value(v) => {
|
||||||
|
let v = self.use_ecx(c.span, |this| {
|
||||||
|
this.ecx.const_value_to_value(v, value.ty)
|
||||||
|
})?;
|
||||||
|
Some((v, value.ty, c.span))
|
||||||
|
},
|
||||||
ConstVal::Unevaluated(did, substs) => {
|
ConstVal::Unevaluated(did, substs) => {
|
||||||
let instance = Instance::resolve(
|
let instance = Instance::resolve(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
|
@ -162,7 +196,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
};
|
};
|
||||||
// cannot use `const_eval` here, because that would require having the MIR
|
// cannot use `const_eval` here, because that would require having the MIR
|
||||||
// for the current function available, but we're producing said MIR right now
|
// for the current function available, but we're producing said MIR right now
|
||||||
let (value, _, ty) = eval_promoted(self.tcx, cid, self.mir, self.param_env)?;
|
let span = self.mir.span;
|
||||||
|
let (value, _, ty) = self.use_ecx(span, |this| {
|
||||||
|
Ok(eval_promoted(&mut this.ecx, cid, this.mir, this.param_env))
|
||||||
|
})??;
|
||||||
let val = (value, ty, c.span);
|
let val = (value, ty, c.span);
|
||||||
trace!("evaluated {:?} to {:?}", c, val);
|
trace!("evaluated {:?} to {:?}", c, val);
|
||||||
Some(val)
|
Some(val)
|
||||||
|
@ -185,7 +222,11 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
let field_index = field.index();
|
let field_index = field.index();
|
||||||
let val = [a, b][field_index];
|
let val = [a, b][field_index];
|
||||||
let field = base_layout.field(&*self, field_index).ok()?;
|
let cx = LayoutCx {
|
||||||
|
tcx: self.tcx,
|
||||||
|
param_env: self.param_env,
|
||||||
|
};
|
||||||
|
let field = base_layout.field(cx, field_index).ok()?;
|
||||||
trace!("projection resulted in: {:?}", val);
|
trace!("projection resulted in: {:?}", val);
|
||||||
Some((Value::ByVal(val), field.ty, span))
|
Some((Value::ByVal(val), field.ty, span))
|
||||||
},
|
},
|
||||||
|
@ -258,19 +299,13 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
// FIXME: can't handle code with generics
|
// FIXME: can't handle code with generics
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
|
|
||||||
let instance = Instance::new(self.source.def_id, substs);
|
|
||||||
let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap();
|
|
||||||
|
|
||||||
let val = self.eval_operand(arg)?;
|
let val = self.eval_operand(arg)?;
|
||||||
let prim = ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }).ok()?;
|
let prim = self.use_ecx(span, |this| {
|
||||||
match ecx.unary_op(op, prim, val.1) {
|
this.ecx.value_to_primval(ValTy { value: val.0, ty: val.1 })
|
||||||
Ok(val) => Some((Value::ByVal(val), place_ty, span)),
|
})?;
|
||||||
Err(mut err) => {
|
let val = self.use_ecx(span, |this| this.ecx.unary_op(op, prim, val.1))?;
|
||||||
ecx.report(&mut err, false, Some(span));
|
Some((Value::ByVal(val), place_ty, span))
|
||||||
None
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Rvalue::CheckedBinaryOp(op, ref left, ref right) |
|
Rvalue::CheckedBinaryOp(op, ref left, ref right) |
|
||||||
Rvalue::BinaryOp(op, ref left, ref right) => {
|
Rvalue::BinaryOp(op, ref left, ref right) => {
|
||||||
|
@ -287,11 +322,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
// FIXME: can't handle code with generics
|
// FIXME: can't handle code with generics
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
|
|
||||||
let instance = Instance::new(self.source.def_id, substs);
|
|
||||||
let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap();
|
|
||||||
|
|
||||||
let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?;
|
let r = self.use_ecx(span, |this| {
|
||||||
|
this.ecx.value_to_primval(ValTy { value: right.0, ty: right.1 })
|
||||||
|
})?;
|
||||||
if op == BinOp::Shr || op == BinOp::Shl {
|
if op == BinOp::Shr || op == BinOp::Shl {
|
||||||
let param_env = self.tcx.param_env(self.source.def_id);
|
let param_env = self.tcx.param_env(self.source.def_id);
|
||||||
let left_ty = left.ty(self.mir, self.tcx);
|
let left_ty = left.ty(self.mir, self.tcx);
|
||||||
|
@ -316,31 +350,31 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let left = self.eval_operand(left)?;
|
let left = self.eval_operand(left)?;
|
||||||
let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?;
|
let l = self.use_ecx(span, |this| {
|
||||||
|
this.ecx.value_to_primval(ValTy { value: left.0, ty: left.1 })
|
||||||
|
})?;
|
||||||
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
|
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
|
||||||
match ecx.binary_op(op, l, left.1, r, right.1) {
|
let (val, overflow) = self.use_ecx(span, |this| {
|
||||||
Ok((val, overflow)) => {
|
this.ecx.binary_op(op, l, left.1, r, right.1)
|
||||||
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
|
})?;
|
||||||
Value::ByValPair(
|
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
|
||||||
val,
|
Value::ByValPair(
|
||||||
PrimVal::from_bool(overflow),
|
val,
|
||||||
)
|
PrimVal::from_bool(overflow),
|
||||||
} else {
|
)
|
||||||
if overflow {
|
} else {
|
||||||
use rustc::mir::interpret::EvalErrorKind;
|
if overflow {
|
||||||
let mut err = EvalErrorKind::Overflow(op).into();
|
use rustc::mir::interpret::EvalErrorKind;
|
||||||
ecx.report(&mut err, false, Some(span));
|
let mut err = EvalErrorKind::Overflow(op).into();
|
||||||
return None;
|
self.use_ecx(span, |this| {
|
||||||
}
|
this.ecx.report(&mut err, false, Some(span));
|
||||||
Value::ByVal(val)
|
Ok(())
|
||||||
};
|
});
|
||||||
Some((val, place_ty, span))
|
return None;
|
||||||
},
|
}
|
||||||
Err(mut err) => {
|
Value::ByVal(val)
|
||||||
ecx.report(&mut err, false, Some(span));
|
};
|
||||||
None
|
Some((val, place_ty, span))
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@ use dataflow::MoveDataParamEnv;
|
||||||
use dataflow::{self, do_dataflow, DebugFormatted};
|
use dataflow::{self, do_dataflow, DebugFormatted};
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::middle::const_val::ConstVal;
|
|
||||||
use rustc::mir::interpret::{Value, PrimVal};
|
|
||||||
use rustc::util::nodemap::FxHashMap;
|
use rustc::util::nodemap::FxHashMap;
|
||||||
use rustc_data_structures::indexed_set::IdxSetBuf;
|
use rustc_data_structures::indexed_set::IdxSetBuf;
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
|
@ -533,10 +531,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
span,
|
span,
|
||||||
ty: self.tcx.types.bool,
|
ty: self.tcx.types.bool,
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: self.tcx.mk_const(ty::Const {
|
value: ty::Const::from_bool(self.tcx, val)
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val as u128))),
|
|
||||||
ty: self.tcx.types.bool
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,6 @@
|
||||||
|
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::middle::const_val::ConstVal;
|
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor};
|
use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor};
|
||||||
use rustc::ty::{self, TyCtxt, AdtDef, Ty};
|
use rustc::ty::{self, TyCtxt, AdtDef, Ty};
|
||||||
|
@ -79,7 +78,6 @@ use transform::simplify;
|
||||||
use transform::no_landing_pads::no_landing_pads;
|
use transform::no_landing_pads::no_landing_pads;
|
||||||
use dataflow::{do_dataflow, DebugFormatted, state_for_location};
|
use dataflow::{do_dataflow, DebugFormatted, state_for_location};
|
||||||
use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals};
|
use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals};
|
||||||
use rustc::mir::interpret::{Value, PrimVal};
|
|
||||||
|
|
||||||
pub struct StateTransform;
|
pub struct StateTransform;
|
||||||
|
|
||||||
|
@ -180,10 +178,10 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
|
||||||
span: source_info.span,
|
span: source_info.span,
|
||||||
ty: self.tcx.types.u32,
|
ty: self.tcx.types.u32,
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: self.tcx.mk_const(ty::Const {
|
value: ty::Const::from_bits(
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))),
|
self.tcx,
|
||||||
ty: self.tcx.types.u32
|
state_disc.into(),
|
||||||
}),
|
self.tcx.types.u32),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
Statement {
|
Statement {
|
||||||
|
@ -698,10 +696,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
span: mir.span,
|
span: mir.span,
|
||||||
ty: tcx.types.bool,
|
ty: tcx.types.bool,
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: tcx.mk_const(ty::Const {
|
value: ty::Const::from_bool(tcx, false),
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
|
|
||||||
ty: tcx.types.bool
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
expected: true,
|
expected: true,
|
||||||
|
|
|
@ -595,7 +595,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||||
}
|
}
|
||||||
Operand::Constant(ref constant) => {
|
Operand::Constant(ref constant) => {
|
||||||
if let Literal::Value {
|
if let Literal::Value {
|
||||||
value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty }
|
value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty, .. }
|
||||||
} = constant.literal {
|
} = constant.literal {
|
||||||
// Don't peek inside trait associated constants.
|
// Don't peek inside trait associated constants.
|
||||||
if self.tcx.trait_of_item(def_id).is_some() {
|
if self.tcx.trait_of_item(def_id).is_some() {
|
||||||
|
@ -690,7 +690,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
} else if let ty::TyArray(_, len) = ty.sty {
|
} else if let ty::TyArray(_, len) = ty.sty {
|
||||||
len.val.unwrap_u64() == 0 &&
|
len.unwrap_usize(self.tcx) == 0 &&
|
||||||
self.mode == Mode::Fn
|
self.mode == Mode::Fn
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
|
|
@ -10,10 +10,8 @@
|
||||||
|
|
||||||
//! A pass that simplifies branches when their condition is known.
|
//! A pass that simplifies branches when their condition is known.
|
||||||
|
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::TyCtxt;
|
||||||
use rustc::middle::const_val::ConstVal;
|
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::mir::interpret::{Value, PrimVal};
|
|
||||||
use transform::{MirPass, MirSource};
|
use transform::{MirPass, MirSource};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
@ -32,7 +30,7 @@ impl MirPass for SimplifyBranches {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_pass<'a, 'tcx>(&self,
|
fn run_pass<'a, 'tcx>(&self,
|
||||||
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
_src: MirSource,
|
_src: MirSource,
|
||||||
mir: &mut Mir<'tcx>) {
|
mir: &mut Mir<'tcx>) {
|
||||||
for block in mir.basic_blocks_mut() {
|
for block in mir.basic_blocks_mut() {
|
||||||
|
@ -40,8 +38,8 @@ impl MirPass for SimplifyBranches {
|
||||||
terminator.kind = match terminator.kind {
|
terminator.kind = match terminator.kind {
|
||||||
TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
|
TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
|
||||||
literal: Literal::Value { ref value }, ..
|
literal: Literal::Value { ref value }, ..
|
||||||
}), ref values, ref targets, .. } => {
|
}), switch_ty, ref values, ref targets, .. } => {
|
||||||
if let Some(constint) = value.val.to_raw_bits() {
|
if let Some(constint) = value.assert_bits(switch_ty) {
|
||||||
let (otherwise, targets) = targets.split_last().unwrap();
|
let (otherwise, targets) = targets.split_last().unwrap();
|
||||||
let mut ret = TerminatorKind::Goto { target: *otherwise };
|
let mut ret = TerminatorKind::Goto { target: *otherwise };
|
||||||
for (&v, t) in values.iter().zip(targets.iter()) {
|
for (&v, t) in values.iter().zip(targets.iter()) {
|
||||||
|
@ -57,12 +55,9 @@ impl MirPass for SimplifyBranches {
|
||||||
},
|
},
|
||||||
TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
|
TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: &ty::Const {
|
value
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(cond))),
|
|
||||||
.. }
|
|
||||||
}, ..
|
}, ..
|
||||||
}), expected, .. } if (cond == 1) == expected => {
|
}), expected, .. } if (value.assert_bool(tcx) == Some(true)) == expected => {
|
||||||
assert!(cond <= 1);
|
|
||||||
TerminatorKind::Goto { target: target }
|
TerminatorKind::Goto { target: target }
|
||||||
},
|
},
|
||||||
TerminatorKind::FalseEdges { real_target, .. } => {
|
TerminatorKind::FalseEdges { real_target, .. } => {
|
||||||
|
|
|
@ -81,9 +81,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
|
let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
|
||||||
if let ty::TyArray(item_ty, const_size) = place_ty.sty {
|
if let ty::TyArray(item_ty, const_size) = place_ty.sty {
|
||||||
if let Some(size) = const_size.val.to_raw_bits() {
|
if let Some(size) = const_size.assert_usize(self.tcx) {
|
||||||
assert!(size <= (u32::max_value() as u128),
|
assert!(size <= u32::max_value() as u64,
|
||||||
"unform array move out doesn't supported
|
"uniform array move out doesn't supported
|
||||||
for array bigger then u32");
|
for array bigger then u32");
|
||||||
self.uniform(location, dst_place, proj, item_ty, size as u32);
|
self.uniform(location, dst_place, proj, item_ty, size as u32);
|
||||||
}
|
}
|
||||||
|
@ -203,7 +203,7 @@ impl MirPass for RestoreSubsliceArrayMoveOut {
|
||||||
let opt_size = opt_src_place.and_then(|src_place| {
|
let opt_size = opt_src_place.and_then(|src_place| {
|
||||||
let src_ty = src_place.ty(mir, tcx).to_ty(tcx);
|
let src_ty = src_place.ty(mir, tcx).to_ty(tcx);
|
||||||
if let ty::TyArray(_, ref size_o) = src_ty.sty {
|
if let ty::TyArray(_, ref size_o) = src_ty.sty {
|
||||||
size_o.val.to_raw_bits().map(|n| n as u64)
|
size_o.assert_usize(tcx)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::middle::const_val::ConstVal;
|
|
||||||
use rustc::middle::lang_items;
|
use rustc::middle::lang_items;
|
||||||
use rustc::traits::Reveal;
|
use rustc::traits::Reveal;
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
|
@ -19,7 +18,6 @@ use rustc::ty::subst::{Kind, Substs};
|
||||||
use rustc::ty::util::IntTypeExt;
|
use rustc::ty::util::IntTypeExt;
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
use util::patch::MirPatch;
|
use util::patch::MirPatch;
|
||||||
use rustc::mir::interpret::{Value, PrimVal};
|
|
||||||
|
|
||||||
use std::{iter, u32};
|
use std::{iter, u32};
|
||||||
|
|
||||||
|
@ -809,8 +807,10 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||||
let succ = self.succ;
|
let succ = self.succ;
|
||||||
self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
|
self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
|
||||||
}
|
}
|
||||||
ty::TyArray(ety, size) => self.open_drop_for_array(
|
ty::TyArray(ety, size) => {
|
||||||
ety, size.val.to_raw_bits().map(|i| i as u64)),
|
let size = size.assert_usize(self.tcx());
|
||||||
|
self.open_drop_for_array(ety, size)
|
||||||
|
},
|
||||||
ty::TySlice(ety) => self.open_drop_for_array(ety, None),
|
ty::TySlice(ety) => self.open_drop_for_array(ety, None),
|
||||||
|
|
||||||
_ => bug!("open drop from non-ADT `{:?}`", ty)
|
_ => bug!("open drop from non-ADT `{:?}`", ty)
|
||||||
|
@ -961,10 +961,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||||
span: self.source_info.span,
|
span: self.source_info.span,
|
||||||
ty: self.tcx().types.usize,
|
ty: self.tcx().types.usize,
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: self.tcx().mk_const(ty::Const {
|
value: ty::Const::from_usize(self.tcx(), val.into())
|
||||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into()))),
|
|
||||||
ty: self.tcx().types.usize
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -402,7 +402,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> {
|
||||||
|
|
||||||
fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
|
fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
|
||||||
self.super_const(constant);
|
self.super_const(constant);
|
||||||
let ty::Const { ty, val } = constant;
|
let ty::Const { ty, val, .. } = constant;
|
||||||
self.push(&format!("ty::Const"));
|
self.push(&format!("ty::Const"));
|
||||||
self.push(&format!("+ ty: {:?}", ty));
|
self.push(&format!("+ ty: {:?}", ty));
|
||||||
self.push(&format!("+ val: {:?}", val));
|
self.push(&format!("+ val: {:?}", val));
|
||||||
|
|
|
@ -199,7 +199,7 @@ pub fn unsized_info<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>,
|
||||||
let (source, target) = cx.tcx.struct_lockstep_tails(source, target);
|
let (source, target) = cx.tcx.struct_lockstep_tails(source, target);
|
||||||
match (&source.sty, &target.sty) {
|
match (&source.sty, &target.sty) {
|
||||||
(&ty::TyArray(_, len), &ty::TySlice(_)) => {
|
(&ty::TyArray(_, len), &ty::TySlice(_)) => {
|
||||||
C_usize(cx, len.val.unwrap_u64())
|
C_usize(cx, len.unwrap_usize(cx.tcx))
|
||||||
}
|
}
|
||||||
(&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
|
(&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
|
||||||
// For now, upcasts are limited to changes in marker
|
// For now, upcasts are limited to changes in marker
|
||||||
|
@ -1372,7 +1372,7 @@ mod temp_stable_hash_impls {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec<u8>) {
|
fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec<u8>) {
|
||||||
use rustc::mir::interpret::{GlobalId, Value, PrimVal};
|
use rustc::mir::interpret::GlobalId;
|
||||||
use rustc::middle::const_val::ConstVal;
|
use rustc::middle::const_val::ConstVal;
|
||||||
|
|
||||||
info!("loading wasm section {:?}", id);
|
info!("loading wasm section {:?}", id);
|
||||||
|
@ -1392,22 +1392,11 @@ fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec<u8>) {
|
||||||
let param_env = ty::ParamEnv::reveal_all();
|
let param_env = ty::ParamEnv::reveal_all();
|
||||||
let val = tcx.const_eval(param_env.and(cid)).unwrap();
|
let val = tcx.const_eval(param_env.and(cid)).unwrap();
|
||||||
|
|
||||||
let val = match val.val {
|
let const_val = match val.val {
|
||||||
ConstVal::Value(val) => val,
|
ConstVal::Value(val) => val,
|
||||||
ConstVal::Unevaluated(..) => bug!("should be evaluated"),
|
ConstVal::Unevaluated(..) => bug!("should be evaluated"),
|
||||||
};
|
};
|
||||||
let val = match val {
|
|
||||||
Value::ByRef(ptr, _align) => ptr.into_inner_primval(),
|
let alloc = tcx.const_value_to_allocation((const_val, val.ty));
|
||||||
ref v => bug!("should be ByRef, was {:?}", v),
|
|
||||||
};
|
|
||||||
let mem = match val {
|
|
||||||
PrimVal::Ptr(mem) => mem,
|
|
||||||
ref v => bug!("should be Ptr, was {:?}", v),
|
|
||||||
};
|
|
||||||
assert_eq!(mem.offset, 0);
|
|
||||||
let alloc = tcx
|
|
||||||
.interpret_interner
|
|
||||||
.get_alloc(mem.alloc_id)
|
|
||||||
.expect("miri allocation never successfully created");
|
|
||||||
(section.to_string(), alloc.bytes.clone())
|
(section.to_string(), alloc.bytes.clone())
|
||||||
}
|
}
|
||||||
|
|
|
@ -277,7 +277,7 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||||
|
|
||||||
let upper_bound = match array_or_slice_type.sty {
|
let upper_bound = match array_or_slice_type.sty {
|
||||||
ty::TyArray(_, len) => {
|
ty::TyArray(_, len) => {
|
||||||
len.val.unwrap_u64() as c_longlong
|
len.unwrap_usize(cx.tcx) as c_longlong
|
||||||
}
|
}
|
||||||
_ => -1
|
_ => -1
|
||||||
};
|
};
|
||||||
|
|
|
@ -97,7 +97,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||||
ty::TyArray(inner_type, len) => {
|
ty::TyArray(inner_type, len) => {
|
||||||
output.push('[');
|
output.push('[');
|
||||||
push_debuginfo_type_name(cx, inner_type, true, output);
|
push_debuginfo_type_name(cx, inner_type, true, output);
|
||||||
output.push_str(&format!("; {}", len.val.unwrap_u64()));
|
output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx)));
|
||||||
output.push(']');
|
output.push(']');
|
||||||
},
|
},
|
||||||
ty::TySlice(inner_type) => {
|
ty::TySlice(inner_type) => {
|
||||||
|
|
|
@ -14,7 +14,7 @@ use rustc_mir::interpret::{read_target_uint, const_val_field};
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue};
|
use rustc::mir::interpret::{GlobalId, MemoryPointer, PrimVal, Allocation, ConstValue};
|
||||||
use rustc::ty::{self, Ty};
|
use rustc::ty::{self, Ty};
|
||||||
use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar};
|
use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar};
|
||||||
use builder::Builder;
|
use builder::Builder;
|
||||||
|
@ -56,7 +56,7 @@ pub fn primval_to_llvm(cx: &CodegenCx,
|
||||||
consts::get_static(cx, def_id)
|
consts::get_static(cx, def_id)
|
||||||
} else if let Some(alloc) = cx.tcx.interpret_interner
|
} else if let Some(alloc) = cx.tcx.interpret_interner
|
||||||
.get_alloc(ptr.alloc_id) {
|
.get_alloc(ptr.alloc_id) {
|
||||||
let init = global_initializer(cx, alloc);
|
let init = const_alloc_to_llvm(cx, alloc);
|
||||||
if alloc.runtime_mutability == Mutability::Mutable {
|
if alloc.runtime_mutability == Mutability::Mutable {
|
||||||
consts::addr_of_mut(cx, init, alloc.align, "byte_str")
|
consts::addr_of_mut(cx, init, alloc.align, "byte_str")
|
||||||
} else {
|
} else {
|
||||||
|
@ -81,7 +81,50 @@ pub fn primval_to_llvm(cx: &CodegenCx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
|
fn const_value_to_llvm<'tcx>(cx: &CodegenCx<'_, 'tcx>, val: ConstValue, ty: Ty<'tcx>) -> ValueRef {
|
||||||
|
let layout = cx.layout_of(ty);
|
||||||
|
|
||||||
|
if layout.is_zst() {
|
||||||
|
return C_undef(layout.immediate_llvm_type(cx));
|
||||||
|
}
|
||||||
|
|
||||||
|
match val {
|
||||||
|
ConstValue::ByVal(x) => {
|
||||||
|
let scalar = match layout.abi {
|
||||||
|
layout::Abi::Scalar(ref x) => x,
|
||||||
|
_ => bug!("const_value_to_llvm: invalid ByVal layout: {:#?}", layout)
|
||||||
|
};
|
||||||
|
primval_to_llvm(
|
||||||
|
cx,
|
||||||
|
x,
|
||||||
|
scalar,
|
||||||
|
layout.immediate_llvm_type(cx),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
ConstValue::ByValPair(a, b) => {
|
||||||
|
let (a_scalar, b_scalar) = match layout.abi {
|
||||||
|
layout::Abi::ScalarPair(ref a, ref b) => (a, b),
|
||||||
|
_ => bug!("const_value_to_llvm: invalid ByValPair layout: {:#?}", layout)
|
||||||
|
};
|
||||||
|
let a_llval = primval_to_llvm(
|
||||||
|
cx,
|
||||||
|
a,
|
||||||
|
a_scalar,
|
||||||
|
layout.scalar_pair_element_llvm_type(cx, 0),
|
||||||
|
);
|
||||||
|
let b_llval = primval_to_llvm(
|
||||||
|
cx,
|
||||||
|
b,
|
||||||
|
b_scalar,
|
||||||
|
layout.scalar_pair_element_llvm_type(cx, 1),
|
||||||
|
);
|
||||||
|
C_struct(cx, &[a_llval, b_llval], false)
|
||||||
|
},
|
||||||
|
ConstValue::ByRef(alloc) => const_alloc_to_llvm(cx, alloc),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
|
||||||
let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
|
let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
|
||||||
let layout = cx.data_layout();
|
let layout = cx.data_layout();
|
||||||
let pointer_size = layout.pointer_size.bytes() as usize;
|
let pointer_size = layout.pointer_size.bytes() as usize;
|
||||||
|
@ -96,7 +139,7 @@ pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
|
||||||
let ptr_offset = read_target_uint(
|
let ptr_offset = read_target_uint(
|
||||||
layout.endian,
|
layout.endian,
|
||||||
&alloc.bytes[offset..(offset + pointer_size)],
|
&alloc.bytes[offset..(offset + pointer_size)],
|
||||||
).expect("global_initializer: could not read relocation pointer") as u64;
|
).expect("const_alloc_to_llvm: could not read relocation pointer") as u64;
|
||||||
llvals.push(primval_to_llvm(
|
llvals.push(primval_to_llvm(
|
||||||
cx,
|
cx,
|
||||||
PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }),
|
PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }),
|
||||||
|
@ -128,25 +171,19 @@ pub fn trans_static_initializer<'a, 'tcx>(
|
||||||
let param_env = ty::ParamEnv::reveal_all();
|
let param_env = ty::ParamEnv::reveal_all();
|
||||||
let static_ = cx.tcx.const_eval(param_env.and(cid))?;
|
let static_ = cx.tcx.const_eval(param_env.and(cid))?;
|
||||||
|
|
||||||
let ptr = match static_.val {
|
let val = match static_.val {
|
||||||
ConstVal::Value(MiriValue::ByRef(ptr, _)) => ptr,
|
ConstVal::Value(val) => val,
|
||||||
_ => bug!("static const eval returned {:#?}", static_),
|
_ => bug!("static const eval returned {:#?}", static_),
|
||||||
};
|
};
|
||||||
|
Ok(const_value_to_llvm(cx, val, static_.ty))
|
||||||
let alloc = cx
|
|
||||||
.tcx
|
|
||||||
.interpret_interner
|
|
||||||
.get_alloc(ptr.primval.to_ptr().expect("static has integer pointer").alloc_id)
|
|
||||||
.expect("miri allocation never successfully created");
|
|
||||||
Ok(global_initializer(cx, alloc))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||||
fn const_to_miri_value(
|
fn const_to_const_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
bx: &Builder<'a, 'tcx>,
|
bx: &Builder<'a, 'tcx>,
|
||||||
constant: &'tcx ty::Const<'tcx>,
|
constant: &'tcx ty::Const<'tcx>,
|
||||||
) -> Result<MiriValue, ConstEvalErr<'tcx>> {
|
) -> Result<ConstValue<'tcx>, ConstEvalErr<'tcx>> {
|
||||||
match constant.val {
|
match constant.val {
|
||||||
ConstVal::Unevaluated(def_id, ref substs) => {
|
ConstVal::Unevaluated(def_id, ref substs) => {
|
||||||
let tcx = bx.tcx();
|
let tcx = bx.tcx();
|
||||||
|
@ -157,17 +194,17 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||||
promoted: None,
|
promoted: None,
|
||||||
};
|
};
|
||||||
let c = tcx.const_eval(param_env.and(cid))?;
|
let c = tcx.const_eval(param_env.and(cid))?;
|
||||||
self.const_to_miri_value(bx, c)
|
self.const_to_const_value(bx, c)
|
||||||
},
|
},
|
||||||
ConstVal::Value(miri_val) => Ok(miri_val),
|
ConstVal::Value(val) => Ok(val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mir_constant_to_miri_value(
|
pub fn mir_constant_to_const_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
bx: &Builder<'a, 'tcx>,
|
bx: &Builder<'a, 'tcx>,
|
||||||
constant: &mir::Constant<'tcx>,
|
constant: &mir::Constant<'tcx>,
|
||||||
) -> Result<MiriValue, ConstEvalErr<'tcx>> {
|
) -> Result<ConstValue<'tcx>, ConstEvalErr<'tcx>> {
|
||||||
match constant.literal {
|
match constant.literal {
|
||||||
mir::Literal::Promoted { index } => {
|
mir::Literal::Promoted { index } => {
|
||||||
let param_env = ty::ParamEnv::reveal_all();
|
let param_env = ty::ParamEnv::reveal_all();
|
||||||
|
@ -180,7 +217,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||||
mir::Literal::Value { value } => {
|
mir::Literal::Value { value } => {
|
||||||
Ok(self.monomorphize(&value))
|
Ok(self.monomorphize(&value))
|
||||||
}
|
}
|
||||||
}.and_then(|c| self.const_to_miri_value(bx, c))
|
}.and_then(|c| self.const_to_const_value(bx, c))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// process constant containing SIMD shuffle indices
|
/// process constant containing SIMD shuffle indices
|
||||||
|
@ -189,11 +226,11 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||||
bx: &Builder<'a, 'tcx>,
|
bx: &Builder<'a, 'tcx>,
|
||||||
constant: &mir::Constant<'tcx>,
|
constant: &mir::Constant<'tcx>,
|
||||||
) -> (ValueRef, Ty<'tcx>) {
|
) -> (ValueRef, Ty<'tcx>) {
|
||||||
self.mir_constant_to_miri_value(bx, constant)
|
self.mir_constant_to_const_value(bx, constant)
|
||||||
.and_then(|c| {
|
.and_then(|c| {
|
||||||
let field_ty = constant.ty.builtin_index().unwrap();
|
let field_ty = constant.ty.builtin_index().unwrap();
|
||||||
let fields = match constant.ty.sty {
|
let fields = match constant.ty.sty {
|
||||||
ty::TyArray(_, n) => n.val.unwrap_u64(),
|
ty::TyArray(_, n) => n.unwrap_usize(bx.tcx()),
|
||||||
ref other => bug!("invalid simd shuffle type: {}", other),
|
ref other => bug!("invalid simd shuffle type: {}", other),
|
||||||
};
|
};
|
||||||
let values: Result<Vec<ValueRef>, _> = (0..fields).map(|field| {
|
let values: Result<Vec<ValueRef>, _> = (0..fields).map(|field| {
|
||||||
|
@ -206,19 +243,18 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||||
c,
|
c,
|
||||||
constant.ty,
|
constant.ty,
|
||||||
)?;
|
)?;
|
||||||
match field.val {
|
if let Some(prim) = field.to_primval() {
|
||||||
ConstVal::Value(MiriValue::ByVal(prim)) => {
|
let layout = bx.cx.layout_of(field_ty);
|
||||||
let layout = bx.cx.layout_of(field_ty);
|
let scalar = match layout.abi {
|
||||||
let scalar = match layout.abi {
|
layout::Abi::Scalar(ref x) => x,
|
||||||
layout::Abi::Scalar(ref x) => x,
|
_ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
|
||||||
_ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
|
};
|
||||||
};
|
Ok(primval_to_llvm(
|
||||||
Ok(primval_to_llvm(
|
bx.cx, prim, scalar,
|
||||||
bx.cx, prim, scalar,
|
layout.immediate_llvm_type(bx.cx),
|
||||||
layout.immediate_llvm_type(bx.cx),
|
))
|
||||||
))
|
} else {
|
||||||
},
|
bug!("simd shuffle field {:?}", field)
|
||||||
other => bug!("simd shuffle field {:?}, {}", other, constant.ty),
|
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
let llval = C_struct(bx.cx, &values?, false);
|
let llval = C_struct(bx.cx, &values?, false);
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
use llvm::ValueRef;
|
use llvm::ValueRef;
|
||||||
use rustc::middle::const_val::ConstEvalErr;
|
use rustc::middle::const_val::ConstEvalErr;
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::mir::interpret::Value as MiriValue;
|
use rustc::mir::interpret::ConstValue;
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
|
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
|
@ -22,12 +22,13 @@ use builder::Builder;
|
||||||
use value::Value;
|
use value::Value;
|
||||||
use type_of::LayoutLlvmExt;
|
use type_of::LayoutLlvmExt;
|
||||||
use type_::Type;
|
use type_::Type;
|
||||||
|
use consts;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use super::{FunctionCx, LocalRef};
|
use super::{FunctionCx, LocalRef};
|
||||||
use super::constant::{primval_to_llvm};
|
use super::constant::{primval_to_llvm, const_alloc_to_llvm};
|
||||||
use super::place::PlaceRef;
|
use super::place::PlaceRef;
|
||||||
|
|
||||||
/// The representation of a Rust value. The enum variant is in fact
|
/// The representation of a Rust value. The enum variant is in fact
|
||||||
|
@ -94,7 +95,7 @@ impl<'a, 'tcx> OperandRef<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_const(bx: &Builder<'a, 'tcx>,
|
pub fn from_const(bx: &Builder<'a, 'tcx>,
|
||||||
miri_val: MiriValue,
|
val: ConstValue<'tcx>,
|
||||||
ty: ty::Ty<'tcx>)
|
ty: ty::Ty<'tcx>)
|
||||||
-> Result<OperandRef<'tcx>, ConstEvalErr<'tcx>> {
|
-> Result<OperandRef<'tcx>, ConstEvalErr<'tcx>> {
|
||||||
let layout = bx.cx.layout_of(ty);
|
let layout = bx.cx.layout_of(ty);
|
||||||
|
@ -103,8 +104,8 @@ impl<'a, 'tcx> OperandRef<'tcx> {
|
||||||
return Ok(OperandRef::new_zst(bx.cx, layout));
|
return Ok(OperandRef::new_zst(bx.cx, layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
let val = match miri_val {
|
let val = match val {
|
||||||
MiriValue::ByVal(x) => {
|
ConstValue::ByVal(x) => {
|
||||||
let scalar = match layout.abi {
|
let scalar = match layout.abi {
|
||||||
layout::Abi::Scalar(ref x) => x,
|
layout::Abi::Scalar(ref x) => x,
|
||||||
_ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
|
_ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
|
||||||
|
@ -117,7 +118,7 @@ impl<'a, 'tcx> OperandRef<'tcx> {
|
||||||
);
|
);
|
||||||
OperandValue::Immediate(llval)
|
OperandValue::Immediate(llval)
|
||||||
},
|
},
|
||||||
MiriValue::ByValPair(a, b) => {
|
ConstValue::ByValPair(a, b) => {
|
||||||
let (a_scalar, b_scalar) = match layout.abi {
|
let (a_scalar, b_scalar) = match layout.abi {
|
||||||
layout::Abi::ScalarPair(ref a, ref b) => (a, b),
|
layout::Abi::ScalarPair(ref a, ref b) => (a, b),
|
||||||
_ => bug!("from_const: invalid ByValPair layout: {:#?}", layout)
|
_ => bug!("from_const: invalid ByValPair layout: {:#?}", layout)
|
||||||
|
@ -136,18 +137,11 @@ impl<'a, 'tcx> OperandRef<'tcx> {
|
||||||
);
|
);
|
||||||
OperandValue::Pair(a_llval, b_llval)
|
OperandValue::Pair(a_llval, b_llval)
|
||||||
},
|
},
|
||||||
MiriValue::ByRef(ptr, align) => {
|
ConstValue::ByRef(alloc) => {
|
||||||
let scalar = layout::Scalar {
|
let init = const_alloc_to_llvm(bx.cx, alloc);
|
||||||
value: layout::Primitive::Pointer,
|
let llval = consts::addr_of(bx.cx, init, layout.align, "byte_str");
|
||||||
valid_range: 0..=!0
|
let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to());
|
||||||
};
|
return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx));
|
||||||
let ptr = primval_to_llvm(
|
|
||||||
bx.cx,
|
|
||||||
ptr.into_inner_primval(),
|
|
||||||
&scalar,
|
|
||||||
layout.llvm_type(bx.cx).ptr_to(),
|
|
||||||
);
|
|
||||||
return Ok(PlaceRef::new_sized(ptr, layout, align).load(bx));
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -396,7 +390,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||||
|
|
||||||
mir::Operand::Constant(ref constant) => {
|
mir::Operand::Constant(ref constant) => {
|
||||||
let ty = self.monomorphize(&constant.ty);
|
let ty = self.monomorphize(&constant.ty);
|
||||||
self.mir_constant_to_miri_value(bx, constant)
|
self.mir_constant_to_const_value(bx, constant)
|
||||||
.and_then(|c| OperandRef::from_const(bx, c, ty))
|
.and_then(|c| OperandRef::from_const(bx, c, ty))
|
||||||
.unwrap_or_else(|err| {
|
.unwrap_or_else(|err| {
|
||||||
match constant.literal {
|
match constant.literal {
|
||||||
|
|
|
@ -516,7 +516,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||||
if let mir::Place::Local(index) = *place {
|
if let mir::Place::Local(index) = *place {
|
||||||
if let LocalRef::Operand(Some(op)) = self.locals[index] {
|
if let LocalRef::Operand(Some(op)) = self.locals[index] {
|
||||||
if let ty::TyArray(_, n) = op.layout.ty.sty {
|
if let ty::TyArray(_, n) = op.layout.ty.sty {
|
||||||
let n = n.val.unwrap_u64();
|
let n = n.unwrap_usize(bx.cx.tcx);
|
||||||
return common::C_usize(bx.cx, n);
|
return common::C_usize(bx.cx, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
//! representation. The main routine here is `ast_ty_to_ty()`: each use
|
//! representation. The main routine here is `ast_ty_to_ty()`: each use
|
||||||
//! is parameterized by an instance of `AstConv`.
|
//! is parameterized by an instance of `AstConv`.
|
||||||
|
|
||||||
use rustc::middle::const_val::ConstVal;
|
|
||||||
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
||||||
use hir;
|
use hir;
|
||||||
use hir::def::Def;
|
use hir::def::Def;
|
||||||
|
@ -1087,10 +1086,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||||
hir::TyArray(ref ty, length) => {
|
hir::TyArray(ref ty, length) => {
|
||||||
let length_def_id = tcx.hir.body_owner_def_id(length);
|
let length_def_id = tcx.hir.body_owner_def_id(length);
|
||||||
let substs = Substs::identity_for_item(tcx, length_def_id);
|
let substs = Substs::identity_for_item(tcx, length_def_id);
|
||||||
let length = tcx.mk_const(ty::Const {
|
let length = ty::Const::unevaluated(tcx, length_def_id, substs, tcx.types.usize);
|
||||||
val: ConstVal::Unevaluated(length_def_id, substs),
|
|
||||||
ty: tcx.types.usize
|
|
||||||
});
|
|
||||||
let array_ty = tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length));
|
let array_ty = tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length));
|
||||||
self.normalize_ty(ast_ty.span, array_ty)
|
self.normalize_ty(ast_ty.span, array_ty)
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,7 +375,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
let expected_ty = self.structurally_resolved_type(pat.span, expected);
|
let expected_ty = self.structurally_resolved_type(pat.span, expected);
|
||||||
let (inner_ty, slice_ty) = match expected_ty.sty {
|
let (inner_ty, slice_ty) = match expected_ty.sty {
|
||||||
ty::TyArray(inner_ty, size) => {
|
ty::TyArray(inner_ty, size) => {
|
||||||
let size = size.val.unwrap_u64();
|
let size = size.unwrap_usize(tcx);
|
||||||
let min_len = before.len() as u64 + after.len() as u64;
|
let min_len = before.len() as u64 + after.len() as u64;
|
||||||
if slice.is_none() {
|
if slice.is_none() {
|
||||||
if min_len != size {
|
if min_len != size {
|
||||||
|
|
|
@ -4018,7 +4018,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(count) = count {
|
if let Ok(count) = count {
|
||||||
let zero_or_one = count.val.to_raw_bits().map_or(false, |count| count <= 1);
|
let zero_or_one = count.assert_usize(tcx).map_or(false, |count| count <= 1);
|
||||||
if !zero_or_one {
|
if !zero_or_one {
|
||||||
// For [foo, ..n] where n > 1, `foo` must have
|
// For [foo, ..n] where n > 1, `foo` must have
|
||||||
// Copy type:
|
// Copy type:
|
||||||
|
|
|
@ -2644,10 +2644,7 @@ impl Clean<Type> for hir::Ty {
|
||||||
promoted: None
|
promoted: None
|
||||||
};
|
};
|
||||||
let n = cx.tcx.const_eval(param_env.and(cid)).unwrap_or_else(|_| {
|
let n = cx.tcx.const_eval(param_env.and(cid)).unwrap_or_else(|_| {
|
||||||
cx.tcx.mk_const(ty::Const {
|
ty::Const::unevaluated(cx.tcx, def_id, substs, cx.tcx.types.usize)
|
||||||
val: ConstVal::Unevaluated(def_id, substs),
|
|
||||||
ty: cx.tcx.types.usize
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
let n = print_const(cx, n);
|
let n = print_const(cx, n);
|
||||||
Array(box ty.clean(cx), n)
|
Array(box ty.clean(cx), n)
|
||||||
|
@ -3828,9 +3825,9 @@ fn print_const(cx: &DocContext, n: &ty::Const) -> String {
|
||||||
inline::print_inlined_const(cx, def_id)
|
inline::print_inlined_const(cx, def_id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ConstVal::Value(val) => {
|
ConstVal::Value(..) => {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
::rustc::mir::print_miri_value(val, n.ty, &mut s).unwrap();
|
::rustc::mir::fmt_const_val(&mut s, n).unwrap();
|
||||||
// array lengths are obviously usize
|
// array lengths are obviously usize
|
||||||
if s.ends_with("usize") {
|
if s.ends_with("usize") {
|
||||||
let n = s.len() - "usize".len();
|
let n = s.len() - "usize".len();
|
||||||
|
|
|
@ -12,17 +12,11 @@
|
||||||
|
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one"
|
// CHECK: @VAR1 = constant i32 1, section ".test_one"
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[link_section = ".test_one"]
|
#[link_section = ".test_one"]
|
||||||
#[cfg(target_endian = "little")]
|
|
||||||
pub static VAR1: u32 = 1;
|
pub static VAR1: u32 = 1;
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[link_section = ".test_one"]
|
|
||||||
#[cfg(target_endian = "big")]
|
|
||||||
pub static VAR1: u32 = 0x01000000;
|
|
||||||
|
|
||||||
pub enum E {
|
pub enum E {
|
||||||
A(u32),
|
A(u32),
|
||||||
B(f32)
|
B(f32)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue