Produce instead of pointers

This commit is contained in:
Oliver Schneider 2018-01-16 09:24:38 +01:00
parent c0574c054c
commit 918b6d7633
No known key found for this signature in database
GPG key ID: A69F8D225B3AD7D9
80 changed files with 1497 additions and 533 deletions

View file

@ -427,6 +427,7 @@ impl<T: Ord> Ord for Reverse<T> {
/// }
/// }
/// ```
#[cfg_attr(not(stage0), lang = "ord")]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Ord: Eq + PartialOrd<Self> {
/// This method returns an `Ordering` between `self` and `other`.
@ -596,7 +597,8 @@ impl PartialOrd for Ordering {
/// assert_eq!(x < y, true);
/// assert_eq!(x.lt(&y), true);
/// ```
#[lang = "ord"]
#[cfg_attr(stage0, lang = "ord")]
#[cfg_attr(not(stage0), lang = "partial_ord")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"]
pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {

View file

@ -63,6 +63,7 @@
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
use hir::map::DefPathHash;
use hir::{HirId, ItemLocalId};
use mir;
use ich::Fingerprint;
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};

View file

@ -14,7 +14,7 @@ use hir::def_id::DefId;
use ty::{self, TyCtxt, layout};
use ty::subst::Substs;
use rustc_const_math::*;
use mir::interpret::Value;
use mir::interpret::{Value, PrimVal};
use graphviz::IntoCow;
use errors::DiagnosticBuilder;
@ -39,7 +39,7 @@ pub enum ConstVal<'tcx> {
Function(DefId, &'tcx Substs<'tcx>),
Aggregate(ConstAggregate<'tcx>),
Unevaluated(DefId, &'tcx Substs<'tcx>),
/// A miri value, currently only produced if old ctfe fails, but miri succeeds
/// A miri value, currently only produced if --miri is enabled
Value(Value),
}
@ -71,12 +71,37 @@ impl<'tcx> Decodable for ConstAggregate<'tcx> {
}
impl<'tcx> ConstVal<'tcx> {
pub fn to_const_int(&self) -> Option<ConstInt> {
pub fn to_u128(&self) -> Option<u128> {
match *self {
ConstVal::Integral(i) => Some(i),
ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)),
ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)),
_ => None
ConstVal::Integral(i) => i.to_u128(),
ConstVal::Bool(b) => Some(b as u128),
ConstVal::Char(ch) => Some(ch as u32 as u128),
ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
Some(b)
},
_ => None,
}
}
pub fn unwrap_u64(&self) -> u64 {
match self.to_u128() {
Some(val) => {
assert_eq!(val as u64 as u128, val);
val as u64
},
None => bug!("expected constant u64, got {:#?}", self),
}
}
pub fn unwrap_usize<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> ConstUsize {
match *self {
ConstVal::Integral(ConstInt::Usize(i)) => i,
ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
assert_eq!(b as u64 as u128, b);
match ConstUsize::new(b as u64, tcx.sess.target.usize_ty) {
Ok(val) => val,
Err(e) => bug!("{:#?} is not a usize {:?}", self, e),
}
},
_ => bug!("expected constant u64, got {:#?}", self),
}
}
}

View file

@ -280,6 +280,7 @@ language_item_table! {
GeneratorTraitLangItem, "generator", gen_trait;
EqTraitLangItem, "eq", eq_trait;
PartialOrdTraitLangItem, "partial_ord", partial_ord_trait;
OrdTraitLangItem, "ord", ord_trait;
// A number of panic-related lang items. The `panic` item corresponds to

View file

@ -913,8 +913,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_const_int().and_then(|i| i.to_u64()) == Some(0) => true,
ty::TyArray(_, len) if len.val.to_u128() == Some(0) => true,
_ => promotable,
};

View file

@ -1,6 +1,7 @@
#![allow(unknown_lints)]
use ty::layout::{Align, HasDataLayout};
use ty;
use super::{EvalResult, MemoryPointer, PointerArithmetic};
use syntax::ast::FloatTy;
@ -36,6 +37,15 @@ pub enum Value {
ByValPair(PrimVal, PrimVal),
}
impl<'tcx> ty::TypeFoldable<'tcx> for Value {
fn super_fold_with<'gcx: 'tcx, F: ty::fold::TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self {
*self
}
fn super_visit_with<V: ty::fold::TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
false
}
}
/// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally.
/// This type clears up a few APIs where having a `PrimVal` argument for something that is
/// potentially an integer pointer or a pointer to an allocation was unclear.

View file

@ -15,7 +15,7 @@
use graphviz::IntoCow;
use middle::const_val::ConstVal;
use middle::region;
use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr};
use rustc_const_math::{ConstUsize, ConstMathErr};
use rustc_data_structures::sync::{Lrc};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators};
@ -25,9 +25,11 @@ use rustc_serialize as serialize;
use hir::def::CtorKind;
use hir::def_id::DefId;
use mir::visit::MirVisitable;
use mir::interpret::{Value, PrimVal};
use ty::subst::{Subst, Substs};
use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use ty::TypeAndMut;
use util::ppaux;
use std::slice;
use hir::{self, InlineAsm};
@ -707,7 +709,7 @@ pub enum TerminatorKind<'tcx> {
/// Possible values. The locations to branch to in each case
/// are found in the corresponding indices from the `targets` vector.
values: Cow<'tcx, [ConstInt]>,
values: Cow<'tcx, [u128]>,
/// Possible branch sites. The last element of this vector is used
/// for the otherwise branch, so targets.len() == values.len() + 1
@ -858,7 +860,7 @@ impl<'tcx> Terminator<'tcx> {
impl<'tcx> TerminatorKind<'tcx> {
pub fn if_<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>,
t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::U8(0)];
static BOOL_SWITCH_FALSE: &'static [u128] = &[0];
TerminatorKind::SwitchInt {
discr: cond,
switch_ty: tcx.types.bool,
@ -1144,12 +1146,16 @@ impl<'tcx> TerminatorKind<'tcx> {
match *self {
Return | Resume | Abort | Unreachable | GeneratorDrop => vec![],
Goto { .. } => vec!["".into()],
SwitchInt { ref values, .. } => {
SwitchInt { ref values, switch_ty, .. } => {
values.iter()
.map(|const_val| {
let mut buf = String::new();
fmt_const_val(&mut buf, &ConstVal::Integral(*const_val)).unwrap();
buf.into()
.map(|&u| {
let mut s = String::new();
print_miri_value(
Value::ByVal(PrimVal::Bytes(u)),
switch_ty,
&mut s,
).unwrap();
s.into()
})
.chain(iter::once(String::from("otherwise").into()))
.collect()
@ -1533,7 +1539,12 @@ impl<'tcx> Operand<'tcx> {
ty,
literal: Literal::Value {
value: tcx.mk_const(ty::Const {
val: ConstVal::Function(def_id, substs),
val: if tcx.sess.opts.debugging_opts.miri {
// ZST function type
ConstVal::Value(Value::ByVal(PrimVal::Undef))
} else {
ConstVal::Function(def_id, substs)
},
ty
})
},
@ -1853,7 +1864,7 @@ impl<'tcx> Debug for Literal<'tcx> {
match *self {
Value { value } => {
write!(fmt, "const ")?;
fmt_const_val(fmt, &value.val)
fmt_const_val(fmt, value)
}
Promoted { index } => {
write!(fmt, "{:?}", index)
@ -1863,9 +1874,9 @@ 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: &ConstVal) -> fmt::Result {
fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
use middle::const_val::ConstVal::*;
match *const_val {
match const_val.val {
Float(f) => write!(fmt, "{:?}", f),
Integral(n) => write!(fmt, "{}", n),
Str(s) => write!(fmt, "{:?}", s),
@ -1882,7 +1893,41 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val),
Unevaluated(..) => write!(fmt, "{:?}", const_val),
Value(val) => write!(fmt, "{:?}", val),
Value(val) => print_miri_value(val, const_val.ty, fmt),
}
}
fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Result {
use ty::TypeVariants::*;
use rustc_const_math::ConstFloat;
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(bits)), &TyFloat(fty)) =>
write!(f, "{}", ConstFloat { bits, ty: fty }),
(Value::ByVal(PrimVal::Bytes(n)), &TyUint(ui)) => write!(f, "{:?}{}", n, ui),
(Value::ByVal(PrimVal::Bytes(n)), &TyInt(i)) => write!(f, "{:?}{}", n as i128, i),
(Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
(Value::ByVal(PrimVal::Undef), &TyFnDef(did, _)) =>
write!(f, "{}", item_path_str(did)),
(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len)), &TyRef(_, TypeAndMut {
ty: &ty::TyS { sty: TyStr, .. }, ..
})) => {
ty::tls::with(|tcx| {
let alloc = tcx
.interpret_interner
.borrow()
.get_alloc(ptr.alloc_id.0)
.expect("miri alloc not found");
assert_eq!(len as usize as u128, len);
let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)];
let s = ::std::str::from_utf8(slice)
.expect("non utf8 str from miri");
write!(f, "{:?}", s)
})
},
_ => write!(f, "{:?}:{}", value, ty),
}
}
@ -2468,6 +2513,15 @@ impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection<'tcx, B, V, T>
}
}
impl<'tcx> TypeFoldable<'tcx> for Field {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self {
*self
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
false
}
}
impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
Constant {

View file

@ -70,7 +70,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
PlaceTy::Ty {
ty: match ty.sty {
ty::TyArray(inner, size) => {
let size = size.val.to_const_int().unwrap().to_u64().unwrap();
let size = size.val.unwrap_u64();
let len = size - (from as u64) - (to as u64);
tcx.mk_array(inner, len)
}

View file

@ -243,12 +243,6 @@ macro_rules! make_mir_visitor {
self.super_generator_interior(interior);
}
fn visit_const_int(&mut self,
const_int: &ConstInt,
_: Location) {
self.super_const_int(const_int);
}
fn visit_const_usize(&mut self,
const_usize: & $($mutability)* ConstUsize,
_: Location) {
@ -426,13 +420,10 @@ macro_rules! make_mir_visitor {
TerminatorKind::SwitchInt { ref $($mutability)* discr,
ref $($mutability)* switch_ty,
ref values,
values: _,
ref targets } => {
self.visit_operand(discr, source_location);
self.visit_ty(switch_ty, TyContext::Location(source_location));
for value in &values[..] {
self.visit_const_int(value, source_location);
}
for &target in targets {
self.visit_branch(block, target);
}
@ -798,9 +789,6 @@ macro_rules! make_mir_visitor {
_substs: & $($mutability)* ClosureSubsts<'tcx>) {
}
fn super_const_int(&mut self, _const_int: &ConstInt) {
}
fn super_const_usize(&mut self, _const_usize: & $($mutability)* ConstUsize) {
}

View file

@ -30,7 +30,8 @@ use middle::cstore::EncodedMetadata;
use middle::lang_items;
use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use middle::stability;
use mir::{Mir, interpret};
use mir::{self, Mir, interpret};
use mir::interpret::{Value, PrimVal};
use ty::subst::{Kind, Substs};
use ty::ReprOptions;
use ty::Instance;
@ -1267,6 +1268,36 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.get_lang_items(LOCAL_CRATE)
}
pub fn is_binop_lang_item(&self, def_id: DefId) -> Option<(mir::BinOp, bool)> {
let items = self.lang_items();
let def_id = Some(def_id);
if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
else { None }
}
pub fn stability(self) -> Lrc<stability::Index<'tcx>> {
self.stability_index(LOCAL_CRATE)
}
@ -2068,7 +2099,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn mk_array_const_usize(self, ty: Ty<'tcx>, n: ConstUsize) -> Ty<'tcx> {
self.mk_ty(TyArray(ty, self.mk_const(ty::Const {
val: ConstVal::Integral(ConstInt::Usize(n)),
val: if self.sess.opts.debugging_opts.miri {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.as_u64().into())))
} else {
ConstVal::Integral(ConstInt::Usize(n))
},
ty: self.types.usize
})))
}

View file

@ -11,6 +11,7 @@
use hir::def_id::DefId;
use middle::const_val::ConstVal;
use ty::{self, BoundRegion, Region, Ty, TyCtxt};
use mir::interpret::{Value, PrimVal};
use std::fmt;
use syntax::abi;
@ -186,10 +187,12 @@ 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) => {
if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
format!("array of {} elements", n)
} else {
"array".to_string()
match n.val {
ConstVal::Integral(ConstInt::Usize(n)) =>
format!("array of {} elements", n),
ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))) =>
format!("array of {} elements", n),
_ => "array".to_string(),
}
}
ty::TySlice(_) => "slice".to_string(),

View file

@ -262,7 +262,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
}))
},
TyArray(ty, len) => {
match len.val.to_const_int().and_then(|i| i.to_u64()) {
match len.val.to_u128() {
// 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),

View file

@ -952,7 +952,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
enum StructKind {
/// A tuple, closure, or univariant which cannot be coerced to unsized.
AlwaysSized,
/// A univariant, the last field of which may be coerced to unsized.
/// A univariant, the last field of which fn compute_uncachedmay be coerced to unsized.
MaybeUnsized,
/// A univariant, but with a prefix of an arbitrary size & alignment (e.g. enum tag).
Prefixed(Size, Align),
@ -1237,7 +1237,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
}
let element = self.layout_of(element)?;
let count = count.val.to_const_int().unwrap().to_u64().unwrap();
let count = count.val.unwrap_u64();
let size = element.size.checked_mul(count, dl)
.ok_or(LayoutError::SizeOverflow(ty))?;

View file

@ -13,6 +13,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex};
use ty::{self, Ty, TyCtxt};
use ty::maps::queries;
use ty::subst::Substs;
use mir;
use std::hash::Hash;
use syntax_pos::symbol::InternedString;

View file

@ -14,6 +14,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex};
use ty::{self, Ty, TyCtxt};
use ty::subst::Substs;
use ty::fast_reject::SimplifiedType;
use mir;
use std::fmt::Debug;
use std::hash::Hash;

View file

@ -15,7 +15,7 @@ use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId,
RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE};
use hir::map::definitions::DefPathHash;
use ich::{CachingCodemapView, Fingerprint};
use mir;
use mir::{self, interpret};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@ -542,6 +542,13 @@ impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx,
implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> );
impl<'a, 'tcx, 'x> SpecializedDecoder<interpret::AllocId> for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<interpret::AllocId, Self::Error> {
unimplemented!()
}
}
impl<'a, 'tcx, 'x> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
let tag: u8 = Decodable::decode(self)?;

View file

