Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
@@ -60,7 +60,7 @@
//! user of the `DepNode` API of having to know how to compute the expected
//! 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::map::DefPathHash;
use hir::{HirId, ItemLocalId};
@@ -621,13 +621,14 @@ define_dep_nodes!( <'tcx>
[input] UsedCrateSource(CrateNum),
[input] PostorderCnums,

// This query is not expected to have inputs -- as a result, it's
// not a good candidate for "replay" because it's essentially a
// pure function of its input (and hence the expectation is that
// no caller would be green **apart** from just this
// query). Making it anonymous avoids hashing the result, which
// These queries are not expected to have inputs -- as a result, they
// are not good candidates for "replay" because they are essentially
// pure functions of their input (and hence the expectation is that
// no caller would be green **apart** from just these
// queries). Making them anonymous avoids hashing the result, which
// may save a bit of time.
[anon] EraseRegionsTy { ty: Ty<'tcx> },
[anon] ConstValueToAllocation { val: ConstValue<'tcx>, ty: Ty<'tcx> },

[input] Freevars(DefId),
[input] MaybeUnusedTraitImport(DefId),
24 changes: 24 additions & 0 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
@@ -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 {
ByVal(v),
ByValPair(a, b),
24 changes: 2 additions & 22 deletions src/librustc/middle/const_val.rs
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@
use hir::def_id::DefId;
use ty::{self, TyCtxt, layout};
use ty::subst::Substs;
use mir::interpret::{Value, PrimVal};
use mir::interpret::ConstValue;
use errors::DiagnosticBuilder;

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)]
pub enum ConstVal<'tcx> {
Unevaluated(DefId, &'tcx Substs<'tcx>),
Value(Value),
}

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),
}
}
Value(ConstValue<'tcx>),
}

#[derive(Clone, Debug)]
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
@@ -945,7 +945,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {

// Always promote `[T; 0]` (even when e.g. borrowed mutably).
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,
};

62 changes: 58 additions & 4 deletions src/librustc/mir/interpret/mod.rs
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ mod value;

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::fmt;
@@ -20,8 +20,10 @@ use ty::{self, TyCtxt};
use ty::layout::{self, Align, HasDataLayout};
use middle::region;
use std::iter;
use std::io;
use syntax::ast::Mutability;
use rustc_serialize::{Encoder, Decoder, Decodable, Encodable};
use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian};

#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
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 {
/// The actual bytes of the allocation.
/// Note that the bytes of a pointer represent the offset of the pointer
@@ -254,17 +256,69 @@ pub struct 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);
undef_mask.grow(slice.len() as u64, true);
Self {
bytes: slice.to_owned(),
relocations: BTreeMap::new(),
undef_mask,
align: Align::from_bytes(1, 1).unwrap(),
align,
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()),
}
}

////////////////////////////////////////////////////////////////////////////////
64 changes: 63 additions & 1 deletion src/librustc/mir/interpret/value.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,69 @@
use ty::layout::{Align, HasDataLayout};
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.
///
21 changes: 11 additions & 10 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -13,7 +13,6 @@
//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir.html

use graphviz::IntoCow;
use middle::const_val::ConstVal;
use middle::region;
use rustc_data_structures::sync::{Lrc};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@@ -1549,11 +1548,7 @@ impl<'tcx> Operand<'tcx> {
span,
ty,
literal: Literal::Value {
value: tcx.mk_const(ty::Const {
// ZST function type
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
ty
})
value: ty::Const::zero_sized(tcx, 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.
fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
use middle::const_val::ConstVal::*;
pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
use middle::const_val::ConstVal;
match const_val.val {
Unevaluated(..) => write!(fmt, "{:?}", const_val),
Value(val) => print_miri_value(val, const_val.ty, fmt),
ConstVal::Unevaluated(..) => write!(fmt, "{:?}", const_val),
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)
}
},
}
}

2 changes: 1 addition & 1 deletion src/librustc/mir/tcx.rs
Original file line number Diff line number Diff line change
@@ -69,7 +69,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
PlaceTy::Ty {
ty: match ty.sty {
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);
tcx.mk_array(inner, len)
}
19 changes: 19 additions & 0 deletions src/librustc/ty/codec.rs
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@ use std::hash::Hash;
use std::intrinsics;
use ty::{self, Ty, TyCtxt};
use ty::subst::Substs;
use mir::interpret::Allocation;

/// The shorthand encoding uses an enum's variant index `usize`
/// 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)?))
}

#[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_rules! __impl_decoder_methods {
($($name:ident -> $ty:ty;)*) => {
@@ -393,6 +403,15 @@ macro_rules! implement_ty_decoder {
decode_const(self)
}
}

impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::mir::interpret::Allocation>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this conflict with the derive on Allocation? IIRC this produces runtime issues if done incorrectly. Have a look at what AllocId does

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. This decodes a pointer to an Allocation, while the derive is for Allocation itself.

for $DecoderName<$($typaram),*> {
fn specialized_decode(
&mut self
) -> Result<&'tcx $crate::mir::interpret::Allocation, Self::Error> {
decode_allocation(self)
}
}
}
}
}
9 changes: 2 additions & 7 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
@@ -26,14 +26,12 @@ use lint::{self, Lint};
use ich::{StableHashingContext, NodeIdHashingMode};
use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
use infer::outlives::free_region_map::FreeRegionMap;
use middle::const_val::ConstVal;
use middle::cstore::{CrateStore, LinkMeta};
use middle::cstore::EncodedMetadata;
use middle::lang_items;
use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use middle::stability;
use mir::{self, Mir, interpret};
use mir::interpret::{Value, PrimVal};
use ty::subst::{Kind, Substs, Subst};
use ty::ReprOptions;
use ty::Instance;
@@ -1132,7 +1130,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
return alloc_id;
}
// 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);

// the next unique id
@@ -2375,10 +2373,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}

pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
self.mk_ty(TyArray(ty, self.mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.into()))),
ty: self.types.usize
})))
self.mk_ty(TyArray(ty, ty::Const::from_usize(self, n)))
}

pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> {
2 changes: 1 addition & 1 deletion src/librustc/ty/error.rs
Original file line number Diff line number Diff line change
@@ -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::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)),
ty::TyArray(_, n) => {
match n.val.to_raw_bits() {
match n.assert_usize(tcx) {
Some(n) => format!("array of {} elements", n),
None => "array".to_string(),
}
2 changes: 1 addition & 1 deletion src/librustc/ty/inhabitedness/mod.rs
Original file line number Diff line number Diff line change
@@ -262,7 +262,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
}))
},
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
// the type of its elements is uninhabited.
Some(n) if n != 0 => ty.uninhabited_from(visited, tcx),
2 changes: 1 addition & 1 deletion src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
@@ -543,7 +543,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
}

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)
.ok_or(LayoutError::SizeOverflow(ty))?;

8 changes: 7 additions & 1 deletion src/librustc/ty/maps/config.rs
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@
use dep_graph::SerializedDepNodeIndex;
use dep_graph::DepNode;
use hir::def_id::{CrateNum, DefId, DefIndex};
use mir::interpret::{GlobalId};
use mir::interpret::{GlobalId, ConstValue};
use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal};
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
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> {
fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String {
format!("erasing regions from `{:?}`", ty)
9 changes: 9 additions & 0 deletions src/librustc/ty/maps/keys.rs
Original file line number Diff line number Diff line change
@@ -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> {
fn map_crate(&self) -> CrateNum {
LOCAL_CRATE
13 changes: 12 additions & 1 deletion src/librustc/ty/maps/mod.rs
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol};
use middle::const_val::EvalResult;
use mir::mono::{CodegenUnit, Stats};
use mir;
use mir::interpret::{GlobalId};
use mir::interpret::{GlobalId, Allocation, ConstValue};
use session::{CompileResult, CrateDisambiguator};
use session::config::OutputFilenames;
use traits::{self, Vtable};
@@ -228,6 +228,11 @@ define_maps! { <'tcx>
[] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'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)
-> Result<(), ErrorReported>,

@@ -478,6 +483,12 @@ fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> {
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> {
DepConstructor::TypeParamPredicates {
item_id,
1 change: 1 addition & 0 deletions src/librustc/ty/maps/plumbing.rs
Original file line number Diff line number Diff line change
@@ -956,6 +956,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::FulfillObligation |
DepKind::VtableMethods |
DepKind::EraseRegionsTy |
DepKind::ConstValueToAllocation |
DepKind::NormalizeProjectionTy |
DepKind::NormalizeTyAfterErasingRegions |
DepKind::DropckOutlives |
42 changes: 18 additions & 24 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -22,12 +22,11 @@ use hir::svh::Svh;
use ich::Fingerprint;
use ich::StableHashingContext;
use infer::canonical::{Canonical, Canonicalize};
use middle::const_val::ConstVal;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::privacy::AccessLevels;
use middle::resolve_lifetime::ObjectLifetimeDefault;
use mir::Mir;
use mir::interpret::{GlobalId, Value, PrimVal};
use mir::interpret::GlobalId;
use mir::GeneratorLayout;
use session::CrateDisambiguator;
use traits::{self, Reveal};
@@ -1933,27 +1932,23 @@ impl<'a, 'gcx, 'tcx> AdtDef {
promoted: None
};
match tcx.const_eval(param_env.and(cid)) {
Ok(&ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
ty,
}) => {
trace!("discriminants: {} ({:?})", b, repr_type);
Some(Discr {
val: b,
ty,
})
},
Ok(&ty::Const {
val: ConstVal::Value(other),
..
}) => {
info!("invalid enum discriminant: {:#?}", other);
::middle::const_val::struct_error(
tcx,
tcx.def_span(expr_did),
"constant evaluation of enum discriminant resulted in non-integer",
).emit();
None
Ok(val) => {
// FIXME: Find the right type and use it instead of `val.ty` here
if let Some(b) = val.assert_bits(val.ty) {
trace!("discriminants: {} ({:?})", b, repr_type);
Some(Discr {
val: b,
ty: val.ty,
})
} else {
info!("invalid enum discriminant: {:#?}", val);
::middle::const_val::struct_error(
tcx,
tcx.def_span(expr_did),
"constant evaluation of enum discriminant resulted in non-integer",
).emit();
None
}
}
Err(err) => {
err.report(tcx, tcx.def_span(expr_did), "enum discriminant");
@@ -1964,7 +1959,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
}
None
}
_ => span_bug!(tcx.def_span(expr_did), "const eval "),
}
}

19 changes: 8 additions & 11 deletions src/librustc/ty/relate.rs
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ use middle::const_val::ConstVal;
use ty::subst::{Kind, UnpackedKind, Substs};
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::error::{ExpectedFound, TypeError};
use mir::interpret::{GlobalId, Value, PrimVal};
use mir::interpret::GlobalId;
use util::common::ErrorReported;
use std::rc::Rc;
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_b.ty, tcx.types.usize);
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 {
ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()),
ConstVal::Unevaluated(def_id, substs) => {
// FIXME(eddyb) get the right param_env.
let param_env = ty::ParamEnv::empty();
@@ -487,15 +489,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
instance,
promoted: None
};
match tcx.const_eval(param_env.and(cid)) {
Ok(&ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
..
}) => {
assert_eq!(b as u64 as u128, b);
return Ok(b as u64);
}
_ => {}
if let Some(s) = tcx.const_eval(param_env.and(cid))
.ok()
.map(|c| c.unwrap_usize(tcx)) {
return Ok(s)
}
}
},
153 changes: 153 additions & 0 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ use ty::subst::{Substs, Subst, Kind, UnpackedKind};
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
use ty::{Slice, TyS};
use util::captures::Captures;
use mir::interpret::{Allocation, PrimVal, MemoryPointer, Value, ConstValue};

use std::iter;
use std::cmp::Ordering;
@@ -1730,4 +1731,156 @@ pub struct Const<'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> {}
4 changes: 1 addition & 3 deletions src/librustc/ty/util.rs
Original file line number Diff line number Diff line change
@@ -25,7 +25,6 @@ use ty::TypeVariants::*;
use ty::layout::{Integer, IntegerExt};
use util::common::ErrorReported;
use middle::lang_items;
use mir::interpret::{Value, PrimVal};

use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
HashStable};
@@ -659,9 +658,8 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
TyArray(_, n) => {
self.hash_discriminant_u8(&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),
_ => bug!("arrays should not have {:?} as length", n)
}
}
TyRawPtr(m) => self.hash(m.mutbl),
10 changes: 3 additions & 7 deletions src/librustc/util/ppaux.rs
Original file line number Diff line number Diff line change
@@ -21,7 +21,6 @@ use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, Ty
use ty::{TyDynamic, TyInt, TyUint, TyInfer};
use ty::{self, Ty, TyCtxt, TypeFoldable};
use util::nodemap::FxHashSet;
use mir::interpret::{Value, PrimVal};