@ -26,6 +26,7 @@ use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangIte
use middle::privacy::AccessLevels;
use middle::resolve_lifetime::ObjectLifetimeDefault;
use mir::Mir;
use mir::interpret::{Value, PrimVal};
use mir::GeneratorLayout;
use session::CrateDisambiguator;
use traits;
@ -1838,6 +1839,19 @@ impl<'a, 'gcx, 'tcx> AdtDef {
Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => {
discr = v;
}
Ok(&ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
..
}) => {
trace!("discriminants: {} ({:?})", b, repr_type);
use syntax::attr::IntType;
discr = match repr_type {
IntType::SignedInt(int_type) => ConstInt::new_signed(
b as i128, int_type, tcx.sess.target.isize_ty).unwrap(),
IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned(
b, uint_type, tcx.sess.target.usize_ty).unwrap(),
};
}
err => {
if !expr_did.is_local() {
span_bug!(tcx.def_span(expr_did),
@ -1879,6 +1893,20 @@ impl<'a, 'gcx, 'tcx> AdtDef {
explicit_value = v;
break;
}
Ok(&ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
..
}) => {
trace!("discriminants: {} ({:?})", b, repr_type);
use syntax::attr::IntType;
explicit_value = match repr_type {
IntType::SignedInt(int_type) => ConstInt::new_signed(
b as i128, int_type, tcx.sess.target.isize_ty).unwrap(),
IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned(
b, uint_type, tcx.sess.target.usize_ty).unwrap(),
};
break;
}
err => {
if !expr_did.is_local() {
span_bug!(tcx.def_span(expr_did),

View file

@ -20,6 +20,7 @@ use ty::subst::{UnpackedKind, Substs};
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::fold::{TypeVisitor, TypeFolder};
use ty::error::{ExpectedFound, TypeError};
use mir::interpret::{Value, PrimVal};
use util::common::ErrorReported;
use std::rc::Rc;
use std::iter;
@ -483,6 +484,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> {
match x.val {
ConstVal::Integral(x) => Ok(x.to_u64().unwrap()),
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(Reveal::UserFacing);
@ -492,6 +494,13 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => {
return Ok(x.to_u64().unwrap());
}
Ok(&ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
..
}) => {
assert_eq!(b as u64 as u128, b);
return Ok(b as u64);
}
_ => {}
}
}

View file

@ -890,6 +890,61 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<Ty<'tcx>> {
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
use ty::InstanceDef::*;
Self {
substs: self.substs.fold_with(folder),
def: match self.def {
Item(did) => Item(did.fold_with(folder)),
Intrinsic(did) => Intrinsic(did.fold_with(folder)),
FnPtrShim(did, ty) => FnPtrShim(
did.fold_with(folder),
ty.fold_with(folder),
),
Virtual(did, i) => Virtual(
did.fold_with(folder),
i,
),
ClosureOnceShim { call_once } => ClosureOnceShim {
call_once: call_once.fold_with(folder),
},
DropGlue(did, ty) => DropGlue(
did.fold_with(folder),
ty.fold_with(folder),
),
CloneShim(did, ty) => CloneShim(
did.fold_with(folder),
ty.fold_with(folder),
),
},
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
use ty::InstanceDef::*;
self.substs.visit_with(visitor) ||
match self.def {
Item(did) => did.visit_with(visitor),
Intrinsic(did) => did.visit_with(visitor),
FnPtrShim(did, ty) => {
did.visit_with(visitor) ||
ty.visit_with(visitor)
},
Virtual(did, _) => did.visit_with(visitor),
ClosureOnceShim { call_once } => call_once.visit_with(visitor),
DropGlue(did, ty) => {
did.visit_with(visitor) ||
ty.visit_with(visitor)
},
CloneShim(did, ty) => {
did.visit_with(visitor) ||
ty.visit_with(visitor)
},
}
}
}
impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
let sty = match self.sty {

View file

@ -24,6 +24,7 @@ use ty::maps::TyCtxtAt;
use ty::TypeVariants::*;
use util::common::ErrorReported;
use middle::lang_items;
use mir::interpret::{Value, PrimVal};
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
@ -765,6 +766,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
self.hash_discriminant_u8(&n.val);
match n.val {
ConstVal::Integral(x) => self.hash(x.to_u64().unwrap()),
ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b),
ConstVal::Unevaluated(def_id, _) => self.def_id(def_id),
_ => bug!("arrays should not have {:?} as length", n)
}

View file

@ -21,6 +21,7 @@ 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;
@ -1168,6 +1169,9 @@ define_print! {
ConstVal::Integral(ConstInt::Usize(sz)) => {
write!(f, "{}", sz)?;
}
ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => {
write!(f, "{}", sz)?;
}
ConstVal::Unevaluated(_def_id, substs) => {
write!(f, "<unevaluated{:?}>", &substs[..])?;
}

View file

@ -28,6 +28,7 @@ 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};
@ -195,6 +196,41 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
}
})).collect()
}
box PatternKind::Constant {
value: &ty::Const { val: ConstVal::Value(b), ty }
} => {
match b {
Value::ByVal(PrimVal::Ptr(ptr)) => {
let is_array_ptr = ty
.builtin_deref(true, ty::NoPreference)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == tcx.types.u8);
assert!(is_array_ptr);
let alloc = tcx
.interpret_interner
.borrow()
.get_alloc(ptr.alloc_id.0)
.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),
}
}
_ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat)
}
}).clone()
@ -422,13 +458,17 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
ty::TyBool => {
[true, false].iter().map(|&b| {
ConstantValue(cx.tcx.mk_const(ty::Const {
val: ConstVal::Bool(b),
val: if cx.tcx.sess.opts.debugging_opts.miri {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128)))
} else {
ConstVal::Bool(b)
},
ty: cx.tcx.types.bool
}))
}).collect()
}
ty::TyArray(ref sub_ty, len) if len.val.to_const_int().is_some() => {
let len = len.val.to_const_int().unwrap().to_u64().unwrap();
ty::TyArray(ref sub_ty, len) if len.val.to_u128().is_some() => {
let len = len.val.unwrap_u64();
if len != 0 && cx.is_uninhabited(sub_ty) {
vec![]
} else {
@ -461,7 +501,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
}
fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
_cx: &mut MatchCheckCtxt<'a, 'tcx>,
cx: &mut MatchCheckCtxt<'a, 'tcx>,
patterns: I) -> u64
where I: Iterator<Item=&'p Pattern<'tcx>>
{
@ -538,6 +578,25 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
PatternKind::Constant { value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => {
max_fixed_len = cmp::max(max_fixed_len, b.data.len() as u64);
}
PatternKind::Constant {
value: &ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))),
ty,
}
} => {
let is_array_ptr = ty
.builtin_deref(true, ty::NoPreference)
.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
.borrow()
.get_alloc(ptr.alloc_id.0)
.unwrap();
max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
}
}
PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
let fixed_len = prefix.len() as u64 + suffix.len() as u64;
max_fixed_len = cmp::max(max_fixed_len, fixed_len);
@ -581,7 +640,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
witness: WitnessPreference)
-> Usefulness<'tcx> {
let &Matrix(ref rows) = matrix;
debug!("is_useful({:?}, {:?})", matrix, v);
debug!("is_useful({:#?}, {:#?})", matrix, v);
// The base case. We are pattern-matching on () and the return value is
// based on whether our matrix has a row or not.
@ -626,10 +685,10 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0])))
};
debug!("is_useful_expand_first_col: pcx={:?}, expanding {:?}", pcx, v[0]);
debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]);
if let Some(constructors) = pat_constructors(cx, v[0], pcx) {
debug!("is_useful - expanding constructors: {:?}", constructors);
debug!("is_useful - expanding constructors: {:#?}", constructors);
constructors.into_iter().map(|c|
is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
).find(|result| result.is_useful()).unwrap_or(NotUseful)
@ -639,9 +698,9 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
let used_ctors: Vec<Constructor> = rows.iter().flat_map(|row| {
pat_constructors(cx, row[0], pcx).unwrap_or(vec![])
}).collect();
debug!("used_ctors = {:?}", used_ctors);
debug!("used_ctors = {:#?}", used_ctors);
let all_ctors = all_constructors(cx, pcx);
debug!("all_ctors = {:?}", all_ctors);
debug!("all_ctors = {:#?}", all_ctors);
let missing_ctors: Vec<Constructor> = all_ctors.iter().filter(|c| {
!used_ctors.contains(*c)
}).cloned().collect();
@ -669,7 +728,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
let is_declared_nonexhaustive =
cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
debug!("missing_ctors={:?} is_privately_empty={:?} is_declared_nonexhaustive={:?}",
debug!("missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
missing_ctors, is_privately_empty, is_declared_nonexhaustive);
// For privately empty and non-exhaustive enums, we work as if there were an "extra"
@ -769,7 +828,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
lty: Ty<'tcx>,
witness: WitnessPreference) -> Usefulness<'tcx>
{
debug!("is_useful_specialized({:?}, {:?}, {:?})", v, ctor, lty);
debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty);
let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| {
Pattern {
@ -821,7 +880,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.to_const_int().unwrap().to_u64().unwrap())
Slice(length.val.unwrap_u64())
]),
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
},
@ -842,7 +901,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
/// A struct pattern's arity is the number of fields it contains, etc.
fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
debug!("constructor_arity({:?}, {:?})", ctor, ty);
debug!("constructor_arity({:#?}, {:?})", ctor, ty);
match ty.sty {
ty::TyTuple(ref fs, _) => fs.len() as u64,
ty::TySlice(..) | ty::TyArray(..) => match *ctor {
@ -866,12 +925,13 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
ctor: &Constructor,
ty: Ty<'tcx>) -> Vec<Ty<'tcx>>
{
debug!("constructor_sub_pattern_tys({:?}, {:?})", ctor, ty);
debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
match ty.sty {
ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(),
ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor {
Slice(length) => (0..length).map(|_| ty).collect(),
ConstantValue(_) => vec![],
Single => vec![ty],
_ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
},
ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty],
@ -880,6 +940,9 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
// Use T as the sub pattern type of Box<T>.
vec![substs.type_at(0)]
} else {
if let ConstantValue(_) = *ctor {
return vec![];
}
adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
let is_visible = adt.is_enum()
|| field.vis.is_accessible_from(cx.module, cx.tcx);
@ -901,14 +964,30 @@ 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: TyCtxt, _span: Span,
ctor: &Constructor,
prefix: &[Pattern],
slice: &Option<Pattern>,
suffix: &[Pattern])
-> Result<bool, ErrorReported> {
let data = match *ctor {
let data: &[u8] = match *ctor {
ConstantValue(&ty::Const { val: ConstVal::ByteStr(b), .. }) => b.data,
ConstantValue(&ty::Const { val: ConstVal::Value(
Value::ByVal(PrimVal::Ptr(ptr))
), ty }) => {
let is_array_ptr = ty
.builtin_deref(true, ty::NoPreference)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == tcx.types.u8);
assert!(is_array_ptr);
tcx
.interpret_interner
.borrow()
.get_alloc(ptr.alloc_id.0)
.unwrap()
.bytes
.as_ref()
}
_ => bug!()
};
@ -928,6 +1007,12 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
return Ok(false);
}
},
ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
assert_eq!(b as u8 as u128, b);
if b as u8 != *ch {
return Ok(false);
}
}
_ => span_bug!(pat.span, "bad const u8 {:?}", value)
},
_ => {}
@ -937,32 +1022,43 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
Ok(true)
}
fn constructor_covered_by_range(tcx: TyCtxt, span: Span,
ctor: &Constructor,
fn constructor_covered_by_range(ctor: &Constructor,
from: &ConstVal, to: &ConstVal,
end: RangeEnd)
end: RangeEnd,
ty: Ty)
-> Result<bool, ErrorReported> {
let cmp_from = |c_from| Ok(compare_const_vals(tcx, span, c_from, from)? != Ordering::Less);
let cmp_to = |c_to| compare_const_vals(tcx, span, c_to, to);
trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty);
let cmp_from = |c_from| compare_const_vals(c_from, from, ty)
.map(|res| res != Ordering::Less);
let cmp_to = |c_to| compare_const_vals(c_to, to, ty);
macro_rules! some_or_ok {
($e:expr) => {
match $e {
Some(to) => to,
None => return Ok(false), // not char or int
}
};
}
match *ctor {
ConstantValue(value) => {
let to = cmp_to(&value.val)?;
let to = some_or_ok!(cmp_to(&value.val));
let end = (to == Ordering::Less) ||
(end == RangeEnd::Included && to == Ordering::Equal);
Ok(cmp_from(&value.val)? && end)
Ok(some_or_ok!(cmp_from(&value.val)) && end)
},
ConstantRange(from, to, RangeEnd::Included) => {
let to = cmp_to(&to.val)?;
let to = some_or_ok!(cmp_to(&to.val));
let end = (to == Ordering::Less) ||
(end == RangeEnd::Included && to == Ordering::Equal);
Ok(cmp_from(&from.val)? && end)
Ok(some_or_ok!(cmp_from(&from.val)) && end)
},
ConstantRange(from, to, RangeEnd::Excluded) => {
let to = cmp_to(&to.val)?;
let to = some_or_ok!(cmp_to(&to.val));
let end = (to == Ordering::Less) ||
(end == RangeEnd::Excluded && to == Ordering::Equal);
Ok(cmp_from(&from.val)? && end)
Ok(some_or_ok!(cmp_from(&from.val)) && end)
}
Variant(_) |
Single => Ok(true),
_ => bug!(),
}
@ -979,7 +1075,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>(
result[subpat.field.index()] = &subpat.pattern;
}
debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, wild_patterns, result);
debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result);
result
}
@ -994,7 +1090,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>(
fn specialize<'p, 'a: 'p, 'tcx: 'a>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
r: &[&'p Pattern<'tcx>],
constructor: &Constructor,
constructor: &Constructor<'tcx>,
wild_patterns: &[&'p Pattern<'tcx>])
-> Option<Vec<&'p Pattern<'tcx>>>
{
@ -1031,12 +1127,32 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
None
}
}
ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => {
let is_array_ptr = value.ty
.builtin_deref(true, ty::NoPreference)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == cx.tcx.types.u8);
assert!(is_array_ptr);
let data_len = cx.tcx
.interpret_interner
.borrow()
.get_alloc(ptr.alloc_id.0)
.unwrap()
.bytes
.len();
if wild_patterns.len() == data_len {
Some(cx.lower_byte_str_pattern(pat))
} else {
None
}
}
_ => span_bug!(pat.span,
"unexpected const-val {:?} with ctor {:?}", value, constructor)
},
_ => {
match constructor_covered_by_range(
cx.tcx, pat.span, constructor, &value.val, &value.val, RangeEnd::Included
constructor, &value.val, &value.val, RangeEnd::Included,
value.ty,
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
@ -1048,7 +1164,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
PatternKind::Range { lo, hi, ref end } => {
match constructor_covered_by_range(
cx.tcx, pat.span, constructor, &lo.val, &hi.val, end.clone()
constructor, &lo.val, &hi.val, end.clone(), lo.ty,
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
@ -1092,7 +1208,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
}
}
};
debug!("specialize({:?}, {:?}) = {:?}", r[0], wild_patterns, head);
debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head);
head.map(|mut head| {
head.extend_from_slice(&r[1 ..]);

View file

@ -26,7 +26,6 @@ use syntax::abi::Abi;
use syntax::ast;
use syntax::attr;
use rustc::hir::{self, Expr};
use syntax_pos::Span;
use std::cmp::Ordering;
@ -104,60 +103,10 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
hir::ExprUnary(hir::UnNeg, ref inner) => {
// unary neg literals already got their sign during creation
if let hir::ExprLit(ref lit) = inner.node {
use syntax::ast::*;
use syntax::ast::LitIntType::*;
const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128;
const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128;
const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
const I128_OVERFLOW: u128 = i128::min_value() as u128;
let negated = match (&lit.node, &ty.sty) {
(&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
(&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
Some(I8(i8::min_value()))
},
(&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
(&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
Some(I16(i16::min_value()))
},
(&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
(&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
Some(I32(i32::min_value()))
},
(&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
(&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
Some(I64(i64::min_value()))
},
(&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
(&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
Some(I128(i128::min_value()))
},
(&LitKind::Int(n, _), &ty::TyInt(IntTy::Isize)) |
(&LitKind::Int(n, Signed(IntTy::Isize)), _) => {
match tcx.sess.target.isize_ty {
IntTy::I16 => if n == I16_OVERFLOW {
Some(Isize(Is16(i16::min_value())))
} else {
None
},
IntTy::I32 => if n == I32_OVERFLOW {
Some(Isize(Is32(i32::min_value())))
} else {
None
},
IntTy::I64 => if n == I64_OVERFLOW {
Some(Isize(Is64(i64::min_value())))
} else {
None
},
_ => span_bug!(e.span, "typeck error")
}
},
_ => None
return match lit_to_const(&lit.node, tcx, ty, true) {
Ok(val) => Ok(mk_const(val)),
Err(err) => signal!(e, err),
};
if let Some(i) = negated {
return Ok(mk_const(Integral(i)));
}
}
mk_const(match cx.eval(inner)?.val {
Float(f) => Float(-f),
@ -377,7 +326,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
};
callee_cx.eval(&body.value)?
},
hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty) {
hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty, false) {
Ok(val) => mk_const(val),
Err(err) => signal!(e, err),
},
@ -438,7 +387,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
}
hir::ExprRepeat(ref elem, _) => {
let n = match ty.sty {
ty::TyArray(_, n) => n.val.to_const_int().unwrap().to_u64().unwrap(),
ty::TyArray(_, n) => n.val.unwrap_u64(),
_ => span_bug!(e.span, "typeck error")
};
mk_const(Aggregate(Repeat(cx.eval(elem)?, n)))
@ -447,7 +396,8 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
if let Aggregate(Tuple(fields)) = cx.eval(base)?.val {
fields[index.node]
} else {
signal!(base, ExpectedConstTuple);
span_bug!(base.span, "{:#?}", cx.eval(base)?.val);
//signal!(base, ExpectedConstTuple);
}
}
hir::ExprField(ref base, field_name) => {
@ -557,7 +507,7 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
},
ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
ty::TyArray(ty, n) => {
let n = n.val.to_const_int().unwrap().to_u64().unwrap();
let n = n.val.unwrap_u64();
if ty == tcx.types.u8 && n == b.data.len() as u64 {
Ok(val)
} else {
@ -583,13 +533,66 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
pub fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mut ty: Ty<'tcx>)
mut ty: Ty<'tcx>,
neg: bool)
-> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
use syntax::ast::*;
use syntax::ast::LitIntType::*;
if tcx.sess.opts.debugging_opts.miri {
use rustc::mir::interpret::*;
let lit = match *lit {
LitKind::Str(ref s, _) => {
let s = s.as_str();
let id = tcx.allocate_cached(s.as_bytes());
let ptr = MemoryPointer::new(AllocId(id), 0);
Value::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(AllocId(id), 0);
Value::ByVal(PrimVal::Ptr(ptr))
},
LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
LitKind::Int(n, _) if neg => {
let n = n as i128;
let n = n.overflowing_neg().0;
Value::ByVal(PrimVal::Bytes(n as u128))
},
LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n as u128)),
LitKind::Float(n, fty) => {
let n = n.as_str();
let mut f = parse_float(&n, fty)?;
if neg {
f = -f;
}
let bits = f.bits;
Value::ByVal(PrimVal::Bytes(bits))
}
LitKind::FloatUnsuffixed(n) => {
let fty = match ty.sty {
ty::TyFloat(fty) => fty,
_ => bug!()
};
let n = n.as_str();
let mut f = parse_float(&n, fty)?;
if neg {
f = -f;
}
let bits = f.bits;
Value::ByVal(PrimVal::Bytes(bits))
}
LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
};
return Ok(ConstVal::Value(lit));
}
if let ty::TyAdt(adt, _) = ty.sty {
if adt.is_enum() {
ty = adt.repr.discr_type().to_ty(tcx)
@ -604,26 +607,38 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
match (&ty.sty, hint) {
(&ty::TyInt(ity), _) |
(_, Signed(ity)) => {
Ok(Integral(ConstInt::new_signed_truncating(n as i128,
let mut n = n as i128;
if neg {
n = n.overflowing_neg().0;
}
Ok(Integral(ConstInt::new_signed_truncating(n,
ity, tcx.sess.target.isize_ty)))
}
(&ty::TyUint(uty), _) |
(_, Unsigned(uty)) => {
Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
Ok(Integral(ConstInt::new_unsigned_truncating(n,
uty, tcx.sess.target.usize_ty)))
}
_ => bug!()
}
}
LitKind::Float(n, fty) => {
parse_float(&n.as_str(), fty).map(Float)
let mut f = parse_float(&n.as_str(), fty)?;
if neg {
f = -f;
}
Ok(Float(f))
}
LitKind::FloatUnsuffixed(n) => {
let fty = match ty.sty {
ty::TyFloat(fty) => fty,
_ => bug!()
};
parse_float(&n.as_str(), fty).map(Float)
let mut f = parse_float(&n.as_str(), fty)?;
if neg {
f = -f;
}
Ok(Float(f))
}
LitKind::Bool(b) => Ok(Bool(b)),
LitKind::Char(c) => Ok(Char(c)),
@ -638,36 +653,31 @@ fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
})
}
pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
-> Result<Ordering, ErrorReported>
{
let result = match (a, b) {
pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option<Ordering> {
trace!("compare_const_vals: {:?}, {:?}", a, b);
use rustc::mir::interpret::{Value, PrimVal};
match (a, b) {
(&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
(&Float(a), &Float(b)) => a.try_cmp(b).ok(),
(&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
(&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
(&ByteStr(a), &ByteStr(b)) => Some(a.data.cmp(b.data)),
(&Char(a), &Char(b)) => Some(a.cmp(&b)),
(&Value(Value::ByVal(PrimVal::Bytes(a))),
&Value(Value::ByVal(PrimVal::Bytes(b)))) => {
Some(if ty.is_signed() {
(a as i128).cmp(&(b as i128))
} else {
a.cmp(&b)
})
},
_ if a == b => Some(Ordering::Equal),
_ => None,
};
match result {
Some(result) => Ok(result),
None => {
// FIXME: can this ever be reached?
tcx.sess.delay_span_bug(span,
&format!("type mismatch comparing {:?} and {:?}", a, b));
Err(ErrorReported)
}
}
}
impl<'a, 'tcx> ConstContext<'a, 'tcx> {
pub fn compare_lit_exprs(&self,
span: Span,
a: &'tcx Expr,
b: &'tcx Expr) -> Result<Ordering, ErrorReported> {
b: &'tcx Expr) -> Result<Option<Ordering>, ErrorReported> {
let tcx = self.tcx;
let ty = self.tables.expr_ty(a);
let a = match self.eval(a) {
Ok(a) => a,
Err(e) => {
@ -682,6 +692,6 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
return Err(ErrorReported);
}
};
compare_const_vals(tcx, span, &a.val, &b.val)
Ok(compare_const_vals(&a.val, &b.val, ty))
}
}

View file

@ -10,8 +10,9 @@
use eval;
use rustc::middle::const_val::{ConstEvalErr, ConstVal};
use rustc::middle::const_val::{ConstEvalErr, ConstVal, ConstAggregate};
use rustc::mir::{Field, BorrowKind, Mutability};
use rustc::mir::interpret::{Value, PrimVal};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
use rustc::ty::subst::{Substs, Kind};
use rustc::hir::{self, PatKind, RangeEnd};
@ -110,22 +111,35 @@ pub enum PatternKind<'tcx> {
},
}
fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
match *value {
fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result {
match value.val {
ConstVal::Float(ref x) => write!(f, "{}", x),
ConstVal::Integral(ref i) => write!(f, "{}", i),
ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]),
ConstVal::ByteStr(b) => write!(f, "{:?}", b.data),
ConstVal::Bool(b) => write!(f, "{:?}", b),
ConstVal::Char(c) => write!(f, "{:?}", c),
ConstVal::Value(v) => print_miri_value(v, value.ty, f),
ConstVal::Variant(_) |
ConstVal::Function(..) |
ConstVal::Aggregate(_) |
ConstVal::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 {
@ -233,15 +247,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
write!(f, "{}", subpattern)
}
PatternKind::Constant { value } => {
print_const_val(&value.val, f)
print_const_val(value, f)
}
PatternKind::Range { lo, hi, end } => {
print_const_val(&lo.val, f)?;
print_const_val(lo, f)?;
match end {
RangeEnd::Included => write!(f, "...")?,
RangeEnd::Excluded => write!(f, "..")?,
}
print_const_val(&hi.val, f)
print_const_val(hi, f)
}
PatternKind::Slice { ref prefix, ref slice, ref suffix } |
PatternKind::Array { ref prefix, ref slice, ref suffix } => {
@ -362,7 +376,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
}
PatKind::Path(ref qpath) => {
return self.lower_path(qpath, pat.hir_id, pat.id, pat.span);
return self.lower_path(qpath, pat.hir_id, pat.span);
}
PatKind::Ref(ref subpattern, _) |
@ -581,7 +595,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
ty::TyArray(_, len) => {
// fixed-length array
let len = len.val.to_const_int().unwrap().to_u64().unwrap();
let len = len.val.unwrap_u64();
assert!(len >= prefix.len() as u64 + suffix.len() as u64);
PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
}
@ -632,7 +646,6 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
fn lower_path(&mut self,
qpath: &hir::QPath,
id: hir::HirId,
pat_id: ast::NodeId,
span: Span)
-> Pattern<'tcx> {
let ty = self.tables.node_id_to_type(id);
@ -644,29 +657,23 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
let kind = match def {
Def::Const(def_id) | Def::AssociatedConst(def_id) => {
let substs = self.tables.node_substs(id);
match eval::lookup_const_by_id(self.tcx, self.param_env.and((def_id, substs))) {
Some((def_id, substs)) => {
// Enter the inlined constant's tables&substs temporarily.
let old_tables = self.tables;
let old_substs = self.substs;
self.tables = self.tcx.typeck_tables_of(def_id);
self.substs = substs;
let body = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
self.tcx.hir.body(self.tcx.hir.body_owned_by(id))
} else {
self.tcx.extern_const_body(def_id).body
};
let pat = self.lower_const_expr(&body.value, pat_id, span);
self.tables = old_tables;
self.substs = old_substs;
return pat;
}
None => {
self.errors.push(if is_associated_const {
PatternError::AssociatedConstInPattern(span)
} else {
PatternError::StaticInPattern(span)
});
match self.tcx.at(span).const_eval(self.param_env.and((def_id, substs))) {
Ok(value) => {
if self.tcx.sess.opts.debugging_opts.miri {
if let ConstVal::Value(_) = value.val {} else {
panic!("const eval produced non-miri value: {:#?}", value);
}
}
let instance = ty::Instance::resolve(
self.tcx,
self.param_env,
def_id,
substs,
).unwrap();
return self.const_to_pat(instance, value, span)
},
Err(e) => {
self.errors.push(PatternError::ConstEval(e));
PatternKind::Wild
}
}
@ -682,6 +689,52 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
}
fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
if self.tcx.sess.opts.debugging_opts.miri {
return match expr.node {
hir::ExprLit(ref lit) => {
let ty = self.tables.expr_ty(expr);
match ::eval::lit_to_const(&lit.node, self.tcx, ty, false) {
Ok(value) => PatternKind::Constant {
value: self.tcx.mk_const(ty::Const {
ty,
val: value,
}),
},
Err(e) => {
self.errors.push(PatternError::ConstEval(ConstEvalErr {
span: lit.span,
kind: e,
}));
PatternKind::Wild
},
}
},
hir::ExprPath(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind,
hir::ExprUnary(hir::UnNeg, ref expr) => {
let ty = self.tables.expr_ty(expr);
let lit = match expr.node {
hir::ExprLit(ref lit) => lit,
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
};
match ::eval::lit_to_const(&lit.node, self.tcx, ty, true) {
Ok(value) => PatternKind::Constant {
value: self.tcx.mk_const(ty::Const {
ty,
val: value,
}),
},
Err(e) => {
self.errors.push(PatternError::ConstEval(ConstEvalErr {
span: lit.span,
kind: e,
}));
PatternKind::Wild
},
}
}
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
}
}
let const_cx = eval::ConstContext::new(self.tcx,
self.param_env.and(self.substs),
self.tables);
@ -701,118 +754,156 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
}
}
fn lower_const_expr(&mut self,
expr: &'tcx hir::Expr,
pat_id: ast::NodeId,
span: Span)
-> Pattern<'tcx> {
let pat_ty = self.tables.expr_ty(expr);
debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id);
match pat_ty.sty {
fn const_to_pat(
&self,
instance: ty::Instance<'tcx>,
cv: &'tcx ty::Const<'tcx>,
span: Span,
) -> Pattern<'tcx> {
debug!("const_to_pat: cv={:#?}", cv);
let kind = match cv.ty.sty {
ty::TyFloat(_) => {
self.tcx.sess.span_err(span, "floating point constants cannot be used in patterns");
PatternKind::Wild
}
ty::TyAdt(adt_def, _) if adt_def.is_union() => {
// Matching on union fields is unsafe, we can't hide it in constants
self.tcx.sess.span_err(span, "cannot use unions in constant patterns");
PatternKind::Wild
}
ty::TyAdt(adt_def, _) => {
if !self.tcx.has_attr(adt_def.did, "structural_match") {
let msg = format!("to use a constant of type `{}` in a pattern, \
`{}` must be annotated with `#[derive(PartialEq, Eq)]`",
self.tcx.item_path_str(adt_def.did),
self.tcx.item_path_str(adt_def.did));
self.tcx.sess.span_err(span, &msg);
ty::TyAdt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => {
let msg = format!("to use a constant of type `{}` in a pattern, \
`{}` must be annotated with `#[derive(PartialEq, Eq)]`",
self.tcx.item_path_str(adt_def.did),
self.tcx.item_path_str(adt_def.did));
self.tcx.sess.span_err(span, &msg);
PatternKind::Wild
},
ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
match cv.val {
ConstVal::Value(val) => {
let discr = self.tcx.const_discr(self.param_env.and((
instance, val, cv.ty
))).unwrap();
let variant_index = adt_def
.discriminants(self.tcx)
.position(|var| var.to_u128_unchecked() == discr)
.unwrap();
PatternKind::Variant {
adt_def,
substs,
variant_index,
subpatterns: adt_def
.variants[variant_index]
.fields
.iter()
.enumerate()
.map(|(i, _)| {
let field = Field::new(i);
let val = match cv.val {
ConstVal::Value(miri) => self.tcx.const_val_field(
self.param_env.and((instance, field, miri, cv.ty)),
).unwrap(),
_ => bug!("{:#?} is not a valid tuple", cv),
};
FieldPattern {
field,
pattern: self.const_to_pat(instance, val, span),
}
}).collect(),
}
},
ConstVal::Variant(var_did) => {
let variant_index = adt_def
.variants
.iter()
.position(|var| var.did == var_did)
.unwrap();
PatternKind::Variant {
adt_def,
substs,
variant_index,
subpatterns: Vec::new(),
}
}
_ => return Pattern {
span,
ty: cv.ty,
kind: Box::new(PatternKind::Constant {
value: cv,
}),
}
}
}
_ => { }
}
let kind = match expr.node {
hir::ExprTup(ref exprs) => {
},
ty::TyAdt(adt_def, _) => {
let struct_var = adt_def.struct_variant();
PatternKind::Leaf {
subpatterns: exprs.iter().enumerate().map(|(i, expr)| {
subpatterns: struct_var.fields.iter().enumerate().map(|(i, f)| {
let field = Field::new(i);
let val = match cv.val {
ConstVal::Aggregate(ConstAggregate::Struct(consts)) => {
consts.iter().find(|&&(name, _)| name == f.name).unwrap().1
},
ConstVal::Value(miri) => self.tcx.const_val_field(
self.param_env.and((instance, field, miri, cv.ty)),
).unwrap(),
_ => bug!("{:#?} is not a valid tuple", cv),
};
FieldPattern {
field: Field::new(i),
pattern: self.lower_const_expr(expr, pat_id, span)
field,
pattern: self.const_to_pat(instance, val, span),
}
}).collect()
}
}
hir::ExprCall(ref callee, ref args) => {
let qpath = match callee.node {
hir::ExprPath(ref qpath) => qpath,
_ => bug!()
};
let ty = self.tables.node_id_to_type(callee.hir_id);
let def = self.tables.qpath_def(qpath, callee.hir_id);
match def {
Def::Fn(..) | Def::Method(..) => self.lower_lit(expr),
_ => {
let subpatterns = args.iter().enumerate().map(|(i, expr)| {
FieldPattern {
field: Field::new(i),
pattern: self.lower_const_expr(expr, pat_id, span)
}
}).collect();
self.lower_variant_or_leaf(def, ty, subpatterns)
}
ty::TyTuple(fields, _) => {
PatternKind::Leaf {
subpatterns: (0..fields.len()).map(|i| {
let field = Field::new(i);
let val = match cv.val {
ConstVal::Aggregate(ConstAggregate::Tuple(consts)) => consts[i],
ConstVal::Value(miri) => self.tcx.const_val_field(
self.param_env.and((instance, field, miri, cv.ty)),
).unwrap(),
_ => bug!("{:#?} is not a valid tuple", cv),
};
FieldPattern {
field,
pattern: self.const_to_pat(instance, val, span),
}
}).collect()
}
}
hir::ExprStruct(ref qpath, ref fields, None) => {
let def = self.tables.qpath_def(qpath, expr.hir_id);
let adt_def = match pat_ty.sty {
ty::TyAdt(adt_def, _) => adt_def,
_ => {
span_bug!(
expr.span,
"struct expr without ADT type");
}
};
let variant_def = adt_def.variant_of_def(def);
let subpatterns =
fields.iter()
.map(|field| {
let index = variant_def.index_of_field_named(field.name.node);
let index = index.unwrap_or_else(|| {
span_bug!(
expr.span,
"no field with name {:?}",
field.name);
});
FieldPattern {
field: Field::new(index),
pattern: self.lower_const_expr(&field.expr, pat_id, span),
}
})
.collect();
self.lower_variant_or_leaf(def, pat_ty, subpatterns)
}
hir::ExprArray(ref exprs) => {
let pats = exprs.iter()
.map(|expr| self.lower_const_expr(expr, pat_id, span))
.collect();
PatternKind::Array {
prefix: pats,
slice: None,
suffix: vec![]
ty::TyArray(_, n) => {
PatternKind::Leaf {
subpatterns: (0..n.val.unwrap_u64()).map(|i| {
let i = i as usize;
let field = Field::new(i);
let val = match cv.val {
ConstVal::Aggregate(ConstAggregate::Array(consts)) => consts[i],
ConstVal::Aggregate(ConstAggregate::Repeat(cv, _)) => cv,
ConstVal::Value(miri) => self.tcx.const_val_field(
self.param_env.and((instance, field, miri, cv.ty)),
).unwrap(),
_ => bug!("{:#?} is not a valid tuple", cv),
};
FieldPattern {
field,
pattern: self.const_to_pat(instance, val, span),
}
}).collect()
}
}
hir::ExprPath(ref qpath) => {
return self.lower_path(qpath, expr.hir_id, pat_id, span);
}
_ => self.lower_lit(expr)
_ => {
PatternKind::Constant {
value: cv,
}
},
};
Pattern {
span,
ty: pat_ty,
ty: cv.ty,
kind: Box::new(kind),
}
}

View file

@ -259,6 +259,14 @@ impl<CTX> HashStable<CTX> for f64 {
}
}
impl<CTX> HashStable<CTX> for ::std::cmp::Ordering {
fn hash_stable<W: StableHasherResult>(&self,
ctx: &mut CTX,
hasher: &mut StableHasher<W>) {
(*self as i8).hash_stable(ctx, hasher);
}
}
impl<T1: HashStable<CTX>, CTX> HashStable<CTX> for (T1,) {
fn hash_stable<W: StableHasherResult>(&self,
ctx: &mut CTX,

View file

@ -16,6 +16,7 @@ use rustc::ty::{self, AdtKind, Ty, TyCtxt};
use rustc::ty::layout::{self, LayoutOf};
use middle::const_val::ConstVal;
use rustc_const_eval::ConstContext;
use rustc::mir::interpret::{Value, PrimVal};
use util::nodemap::FxHashSet;
use lint::{LateContext, LintContext, LintArray};
use lint::{LintPass, LateLintPass};
@ -122,6 +123,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
.map(|i| i >= bits)
.unwrap_or(true)
}
Ok(&ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
ty,
}) => {
if ty.is_signed() {
(b as i128) < 0
} else {
b >= bits as u128
}
}
_ => false,
}
};

View file

@ -276,38 +276,54 @@ impl<'a, 'tcx> SpecializedDecoder<DefIndex> for DecodeContext<'a, 'tcx> {
impl<'a, 'tcx> SpecializedDecoder<interpret::AllocId> for DecodeContext<'a, 'tcx> {
fn specialized_decode(&mut self) -> Result<interpret::AllocId, Self::Error> {
const MAX1: usize = usize::max_value() - 1;
let mut interpret_interner = self.tcx.unwrap().interpret_interner.borrow_mut();
let tcx = self.tcx;
let interpret_interner = || tcx.unwrap().interpret_interner.borrow_mut();
let pos = self.position();
match self.read_usize()? {
match usize::decode(self)? {
::std::usize::MAX => {
let id = interpret_interner().reserve();
let alloc_id = interpret::AllocId(id);
trace!("creating alloc id {:?} at {}", alloc_id, pos);
// insert early to allow recursive allocs
self.interpret_alloc_cache.insert(pos, alloc_id);
let allocation = interpret::Allocation::decode(self)?;
let id = interpret_interner.reserve();
trace!("decoded alloc {:?} {:#?}", alloc_id, allocation);
let allocation = self.tcx.unwrap().intern_const_alloc(allocation);
interpret_interner.intern_at_reserved(id, allocation);
let id = interpret::AllocId(id);
self.interpret_alloc_cache.insert(pos, id);
interpret_interner().intern_at_reserved(id, allocation);
let num = usize::decode(self)?;
let ptr = interpret::Pointer {
primval: interpret::PrimVal::Ptr(interpret::MemoryPointer {
alloc_id: id,
alloc_id,
offset: 0,
}),
};
for _ in 0..num {
let glob = interpret::GlobalId::decode(self)?;
interpret_interner.cache(glob, ptr);
interpret_interner().cache(glob, ptr);
}
Ok(id)
Ok(alloc_id)
},
MAX1 => {
trace!("creating fn alloc id at {}", pos);
let instance = ty::Instance::decode(self)?;
let id = interpret::AllocId(interpret_interner.create_fn_alloc(instance));
trace!("decoded fn alloc instance: {:?}", instance);
let id = interpret::AllocId(interpret_interner().create_fn_alloc(instance));
trace!("created fn alloc id: {:?}", id);
self.interpret_alloc_cache.insert(pos, id);
Ok(id)
},
shorthand => Ok(self.interpret_alloc_cache[&shorthand]),
shorthand => {
trace!("loading shorthand {}", shorthand);
if let Some(&alloc_id) = self.interpret_alloc_cache.get(&shorthand) {
return Ok(alloc_id);
}
trace!("shorthand {} not cached, loading entire allocation", shorthand);
// need to load allocation
self.with_position(shorthand, |this| interpret::AllocId::decode(this))
},
}
}
}

View file

@ -189,12 +189,18 @@ impl<'a, 'tcx> SpecializedEncoder<Ty<'tcx>> for EncodeContext<'a, 'tcx> {
impl<'a, 'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'a, 'tcx> {
fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
trace!("encoding {:?} at {}", alloc_id, self.position());
if let Some(shorthand) = self.interpret_alloc_shorthands.get(alloc_id).cloned() {
return self.emit_usize(shorthand);
trace!("encoding {:?} as shorthand to {}", alloc_id, shorthand);
return shorthand.encode(self);
}
let start = self.position();
// cache the allocation shorthand now, because the allocation itself might recursively
// point to itself.
self.interpret_alloc_shorthands.insert(*alloc_id, start);
let interpret_interner = self.tcx.interpret_interner.borrow();
if let Some(alloc) = interpret_interner.get_alloc(alloc_id.0) {
trace!("encoding {:?} with {:#?}", alloc_id, alloc);
usize::max_value().encode(self)?;
alloc.encode(self)?;
let globals = interpret_interner.get_globals(interpret::Pointer {
@ -208,16 +214,12 @@ impl<'a, 'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'a, 'tcx
glob.encode(self)?;
}
} else if let Some(fn_instance) = interpret_interner.get_fn(alloc_id.0) {
trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
(usize::max_value() - 1).encode(self)?;
fn_instance.encode(self)?;
} else {
bug!("alloc id without corresponding allocation: {}", alloc_id.0);
}
let len = self.position() - start * 7;
// Check that the shorthand is a not longer than the
// full encoding itself, i.e. it's an obvious win.
assert!(len >= 64 || (start as u64) < (1 << len));
self.interpret_alloc_shorthands.insert(*alloc_id, start);
Ok(())
}
}

View file

@ -26,6 +26,7 @@ use rustc::ty::fold::TypeFoldable;
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
use rustc::middle::const_val::ConstVal;
use rustc::mir::*;
use rustc::mir::interpret::{Value, PrimVal};
use rustc::mir::tcx::PlaceTy;
use rustc::mir::visit::{PlaceContext, Visitor};
use std::fmt;
@ -258,7 +259,24 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
// constraints on `'a` and `'b`. These constraints
// would be lost if we just look at the normalized
// value.
if let ConstVal::Function(def_id, ..) = value.val {
let did = match value.val {
ConstVal::Function(def_id, ..) => Some(def_id),
ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => {
self.tcx()
.interpret_interner
.borrow()
.get_fn(p.alloc_id.0)
.map(|instance| instance.def_id())
},
ConstVal::Value(Value::ByVal(PrimVal::Undef)) => {
match value.ty.sty {
ty::TyFnDef(ty_def_id, _) => Some(ty_def_id),
_ => None,
}
},
_ => None,
};
if let Some(def_id) = did {
let tcx = self.tcx();
let type_checker = &mut self.cx;
@ -436,7 +454,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.to_const_int().unwrap().to_u64().unwrap();
let size = size.val.unwrap_u64();
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)
@ -1019,13 +1037,32 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
Literal::Value {
value:
&ty::Const {
val: ConstVal::Function(def_id, _),
..
val,
ty,
},
..
},
..
}) => Some(def_id) == self.tcx().lang_items().box_free_fn(),
}) => match val {
ConstVal::Function(def_id, _) => {
Some(def_id) == self.tcx().lang_items().box_free_fn()
},
ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => {
let inst = self.tcx().interpret_interner.borrow().get_fn(p.alloc_id.0);
inst.map_or(false, |inst| {
Some(inst.def_id()) == self.tcx().lang_items().box_free_fn()
})
},
ConstVal::Value(Value::ByVal(PrimVal::Undef)) => {
match ty.sty {
ty::TyFnDef(ty_def_id, _) => {
Some(ty_def_id) == self.tcx().lang_items().box_free_fn()
}
_ => false,
}
}
_ => false,
}
_ => false,
}
}

View file

@ -24,6 +24,7 @@ use rustc::middle::const_val::ConstVal;
use rustc::middle::region;
use rustc::ty::{self, Ty};
use rustc::mir::*;
use rustc::mir::interpret::{Value, PrimVal};
use syntax::ast;
use syntax_pos::Span;
@ -203,7 +204,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ty: this.hir.tcx().types.u32,
literal: Literal::Value {
value: this.hir.tcx().mk_const(ty::Const {
val: ConstVal::Integral(ConstInt::U32(0)),
val: if this.hir.tcx().sess.opts.debugging_opts.miri {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(0)))
} else {
ConstVal::Integral(ConstInt::U32(0))
},
ty: this.hir.tcx().types.u32
}),
},
@ -401,7 +406,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Integral(val),
val: if self.hir.tcx().sess.opts.debugging_opts.miri {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.to_u128_unchecked())))
} else {
ConstVal::Integral(val)
},
ty
})
}
@ -439,7 +448,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Integral(val),
val: if self.hir.tcx().sess.opts.debugging_opts.miri {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(
val.to_u128_unchecked()
)))
} else {
ConstVal::Integral(val)
},
ty
})
}

View file

@ -354,7 +354,7 @@ enum TestKind<'tcx> {
// test the branches of enum
SwitchInt {
switch_ty: Ty<'tcx>,
options: Vec<&'tcx ty::Const<'tcx>>,
options: Vec<u128>,
indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
},

View file

@ -24,6 +24,7 @@ use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, Ty};
use rustc::ty::util::IntTypeExt;
use rustc::mir::*;
use rustc::mir::interpret::{Value, PrimVal};
use rustc::hir::RangeEnd;
use syntax_pos::Span;
use std::cmp::Ordering;
@ -112,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
test_place: &Place<'tcx>,
candidate: &Candidate<'pat, 'tcx>,
switch_ty: Ty<'tcx>,
options: &mut Vec<&'tcx ty::Const<'tcx>>,
options: &mut Vec<u128>,
indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>)
-> bool
{
@ -128,7 +129,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
indices.entry(value)
.or_insert_with(|| {
options.push(value);
options.push(value.val.to_u128().expect("switching on int"));
options.len() - 1
});
true
@ -231,7 +232,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let tcx = self.hir.tcx();
for (idx, discr) in adt_def.discriminants(tcx).enumerate() {
target_blocks.place_back() <- if variants.contains(idx) {
values.push(discr);
values.push(discr.to_u128_unchecked());
*(targets.place_back() <- self.cfg.start_new_block())
} else {
if otherwise_block.is_none() {
@ -266,9 +267,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
assert!(options.len() > 0 && options.len() <= 2);
let (true_bb, false_bb) = (self.cfg.start_new_block(),
self.cfg.start_new_block());
let ret = match options[0].val {
ConstVal::Bool(true) => vec![true_bb, false_bb],
ConstVal::Bool(false) => vec![false_bb, true_bb],
let ret = match options[0] {
1 => vec![true_bb, false_bb],
0 => vec![false_bb, true_bb],
v => span_bug!(test.span, "expected boolean value but got {:?}", v)
};
(ret, TerminatorKind::if_(self.hir.tcx(), Operand::Copy(place.clone()),
@ -282,13 +283,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
.map(|_| self.cfg.start_new_block())
.chain(Some(otherwise))
.collect();
let values: Vec<_> = options.iter().map(|v|
v.val.to_const_int().expect("switching on integral")
).collect();
(targets.clone(), TerminatorKind::SwitchInt {
discr: Operand::Copy(place.clone()),
switch_ty,
values: From::from(values),
values: options.clone().into(),
targets,
})
};
@ -300,14 +298,49 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let tcx = self.hir.tcx();
let mut val = Operand::Copy(place.clone());
let bytes = match value.val {
ConstVal::ByteStr(bytes) => Some(bytes.data),
ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => {
let is_array_ptr = ty
.builtin_deref(true, ty::NoPreference)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == self.hir.tcx().types.u8);
if is_array_ptr {
self.hir
.tcx()
.interpret_interner
.borrow()
.get_alloc(p.alloc_id.0)
.map(|alloc| &alloc.bytes[..])
} else {
None
}
},
_ => None,
};
// If we're using b"..." as a pattern, we need to insert an
// unsizing coercion, as the byte string has the type &[u8; N].
//
// We want to do this even when the scrutinee is a reference to an
// array, so we can call `<[u8]>::eq` rather than having to find an
// `<[u8; N]>::eq`.
let (expect, val) = if let ConstVal::ByteStr(bytes) = value.val {
let array_ty = tcx.mk_array(tcx.types.u8, bytes.data.len() as u64);
let expect = if let Some(bytes) = bytes {
let tcx = self.hir.tcx();
// Unsize the place to &[u8], too, if necessary.
if let ty::TyRef(region, mt) = ty.sty {
if let ty::TyArray(_, _) = mt.ty.sty {
ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8));
let val_slice = self.temp(ty, test.span);
self.cfg.push_assign(block, source_info, &val_slice,
Rvalue::Cast(CastKind::Unsize, val, ty));
val = Operand::Move(val_slice);
}
}
assert!(ty.is_slice());
let array_ty = tcx.mk_array(tcx.types.u8, bytes.len() as u64);
let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty);
let array = self.literal_operand(test.span, array_ref, Literal::Value {
value
@ -324,11 +357,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// Use PartialEq::eq for &str and &[u8] slices, instead of BinOp::Eq.
let fail = self.cfg.start_new_block();
let ty = expect.ty(&self.local_decls, tcx);
if let ty::TyRef(_, mt) = ty.sty {
assert!(ty.is_slice());
let str_or_bytestr = ty
.builtin_deref(true, ty::NoPreference)
.and_then(|tam| match tam.ty.sty {
ty::TyStr => Some(tam.ty),
ty::TySlice(inner) if inner == self.hir.tcx().types.u8 => Some(tam.ty),
_ => None,
});
if let Some(ty) = str_or_bytestr {
let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap();
let ty = mt.ty;
let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]);
let bool_ty = self.hir.bool_ty();

View file

@ -16,6 +16,7 @@ use build::Builder;
use rustc_const_math::{ConstInt, ConstUsize, ConstIsize};
use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, Ty};
use rustc::mir::interpret::{Value, PrimVal};
use rustc::mir::*;
use syntax::ast;
@ -62,7 +63,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ty::TyChar => {
Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Char('\0'),
val: if self.hir.tcx().sess.opts.debugging_opts.miri {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(0)))
} else {
ConstVal::Char('\0')
},
ty
})
}
@ -83,7 +88,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Integral(val),
val: if self.hir.tcx().sess.opts.debugging_opts.miri {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(0)))
} else {
ConstVal::Integral(val)
},
ty
})
}
@ -104,7 +113,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
Literal::Value {
value: self.hir.tcx().mk_const(ty::Const {
val: ConstVal::Integral(val),
val: if self.hir.tcx().sess.opts.debugging_opts.miri {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(0)))
} else {
ConstVal::Integral(val)
},
ty
})
}