use std::cell::Cell;
use std::fmt;
@@ -1183,15 +1182,12 @@ define_print! {
TyArray(ty, sz) => {
print!(f, cx, write("["), print(ty), write("; "))?;
match sz.val {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => {
write!(f, "{}", sz)?;
}
ConstVal::Value(..) => ty::tls::with(|tcx| {
write!(f, "{}", sz.unwrap_usize(tcx))
})?,
ConstVal::Unevaluated(_def_id, _substs) => {
write!(f, "_")?;
}
_ => {
write!(f, "{:?}", sz)?;
}
}
write!(f, "]")
}
2 changes: 1 addition & 1 deletion src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
@@ -425,7 +425,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
ProjectionElem::Subslice { from, to } => PlaceTy::Ty {
ty: match base_ty.sty {
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);
if let Some(rest_size) = size.checked_sub(min_size) {
tcx.mk_array(inner, rest_size)
21 changes: 7 additions & 14 deletions src/librustc_mir/build/expr/as_rvalue.rs
Original file line number Diff line number Diff line change
@@ -16,11 +16,10 @@ use rustc_data_structures::indexed_vec::Idx;
use build::{BlockAnd, BlockAndExtension, Builder};
use build::expr::category::{Category, RvalueFunc};
use hair::*;
use rustc::middle::const_val::ConstVal;
use rustc::middle::region;
use rustc::ty::{self, Ty, UpvarSubsts};
use rustc::mir::*;
use rustc::mir::interpret::{Value, PrimVal, EvalErrorKind};
use rustc::mir::interpret::EvalErrorKind;
use syntax_pos::Span;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@@ -200,10 +199,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
span: expr_span,
ty: this.hir.tcx().types.u32,
literal: Literal::Value {
value: this.hir.tcx().mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
ty: this.hir.tcx().types.u32
}),
value: ty::Const::from_bits(
this.hir.tcx(),
0,
this.hir.tcx().types.u32),
},
}));
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 n = (!0u128) >> (128 - bits);
let literal = Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
ty
})
value: ty::Const::from_bits(self.hir.tcx(), n, ty)
};

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 n = 1 << (bits - 1);
let literal = Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
ty
})
value: ty::Const::from_bits(self.hir.tcx(), n, ty)
};

self.literal_operand(span, ty, literal)
5 changes: 1 addition & 4 deletions src/librustc_mir/build/matches/test.rs
Original file line number Diff line number Diff line change
@@ -122,12 +122,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {

match *match_pair.pattern.kind {
PatternKind::Constant { value } => {
// if the places match, the type should match
assert_eq!(match_pair.pattern.ty, switch_ty);

indices.entry(value)
.or_insert_with(|| {
options.push(value.val.to_raw_bits().expect("switching on int"));
options.push(value.unwrap_bits(switch_ty));
options.len() - 1
});
true
7 changes: 1 addition & 6 deletions src/librustc_mir/build/misc.rs
Original file line number Diff line number Diff line change
@@ -13,9 +13,7 @@
use build::Builder;

use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, Ty};
use rustc::mir::interpret::{Value, PrimVal};

use rustc::mir::*;
use syntax_pos::{Span, DUMMY_SP};
@@ -64,10 +62,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
}
let literal = Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
ty
})
value: ty::Const::from_bits(self.hir.tcx(), 0, ty)
};

self.literal_operand(span, ty, literal)
37 changes: 14 additions & 23 deletions src/librustc_mir/hair/cx/expr.rs
Original file line number Diff line number Diff line change
@@ -14,8 +14,7 @@ use hair::cx::Cx;
use hair::cx::block;
use hair::cx::to_ref::ToRef;
use rustc::hir::def::{Def, CtorKind};
use rustc::middle::const_val::ConstVal;
use rustc::mir::interpret::{GlobalId, Value, PrimVal};
use rustc::mir::interpret::GlobalId;
use rustc::ty::{self, AdtKind, Ty};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
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
};
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) => {
e.report(cx.tcx, cx.tcx.def_span(def_id), "array length");
0
@@ -635,22 +634,17 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
span: expr.span,
kind: ExprKind::Literal {
literal: Literal::Value {
value: cx.tcx().mk_const(ty::Const {
val,
ty,
}),
value: val,
},
},
}.to_ref();
let offset = mk_const(
ConstVal::Value(Value::ByVal(PrimVal::Bytes(offset as u128))),
);
let offset = mk_const(ty::Const::from_bits(cx.tcx, offset as u128, ty));
match did {
Some(did) => {
// in case we are offsetting from a computed discriminant
// and not the beginning of discriminants (which is always `0`)
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 {
op: BinOp::Add,
lhs,
@@ -707,10 +701,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
span: expr.span,
kind: ExprKind::Literal {
literal: Literal::Value {
value: cx.tcx().mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
ty
}),
value: ty::Const::zero_sized(cx.tcx(), ty),
},
},
}
@@ -764,20 +755,20 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal {
literal: Literal::Value {
value: cx.tcx.mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
ty: cx.tables().node_id_to_type(expr.hir_id)
}),
value: ty::Const::zero_sized(
cx.tcx,
cx.tables().node_id_to_type(expr.hir_id)),
},
},

Def::Const(def_id) |
Def::AssociatedConst(def_id) => ExprKind::Literal {
literal: Literal::Value {
value: cx.tcx.mk_const(ty::Const {
val: ConstVal::Unevaluated(def_id, substs),
ty: cx.tables().node_id_to_type(expr.hir_id)
}),
value: ty::Const::unevaluated(
cx.tcx,
def_id,
substs,
cx.tables().node_id_to_type(expr.hir_id))
},
},

45 changes: 14 additions & 31 deletions src/librustc_mir/hair/cx/mod.rs
Original file line number Diff line number Diff line change
@@ -16,7 +16,6 @@
use hair::*;