View file

@ -10,7 +10,6 @@
use hair::*;
use rustc_data_structures::indexed_vec::Idx;
use rustc_const_math::ConstInt;
use hair::cx::Cx;
use hair::cx::block;
use hair::cx::to_ref::ToRef;
@ -18,6 +17,7 @@ use rustc::hir::def::{Def, CtorKind};
use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, AdtKind, VariantDef, Ty};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
use rustc::mir::interpret::{Value, PrimVal};
use rustc::ty::cast::CastKind as TyCastKind;
use rustc::hir;
use rustc::hir::def_id::LocalDefId;
@ -100,7 +100,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
ExprKind::Deref { arg: expr.to_ref() }
}
Adjust::Deref(Some(deref)) => {
let call = deref.method_call(cx.tcx, expr.ty);
let call = deref.method_call(cx.tcx(), expr.ty);
expr = Expr {
temp_lifetime,
@ -314,7 +314,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
}
}
hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) },
hir::ExprLit(ref lit) => ExprKind::Literal {
literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false),
},
hir::ExprBinary(op, ref lhs, ref rhs) => {
if cx.tables().is_method_call(expr) {
@ -400,9 +402,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
if cx.tables().is_method_call(expr) {
overloaded_operator(cx, expr, vec![arg.to_ref()])
} else {
// FIXME runtime-overflow
if let hir::ExprLit(_) = arg.node {
ExprKind::Literal { literal: cx.const_eval_literal(expr) }
if let hir::ExprLit(ref lit) = arg.node {
ExprKind::Literal {
literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true),
}
} else {
ExprKind::Unary {
op: UnOp::Neg,
@ -509,8 +512,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
let def_id = cx.tcx.hir.body_owner_def_id(count);
let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id);
let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and((def_id, substs))) {
Ok(&ty::Const { val: ConstVal::Integral(ConstInt::Usize(u)), .. }) => u,
Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
Ok(cv) => cv.val.unwrap_usize(cx.tcx),
Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression")
};
@ -634,8 +636,8 @@ 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::Function(def_id, substs),
value: cx.tcx().mk_const(ty::Const {
val: const_fn(cx.tcx, def_id, substs),
ty
}),
},
@ -675,6 +677,28 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm)
}
}
fn const_fn<'a, 'gcx, 'tcx>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
def_id: DefId,
substs: &'tcx Substs<'tcx>,
) -> ConstVal<'tcx> {
if tcx.sess.opts.debugging_opts.miri {
/*
let inst = ty::Instance::new(def_id, substs);
let ptr = tcx
.interpret_interner
.borrow_mut()
.create_fn_alloc(inst);
let ptr = MemoryPointer::new(AllocId(ptr), 0);
ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr)))
*/
// ZST function type
ConstVal::Value(Value::ByVal(PrimVal::Undef))
} else {
ConstVal::Function(def_id, substs)
}
}
fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
expr: &'tcx hir::Expr,
def: Def)
@ -688,7 +712,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal {
literal: Literal::Value {
value: cx.tcx.mk_const(ty::Const {
val: ConstVal::Function(def_id, substs),
val: const_fn(cx.tcx.global_tcx(), def_id, substs),
ty: cx.tables().node_id_to_type(expr.hir_id)
}),
},

View file

@ -17,7 +17,6 @@
use hair::*;
use rustc::middle::const_val::{ConstEvalErr, ConstVal};
use rustc_const_eval::ConstContext;
use rustc_data_structures::indexed_vec::Idx;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::hir::map::blocks::FnLikeNode;
@ -32,6 +31,7 @@ use syntax::symbol::Symbol;
use rustc::hir;
use rustc_const_math::{ConstInt, ConstUsize};
use rustc_data_structures::sync::Lrc;
use rustc::mir::interpret::{Value, PrimVal};
#[derive(Clone)]
pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
@ -119,7 +119,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
Ok(val) => {
Literal::Value {
value: self.tcx.mk_const(ty::Const {
val: ConstVal::Integral(ConstInt::Usize(val)),
val: if self.tcx.sess.opts.debugging_opts.miri {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128)))
} else {
ConstVal::Integral(ConstInt::Usize(val))
},
ty: self.tcx.types.usize
})
}
@ -139,7 +143,11 @@ 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::Bool(true),
val: if self.tcx.sess.opts.debugging_opts.miri {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(1)))
} else {
ConstVal::Bool(true)
},
ty: self.tcx.types.bool
})
}
@ -148,20 +156,161 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
pub fn false_literal(&mut self) -> Literal<'tcx> {
Literal::Value {
value: self.tcx.mk_const(ty::Const {
val: ConstVal::Bool(false),
val: if self.tcx.sess.opts.debugging_opts.miri {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(0)))
} else {
ConstVal::Bool(false)
},
ty: self.tcx.types.bool
})
}
}
pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
pub fn const_eval_literal(
&mut self,
lit: &'tcx ast::LitKind,
ty: Ty<'tcx>,
sp: Span,
neg: bool,
) -> Literal<'tcx> {
let tcx = self.tcx.global_tcx();
let const_cx = ConstContext::new(tcx,
self.param_env.and(self.identity_substs),
self.tables());
match const_cx.eval(tcx.hir.expect_expr(e.id)) {
Ok(value) => Literal::Value { value },
Err(s) => self.fatal_const_eval_err(&s, e.span, "expression")
let mut repr_ty = ty;
if let ty::TyAdt(adt, _) = ty.sty {
if adt.is_enum() {
repr_ty = adt.repr.discr_type().to_ty(tcx)
}
}
let parse_float = |num: &str, fty| -> ConstFloat {
ConstFloat::from_str(num, fty).unwrap_or_else(|_| {
// FIXME(#31407) this is only necessary because float parsing is buggy
tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)");
})
};
if tcx.sess.opts.debugging_opts.miri {
use rustc::mir::interpret::*;
let lit = match *lit {
LitKind::Str(ref s, _) => {
let s = s.as_str();
let id = self.tcx.allocate_cached(s.as_bytes());
let ptr = MemoryPointer::new(AllocId(id), 0);
Value::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(AllocId(id), 0);
Value::ByVal(PrimVal::Ptr(ptr))
},
LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
LitKind::Int(n, _) if neg => {
let n = n as i128;
let n = n.overflowing_neg().0;
Value::ByVal(PrimVal::Bytes(n as u128))
},
LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n)),
LitKind::Float(n, fty) => {
let n = n.as_str();
let mut f = parse_float(&n, fty);
if neg {
f = -f;
}
let bits = f.bits;
Value::ByVal(PrimVal::Bytes(bits))
}
LitKind::FloatUnsuffixed(n) => {
let fty = match ty.sty {
ty::TyFloat(fty) => fty,
_ => bug!()
};
let n = n.as_str();
let mut f = parse_float(&n, fty);
if neg {
f = -f;
}
let bits = f.bits;
Value::ByVal(PrimVal::Bytes(bits))
}
LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
};
return Literal::Value {
value: self.tcx.mk_const(ty::Const {
val: Value(lit),
ty,
}),
};
}
use syntax::ast::*;
use syntax::ast::LitIntType::*;
use rustc::middle::const_val::ConstVal::*;
use rustc_const_math::ConstInt::*;
use rustc::ty::util::IntTypeExt;
use rustc::middle::const_val::ByteArray;
use rustc_const_math::ConstFloat;
let lit = match *lit {
LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
LitKind::ByteStr(ref data) => {
let data: &'tcx [u8] = data;
Ok(ByteStr(ByteArray { data }))
},
LitKind::Byte(n) => Ok(Integral(U8(n))),
LitKind::Int(n, hint) => {
match (&repr_ty.sty, hint) {
(&ty::TyInt(ity), _) |
(_, Signed(ity)) => {
let mut n = n as i128;
if neg {
n = n.overflowing_neg().0;
}
Ok(Integral(ConstInt::new_signed_truncating(n,
ity, tcx.sess.target.isize_ty)))
}
(&ty::TyUint(uty), _) |
(_, Unsigned(uty)) => {
Ok(Integral(ConstInt::new_unsigned_truncating(n,
uty, tcx.sess.target.usize_ty)))
}
_ => bug!()
}
}
LitKind::Float(n, fty) => {
let mut f = parse_float(&n.as_str(), fty);
if neg {
f = -f;
}
Ok(ConstVal::Float(f))
}
LitKind::FloatUnsuffixed(n) => {
let fty = match ty.sty {
ty::TyFloat(fty) => fty,
_ => bug!()
};
let mut f = parse_float(&n.as_str(), fty);
if neg {
f = -f;
}
Ok(ConstVal::Float(f))
}
LitKind::Bool(b) => Ok(Bool(b)),
LitKind::Char(c) => Ok(Char(c)),
};
match lit {
Ok(value) => Literal::Value { value: self.tcx.mk_const(ty::Const {
val: value,
ty,
}) },
Err(kind) => self.fatal_const_eval_err(&ConstEvalErr {
span: sp,
kind,
}, sp, "expression")
}
}
@ -203,7 +352,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
return (method_ty,
Literal::Value {
value: self.tcx.mk_const(ty::Const {
val: ConstVal::Function(item.def_id, substs),
val: if self.tcx.sess.opts.debugging_opts.miri {
// ZST function type
ConstVal::Value(Value::ByVal(PrimVal::Undef))
} else {
ConstVal::Function(item.def_id, substs)
},
ty: method_ty
}),
});