use rustc::middle::const_val::ConstVal;
use rustc_data_structures::indexed_vec::Idx;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::hir::map::blocks::FnLikeNode;
@@ -31,7 +30,6 @@ use syntax::attr;
use syntax::symbol::Symbol;
use rustc::hir;
use rustc_data_structures::sync::Lrc;
use rustc::mir::interpret::{Value, PrimVal};
use hair::pattern::parse_float;

#[derive(Clone)]
@@ -117,10 +115,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {

pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
Literal::Value {
value: self.tcx.mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))),
ty: self.tcx.types.usize
})
value: ty::Const::from_usize(self.tcx, value),
}
}

@@ -134,19 +129,13 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {

pub fn true_literal(&mut self) -> Literal<'tcx> {
Literal::Value {
value: self.tcx.mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))),
ty: self.tcx.types.bool
})
value: ty::Const::from_bool(self.tcx, true),
}
}

pub fn false_literal(&mut self) -> Literal<'tcx> {
Literal::Value {
value: self.tcx.mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
ty: self.tcx.types.bool
})
value: ty::Const::from_bool(self.tcx, false),
}
}

@@ -162,6 +151,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
layout::Integer::from_attr(self.tcx, ty).size().bits()
}

// FIXME: Combine with rustc_mir::hair::pattern::lit_to_const
pub fn const_eval_literal(
&mut self,
lit: &'tcx ast::LitKind,
@@ -171,7 +161,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
) -> Literal<'tcx> {
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(|_| {
// 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)");
@@ -193,24 +183,24 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
let s = s.as_str();
let id = self.tcx.allocate_cached(s.as_bytes());
let ptr = MemoryPointer::new(id, 0);
Value::ByValPair(
ConstValue::ByValPair(
PrimVal::Ptr(ptr),
PrimVal::from_u128(s.len() as u128),
)
},
LitKind::ByteStr(ref data) => {
let id = self.tcx.allocate_cached(data);
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 => {
let n = n as i128;
let n = n.overflowing_neg().0;
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) => {
parse_float(n, fty)
}
@@ -221,14 +211,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
};
parse_float(n, fty)
}
LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)),
LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)),
};
Literal::Value {
value: self.tcx.mk_const(ty::Const {
val: ConstVal::Value(lit),
ty,
}),
value: ty::Const::from_const_value(self.tcx, lit, ty)
}
}

@@ -258,11 +245,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
let method_ty = method_ty.subst(self.tcx, substs);
return (method_ty,
Literal::Value {
value: self.tcx.mk_const(ty::Const {
// ZST function type
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
ty: method_ty
}),
value: ty::Const::zero_sized(self.tcx, method_ty)
});
}
}
186 changes: 92 additions & 94 deletions src/librustc_mir/hair/pattern/_match.rs
Original file line number Diff line number Diff line change
@@ -25,7 +25,6 @@ use rustc::hir::RangeEnd;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};