View file

@ -13,14 +13,13 @@ use syntax::ast::Mutability;
use syntax::codemap::Span;
use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal};
use super::{Place, EvalContext, StackPopCleanup, ValTy};
use super::{Place, EvalContext, StackPopCleanup, ValTy, HasMemory};
use rustc_const_math::ConstInt;
use std::fmt;
use std::error::Error;
pub fn mk_eval_cx<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
instance: Instance<'tcx>,
@ -45,7 +44,7 @@ pub fn eval_body<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
instance: Instance<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> EvalResult<'tcx, (Pointer, Ty<'tcx>)> {
) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> {
debug!("eval_body: {:?}, {:?}", instance, param_env);
let limits = super::ResourceLimits::default();
let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ());
@ -82,7 +81,13 @@ pub fn eval_body<'a, 'tcx>(
while ecx.step()? {}
}
let alloc = tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached");
Ok((MemoryPointer::new(alloc, 0).into(), instance_ty))
let align = ecx.layout_of(instance_ty)?.align;
let ptr = MemoryPointer::new(alloc, 0).into();
let value = match ecx.try_read_value(ptr, align, instance_ty)? {
Some(val) => val,
_ => Value::ByRef(ptr, align),
};
Ok((value, ptr, instance_ty))
}
pub fn eval_body_as_integer<'a, 'tcx>(
@ -90,11 +95,9 @@ pub fn eval_body_as_integer<'a, 'tcx>(
param_env: ty::ParamEnv<'tcx>,
instance: Instance<'tcx>,
) -> EvalResult<'tcx, ConstInt> {
let ptr_ty = eval_body(tcx, instance, param_env);
let (ptr, ty) = ptr_ty?;
let ecx = mk_eval_cx(tcx, instance, param_env)?;
let prim = match ecx.try_read_value(ptr, ecx.layout_of(ty)?.align, ty)? {
Some(Value::ByVal(prim)) => prim.to_bytes()?,
let (value, _, ty) = eval_body(tcx, instance, param_env)?;
let prim = match value {
Value::ByVal(prim) => prim.to_bytes()?,
_ => return err!(TypeNotPrimitive(ty)),
};
use syntax::ast::{IntTy, UintTy};
@ -133,7 +136,7 @@ pub struct CompileTimeEvaluator;
impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
fn into(self) -> EvalError<'tcx> {
EvalErrorKind::MachineError(Box::new(self)).into()
EvalErrorKind::MachineError(self.to_string()).into()
}
}
@ -193,7 +196,6 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
let mir = match ecx.load_mir(instance.def) {
Ok(mir) => mir,
Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => {
// some simple things like `malloc` might get accepted in the future
return Err(
ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
.into(),
@ -302,6 +304,70 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
}
}
pub fn const_val_field<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>,
) -> ::rustc::middle::const_val::EvalResult<'tcx> {
trace!("const_val_field: {:#?}", key);
match const_val_field_inner(tcx, key) {
Ok((field, ty)) => Ok(tcx.mk_const(ty::Const {
val: ConstVal::Value(field),
ty,
})),
Err(err) => Err(ConstEvalErr {
span: tcx.def_span(key.value.0.def_id()),
kind: err.into(),
}),
}
}
fn const_val_field_inner<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>,
) -> ::rustc::mir::interpret::EvalResult<'tcx, (Value, Ty<'tcx>)> {
trace!("const_val_field: {:#?}", key);
let (instance, field, value, ty) = key.value;
let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
let (mut field, ty) = match value {
Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, field, ty)?.expect("const_val_field on non-field"),
Value::ByRef(ptr, align) => {
let place = Place::from_primval_ptr(ptr, align);
let layout = ecx.layout_of(ty)?;
let (place, layout) = ecx.place_field(place, field, layout)?;
let (ptr, align) = place.to_ptr_align();
(Value::ByRef(ptr, align), layout.ty)
}
};
if let Value::ByRef(ptr, align) = field {
if let Some(val) = ecx.try_read_value(ptr, align, ty)? {
field = val;
}
}
Ok((field, ty))
}
pub fn const_discr<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, Value, Ty<'tcx>)>,
) -> EvalResult<'tcx, u128> {
trace!("const_discr: {:#?}", key);
let (instance, value, ty) = key.value;
let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
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)?;
(ptr, layout.align)
},
Value::ByRef(ptr, align) => (ptr, align),
};
let place = Place::from_primval_ptr(ptr, align);
ecx.read_discriminant_value(place, ty)
}
pub fn const_eval_provider<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>,
@ -340,35 +406,48 @@ pub fn const_eval_provider<'a, 'tcx>(
return Err(ConstEvalErr { span: body.value.span, kind: TypeckError })
}
let instance = ty::Instance::new(def_id, substs);
if tcx.sess.opts.debugging_opts.miri {
return match ::interpret::eval_body(tcx, instance, key.param_env) {
Ok((miri_value, _, miri_ty)) => Ok(tcx.mk_const(ty::Const {
val: ConstVal::Value(miri_value),
ty: miri_ty,
})),
Err(err) => {
Err(ConstEvalErr { span: body.value.span, kind: err.into() })
}
};
}
trace!("running old const eval");
let old_result = ConstContext::new(tcx, key.param_env.and(substs), tables).eval(&body.value);
trace!("old const eval produced {:?}", old_result);
if tcx.sess.opts.debugging_opts.miri {
let instance = ty::Instance::new(def_id, substs);
trace!("const eval instance: {:?}, {:?}", instance, key.param_env);
let miri_result = ::interpret::eval_body(tcx, instance, key.param_env);
match (miri_result, old_result) {
(Err(err), Ok(ok)) => {
trace!("miri failed, ctfe returned {:?}", ok);
tcx.sess.span_warn(
tcx.def_span(key.value.0),
"miri failed to eval, while ctfe succeeded",
);
let ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
let () = unwrap_miri(&ecx, Err(err));
Ok(ok)
},
(_, Err(err)) => Err(err),
(Ok((miri_val, miri_ty)), Ok(ctfe)) => {
let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
let layout = ecx.layout_of(miri_ty).unwrap();
let miri_place = Place::from_primval_ptr(miri_val, layout.align);
check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val);
Ok(ctfe)
}
trace!("const eval instance: {:?}, {:?}", instance, key.param_env);
let miri_result = ::interpret::eval_body(tcx, instance, key.param_env);
match (miri_result, old_result) {
(Err(err), Ok(ok)) => {
trace!("miri failed, ctfe returned {:?}", ok);
tcx.sess.span_warn(
tcx.def_span(key.value.0),
"miri failed to eval, while ctfe succeeded",
);
let ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
let () = unwrap_miri(&ecx, Err(err));
Ok(ok)
},
(Ok((value, _, ty)), Err(_)) => Ok(tcx.mk_const(ty::Const {
val: ConstVal::Value(value),
ty,
})),
(Err(_), Err(err)) => Err(err),
(Ok((_, miri_ptr, miri_ty)), Ok(ctfe)) => {
let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
let layout = ecx.layout_of(miri_ty).unwrap();
let miri_place = Place::from_primval_ptr(miri_ptr, layout.align);
check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val);
Ok(ctfe)
}
} else {
old_result
}
}
@ -451,7 +530,7 @@ fn check_ctfe_against_miri<'a, 'tcx>(
}
},
TyArray(elem_ty, n) => {
let n = n.val.to_const_int().unwrap().to_u64().unwrap();
let n = n.val.unwrap_u64();
let vec: Vec<(ConstVal, Ty<'tcx>)> = match ctfe {
ConstVal::ByteStr(arr) => arr.data.iter().map(|&b| {
(ConstVal::Integral(ConstInt::U8(b)), ecx.tcx.types.u8)

View file

@ -601,7 +601,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
Repeat(ref operand, _) => {
let (elem_ty, length) = match dest_ty.sty {
ty::TyArray(elem_ty, n) => (elem_ty, n.val.to_const_int().unwrap().to_u64().unwrap()),
ty::TyArray(elem_ty, n) => (elem_ty, n.val.unwrap_u64()),
_ => {
bug!(
"tried to assign array-repeat to non-array type {:?}",
@ -1386,7 +1386,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, '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.to_const_int().unwrap().to_u64().unwrap() ),
value: ptr.to_value_with_len(length.val.unwrap_u64() ),
ty: dest_ty,
};
self.write_value(valty, dest)

View file

@ -18,6 +18,6 @@ pub use self::place::{Place, PlaceExtra};
pub use self::memory::{Memory, MemoryKind, HasMemory};
pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider};
pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider, const_val_field, const_discr};
pub use self::machine::Machine;

View file

@ -248,10 +248,15 @@ pub fn unary_op<'tcx>(
(Not, I64) => !(bytes as i64) as u128,
(Not, I128) => !(bytes as i128) as u128,
(Neg, I8) if bytes == i8::min_value() as u128 => return err!(OverflowingMath),
(Neg, I8) => -(bytes as i8) as u128,
(Neg, I16) if bytes == i16::min_value() as u128 => return err!(OverflowingMath),
(Neg, I16) => -(bytes as i16) as u128,
(Neg, I32) if bytes == i32::min_value() as u128 => return err!(OverflowingMath),
(Neg, I32) => -(bytes as i32) as u128,
(Neg, I64) if bytes == i64::min_value() as u128 => return err!(OverflowingMath),
(Neg, I64) => -(bytes as i64) as u128,
(Neg, I128) if bytes == i128::min_value() as u128 => return err!(OverflowingMath),
(Neg, I128) => -(bytes as i128) as u128,
(Neg, F32) => (-bytes_to_f32(bytes)).bits,

View file

@ -71,7 +71,7 @@ impl<'tcx> Place {
pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) {
match ty.sty {
ty::TyArray(elem, n) => (elem, n.val.to_const_int().unwrap().to_u64().unwrap() as u64),
ty::TyArray(elem, n) => (elem, n.val.unwrap_u64() as u64),
ty::TySlice(elem) => {
match self {
@ -115,6 +115,29 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
}
}
pub fn read_field(
&self,
base: Value,
field: mir::Field,
base_ty: Ty<'tcx>,
) -> EvalResult<'tcx, Option<(Value, Ty<'tcx>)>> {
let base_layout = self.layout_of(base_ty)?;
let field_index = field.index();
let field = base_layout.field(self, field_index)?;
let offset = base_layout.fields.offset(field_index);
match base {
// the field covers the entire type
Value::ByValPair(..) |
Value::ByVal(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some((base, field.ty))),
// split fat pointers, 2 element tuples, ...
Value::ByValPair(a, b) if base_layout.fields.count() == 2 => {
let val = [a, b][field_index];
Ok(Some((Value::ByVal(val), field.ty)))
},
_ => Ok(None),
}
}
fn try_read_place_projection(
&mut self,
proj: &mir::PlaceProjection<'tcx>,
@ -126,23 +149,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
};
let base_ty = self.place_ty(&proj.base);
match proj.elem {
Field(field, _) => {
let base_layout = self.layout_of(base_ty)?;
let field_index = field.index();
let field = base_layout.field(&self, field_index)?;
let offset = base_layout.fields.offset(field_index);
match base {
// the field covers the entire type
Value::ByValPair(..) |
Value::ByVal(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some(base)),
// split fat pointers, 2 element tuples, ...
Value::ByValPair(a, b) if base_layout.fields.count() == 2 => {
let val = [a, b][field_index];
Ok(Some(Value::ByVal(val)))
},
_ => Ok(None),
}
},
Field(field, _) => Ok(self.read_field(base, field, base_ty)?.map(|(f, _)| f)),
// The NullablePointer cases should work fine, need to take care for normal enums
Downcast(..) |
Subslice { .. } |

View file

@ -45,8 +45,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
// Branch to the `otherwise` case by default, if no match is found.
let mut target_block = targets[targets.len() - 1];
for (index, const_int) in values.iter().enumerate() {
let prim = PrimVal::Bytes(const_int.to_u128_unchecked());
for (index, &const_int) in values.iter().enumerate() {
let prim = PrimVal::Bytes(const_int);
if discr_prim.to_bytes()? == prim.to_bytes()? {
target_block = targets[index];
break;

View file

@ -314,7 +314,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
output.push('[');
self.push_type_name(inner_type, output);
write!(output, "; {}",
len.val.to_const_int().unwrap().to_u64().unwrap()).unwrap();
len.val.unwrap_u64()).unwrap();
output.push(']');
},
ty::TySlice(inner_type) => {

View file

@ -17,6 +17,7 @@ use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::ty::maps::Providers;
use rustc_const_math::{ConstInt, ConstUsize};
use rustc::mir::interpret::{Value, PrimVal};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@ -303,7 +304,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.to_const_int().unwrap().to_u64().unwrap();
let len = len.val.unwrap_u64();
builder.array_shim(dest, src, ty, len)
}
ty::TyClosure(def_id, substs) => {
@ -443,7 +444,12 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
ty: func_ty,
literal: Literal::Value {
value: tcx.mk_const(ty::Const {
val: ConstVal::Function(self.def_id, substs),
val: if tcx.sess.opts.debugging_opts.miri {
// ZST function type
ConstVal::Value(Value::ByVal(PrimVal::Undef))
} else {
ConstVal::Function(self.def_id, substs)
},
ty: func_ty
}),
},
@ -501,13 +507,20 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
}
fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
let value = ConstUsize::new(value, self.tcx.sess.target.usize_ty).unwrap();
box Constant {
span: self.span,
ty: self.tcx.types.usize,
literal: Literal::Value {
value: self.tcx.mk_const(ty::Const {
val: ConstVal::Integral(ConstInt::Usize(value)),
val: if self.tcx.sess.opts.debugging_opts.miri {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into())))
} else {
let value = ConstUsize::new(
value,
self.tcx.sess.target.usize_ty,
).unwrap();
ConstVal::Integral(ConstInt::Usize(value))
},
ty: self.tcx.types.usize,
})
}
@ -739,8 +752,12 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty,
literal: Literal::Value {
value: tcx.mk_const(ty::Const {
val: ConstVal::Function(def_id,
Substs::identity_for_item(tcx, def_id)),
val: if tcx.sess.opts.debugging_opts.miri {
// ZST function type
ConstVal::Value(Value::ByVal(PrimVal::Undef))
} else {
ConstVal::Function(def_id, Substs::identity_for_item(tcx, def_id))
},
ty
}),
},

View file

@ -80,6 +80,7 @@ use transform::simplify;
use transform::no_landing_pads::no_landing_pads;
use dataflow::{do_dataflow, DebugFormatted, state_for_location};
use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals};
use rustc::mir::interpret::{Value, PrimVal};
pub struct StateTransform;
@ -181,7 +182,11 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
ty: self.tcx.types.u32,
literal: Literal::Value {
value: self.tcx.mk_const(ty::Const {
val: ConstVal::Integral(ConstInt::U32(state_disc)),
val: if self.tcx.sess.opts.debugging_opts.miri {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into())))
} else {
ConstVal::Integral(ConstInt::U32(state_disc))
},
ty: self.tcx.types.u32
}),
},
@ -534,7 +539,7 @@ fn insert_switch<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let switch = TerminatorKind::SwitchInt {
discr: Operand::Copy(transform.make_field(transform.state_field, tcx.types.u32)),
switch_ty: tcx.types.u32,
values: Cow::from(cases.iter().map(|&(i, _)| ConstInt::U32(i)).collect::<Vec<_>>()),
values: Cow::from(cases.iter().map(|&(i, _)| i.into()).collect::<Vec<_>>()),
targets: cases.iter().map(|&(_, d)| d).chain(once(default_block)).collect(),
};

View file

@ -207,6 +207,13 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
return false;
}
// Do not inline {u,i}128 lang items, trans const eval depends
// on detecting calls to these lang items and intercepting them
if tcx.is_binop_lang_item(callsite.callee).is_some() {
debug!(" not inlining 128bit integer lang item");
return false;
}
let trans_fn_attrs = tcx.trans_fn_attrs(callsite.callee);
let hinted = match trans_fn_attrs.inline {

View file

@ -690,7 +690,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
_ => false
}
} else if let ty::TyArray(_, len) = ty.sty {
len.val.to_const_int().unwrap().to_u64().unwrap() == 0 &&
len.val.unwrap_u64() == 0 &&
self.mode == Mode::Fn
} else {
false

View file

@ -40,10 +40,10 @@ impl MirPass for SimplifyBranches {
TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
literal: Literal::Value { ref value }, ..
}), ref values, ref targets, .. } => {
if let Some(ref constint) = value.val.to_const_int() {
if let Some(constint) = value.val.to_u128() {
let (otherwise, targets) = targets.split_last().unwrap();
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()) {
if v == constint {
ret = TerminatorKind::Goto { target: *t };
break;

View file

@ -11,13 +11,14 @@
use std::fmt;
use rustc::hir;
use rustc::mir::*;
use rustc::middle::const_val::{ConstInt, ConstVal};
use rustc::middle::const_val::ConstVal;
use rustc::middle::lang_items;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::{Kind, Substs};
use rustc::ty::util::IntTypeExt;
use rustc_data_structures::indexed_vec::Idx;
use util::patch::MirPatch;
use rustc::mir::interpret::{Value, PrimVal};
use std::{iter, u32};
@ -425,7 +426,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
variant_path,
&adt.variants[variant_index],
substs);
values.push(discr);
values.push(discr.to_u128().unwrap());
if let Unwind::To(unwind) = unwind {
// We can't use the half-ladder from the original
// drop ladder, because this breaks the
@ -480,7 +481,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
fn adt_switch_block(&mut self,
adt: &'tcx ty::AdtDef,
blocks: Vec<BasicBlock>,
values: &[ConstInt],
values: &[u128],
succ: BasicBlock,
unwind: Unwind)
-> BasicBlock {
@ -803,7 +804,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
}
ty::TyArray(ety, size) => self.open_drop_for_array(
ety, size.val.to_const_int().and_then(|v| v.to_u64())),
ety, size.val.to_u128().map(|i| i as u64)),
ty::TySlice(ety) => self.open_drop_for_array(ety, None),
_ => bug!("open drop from non-ADT `{:?}`", ty)
@ -949,7 +950,11 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
ty: self.tcx().types.usize,
literal: Literal::Value {
value: self.tcx().mk_const(ty::Const {
val: ConstVal::Integral(self.tcx().const_usize(val)),
val: if self.tcx().sess.opts.debugging_opts.miri {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into())))
} else {
ConstVal::Integral(self.tcx().const_usize(val))
},
ty: self.tcx().types.usize
})
}

View file

@ -129,6 +129,9 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
}
fn check_const_eval(&self, expr: &'gcx hir::Expr) {
if self.tcx.sess.opts.debugging_opts.miri {
return;
}
if let Err(err) = self.const_cx().eval(expr) {
match err.kind {
UnimplementedConstVal(_) => {}
@ -220,23 +223,24 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
self.check_const_eval(lit);
}
PatKind::Range(ref start, ref end, RangeEnd::Excluded) => {
match self.const_cx().compare_lit_exprs(p.span, start, end) {
Ok(Ordering::Less) => {}
Ok(Ordering::Equal) |
Ok(Ordering::Greater) => {
match self.const_cx().compare_lit_exprs(start, end) {
Ok(Some(Ordering::Less)) => {}
Ok(Some(Ordering::Equal)) |
Ok(Some(Ordering::Greater)) => {
span_err!(self.tcx.sess,
start.span,
E0579,
"lower range bound must be less than upper");
}
Ok(None) => bug!("ranges must be char or int"),
Err(ErrorReported) => {}
}
}
PatKind::Range(ref start, ref end, RangeEnd::Included) => {
match self.const_cx().compare_lit_exprs(p.span, start, end) {
Ok(Ordering::Less) |
Ok(Ordering::Equal) => {}
Ok(Ordering::Greater) => {
match self.const_cx().compare_lit_exprs(start, end) {
Ok(Some(Ordering::Less)) |
Ok(Some(Ordering::Equal)) => {}
Ok(Some(Ordering::Greater)) => {
let mut err = struct_span_err!(
self.tcx.sess,
start.span,
@ -252,6 +256,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
}
err.emit();
}
Ok(None) => bug!("ranges must be char or int"),
Err(ErrorReported) => {}
}
}
@ -308,7 +313,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
self.promotable = false;
}
if self.in_fn && self.promotable {
if self.in_fn && self.promotable && !self.tcx.sess.opts.debugging_opts.miri {
match self.const_cx().eval(ex) {
Ok(_) => {}
Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |

View file

@ -195,7 +195,7 @@ pub fn unsized_info<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>,
let (source, target) = cx.tcx.struct_lockstep_tails(source, target);
match (&source.sty, &target.sty) {
(&ty::TyArray(_, len), &ty::TySlice(_)) => {
C_usize(cx, len.val.to_const_int().unwrap().to_u64().unwrap())
C_usize(cx, len.val.unwrap_u64())
}
(&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
// For now, upcasts are limited to changes in marker

View file

@ -276,7 +276,7 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
let upper_bound = match array_or_slice_type.sty {
ty::TyArray(_, len) => {
len.val.to_const_int().unwrap().to_u64().unwrap() as c_longlong
len.val.unwrap_u64() as c_longlong
}
_ => -1
};

View file

@ -97,7 +97,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
ty::TyArray(inner_type, len) => {
output.push('[');
push_debuginfo_type_name(cx, inner_type, true, output);
output.push_str(&format!("; {}", len.val.to_const_int().unwrap().to_u64().unwrap()));
output.push_str(&format!("; {}", len.val.unwrap_u64()));
output.push(']');
},
ty::TySlice(inner_type) => {

View file

@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal;
use rustc::mir::{self, Location, TerminatorKind, Literal};
use rustc::mir::visit::{Visitor, PlaceContext};
use rustc::mir::traversal;
use rustc::mir::interpret::{Value, PrimVal};
use rustc::ty;
use rustc::ty::layout::LayoutOf;
use type_of::LayoutLlvmExt;
@ -109,15 +110,26 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
block: mir::BasicBlock,
kind: &mir::TerminatorKind<'tcx>,
location: Location) {
match *kind {
let check = match *kind {
mir::TerminatorKind::Call {
func: mir::Operand::Constant(box mir::Constant {
literal: Literal::Value {
value: &ty::Const { val: ConstVal::Function(def_id, _), .. }, ..
value: &ty::Const { val, ty }, ..
}, ..
}),
ref args, ..
} if Some(def_id) == self.fx.cx.tcx.lang_items().box_free_fn() => {
} => match val {
ConstVal::Function(def_id, _) => Some((def_id, args)),
ConstVal::Value(Value::ByVal(PrimVal::Undef)) => match ty.sty {
ty::TyFnDef(did, _) => Some((did, args)),
_ => None,
},
_ => None,
}
_ => None,
};
if let Some((def_id, args)) = check {
if Some(def_id) == self.cx.ccx.tcx().lang_items().box_free_fn() {
// box_free(x) shares with `drop x` the property that it
// is not guaranteed to be statically dominated by the
// definition of x, so x must always be in an alloca.
@ -125,7 +137,6 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
self.visit_place(place, PlaceContext::Drop, location);
}
}
_ => {}
}
self.super_terminator_kind(block, kind, location);

View file

@ -10,7 +10,7 @@
use llvm::{self, ValueRef, BasicBlockRef};
use rustc::middle::lang_items;
use rustc::middle::const_val::{ConstEvalErr, ConstInt, ErrKind};
use rustc::middle::const_val::{ConstEvalErr, ErrKind};
use rustc::ty::{self, TypeFoldable};
use rustc::ty::layout::{self, LayoutOf};
use rustc::traits;
@ -196,17 +196,18 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
if switch_ty == bx.tcx().types.bool {
let lltrue = llblock(self, targets[0]);
let llfalse = llblock(self, targets[1]);
if let [ConstInt::U8(0)] = values[..] {
if let [0] = values[..] {
bx.cond_br(discr.immediate(), llfalse, lltrue);
} else {
assert_eq!(&values[..], &[1]);
bx.cond_br(discr.immediate(), lltrue, llfalse);
}
} else {
let (otherwise, targets) = targets.split_last().unwrap();
let switch = bx.switch(discr.immediate(),
llblock(self, *otherwise), values.len());
for (value, target) in values.iter().zip(targets) {
let val = Const::from_constint(bx.cx, value);
for (&value, target) in values.iter().zip(targets) {
let val = Const::from_bytes(bx.cx, value, switch_ty);
let llbb = llblock(self, *target);
bx.add_case(switch, val.llval, llbb)
}

View file

@ -16,6 +16,7 @@ use rustc::hir::def_id::DefId;
use rustc::infer::TransNormalize;
use rustc::traits;
use rustc::mir;
use rustc::mir::interpret::{Value as MiriValue, PrimVal};
use rustc::mir::tcx::PlaceTy;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::layout::{self, LayoutOf, Size};
@ -38,6 +39,7 @@ use value::Value;
use syntax_pos::Span;
use syntax::ast;
use syntax::symbol::Symbol;
use std::fmt;
use std::ptr;
@ -81,12 +83,46 @@ impl<'a, 'tcx> Const<'tcx> {
Const { llval: llval, ty: ty }
}
pub fn from_bytes(ccx: &CrateContext<'a, 'tcx>, b: u128, ty: Ty<'tcx>) -> Const<'tcx> {
let llval = match ty.sty {
ty::TyInt(ast::IntTy::I128) |
ty::TyUint(ast::UintTy::U128) => C_uint_big(Type::i128(ccx), b),
ty::TyInt(i) => C_int(Type::int_from_ty(ccx, i), b as i128 as i64),
ty::TyUint(u) => C_uint(Type::uint_from_ty(ccx, u), b as u64),
ty::TyBool => {
assert!(b <= 1);
C_bool(ccx, b == 1)
},
ty::TyChar => {
assert_eq!(b as u32 as u128, b);
let c = b as u32;
assert!(::std::char::from_u32(c).is_some());
C_uint(Type::char(ccx), c as u64)
},
ty::TyFloat(fty) => {
let llty = ccx.layout_of(ty).llvm_type(ccx);
let bits = match fty {
ast::FloatTy::F32 => C_u32(ccx, b as u32),
ast::FloatTy::F64 => C_u64(ccx, b as u64),
};
consts::bitcast(bits, llty)
},
ty::TyAdt(adt, _) if adt.is_enum() => {
use rustc::ty::util::IntTypeExt;
Const::from_bytes(ccx, b, adt.repr.discr_type().to_ty(ccx.tcx())).llval
},
_ => bug!("from_bytes({}, {})", b, ty),
};
Const { llval, ty }
}
/// Translate ConstVal into a LLVM constant value.
pub fn from_constval(cx: &CodegenCx<'a, 'tcx>,
cv: &ConstVal,
ty: Ty<'tcx>)
-> Const<'tcx> {
let llty = cx.layout_of(ty).llvm_type(cx);
trace!("from_constval: {:#?}: {}", cv, ty);
let val = match *cv {
ConstVal::Float(v) => {
let bits = match v.ty {
@ -108,7 +144,41 @@ impl<'a, 'tcx> Const<'tcx> {
ConstVal::Unevaluated(..) => {
bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv)
}
ConstVal::Value(_) => unimplemented!(),
ConstVal::Value(MiriValue::ByRef(..)) => unimplemented!("{:#?}:{}", cv, ty),
ConstVal::Value(MiriValue::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len))) => {
match ty.sty {
ty::TyRef(_, ref tam) => match tam.ty.sty {
ty::TyStr => {},
_ => unimplemented!("non-str fat pointer: {:?}: {:?}", ptr, ty),
},
_ => unimplemented!("non-str fat pointer: {:?}: {:?}", ptr, ty),
}
let alloc = ccx
.tcx()
.interpret_interner
.borrow()
.get_alloc(ptr.alloc_id.0)
.expect("miri alloc not found");
assert_eq!(len as usize as u128, len);
let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)];
let s = ::std::str::from_utf8(slice)
.expect("non utf8 str from miri");
C_str_slice(ccx, Symbol::intern(s).as_str())
},
ConstVal::Value(MiriValue::ByValPair(..)) => unimplemented!(),
ConstVal::Value(MiriValue::ByVal(PrimVal::Bytes(b))) =>
return Const::from_bytes(ccx, b, ty),
ConstVal::Value(MiriValue::ByVal(PrimVal::Undef)) => C_undef(llty),
ConstVal::Value(MiriValue::ByVal(PrimVal::Ptr(ptr))) => {
let alloc = ccx
.tcx()
.interpret_interner
.borrow()
.get_alloc(ptr.alloc_id.0)
.expect("miri alloc not found");
let data = &alloc.bytes[(ptr.offset as usize)..];
consts::addr_of(ccx, C_bytes(ccx, data), ccx.align_of(ty), "byte_str")
}
};
assert!(!ty.has_erasable_regions());
@ -239,7 +309,7 @@ impl<'tcx> ConstPlace<'tcx> {
pub fn len<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> ValueRef {
match self.ty.sty {
ty::TyArray(_, n) => {
C_usize(cx, n.val.to_const_int().unwrap().to_u64().unwrap())
C_usize(cx, n.val.unwrap_u64())
}
ty::TySlice(_) | ty::TyStr => {
assert!(self.llextra != ptr::null_mut());
@ -316,7 +386,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
let tcx = self.cx.tcx;
let mut bb = mir::START_BLOCK;
// Make sure to evaluate all statemenets to
// Make sure to evaluate all statements to
// report as many errors as we possibly can.
let mut failure = Ok(());
@ -392,6 +462,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
_ => span_bug!(span, "calling {:?} (of type {}) in constant",
func, fn_ty)
};
trace!("trans const fn call {:?}, {:?}, {:#?}", func, fn_ty, args);
let mut arg_vals = IndexVec::with_capacity(args.len());
for arg in args {
@ -419,7 +490,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
}
_ => span_bug!(span, "{:?} in constant", terminator.kind)
}
} else if let Some((op, is_checked)) = self.is_binop_lang_item(def_id) {
} else if let Some((op, is_checked)) = tcx.is_binop_lang_item(def_id) {
(||{
assert_eq!(arg_vals.len(), 2);
let rhs = arg_vals.pop().unwrap()?;
@ -470,37 +541,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
}
}
fn is_binop_lang_item(&mut self, def_id: DefId) -> Option<(mir::BinOp, bool)> {
let tcx = self.cx.tcx;
let items = tcx.lang_items();
let def_id = Some(def_id);
if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
else { None }
}
fn store(&mut self,
dest: &mir::Place<'tcx>,
value: Result<Const<'tcx>, ConstEvalErr<'tcx>>,

View file

@ -497,7 +497,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
if let mir::Place::Local(index) = *place {
if let LocalRef::Operand(Some(op)) = self.locals[index] {
if let ty::TyArray(_, n) = op.layout.ty.sty {
let n = n.val.to_const_int().unwrap().to_u64().unwrap();
let n = n.val.unwrap_u64();
return common::C_usize(bx.cx, n);
}
}

View file

@ -413,7 +413,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let expected_ty = self.structurally_resolved_type(pat.span, expected);
let (inner_ty, slice_ty) = match expected_ty.sty {
ty::TyArray(inner_ty, size) => {
let size = size.val.to_const_int().unwrap().to_u64().unwrap();
let size = size.val.unwrap_u64();
let min_len = before.len() as u64 + after.len() as u64;
if slice.is_none() {
if min_len != size {

View file

@ -4029,9 +4029,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
};
if let Ok(count) = count {
let zero_or_one = count.val.to_const_int().and_then(|count| {
count.to_u64().map(|count| count <= 1)
}).unwrap_or(false);
let zero_or_one = count.val.to_u128().map_or(false, |count| count <= 1);
if !zero_or_one {
// For [foo, ..n] where n > 1, `foo` must have
// Copy type:

View file

@ -447,10 +447,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
hir::BiBitOr => ("bitor", lang.bitor_trait()),
hir::BiShl => ("shl", lang.shl_trait()),
hir::BiShr => ("shr", lang.shr_trait()),
hir::BiLt => ("lt", lang.ord_trait()),
hir::BiLe => ("le", lang.ord_trait()),
hir::BiGe => ("ge", lang.ord_trait()),
hir::BiGt => ("gt", lang.ord_trait()),
hir::BiLt => ("lt", lang.partial_ord_trait()),
hir::BiLe => ("le", lang.partial_ord_trait()),
hir::BiGe => ("ge", lang.partial_ord_trait()),
hir::BiGt => ("gt", lang.partial_ord_trait()),
hir::BiEq => ("eq", lang.eq_trait()),
hir::BiNe => ("ne", lang.eq_trait()),
hir::BiAnd | hir::BiOr => {

View file

@ -37,8 +37,8 @@ use rustc::ty::{ToPredicate, ReprOptions};
use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
use rustc::ty::maps::Providers;
use rustc::ty::util::IntTypeExt;
use rustc::util::nodemap::FxHashSet;
use util::nodemap::FxHashMap;
use rustc::util::nodemap::{FxHashSet, FxHashMap};
use rustc::mir::interpret::{Value, PrimVal};
use rustc_const_math::ConstInt;
@ -534,6 +534,18 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
match result {
Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => Some(x),
Ok(&ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
..
}) => {
use syntax::attr::IntType;
Some(match repr_type {
IntType::SignedInt(int_type) => ConstInt::new_signed(
b as i128, int_type, tcx.sess.target.isize_ty).unwrap(),
IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned(
b, uint_type, tcx.sess.target.usize_ty).unwrap(),
})
}
_ => None
}
} else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {

View file

@ -86,6 +86,7 @@ This API is completely unstable and subject to change.
#![feature(refcell_replace_swap)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_patterns)]
#![feature(i128_type)]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;

View file

@ -49,7 +49,7 @@ fn main() {
// _3 = &'23_1rs _2;
// StorageLive(_5);
// _5 = _2;
// switchInt(move _5) -> [0u8: bb5, otherwise: bb4];
// switchInt(move _5) -> [false: bb5, otherwise: bb4];
// }
// bb3: {
// ...

View file

@ -51,7 +51,7 @@ fn main() {
// _3 = &'26_1rs _1;
// StorageLive(_5);
// _5 = _1;
// switchInt(move _5) -> [0u8: bb5, otherwise: bb4];
// switchInt(move _5) -> [false: bb5, otherwise: bb4];
// }
// bb3: {
// ...

View file

@ -72,7 +72,7 @@ fn main() {
// bb4: {
// StorageLive(_7);
// _7 = _1;
// switchInt(move _7) -> [0u8: bb6, otherwise: bb5];
// switchInt(move _7) -> [false: bb6, otherwise: bb5];
// }
// bb5: {
// _0 = ();

View file

@ -103,7 +103,7 @@ fn query() -> bool { true }
// _11 = const query() -> [return: bb6, unwind: bb3];
// }
// bb6: {
// switchInt(move _11) -> [0u8: bb8, otherwise: bb7];
// switchInt(move _11) -> [false: bb8, otherwise: bb7];
// }
// bb7: {
// _0 = ();

View file

@ -36,7 +36,7 @@ fn main() {
// bb3: {
// StorageLive(_4);
// _4 = _1;
// switchInt(move _4) -> [0u8: bb5, otherwise: bb4];
// switchInt(move _4) -> [false: bb5, otherwise: bb4];
// }
// bb4: {
// _0 = ();

View file

@ -93,7 +93,7 @@ fn main() {
// _7 = const guard() -> [return: bb10, unwind: bb1];
// }
// bb10: { // end of guard
// switchInt(move _7) -> [0u8: bb11, otherwise: bb2];
// switchInt(move _7) -> [false: bb11, otherwise: bb2];
// }
// bb11: { // to pre_binding2
// falseEdges -> [real: bb5, imaginary: bb5];
@ -157,7 +157,7 @@ fn main() {
// _7 = const guard() -> [return: bb10, unwind: bb1];
// }
// bb10: { // end of guard
// switchInt(move _7) -> [0u8: bb11, otherwise: bb2];
// switchInt(move _7) -> [false: bb11, otherwise: bb2];
// }
// bb11: { // to pre_binding2
// falseEdges -> [real: bb6, imaginary: bb5];
@ -219,7 +219,7 @@ fn main() {
// _9 = const guard() -> [return: bb10, unwind: bb1];
// }
// bb10: { //end of guard
// switchInt(move _9) -> [0u8: bb11, otherwise: bb2];
// switchInt(move _9) -> [false: bb11, otherwise: bb2];
// }
// bb11: { // to pre_binding2
// falseEdges -> [real: bb5, imaginary: bb5];
@ -239,8 +239,8 @@ fn main() {
// _11 = const guard2(move _12) -> [return: bb14, unwind: bb1];
// }
// bb14: { // end of guard2
// StorageDead(_12);
// switchInt(move _11) -> [0u8: bb15, otherwise: bb3];
// StorageDead(_11);
// switchInt(move _11) -> [false: bb15, otherwise: bb3];
// }
// bb15: { // to pre_binding4
// falseEdges -> [real: bb7, imaginary: bb7];

View file

@ -41,7 +41,7 @@ fn main() {
// | Live variables on entry to bb2[0]: [_1, _3]
// _2 = &'_#2r _1[_3];
// | Live variables on entry to bb2[1]: [_2]
// switchInt(const true) -> [0u8: bb4, otherwise: bb3];
// switchInt(const true) -> [false: bb4, otherwise: bb3];
// }
// END rustc.main.nll.0.mir
// START rustc.main.nll.0.mir

View file

@ -17,7 +17,7 @@ fn main() {
// END RUST SOURCE
// START rustc.main.SimplifyBranches-initial.before.mir
// bb0: {
// switchInt(const false) -> [0u8: bb3, otherwise: bb2];
// switchInt(const false) -> [false: bb3, otherwise: bb2];
// }
// END rustc.main.SimplifyBranches-initial.before.mir
// START rustc.main.SimplifyBranches-initial.after.mir

View file

@ -19,8 +19,7 @@ use std::{u8, u16, u32, u64, usize};
const NEG_128: i8 = -128;
const NEG_NEG_128: i8 = -NEG_128;
//~^ ERROR constant evaluation error
//~| attempt to negate with overflow
//~^ ERROR E0080
fn main() {
match -128i8 {

View file

@ -21,8 +21,7 @@ use std::{u8, u16, u32, u64, usize};
const A_I8_T
: [u32; (i8::MAX as i8 + 1i8) as usize]
//~^ ERROR constant evaluation error
//~| WARNING constant evaluation error
//~^ ERROR E0080
= [0; (i8::MAX as usize) + 1];
fn main() {

View file

@ -16,8 +16,6 @@ const fn foo(x: u32) -> u32 {
fn main() {
const X: u32 = 0-1; //~ ERROR constant evaluation error
//~^ WARN constant evaluation error
const Y: u32 = foo(0-1); //~ ERROR constant evaluation error
//~^ WARN constant evaluation error
println!("{} {}", X, Y);
}

View file

@ -9,10 +9,11 @@
// except according to those terms.
// Encountered while testing #44614.
// must-compile-successfully
pub fn main() {
// Constant of generic type (int)
const X: &'static u32 = &22; //~ ERROR constant evaluation error
const X: &'static u32 = &22;
assert_eq!(0, match &22 {
X => 0,
_ => 1,

View file

@ -13,17 +13,18 @@
const X : usize = 2;
const fn f(x: usize) -> usize {
let mut sum = 0; //~ ERROR blocks in constant functions are limited
for i in 0..x { //~ ERROR calls in constant functions
//~| ERROR constant function contains unimplemented
let mut sum = 0;
//~^ ERROR E0016
for i in 0..x {
//~^ ERROR E0015
//~| ERROR E0019
sum += i;
}
sum //~ ERROR E0080
//~| non-constant path in constant
sum
}
#[allow(unused_variables)]
fn main() {
let a : [i32; f(X)];
//~^ WARNING constant evaluation error: non-constant path
//~^ ERROR E0080
}

View file

@ -1,3 +1,4 @@
<<<<<<< HEAD
warning: constant evaluation error: non-constant path in constant expression
--> $DIR/const-fn-error.rs:27:19
|
@ -10,6 +11,12 @@ error[E0016]: blocks in constant functions are limited to items and tail express
--> $DIR/const-fn-error.rs:16:19
|
LL | let mut sum = 0; //~ ERROR blocks in constant functions are limited
=======
error[E0016]: blocks in constant functions are limited to items and tail expressions
--> $DIR/const-fn-error.rs:16:19
|
16 | let mut sum = 0;
>>>>>>> Produce instead of pointers
| ^
error[E0015]: calls in constant functions are limited to constant functions, struct and enum constructors
@ -25,6 +32,7 @@ LL | for i in 0..x { //~ ERROR calls in constant functions
| ^^^^
error[E0080]: constant evaluation error
<<<<<<< HEAD
--> $DIR/const-fn-error.rs:21:5
|
LL | sum //~ ERROR E0080
@ -35,6 +43,12 @@ note: for constant expression here
|
LL | let a : [i32; f(X)];
| ^^^^^^^^^^^
=======
--> $DIR/const-fn-error.rs:28:19
|
28 | let a : [i32; f(X)];
| ^^^^ miri failed: machine error: Cannot evaluate within constants: "calling non-const fn `<I as std::iter::IntoIterator><std::ops::Range<usize>>::into_iter`"
>>>>>>> Produce instead of pointers
error: aborting due to 4 previous errors

View file

@ -15,9 +15,8 @@
const ONE: usize = 1;
const TWO: usize = 2;
const LEN: usize = ONE - TWO;
//~^ ERROR constant evaluation error [E0080]
//~| WARN attempt to subtract with overflow
fn main() {
let a: [i8; LEN] = unimplemented!();
//~^ ERROR E0080
}

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// must-compile-successfully
#![feature(const_fn)]
#[derive(PartialEq, Eq)]
@ -20,8 +22,6 @@ use Cake::*;
struct Pair<A, B>(A, B);
const BOO: Pair<Cake, Cake> = Pair(Marmor, BlackForest);
//~^ ERROR: constant evaluation error [E0080]
//~| unimplemented constant expression: tuple struct constructors
const FOO: Cake = BOO.1;
const fn foo() -> Cake {

View file

@ -8,10 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// must-compile-successfully
fn main() {
const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47];
const IDX: usize = 3;
const VAL: i32 = ARR[IDX];
const BLUB: [i32; (ARR[0] - 41) as usize] = [5]; //~ ERROR constant evaluation error
const BLUB: [i32; (ARR[0] - 41) as usize] = [5];
}

View file

@ -9,6 +9,7 @@
// except according to those terms.
// aux-build:issue_38875_b.rs
// must-compile-successfully
extern crate issue_38875_b;

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// must-compile-successfully
union U {
a: usize,
b: usize,
@ -16,9 +18,6 @@ union U {
const C: U = U { a: 10 };
fn main() {
unsafe {
let a: [u8; C.a]; // OK
let b: [u8; C.b]; //~ ERROR constant evaluation error
//~| WARNING constant evaluation error
}
let a: [u8; unsafe { C.a }];
let b: [u8; unsafe { C.b }];
}