use rustc::mir::Field;
use rustc::mir::interpret::{Value, PrimVal};
use rustc::util::common::ErrorReported;

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(|| {
match pat.kind {
box PatternKind::Constant {
value: &ty::Const { val: ConstVal::Value(b), ty }
value: const_val
} => {
match b {
Value::ByVal(PrimVal::Ptr(ptr)) => {
let is_array_ptr = ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == tcx.types.u8);
assert!(is_array_ptr);
let alloc = tcx
.interpret_interner
.get_alloc(ptr.alloc_id)
.unwrap();
assert_eq!(ptr.offset, 0);
// FIXME: check length
alloc.bytes.iter().map(|b| {
&*pattern_arena.alloc(Pattern {
ty: tcx.types.u8,
span: pat.span,
kind: box PatternKind::Constant {
value: tcx.mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(
PrimVal::Bytes(*b as u128),
)),
ty: tcx.types.u8
})
}
})
}).collect()
},
_ => bug!("not a byte str: {:?}", b),
if let Some(ptr) = const_val.to_ptr() {
let is_array_ptr = const_val.ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == tcx.types.u8);
assert!(is_array_ptr);
let alloc = tcx
.interpret_interner
.get_alloc(ptr.alloc_id)
.unwrap();
assert_eq!(ptr.offset, 0);
// FIXME: check length
alloc.bytes.iter().map(|b| {
&*pattern_arena.alloc(Pattern {
ty: tcx.types.u8,
span: pat.span,
kind: box PatternKind::Constant {
value: ty::Const::from_bits(
tcx,
*b as u128,
tcx.types.u8)
}
})
}).collect()
} else {
bug!("not a byte str: {:?}", const_val)
}
}
_ => 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 {
ty::TyBool => {
[true, false].iter().map(|&b| {
ConstantValue(cx.tcx.mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))),
ty: cx.tcx.types.bool
}))
ConstantValue(ty::Const::from_bool(cx.tcx, b))
}).collect()
}
ty::TyArray(ref sub_ty, len) if len.val.to_raw_bits().is_some() => {
let len = len.val.unwrap_u64();
ty::TyArray(ref sub_ty, len) if len.assert_usize(cx.tcx).is_some() => {
let len = len.unwrap_usize(cx.tcx);
if len != 0 && cx.is_uninhabited(sub_ty) {
vec![]
} else {
@@ -554,21 +547,23 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
for row in patterns {
match *row.kind {
PatternKind::Constant {
value: &ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))),
ty,
value: const_val @ &ty::Const {
val: ConstVal::Value(..),
..
}
} => {
let is_array_ptr = ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == cx.tcx.types.u8);
if is_array_ptr {
let alloc = cx.tcx
.interpret_interner
.get_alloc(ptr.alloc_id)
.unwrap();
max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
if let Some(ptr) = const_val.to_ptr() {
let is_array_ptr = const_val.ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == cx.tcx.types.u8);
if is_array_ptr {
let alloc = cx.tcx
.interpret_interner
.get_alloc(ptr.alloc_id)
.unwrap();
max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
}
}
}
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.
///
/// 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>,
pcx: PatternContext)
-> Option<Vec<Constructor<'tcx>>>
@@ -854,7 +849,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
Some(vec![ConstantRange(lo, hi, end)]),
PatternKind::Array { .. } => match pcx.ty.sty {
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)
},
@@ -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,
ctor: &Constructor,
prefix: &[Pattern],
slice: &Option<Pattern>,
suffix: &[Pattern])
-> Result<bool, ErrorReported> {
fn slice_pat_covered_by_constructor<'tcx>(
tcx: TyCtxt<'_, 'tcx, '_>,
_span: Span,
ctor: &Constructor,
prefix: &[Pattern<'tcx>],
slice: &Option<Pattern<'tcx>>,
suffix: &[Pattern<'tcx>]
) -> Result<bool, ErrorReported> {
let data: &[u8] = match *ctor {
ConstantValue(&ty::Const { val: ConstVal::Value(
Value::ByVal(PrimVal::Ptr(ptr))
), ty }) => {
let is_array_ptr = ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == tcx.types.u8);
assert!(is_array_ptr);
tcx
.interpret_interner
.get_alloc(ptr.alloc_id)
.unwrap()
.bytes
.as_ref()
ConstantValue(const_val @ &ty::Const { val: ConstVal::Value(..), .. }) => {
if let Some(ptr) = const_val.to_ptr() {
let is_array_ptr = const_val.ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == tcx.types.u8);
assert!(is_array_ptr);
tcx
.interpret_interner
.get_alloc(ptr.alloc_id)
.unwrap()
.bytes
.as_ref()
} else {
bug!()
}
}
_ => bug!()
};
@@ -969,15 +968,13 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
data[data.len()-suffix.len()..].iter().zip(suffix))
{
match pat.kind {
box PatternKind::Constant { value } => match value.val {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
assert_eq!(b as u8 as u128, b);
if b as u8 != *ch {
return Ok(false);
}
box PatternKind::Constant { value } => {
let b = value.unwrap_bits(pat.ty);
assert_eq!(b as u8 as u128, b);
if b as u8 != *ch {
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>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
ctor: &Constructor,
from: &ConstVal, to: &ConstVal,
ctor: &Constructor<'tcx>,
from: &'tcx ty::Const<'tcx>, to: &'tcx ty::Const<'tcx>,
end: RangeEnd,
ty: Ty<'tcx>,
) -> Result<bool, ErrorReported> {
@@ -1006,22 +1003,22 @@ fn constructor_covered_by_range<'a, 'tcx>(
}
match *ctor {
ConstantValue(value) => {
let to = some_or_ok!(cmp_to(&value.val));
let to = some_or_ok!(cmp_to(value));
let end = (to == Ordering::Less) ||
(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) => {
let to = some_or_ok!(cmp_to(&to.val));
let to = some_or_ok!(cmp_to(to));
let end = (to == Ordering::Less) ||
(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) => {
let to = some_or_ok!(cmp_to(&to.val));
let to = some_or_ok!(cmp_to(to));
let end = (to == Ordering::Less) ||
(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),
_ => bug!(),
@@ -1083,8 +1080,8 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(

PatternKind::Constant { value } => {
match *constructor {
Slice(..) => match value.val {
ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => {
Slice(..) => {
if let Some(ptr) = value.to_ptr() {
let is_array_ptr = value.ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
@@ -1101,14 +1098,15 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
} else {
None
}
}
_ => span_bug!(pat.span,
} else {
span_bug!(pat.span,
"unexpected const-val {:?} with ctor {:?}", value, constructor)
}
},
_ => {
match constructor_covered_by_range(
cx.tcx,
constructor, &value.val, &value.val, RangeEnd::Included,
constructor, value, value, RangeEnd::Included,
value.ty,
) {
Ok(true) => Some(vec![]),
@@ -1122,7 +1120,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
PatternKind::Range { lo, hi, ref end } => {
match constructor_covered_by_range(
cx.tcx,
constructor, &lo.val, &hi.val, end.clone(), lo.ty,
constructor, lo, hi, end.clone(), lo.ty,
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
137 changes: 61 additions & 76 deletions src/librustc_mir/hair/pattern/mod.rs
Original file line number Diff line number Diff line change
@@ -19,8 +19,8 @@ pub(crate) use self::check_match::check_match;
use interpret::{const_val_field, const_variant_index, self};

use rustc::middle::const_val::ConstVal;
use rustc::mir::{Field, BorrowKind, Mutability};
use rustc::mir::interpret::{GlobalId, Value, PrimVal};
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
use rustc::mir::interpret::{PrimVal, GlobalId, ConstValue};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
use rustc::ty::subst::{Substs, Kind};
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 {
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)
}
}

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> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.kind {
@@ -372,7 +359,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
(PatternKind::Constant { value: lo },
PatternKind::Constant { value: hi }) => {
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) =>
PatternKind::Range { lo, hi, end },
(RangeEnd::Excluded, _) => {
@@ -616,7 +603,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {

ty::TyArray(_, len) => {
// 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);
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.substs,
);
let cv = self.tcx.mk_const(ty::Const { val, ty });
*self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
*self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
},
Err(()) => {
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.substs,
);
let cv = self.tcx.mk_const(ty::Const { val, ty });
*self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
*self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
},
Err(()) => {
self.errors.push(PatternError::FloatBug);
@@ -866,7 +851,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
}
ty::TyArray(_, n) => {
PatternKind::Array {
prefix: (0..n.val.unwrap_u64())
prefix: (0..n.unwrap_usize(self.tcx))
.map(|i| adt_subpattern(i as usize, None))
.collect(),
slice: None,
@@ -1049,45 +1034,48 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {

pub fn compare_const_vals<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
a: &ConstVal,
b: &ConstVal,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
ty: Ty<'tcx>,
) -> Option<Ordering> {
trace!("compare_const_vals: {:?}, {:?}", a, b);
use rustc::mir::interpret::{Value, PrimVal};
match (a, b) {
(&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))),
&ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => {
use ::rustc_apfloat::Float;
match ty.sty {
ty::TyFloat(ast::FloatTy::F32) => {
let l = ::rustc_apfloat::ieee::Single::from_bits(a);
let r = ::rustc_apfloat::ieee::Single::from_bits(b);
l.partial_cmp(&r)
},
ty::TyFloat(ast::FloatTy::F64) => {
let l = ::rustc_apfloat::ieee::Double::from_bits(a);
let r = ::rustc_apfloat::ieee::Double::from_bits(b);
l.partial_cmp(&r)
},
ty::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");
Some((a as i128).cmp(&(b as i128)))
},
_ => Some(a.cmp(&b)),
}
},
_ if a == b => Some(Ordering::Equal),
_ => None,
// FIXME: This should use assert_bits(ty) instead of use_bits
// but triggers possibly bugs due to mismatching of arrays and slices
if let (Some(a), Some(b)) = (a.to_bits(ty), b.to_bits(ty)) {
use ::rustc_apfloat::Float;
match ty.sty {
ty::TyFloat(ast::FloatTy::F32) => {
let l = ::rustc_apfloat::ieee::Single::from_bits(a);
let r = ::rustc_apfloat::ieee::Single::from_bits(b);
l.partial_cmp(&r)
},
ty::TyFloat(ast::FloatTy::F64) => {
let l = ::rustc_apfloat::ieee::Double::from_bits(a);
let r = ::rustc_apfloat::ieee::Double::from_bits(b);
l.partial_cmp(&r)
},
ty::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");
Some((a as i128).cmp(&(b as i128)))
},
_ => Some(a.cmp(&b)),
}
} else {
if a == b {
Some(Ordering::Equal)
} else {
None
}
}
}

// FIXME: Combine with rustc_mir::hair::cx::const_eval_literal
fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: Ty<'tcx>,
neg: bool)
-> Result<ConstVal<'tcx>, ()> {
-> Result<&'tcx ty::Const<'tcx>, ()> {
use syntax::ast::*;

use rustc::mir::interpret::*;
@@ -1096,17 +1084,17 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
let s = s.as_str();
let id = tcx.allocate_cached(s.as_bytes());
let ptr = MemoryPointer::new(id, 0);
Value::ByValPair(
ConstValue::ByValPair(
PrimVal::Ptr(ptr),
PrimVal::from_u128(s.len() as u128),
)
},
LitKind::ByteStr(ref data) => {
let id = tcx.allocate_cached(data);
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, _) => {
enum Int {
Signed(IntTy),
@@ -1119,31 +1107,28 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
ty::TyUint(other) => Int::Unsigned(other),
_ => bug!(),
};
// This converts from LitKind::Int (which is sign extended) to
// PrimVal::Bytes (which is zero extended)
let n = match ty {
// FIXME(oli-obk): are these casts correct?
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 =>
(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 =>
(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 =>
(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 =>
(n as i128).overflowing_neg().0 as u128,
Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128,
Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128,
Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128,
Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128,
Int::Signed(IntTy::I128) => 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,
Int::Signed(IntTy::I8) | Int::Unsigned(UintTy::U8) => n as u8 as u128,
Int::Signed(IntTy::I16) | Int::Unsigned(UintTy::U16) => n as u16 as u128,
Int::Signed(IntTy::I32) | Int::Unsigned(UintTy::U32) => n as u32 as u128,
Int::Signed(IntTy::I64) | Int::Unsigned(UintTy::U64) => n as u64 as u128,
Int::Signed(IntTy::I128)| Int::Unsigned(UintTy::U128) => n,
_ => bug!(),
};
Value::ByVal(PrimVal::Bytes(n))
ConstValue::ByVal(PrimVal::Bytes(n))
},
LitKind::Float(n, fty) => {
parse_float(n, fty, neg)?
@@ -1155,17 +1140,17 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
};
parse_float(n, fty, neg)?
}
LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b 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,
fty: ast::FloatTy,
neg: bool,
) -> Result<Value, ()> {
) -> Result<ConstValue<'tcx>, ()> {
let num = num.as_str();
use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::Float;
@@ -1192,5 +1177,5 @@ pub fn parse_float(
}
};

Ok(Value::ByVal(PrimVal::Bytes(bits)))
Ok(ConstValue::ByVal(PrimVal::Bytes(bits)))
}
156 changes: 112 additions & 44 deletions src/librustc_mir/interpret/const_eval.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
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::mir;
use rustc::ty::{self, TyCtxt, Ty, Instance};
@@ -8,9 +8,13 @@ use rustc::ty::subst::Subst;

use syntax::ast::Mutability;
use syntax::codemap::Span;
use syntax::codemap::DUMMY_SP;

use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal, AllocId};
use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory};
use rustc::mir::interpret::{
EvalResult, EvalError, EvalErrorKind, GlobalId,
Value, Pointer, PrimVal, AllocId, Allocation, ConstValue,
};
use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory, MemoryKind};

use std::fmt;
use std::error::Error;
@@ -57,19 +61,21 @@ pub fn mk_eval_cx<'a, 'tcx>(
}

pub fn eval_promoted<'a, 'mir, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
cid: GlobalId<'tcx>,
mir: &'mir mir::Mir<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Option<(Value, Pointer, Ty<'tcx>)> {
let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env);
match res {
Ok(val) => Some(val),
Err(mut err) => {
ecx.report(&mut err, false, None);
None
ecx.with_fresh_body(|ecx| {
let res = eval_body_using_ecx(ecx, cid, Some(mir), param_env);
match res {
Ok(val) => Some(val),
Err(mut err) => {
ecx.report(&mut err, false, None);
None
}
}
}
})
}

pub fn eval_body<'a, 'tcx>(
@@ -87,27 +93,83 @@ 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>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cid: GlobalId<'tcx>,
mir: Option<&'mir mir::Mir<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
) -> (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
// and try improving it down the road when more information is available
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 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 {
Some(mir) => mir,
None => ecx.load_mir(cid.instance.def)?,
};
if let Some(index) = cid.promoted {
mir = &mir.promoted[index];
}
span = mir.span;
let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
assert!(!layout.is_unsized());
let ptr = ecx.memory.allocate(
@@ -139,14 +201,11 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
let ptr = ptr.into();
// always try to read the value and report errors
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) if tcx.is_static(cid.instance.def_id()).is_none() => val,
Some(val) => val,
// point at the allocation
_ => Value::ByRef(ptr, layout.align),
};
Ok((value, ptr, layout.ty))
})();
(res, ecx)
}

pub struct CompileTimeEvaluator;
@@ -357,14 +416,16 @@ pub fn const_val_field<'a, 'tcx>(
instance: ty::Instance<'tcx>,
variant: Option<usize>,
field: mir::Field,
value: Value,
value: ConstValue<'tcx>,
ty: Ty<'tcx>,
) -> ::rustc::middle::const_val::EvalResult<'tcx> {
trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
let result = (|| {
let value = ecx.const_value_to_value(value, ty)?;
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) => {
let place = Place::Ptr {
ptr,
@@ -385,10 +446,7 @@ pub fn const_val_field<'a, 'tcx>(
Ok((field, ty))
})();
match result {
Ok((field, ty)) => Ok(tcx.mk_const(ty::Const {
val: ConstVal::Value(field),
ty,
})),
Ok((field, ty)) => Ok(value_to_const_value(tcx, field, ty)),
Err(err) => {
let (trace, span) = ecx.generate_stacktrace(None);
let err = ErrKind::Miri(err, trace);
@@ -404,15 +462,15 @@ pub fn const_variant_index<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
value: Value,
val: ConstValue<'tcx>,
ty: Ty<'tcx>,
) -> 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 value = ecx.const_value_to_value(val, ty)?;
let (ptr, align) = match value {
Value::ByValPair(..) | Value::ByVal(_) => {
let layout = ecx.layout_of(ty)?;
use super::MemoryKind;
let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
let ptr: Pointer = ptr.into();
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)
}

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>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
@@ -432,17 +514,6 @@ pub fn const_eval_provider<'a, 'tcx>(
let cid = key.value;
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) {
let tables = tcx.typeck_tables_of(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);
res.map(|(miri_value, _, miri_ty)| {
tcx.mk_const(ty::Const {
val: ConstVal::Value(miri_value),
ty: miri_ty,
})
res.map(|(val, _, miri_ty)| {
value_to_const_value(tcx, val, miri_ty)
}).map_err(|mut err| {
if tcx.is_static(def_id).is_some() {
ecx.report(&mut err, true, None);
171 changes: 93 additions & 78 deletions src/librustc_mir/interpret/eval_context.rs
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ use syntax::codemap::{self, Span};
use syntax::ast::Mutability;
use rustc::mir::interpret::{
GlobalId, Value, Pointer, PrimVal, PrimValKind,
EvalError, EvalResult, EvalErrorKind, MemoryPointer,
EvalError, EvalResult, EvalErrorKind, MemoryPointer, ConstValue,
};
use std::mem;

@@ -116,15 +116,6 @@ pub struct ValTy<'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> {
type Target = 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> {
pub fn new(
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),
stack: Vec::new(),
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> {
let layout = self.layout_of(ty)?;
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 {
ConstVal::Unevaluated(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,
}, 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, _) => {
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!(
"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
let src = self.eval_place(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(
dest,
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::Promoted { index } => {
let instance = self.frame().instance;
self.read_global_as_value(GlobalId {
instance: self.frame().instance,
instance,
promoted: Some(index),
}, ty)?
}
@@ -997,7 +1020,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
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() {
let alloc_id = self
.tcx
@@ -1341,92 +1364,84 @@ 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>> {
use syntax::ast::FloatTy;

let layout = self.layout_of(ty)?;
self.memory.check_align(ptr, ptr_align)?;

if layout.size.bytes() == 0 {
return Ok(Some(Value::ByVal(PrimVal::Undef)));
}

let ptr = ptr.to_ptr()?;
let val = match ty.sty {
pub fn validate_ptr_target(
&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)?;
let val = match val {
PrimVal::Bytes(0) => false,
PrimVal::Bytes(1) => true,
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),
};
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),
Some(..) => (),
None => return err!(InvalidChar(c as u128)),
}
}

ty::TyInt(int_ty) => {
use syntax::ast::IntTy::*;
let size = match int_ty {
I8 => 1,
I16 => 2,
I32 => 4,
I64 => 8,
I128 => 16,
Isize => self.memory.pointer_size(),
};
self.memory.read_primval(ptr, ptr_align, size)?
}

ty::TyUint(uint_ty) => {
use syntax::ast::UintTy::*;
let size = match uint_ty {
U8 => 1,
U16 => 2,
U32 => 4,
U64 => 8,
U128 => 16,
Usize => self.memory.pointer_size(),
};
self.memory.read_primval(ptr, ptr_align, size)?
}

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::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)
self.read_ptr(ptr, ptr_align, rty)?;
}

ty::TyAdt(def, _) => {
if def.is_box() {
return self.read_ptr(ptr, ptr_align, ty.boxed_ty()).map(Some);
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)?
} else {
return Ok(None);
self.memory.read_primval(ptr, ptr_align, size)?;
}
}

_ => return Ok(None),
};
_ => (),
}
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)?;
self.memory.check_align(ptr, ptr_align)?;

Ok(Some(Value::ByVal(val)))
if layout.size.bytes() == 0 {
return Ok(Some(Value::ByVal(PrimVal::Undef)));
}

let ptr = ptr.to_ptr()?;

// Not the right place to do this
//self.validate_ptr_target(ptr, ptr_align, ty)?;

match layout.abi {
layout::Abi::Scalar(..) => {
let primval = self.memory.read_primval(ptr, ptr_align, layout.size.bytes())?;
Ok(Some(Value::ByVal(primval)))
}
layout::Abi::ScalarPair(ref a, ref b) => {
let (a, b) = (&a.value, &b.value);
let (a_size, b_size) = (a.size(self), b.size(self));
let a_ptr = ptr;
let b_offset = a_size.abi_align(b.align(self));
let b_ptr = ptr.offset(b_offset.bytes(), self)?.into();
let a_val = self.memory.read_primval(a_ptr, ptr_align, a_size.bytes())?;
let b_val = self.memory.read_primval(b_ptr, ptr_align, b_size.bytes())?;
Ok(Some(Value::ByValPair(a_val, b_val)))
}
_ => Ok(None),
}
}

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)?;
// u64 cast is from usize to u64, which is always good
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,
};
self.write_value(valty, dest)
119 changes: 60 additions & 59 deletions src/librustc_mir/interpret/memory.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian};
use std::collections::{btree_map, BTreeMap, VecDeque};
use std::{ptr, io};
use std::collections::{btree_map, VecDeque};
use std::ptr;

use rustc::hir::def_id::DefId;
use rustc::ty::Instance;
use rustc::ty::ParamEnv;
use rustc::ty::maps::TyCtxtAt;
use rustc::ty::layout::{self, Align, TargetDataLayout};
use syntax::ast::Mutability;
use rustc::middle::const_val::{ConstVal, ErrKind};

use rustc_data_structures::fx::{FxHashSet, FxHashMap};
use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, UndefMask, Value, Pointer,
EvalResult, PrimVal, EvalErrorKind};
use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, Value, Pointer,
EvalResult, PrimVal, EvalErrorKind, GlobalId};
pub use rustc::mir::interpret::{write_target_uint, write_target_int, read_target_uint};

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
pub fn allocate(
pub fn allocate_value(
&mut self,
size: u64,
align: Align,
alloc: Allocation,
kind: Option<MemoryKind<M::MemoryKinds>>,
) -> EvalResult<'tcx, MemoryPointer> {
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,
};
) -> EvalResult<'tcx, AllocId> {
let id = self.tcx.interpret_interner.reserve();
M::add_lock(self, id);
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);
},
}
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))
}

@@ -272,6 +277,31 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {

/// Allocation accessors
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> {
// normal alloc?
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),
None => {
// static alloc?
self.tcx.interpret_interner.get_alloc(id)
// no alloc? produce an error
.ok_or_else(|| if self.tcx.interpret_interner.get_fn(id).is_some() {
EvalErrorKind::DerefFunctionPointer.into()
} else {
EvalErrorKind::DanglingPointerDeref.into()
})
if let Some(a) = self.tcx.interpret_interner.get_alloc(id) {
return Ok(a);
}
// static variable?
if let Some(did) = self.tcx.interpret_interner.get_static(id) {
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
////////////////////////////////////////////////////////////////////////////////
2 changes: 2 additions & 0 deletions src/librustc_mir/interpret/mod.rs
Original file line number Diff line number Diff line change
@@ -23,9 +23,11 @@ pub use self::const_eval::{
mk_borrowck_eval_cx,
eval_body,
CompileTimeEvaluator,
const_value_to_allocation_provider,
const_eval_provider,
const_val_field,
const_variant_index,
value_to_const_value,
};

pub use self::machine::Machine;
16 changes: 10 additions & 6 deletions src/librustc_mir/interpret/place.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use rustc::mir;
use rustc::ty::{self, Ty};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
use rustc_data_structures::indexed_vec::Idx;

@@ -69,9 +69,13 @@ impl<'tcx> Place {
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 {
ty::TyArray(elem, n) => (elem, n.val.unwrap_u64() as u64),
ty::TyArray(elem, n) => (elem, n.unwrap_usize(tcx)),

ty::TySlice(elem) => {
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_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();
assert!(
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_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();
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_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();
assert!(u64::from(from) <= n - u64::from(to));
let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?;
1 change: 1 addition & 0 deletions src/librustc_mir/lib.rs
Original file line number Diff line number Diff line change
@@ -85,6 +85,7 @@ pub fn provide(providers: &mut Providers) {
shim::provide(providers);
transform::provide(providers);
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;
}

23 changes: 9 additions & 14 deletions src/librustc_mir/monomorphize/collector.rs
Original file line number Diff line number Diff line change
@@ -194,7 +194,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
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::ty::subst::{Substs, Kind};
use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
@@ -203,7 +203,7 @@ use rustc::session::config;
use rustc::mir::{self, Location, Promoted};
use rustc::mir::visit::Visitor as MirVisitor;
use rustc::mir::mono::MonoItem;
use rustc::mir::interpret::GlobalId;
use rustc::mir::interpret::{PrimVal, GlobalId};

use monomorphize::{self, Instance};
use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
@@ -1237,22 +1237,17 @@ fn collect_const<'a, 'tcx>(
};
match val {
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, b.alloc_id, output);
}
ConstVal::Value(Value::ByValPair(_, PrimVal::Ptr(ptr))) |
ConstVal::Value(Value::ByValPair(PrimVal::Ptr(ptr), _)) |
ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) =>
ConstVal::Value(ConstValue::ByValPair(_, PrimVal::Ptr(ptr))) |
ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(ptr), _)) |
ConstVal::Value(ConstValue::ByVal(PrimVal::Ptr(ptr))) =>
collect_miri(tcx, ptr.alloc_id, output),
ConstVal::Value(Value::ByRef(Pointer { primval: PrimVal::Ptr(ptr) }, _)) => {
// by ref should only collect the inner allocation, not the value itself
let alloc = tcx
.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);
ConstVal::Value(ConstValue::ByRef(alloc)) => {
for &id in alloc.relocations.values() {
collect_miri(tcx, id, output);
}
}
_ => {},
3 changes: 1 addition & 2 deletions src/librustc_mir/monomorphize/item.rs
Original file line number Diff line number Diff line change
@@ -313,8 +313,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
ty::TyArray(inner_type, len) => {
output.push('[');
self.push_type_name(inner_type, output);
write!(output, "; {}",
len.val.unwrap_u64()).unwrap();
write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
output.push(']');
},
ty::TySlice(inner_type) => {
21 changes: 4 additions & 17 deletions src/librustc_mir/shim.rs
Original file line number Diff line number Diff line change
@@ -11,12 +11,10 @@
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::infer;
use rustc::middle::const_val::ConstVal;
use rustc::mir::*;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::ty::maps::Providers;
use rustc::mir::interpret::{Value, PrimVal};

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 {
_ if is_copy => builder.copy_shim(),
ty::TyArray(ty, len) => {
let len = len.val.unwrap_u64();
let len = len.unwrap_usize(tcx);
builder.array_shim(dest, src, ty, len)
}
ty::TyClosure(def_id, substs) => {
@@ -442,11 +440,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
span: self.span,
ty: func_ty,
literal: Literal::Value {
value: tcx.mk_const(ty::Const {
// ZST function type
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
ty: func_ty
}),
value: ty::Const::zero_sized(self.tcx, func_ty)
},
});

@@ -506,10 +500,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
span: self.span,
ty: self.tcx.types.usize,
literal: Literal::Value {
value: self.tcx.mk_const(ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))),
ty: self.tcx.types.usize,
})
value: ty::Const::from_usize(self.tcx, value),
}
}
}
@@ -738,11 +729,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
span,
ty,
literal: Literal::Value {
value: tcx.mk_const(ty::Const {
// ZST function type
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
ty
}),
value: ty::Const::zero_sized(tcx, ty)
},
}),
vec![rcvr])
Loading