//! user of the `DepNode` API of having to know how to compute the expected
//! fingerprint for a given set of node parameters.
-use mir::interpret::{GlobalId, ConstValue};
+use mir::interpret::GlobalId;
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
use hir::map::DefPathHash;
use hir::{HirId, ItemLocalId};
CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal,
};
use ty::{TyCtxt, FnSig, Instance, InstanceDef,
- ParamEnv, ParamEnvAnd, Predicate, PolyFnSig, PolyTraitRef, Ty};
+ ParamEnv, ParamEnvAnd, Predicate, PolyFnSig, PolyTraitRef, Ty, self};
use ty::subst::Substs;
// erase!() just makes tokens go away. It's used to specify which macro argument
// queries). Making them anonymous avoids hashing the result, which
// may save a bit of time.
[anon] EraseRegionsTy { ty: Ty<'tcx> },
- [anon] ConstValueToAllocation { val: ConstValue<'tcx>, ty: Ty<'tcx> },
+ [anon] ConstValueToAllocation { val: &'tcx ty::Const<'tcx> },
[input] Freevars(DefId),
[input] MaybeUnusedTraitImport(DefId),
}
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
-for ::mir::interpret::ConstVal<'gcx> {
+for ::mir::interpret::ConstValue<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
- use mir::interpret::ConstVal::*;
+ use mir::interpret::ConstValue::*;
mem::discriminant(self).hash_stable(hcx, hasher);
def_id.hash_stable(hcx, hasher);
substs.hash_stable(hcx, hasher);
}
- Value(ref value) => {
- value.hash_stable(hcx, hasher);
- }
- }
- }
-}
-
-impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
-for ::mir::interpret::ConstValue<'gcx> {
- fn hash_stable<W: StableHasherResult>(&self,
- hcx: &mut StableHashingContext<'a>,
- hasher: &mut StableHasher<W>) {
- use mir::interpret::ConstValue::*;
-
- mem::discriminant(self).hash_stable(hcx, hasher);
-
- match *self {
Scalar(val) => {
val.hash_stable(hcx, hasher);
}
use backtrace::Backtrace;
-
-use hir::def_id::DefId;
use ty;
-use ty::subst::Substs;
use ty::query::TyCtxtAt;
-use mir::interpret::ConstValue;
use errors::DiagnosticBuilder;
use syntax_pos::Span;
pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>>;
-#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)]
-pub enum ConstVal<'tcx> {
- Unevaluated(DefId, &'tcx Substs<'tcx>),
- Value(ConstValue<'tcx>),
-}
-
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ConstEvalErr<'tcx> {
pub span: Span,
mod value;
pub use self::error::{
- EvalError, EvalResult, EvalErrorKind, AssertMessage, ConstVal, ConstEvalErr, struct_error,
+ EvalError, EvalResult, EvalErrorKind, AssertMessage, ConstEvalErr, struct_error,
FrameInfo, ConstEvalResult,
};
use ty::layout::{Align, HasDataLayout, Size};
use ty;
+use ty::subst::Substs;
+use hir::def_id::DefId;
use super::{EvalResult, Pointer, PointerArithmetic, Allocation};
/// Represents a constant value in Rust. ByVal and ScalarPair are optimizations which
/// matches Value's optimizations for easy conversions between these two types
-#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
pub enum ConstValue<'tcx> {
+ /// Never returned from the `const_eval` query, but the HIR contains these frequently in order
+ /// to allow HIR creation to happen for everything before needing to be able to run constant
+ /// evaluation
+ Unevaluated(DefId, &'tcx Substs<'tcx>),
/// Used only for types with layout::abi::Scalar ABI and ZSTs which use Scalar::undef()
Scalar(Scalar),
/// Used only for types with layout::abi::ScalarPair
#[inline]
pub fn to_byval_value(&self) -> Option<Value> {
match *self {
+ ConstValue::Unevaluated(..) |
ConstValue::ByRef(..) => None,
ConstValue::ScalarPair(a, b) => Some(Value::ScalarPair(a, b)),
ConstValue::Scalar(val) => Some(Value::Scalar(val)),
#[inline]
pub fn to_scalar(&self) -> Option<Scalar> {
match *self {
- ConstValue::ByRef(..) => None,
+ ConstValue::Unevaluated(..) |
+ ConstValue::ByRef(..) |
ConstValue::ScalarPair(..) => None,
ConstValue::Scalar(val) => Some(val),
}
}
}
-/// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
+/// Write a `ConstValue` in a way closer to the original source code than the `Debug` output.
pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
- use mir::interpret::ConstVal;
- match const_val.val {
- ConstVal::Unevaluated(..) => write!(fmt, "{:?}", const_val),
- ConstVal::Value(val) => {
- if let Some(value) = val.to_byval_value() {
- print_miri_value(value, const_val.ty, fmt)
- } else {
- write!(fmt, "{:?}:{}", val, const_val.ty)
- }
- }
+ if let Some(value) = const_val.to_byval_value() {
+ print_miri_value(value, const_val.ty, fmt)
+ } else {
+ write!(fmt, "{:?}:{}", const_val.val, const_val.ty)
}
}
use hir::def_id::DefId;
use infer::{InferCtxt, InferOk};
use infer::type_variable::TypeVariableOrigin;
-use mir::interpret::ConstVal;
+use mir::interpret::ConstValue;
use mir::interpret::{GlobalId};
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
use syntax::symbol::Symbol;
}
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- if let ConstVal::Unevaluated(def_id, substs) = constant.val {
+ if let ConstValue::Unevaluated(def_id, substs) = constant.val {
let tcx = self.selcx.tcx().global_tcx();
if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) {
if substs.needs_infer() || substs.has_skol() {
}
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- if let ConstVal::Unevaluated(def_id, substs) = constant.val {
+ if let ConstValue::Unevaluated(def_id, substs) = constant.val {
let tcx = self.infcx.tcx.global_tcx();
if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) {
if substs.needs_infer() || substs.has_skol() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use mir::interpret::ConstVal;
+use mir::interpret::ConstValue;
use ty::subst::Substs;
use ty::{self, Ty, TypeFlags, TypeFoldable};
fn add_const(&mut self, constant: &ty::Const) {
self.add_ty(constant.ty);
- match constant.val {
- ConstVal::Value(_) => {}
- ConstVal::Unevaluated(_, substs) => {
- self.add_flags(TypeFlags::HAS_PROJECTION);
- self.add_substs(substs);
- }
+ if let ConstValue::Unevaluated(_, substs) = constant.val {
+ self.add_flags(TypeFlags::HAS_PROJECTION);
+ self.add_substs(substs);
}
}
//! These methods return true to indicate that the visitor has found what it is looking for
//! and does not need to visit anything else.
-use mir::interpret::ConstVal;
+use mir::interpret::ConstValue;
use hir::def_id::DefId;
use ty::{self, Binder, Ty, TyCtxt, TypeFlags};
}
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
- if let ConstVal::Unevaluated(..) = c.val {
+ if let ConstValue::Unevaluated(..) = c.val {
let projection_flags = TypeFlags::HAS_NORMALIZABLE_PROJECTION |
TypeFlags::HAS_PROJECTION;
if projection_flags.intersects(self.flags) {
use dep_graph::SerializedDepNodeIndex;
use dep_graph::DepNode;
use hir::def_id::{CrateNum, DefId, DefIndex};
-use mir::interpret::{GlobalId, ConstValue};
+use mir::interpret::GlobalId;
use traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal,
CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
}
impl<'tcx> QueryDescription<'tcx> for queries::const_value_to_allocation<'tcx> {
- fn describe(_tcx: TyCtxt, (val, ty): (ConstValue<'tcx>, Ty<'tcx>)) -> String {
- format!("converting value `{:?}` ({}) to an allocation", val, ty)
+ fn describe(_tcx: TyCtxt, val: &'tcx ty::Const<'tcx>) -> String {
+ format!("converting value `{:?}` to an allocation", val)
}
}
}
}
-impl<'tcx> Key for (mir::interpret::ConstValue<'tcx>, Ty<'tcx>) {
+impl<'tcx> Key for &'tcx ty::Const<'tcx> {
fn query_crate(&self) -> CrateNum {
LOCAL_CRATE
}
use mir::interpret::ConstEvalResult;
use mir::mono::{CodegenUnit, Stats};
use mir;
-use mir::interpret::{GlobalId, Allocation, ConstValue};
+use mir::interpret::{GlobalId, Allocation};
use session::{CompileResult, CrateDisambiguator};
use session::config::OutputFilenames;
use traits::{self, Vtable};
/// Converts a constant value to an constant allocation
[] fn const_value_to_allocation: const_value_to_allocation(
- (ConstValue<'tcx>, Ty<'tcx>)
+ &'tcx ty::Const<'tcx>
) -> &'tcx Allocation,
[] fn check_match: CheckMatch(DefId)
}
fn const_value_to_allocation<'tcx>(
- (val, ty): (ConstValue<'tcx>, Ty<'tcx>)
+ val: &'tcx ty::Const<'tcx>,
) -> DepConstructor<'tcx> {
- DepConstructor::ConstValueToAllocation { val, ty }
+ DepConstructor::ConstValueToAllocation { val }
}
fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
//! type equality, etc.
use hir::def_id::DefId;
-use mir::interpret::ConstVal;
+use mir::interpret::ConstValue;
use ty::subst::{Kind, UnpackedKind, Substs};
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::error::{ExpectedFound, TypeError};
return Ok(s);
}
match x.val {
- ConstVal::Unevaluated(def_id, substs) => {
+ ConstValue::Unevaluated(def_id, substs) => {
// FIXME(eddyb) get the right param_env.
let param_env = ty::ParamEnv::empty();
match tcx.lift_to_global(&substs) {
//! hand, though we've recently added some macros (e.g.,
//! `BraceStructLiftImpl!`) to help with the tedium.
-use mir::interpret::{ConstVal, ConstEvalErr};
+use mir::interpret::{ConstValue, ConstEvalErr};
use ty::{self, Lift, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use rustc_data_structures::accumulate_vec::AccumulateVec;
}
}
-impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
- ConstVal::Value(v) => ConstVal::Value(v),
- ConstVal::Unevaluated(def_id, substs) => {
- ConstVal::Unevaluated(def_id, substs.fold_with(folder))
+ ConstValue::Scalar(v) => ConstValue::Scalar(v),
+ ConstValue::ScalarPair(a, b) => ConstValue::ScalarPair(a, b),
+ ConstValue::ByRef(alloc, offset) => ConstValue::ByRef(alloc, offset),
+ ConstValue::Unevaluated(def_id, substs) => {
+ ConstValue::Unevaluated(def_id, substs.fold_with(folder))
}
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
- ConstVal::Value(_) => false,
- ConstVal::Unevaluated(_, substs) => substs.visit_with(visitor),
+ ConstValue::Scalar(_) |
+ ConstValue::ScalarPair(_, _) |
+ ConstValue::ByRef(_, _) => false,
+ ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor),
}
}
}
use hir::def_id::DefId;
-use mir::interpret::ConstVal;
+use mir::interpret::ConstValue;
use middle::region;
use polonius_engine::Atom;
use rustc_data_structures::indexed_vec::Idx;
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
use ty::{Slice, TyS, ParamEnvAnd, ParamEnv};
use util::captures::Captures;
-use mir::interpret::{Scalar, Pointer, Value, ConstValue};
+use mir::interpret::{Scalar, Pointer, Value};
use std::iter;
use std::cmp::Ordering;
pub struct Const<'tcx> {
pub ty: Ty<'tcx>,
- pub val: ConstVal<'tcx>,
+ pub val: ConstValue<'tcx>,
}
impl<'tcx> Const<'tcx> {
ty: Ty<'tcx>,
) -> &'tcx Self {
tcx.mk_const(Const {
- val: ConstVal::Unevaluated(def_id, substs),
+ val: ConstValue::Unevaluated(def_id, substs),
ty,
})
}
#[inline]
- pub fn from_const_val(
+ pub fn from_const_value(
tcx: TyCtxt<'_, '_, 'tcx>,
- val: ConstVal<'tcx>,
+ val: ConstValue<'tcx>,
ty: Ty<'tcx>,
) -> &'tcx Self {
tcx.mk_const(Const {
})
}
- #[inline]
- pub fn from_const_value(
- tcx: TyCtxt<'_, '_, 'tcx>,
- val: ConstValue<'tcx>,
- ty: Ty<'tcx>,
- ) -> &'tcx Self {
- Self::from_const_val(tcx, ConstVal::Value(val), ty)
- }
-
#[inline]
pub fn from_byval_value(
tcx: TyCtxt<'_, '_, 'tcx>,
}
let ty = tcx.lift_to_global(&ty).unwrap();
let size = tcx.layout_of(ty).ok()?.size;
- match self.val {
- ConstVal::Value(val) => val.to_bits(size),
- _ => None,
- }
+ self.val.to_bits(size)
}
#[inline]
pub fn to_ptr(&self) -> Option<Pointer> {
- match self.val {
- ConstVal::Value(val) => val.to_ptr(),
- _ => None,
- }
+ self.val.to_ptr()
}
#[inline]
pub fn to_byval_value(&self) -> Option<Value> {
- match self.val {
- ConstVal::Value(val) => val.to_byval_value(),
- _ => None,
- }
+ self.val.to_byval_value()
}
#[inline]
pub fn to_scalar(&self) -> Option<Scalar> {
- match self.val {
- ConstVal::Value(val) => val.to_scalar(),
- _ => None,
- }
+ self.val.to_scalar()
}
#[inline]
assert_eq!(self.ty, ty.value);
let ty = tcx.lift_to_global(&ty).unwrap();
let size = tcx.layout_of(ty).ok()?.size;
- match self.val {
- ConstVal::Value(val) => val.to_bits(size),
- _ => None,
- }
+ self.val.to_bits(size)
}
#[inline]
//! An iterator over the type substructure.
//! WARNING: this does not keep track of the region depth.
-use mir::interpret::ConstVal;
+use mir::interpret::ConstValue;
use ty::{self, Ty};
use rustc_data_structures::small_vec::SmallVec;
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
}
fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const<'tcx>) {
- match constant.val {
- ConstVal::Value(_) => {}
- ConstVal::Unevaluated(_, substs) => {
- stack.extend(substs.types().rev());
- }
+ if let ConstValue::Unevaluated(_, substs) = constant.val {
+ stack.extend(substs.types().rev());
}
stack.push(constant.ty);
}
// except according to those terms.
use hir::def_id::DefId;
-use mir::interpret::ConstVal;
+use mir::interpret::ConstValue;
use infer::InferCtxt;
use ty::subst::Substs;
use traits;
/// into `self.out`.
fn compute_const(&mut self, constant: &'tcx ty::Const<'tcx>) {
self.require_sized(constant.ty, traits::ConstSized);
- match constant.val {
- ConstVal::Value(_) => {}
- ConstVal::Unevaluated(def_id, substs) => {
- let obligations = self.nominal_obligations(def_id, substs);
- self.out.extend(obligations);
-
- let predicate = ty::Predicate::ConstEvaluatable(def_id, substs);
- let cause = self.cause(traits::MiscObligation);
- self.out.push(traits::Obligation::new(cause,
- self.param_env,
- predicate));
- }
+ if let ConstValue::Unevaluated(def_id, substs) = constant.val {
+ let obligations = self.nominal_obligations(def_id, substs);
+ self.out.extend(obligations);
+
+ let predicate = ty::Predicate::ConstEvaluatable(def_id, substs);
+ let cause = self.cause(traits::MiscObligation);
+ self.out.push(traits::Obligation::new(cause,
+ self.param_env,
+ predicate));
}
}
use hir::def_id::DefId;
use hir::map::definitions::DefPathData;
-use mir::interpret::ConstVal;
+use mir::interpret::ConstValue;
use middle::region::{self, BlockRemainder};
use ty::subst::{self, Subst};
use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
TyArray(ty, sz) => {
print!(f, cx, write("["), print(ty), write("; "))?;
match sz.val {
- ConstVal::Value(..) => ty::tls::with(|tcx| {
- write!(f, "{}", sz.unwrap_usize(tcx))
- })?,
- ConstVal::Unevaluated(_def_id, _substs) => {
+ ConstValue::Unevaluated(_def_id, _substs) => {
write!(f, "_")?;
}
+ _ => ty::tls::with(|tcx| {
+ write!(f, "{}", sz.unwrap_usize(tcx))
+ })?,
}
write!(f, "]")
}
fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec<u8>) {
use rustc::mir::interpret::GlobalId;
- use rustc::mir::interpret::ConstVal;
info!("loading wasm section {:?}", id);
};
let param_env = ty::ParamEnv::reveal_all();
let val = tcx.const_eval(param_env.and(cid)).unwrap();
-
- let const_val = match val.val {
- ConstVal::Value(val) => val,
- ConstVal::Unevaluated(..) => bug!("should be evaluated"),
- };
-
- let alloc = tcx.const_value_to_allocation((const_val, val.ty));
+ let alloc = tcx.const_value_to_allocation(val);
(section.to_string(), alloc.bytes.clone())
}
// except according to those terms.
use llvm::{self, ValueRef};
-use rustc::mir::interpret::{ConstVal, ConstEvalErr};
+use rustc::mir::interpret::ConstEvalErr;
use rustc_mir::interpret::{read_target_uint, const_val_field};
use rustc::hir::def_id::DefId;
use rustc::mir;
let static_ = cx.tcx.const_eval(param_env.and(cid))?;
let alloc = match static_.val {
- ConstVal::Value(ConstValue::ByRef(alloc, n)) if n.bytes() == 0 => alloc,
+ ConstValue::ByRef(alloc, n) if n.bytes() == 0 => alloc,
_ => bug!("static const eval returned {:#?}", static_),
};
Ok(const_alloc_to_llvm(cx, alloc))
}
impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
- fn const_to_const_value(
+ fn fully_evaluate(
&mut self,
bx: &Builder<'a, 'tcx>,
constant: &'tcx ty::Const<'tcx>,
- ) -> Result<ConstValue<'tcx>, Lrc<ConstEvalErr<'tcx>>> {
+ ) -> Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>> {
match constant.val {
- ConstVal::Unevaluated(def_id, ref substs) => {
+ ConstValue::Unevaluated(def_id, ref substs) => {
let tcx = bx.tcx();
let param_env = ty::ParamEnv::reveal_all();
let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap();
instance,
promoted: None,
};
- let c = tcx.const_eval(param_env.and(cid))?;
- self.const_to_const_value(bx, c)
+ tcx.const_eval(param_env.and(cid))
},
- ConstVal::Value(val) => Ok(val),
+ _ => Ok(constant),
}
}
- pub fn mir_constant_to_const_value(
+ pub fn eval_mir_constant(
&mut self,
bx: &Builder<'a, 'tcx>,
constant: &mir::Constant<'tcx>,
- ) -> Result<ConstValue<'tcx>, Lrc<ConstEvalErr<'tcx>>> {
+ ) -> Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>> {
match constant.literal {
mir::Literal::Promoted { index } => {
let param_env = ty::ParamEnv::reveal_all();
mir::Literal::Value { value } => {
Ok(self.monomorphize(&value))
}
- }.and_then(|c| self.const_to_const_value(bx, c))
+ }.and_then(|c| self.fully_evaluate(bx, c))
}
/// process constant containing SIMD shuffle indices
bx: &Builder<'a, 'tcx>,
constant: &mir::Constant<'tcx>,
) -> (ValueRef, Ty<'tcx>) {
- self.mir_constant_to_const_value(bx, constant)
+ self.eval_mir_constant(bx, constant)
.and_then(|c| {
- let field_ty = constant.ty.builtin_index().unwrap();
- let fields = match constant.ty.sty {
+ let field_ty = c.ty.builtin_index().unwrap();
+ let fields = match c.ty.sty {
ty::TyArray(_, n) => n.unwrap_usize(bx.tcx()),
ref other => bug!("invalid simd shuffle type: {}", other),
};
None,
mir::Field::new(field as usize),
c,
- constant.ty,
)?;
if let Some(prim) = field.to_scalar() {
let layout = bx.cx.layout_of(field_ty);
}
}).collect();
let llval = C_struct(bx.cx, &values?, false);
- Ok((llval, constant.ty))
+ Ok((llval, c.ty))
})
.unwrap_or_else(|e| {
e.report_as_error(
}
pub fn from_const(bx: &Builder<'a, 'tcx>,
- val: ConstValue<'tcx>,
- ty: ty::Ty<'tcx>)
+ val: &'tcx ty::Const<'tcx>)
-> Result<OperandRef<'tcx>, Lrc<ConstEvalErr<'tcx>>> {
- let layout = bx.cx.layout_of(ty);
+ let layout = bx.cx.layout_of(val.ty);
if layout.is_zst() {
return Ok(OperandRef::new_zst(bx.cx, layout));
}
- let val = match val {
+ let val = match val.val {
+ ConstValue::Unevaluated(..) => bug!(),
ConstValue::Scalar(x) => {
let scalar = match layout.abi {
layout::Abi::Scalar(ref x) => x,
mir::Operand::Constant(ref constant) => {
let ty = self.monomorphize(&constant.ty);
- self.mir_constant_to_const_value(bx, constant)
- .and_then(|c| OperandRef::from_const(bx, c, ty))
+ self.eval_mir_constant(bx, constant)
+ .and_then(|c| OperandRef::from_const(bx, c))
.unwrap_or_else(|err| {
match constant.literal {
mir::Literal::Promoted { .. } => {
use self::Usefulness::*;
use self::WitnessPreference::*;
-use rustc::mir::interpret::ConstVal;
-
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
for row in patterns {
match *row.kind {
- PatternKind::Constant {
- value: const_val @ &ty::Const {
- val: ConstVal::Value(..),
- ..
- }
- } => {
- if let Some(ptr) = const_val.to_ptr() {
- let is_array_ptr = const_val.ty
+ PatternKind::Constant { value } => {
+ if let Some(ptr) = value.to_ptr() {
+ let is_array_ptr = value.ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == cx.tcx.types.u8);
suffix: &[Pattern<'tcx>]
) -> Result<bool, ErrorReported> {
let data: &[u8] = match *ctor {
- ConstantValue(&ty::Const { val: ConstVal::Value(const_val), ty }) => {
- let val = match const_val {
- ConstValue::ByRef(..) => bug!("unexpected ConstValue::ByRef"),
+ ConstantValue(const_val) => {
+ let val = match const_val.val {
+ ConstValue::Unevaluated(..) |
+ ConstValue::ByRef(..) => bug!("unexpected ConstValue: {:?}", const_val),
ConstValue::Scalar(val) | ConstValue::ScalarPair(val, _) => val,
};
if let Ok(ptr) = val.to_ptr() {
- let is_array_ptr = ty
+ let is_array_ptr = const_val.ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == tcx.types.u8);
use interpret::{const_val_field, const_variant_index, self};
-use rustc::mir::interpret::ConstVal;
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, Value};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
},
}
-fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result {
- match value.val {
- ConstVal::Value(..) => fmt_const_val(f, value),
- ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
- }
-}
-
impl<'tcx> fmt::Display for Pattern<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.kind {
write!(f, "{}", subpattern)
}
PatternKind::Constant { value } => {
- print_const_val(value, f)
+ fmt_const_val(f, value)
}
PatternKind::Range { lo, hi, end } => {
- print_const_val(lo, f)?;
+ fmt_const_val(f, lo)?;
match end {
RangeEnd::Included => write!(f, "...")?,
RangeEnd::Excluded => write!(f, "..")?,
}
- print_const_val(hi, f)
+ fmt_const_val(f, hi)
}
PatternKind::Slice { ref prefix, ref slice, ref suffix } |
PatternKind::Array { ref prefix, ref slice, ref suffix } => {
debug!("const_to_pat: cv={:#?}", cv);
let adt_subpattern = |i, variant_opt| {
let field = Field::new(i);
- let val = match cv.val {
- ConstVal::Value(miri) => const_val_field(
- self.tcx, self.param_env, instance,
- variant_opt, field, miri, cv.ty,
- ).expect("field access failed"),
- _ => bug!("{:#?} is not a valid adt", cv),
- };
+ let val = const_val_field(
+ self.tcx, self.param_env, instance,
+ variant_opt, field, cv,
+ ).expect("field access failed");
self.const_to_pat(instance, val, id, span)
};
let adt_subpatterns = |n, variant_opt| {
PatternKind::Wild
},
ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
- match cv.val {
- ConstVal::Value(val) => {
- let variant_index = const_variant_index(
- self.tcx, self.param_env, instance, val, cv.ty
- ).expect("const_variant_index failed");
- let subpatterns = adt_subpatterns(
- adt_def.variants[variant_index].fields.len(),
- Some(variant_index),
- );
- PatternKind::Variant {
- adt_def,
- substs,
- variant_index,
- subpatterns,
- }
- },
- ConstVal::Unevaluated(..) =>
- span_bug!(span, "{:#?} is not a valid enum constant", cv),
+ let variant_index = const_variant_index(
+ self.tcx, self.param_env, instance, cv
+ ).expect("const_variant_index failed");
+ let subpatterns = adt_subpatterns(
+ adt_def.variants[variant_index].fields.len(),
+ Some(variant_index),
+ );
+ PatternKind::Variant {
+ adt_def,
+ substs,
+ variant_index,
+ subpatterns,
}
},
ty::TyAdt(adt_def, _) => {
instance: ty::Instance<'tcx>,
variant: Option<usize>,
field: mir::Field,
- value: ConstValue<'tcx>,
- ty: Ty<'tcx>,
+ value: &'tcx ty::Const<'tcx>,
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
- trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
+ trace!("const_val_field: {:?}, {:?}, {:?}", instance, field, value);
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
let result = (|| {
- let value = ecx.const_value_to_value(value, ty)?;
+ let ty = value.ty;
+ let value = ecx.const_to_value(value.val)?;
let layout = ecx.layout_of(ty)?;
let (ptr, align) = match value {
Value::ByRef(ptr, align) => (ptr, align),
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
- val: ConstValue<'tcx>,
- ty: Ty<'tcx>,
+ val: &'tcx ty::Const<'tcx>,
) -> EvalResult<'tcx, usize> {
- trace!("const_variant_index: {:?}, {:?}, {:?}", instance, val, ty);
+ trace!("const_variant_index: {:?}, {:?}", instance, val);
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
- let value = ecx.const_value_to_value(val, ty)?;
+ let value = ecx.const_to_value(val.val)?;
let (ptr, align) = match value {
Value::ScalarPair(..) | Value::Scalar(_) => {
- let layout = ecx.layout_of(ty)?;
+ let layout = ecx.layout_of(val.ty)?;
let ptr = ecx.memory.allocate(layout.size, layout.align, Some(MemoryKind::Stack))?.into();
- ecx.write_value_to_ptr(value, ptr, layout.align, ty)?;
+ ecx.write_value_to_ptr(value, ptr, layout.align, val.ty)?;
(ptr, layout.align)
},
Value::ByRef(ptr, align) => (ptr, align),
};
let place = Place::from_scalar_ptr(ptr, align);
- ecx.read_discriminant_as_variant_index(place, ty)
+ ecx.read_discriminant_as_variant_index(place, val.ty)
}
pub fn const_value_to_allocation_provider<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- (val, ty): (ConstValue<'tcx>, Ty<'tcx>),
+ val: &'tcx ty::Const<'tcx>,
) -> &'tcx Allocation {
- match val {
+ match val.val {
ConstValue::ByRef(alloc, offset) => {
assert_eq!(offset.bytes(), 0);
return alloc;
ty::ParamEnv::reveal_all(),
CompileTimeEvaluator,
());
- let value = ecx.const_value_to_value(val, ty)?;
- let layout = ecx.layout_of(ty)?;
+ let value = ecx.const_to_value(val.val)?;
+ let layout = ecx.layout_of(val.ty)?;
let ptr = ecx.memory.allocate(layout.size, layout.align, Some(MemoryKind::Stack))?;
- ecx.write_value_to_ptr(value, ptr.into(), layout.align, ty)?;
+ ecx.write_value_to_ptr(value, ptr.into(), layout.align, val.ty)?;
let alloc = ecx.memory.get(ptr.alloc_id)?;
Ok(tcx.intern_const_alloc(alloc.clone()))
};
- result().expect("unable to convert ConstVal to Allocation")
+ result().expect("unable to convert ConstValue to Allocation")
}
pub fn const_eval_provider<'a, 'tcx>(
use rustc::hir::def_id::DefId;
use rustc::hir::def::Def;
use rustc::hir::map::definitions::DefPathData;
-use rustc::mir::interpret::ConstVal;
use rustc::mir;
use rustc::ty::layout::{self, Size, Align, HasDataLayout, IntegerExt, LayoutOf, TyLayout};
use rustc::ty::subst::{Subst, Substs};
Ok(Scalar::Ptr(ptr).to_value_with_len(s.len() as u64, self.tcx.tcx))
}
- pub fn const_value_to_value(
+ pub fn const_to_value(
&mut self,
val: ConstValue<'tcx>,
- _ty: Ty<'tcx>,
) -> EvalResult<'tcx, Value> {
match val {
+ ConstValue::Unevaluated(def_id, substs) => {
+ let instance = self.resolve(def_id, substs)?;
+ self.read_global_as_value(GlobalId {
+ instance,
+ promoted: None,
+ })
+ }
ConstValue::ByRef(alloc, offset) => {
// FIXME: Allocate new AllocId for all constants inside
let id = self.memory.allocate_value(alloc.clone(), Some(MemoryKind::Stack))?;
}
}
- pub(super) fn const_to_value(
- &mut self,
- const_val: &ConstVal<'tcx>,
- ty: Ty<'tcx>
- ) -> EvalResult<'tcx, Value> {
- match *const_val {
- ConstVal::Unevaluated(def_id, substs) => {
- let instance = self.resolve(def_id, substs)?;
- self.read_global_as_value(GlobalId {
- instance,
- promoted: None,
- }, ty)
- }
- ConstVal::Value(val) => self.const_value_to_value(val, ty)
- }
- }
-
pub(super) fn resolve(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, ty::Instance<'tcx>> {
trace!("resolve: {:?}, {:#?}", def_id, substs);
trace!("substs: {:#?}", self.substs());
use rustc::mir::Literal;
let mir::Constant { ref literal, .. } = **constant;
let value = match *literal {
- Literal::Value { ref value } => self.const_to_value(&value.val, ty)?,
+ Literal::Value { ref value } => self.const_to_value(value.val)?,
Literal::Promoted { index } => {
let instance = self.frame().instance;
self.read_global_as_value(GlobalId {
instance,
promoted: Some(index),
- }, ty)?
+ })?
}
};
Ok(())
}
- pub fn read_global_as_value(&mut self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
- if self.tcx.is_static(gid.instance.def_id()).is_some() {
- let alloc_id = self
- .tcx
- .alloc_map
- .lock()
- .intern_static(gid.instance.def_id());
- let layout = self.layout_of(ty)?;
- return Ok(Value::ByRef(Scalar::Ptr(alloc_id.into()), layout.align))
- }
+ pub fn read_global_as_value(&mut self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, Value> {
let cv = self.const_eval(gid)?;
- self.const_to_value(&cv.val, ty)
+ self.const_to_value(cv.val)
}
pub fn const_eval(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> {
use rustc::ty::query::TyCtxtAt;
use rustc::ty::layout::{self, Align, TargetDataLayout, Size};
use syntax::ast::Mutability;
-use rustc::mir::interpret::ConstVal;
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
use rustc::mir::interpret::{Pointer, AllocId, Allocation, AccessKind, Value,
assert!(self.tcx.is_static(def_id).is_some());
EvalErrorKind::ReferencedConstant(err).into()
}).map(|val| {
- let const_val = match val.val {
- ConstVal::Value(val) => val,
- ConstVal::Unevaluated(..) => bug!("should be evaluated"),
- };
- self.tcx.const_value_to_allocation((const_val, val.ty))
+ self.tcx.const_value_to_allocation(val)
})
}
use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
-use rustc::mir::interpret::ConstVal;
use rustc::mir::interpret::{AllocId, ConstValue};
use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
use rustc::ty::subst::Substs;
debug!("visiting const {:?}", *constant);
let val = match constant.val {
- ConstVal::Unevaluated(def_id, substs) => {
+ ConstValue::Unevaluated(def_id, substs) => {
let param_env = ty::ParamEnv::reveal_all();
let substs = tcx.subst_and_normalize_erasing_regions(
param_substs,
_ => constant.val,
};
match val {
- ConstVal::Unevaluated(..) => bug!("const eval yielded unevaluated const"),
- ConstVal::Value(ConstValue::ScalarPair(Scalar::Ptr(a), Scalar::Ptr(b))) => {
+ ConstValue::Unevaluated(..) => bug!("const eval yielded unevaluated const"),
+ ConstValue::ScalarPair(Scalar::Ptr(a), Scalar::Ptr(b)) => {
collect_miri(tcx, a.alloc_id, output);
collect_miri(tcx, b.alloc_id, output);
}
- ConstVal::Value(ConstValue::ScalarPair(_, Scalar::Ptr(ptr))) |
- ConstVal::Value(ConstValue::ScalarPair(Scalar::Ptr(ptr), _)) |
- ConstVal::Value(ConstValue::Scalar(Scalar::Ptr(ptr))) =>
+ ConstValue::ScalarPair(_, Scalar::Ptr(ptr)) |
+ ConstValue::ScalarPair(Scalar::Ptr(ptr), _) |
+ ConstValue::Scalar(Scalar::Ptr(ptr)) =>
collect_miri(tcx, ptr.alloc_id, output),
- ConstVal::Value(ConstValue::ByRef(alloc, _offset)) => {
+ ConstValue::ByRef(alloc, _offset) => {
for &id in alloc.relocations.values() {
collect_miri(tcx, id, output);
}
use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind};
use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
use rustc::mir::visit::{Visitor, PlaceContext};
-use rustc::mir::interpret::{ConstVal, ConstEvalErr};
+use rustc::mir::interpret::ConstEvalErr;
use rustc::ty::{TyCtxt, self, Instance};
use rustc::mir::interpret::{Value, Scalar, GlobalId, EvalResult};
use interpret::EvalContext;
r
}
- fn const_eval(&mut self, cid: GlobalId<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
- let value = match self.tcx.const_eval(self.param_env.and(cid)) {
- Ok(val) => val,
- Err(err) => {
- err.report_as_error(
- self.tcx.at(err.span),
- "constant evaluation error",
- );
- return None;
- },
- };
- let val = match value.val {
- ConstVal::Value(v) => {
- self.use_ecx(source_info, |this| this.ecx.const_value_to_value(v, value.ty))?
- },
- _ => bug!("eval produced: {:?}", value),
- };
- let val = (val, value.ty, source_info.span);
- trace!("evaluated {:?} to {:?}", cid, val);
- Some(val)
- }
-
fn eval_constant(
&mut self,
c: &Constant<'tcx>,
source_info: SourceInfo,
) -> Option<Const<'tcx>> {
match c.literal {
- Literal::Value { value } => match value.val {
- ConstVal::Value(v) => {
- let v = self.use_ecx(source_info, |this| {
- this.ecx.const_value_to_value(v, value.ty)
- })?;
- Some((v, value.ty, c.span))
- },
- ConstVal::Unevaluated(did, substs) => {
- let instance = Instance::resolve(
- self.tcx,
- self.param_env,
- did,
- substs,
- )?;
- let cid = GlobalId {
- instance,
- promoted: None,
- };
- self.const_eval(cid, source_info)
- },
+ Literal::Value { value } => {
+ let v = self.use_ecx(source_info, |this| {
+ this.ecx.const_to_value(value.val)
+ })?;
+ Some((v, value.ty, c.span))
},
// evaluate the promoted and replace the constant with the evaluated result
Literal::Promoted { index } => {
use rustc_data_structures::fx::FxHashSet;
use rustc::hir;
use rustc::hir::def_id::DefId;
-use rustc::mir::interpret::ConstVal;
+use rustc::mir::interpret::ConstValue;
use rustc::traits::{self, TraitEngine};
use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
use rustc::ty::cast::CastTy;
}
Operand::Constant(ref constant) => {
if let Literal::Value {
- value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty, .. }
+ value: &ty::Const { val: ConstValue::Unevaluated(def_id, _), ty, .. }
} = constant.literal {
// Don't peek inside trait associated constants.
if self.tcx.trait_of_item(def_id).is_some() {
use syntax::symbol::{Symbol, InternedString};
use syntax_pos::{self, DUMMY_SP, Pos, FileName};
-use rustc::mir::interpret::ConstVal;
+use rustc::mir::interpret::ConstValue;
use rustc::middle::privacy::AccessLevels;
use rustc::middle::resolve_lifetime as rl;
use rustc::ty::fold::TypeFolder;
ty::TySlice(ty) => Slice(box ty.clean(cx)),
ty::TyArray(ty, n) => {
let mut n = cx.tcx.lift(&n).unwrap();
- if let ConstVal::Unevaluated(def_id, substs) = n.val {
+ if let ConstValue::Unevaluated(def_id, substs) = n.val {
let param_env = cx.tcx.param_env(def_id);
let cid = GlobalId {
instance: ty::Instance::new(def_id, substs),
fn print_const(cx: &DocContext, n: &ty::Const) -> String {
match n.val {
- ConstVal::Unevaluated(def_id, _) => {
+ ConstValue::Unevaluated(def_id, _) => {
if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) {
print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id))
} else {
inline::print_inlined_const(cx, def_id)
}
},
- ConstVal::Value(..) => {
+ _ => {
let mut s = String::new();
::rustc::mir::fmt_const_val(&mut s, n).unwrap();
// array lengths are obviously usize
#![deny(const_err)]
pub const A: i8 = -std::i8::MIN;
-//~^ ERROR E0080
-//~| ERROR attempt to negate with overflow
+//~^ ERROR attempt to negate with overflow
//~| ERROR this expression will panic at runtime
//~| ERROR this constant cannot be used
pub const B: i8 = A;
//~^ ERROR const_err
//~| ERROR const_err
+//~| ERROR const_err
+//~| ERROR const_err
pub const C: u8 = A as u8;
//~^ ERROR const_err
//~| ERROR const_err
+//~| ERROR const_err
+//~| ERROR const_err
pub const D: i8 = 50 - A;
//~^ ERROR const_err
//~| ERROR const_err
+//~| ERROR const_err
+//~| ERROR const_err
fn main() {
let _ = (A, B, C, D);
// Make sure that the two uses get two errors.
const FOO: u8 = [5u8][1];
//~^ ERROR constant evaluation error
-//~| ERROR constant evaluation error
//~| index out of bounds: the len is 1 but the index is 1
fn main() {
const ONE: usize = 1;
const TWO: usize = 2;
const LEN: usize = ONE - TWO;
-//~^ ERROR E0080
-//~| ERROR attempt to subtract with overflow
+//~^ ERROR attempt to subtract with overflow
fn main() {
let a: [i8; LEN] = unimplemented!();
//~^ ERROR E0080
//~| ERROR E0080
+//~| ERROR const_err
+//~| ERROR const_err
}
|
= note: #[deny(const_err)] on by default
-error[E0080]: constant evaluation error
- --> $DIR/const-len-underflow-separate-spans.rs:17:20
+error: referenced constant
+ --> $DIR/const-len-underflow-separate-spans.rs:21:17
|
LL | const LEN: usize = ONE - TWO;
- | ^^^^^^^^^ attempt to subtract with overflow
+ | --------- attempt to subtract with overflow
+...
+LL | let a: [i8; LEN] = unimplemented!();
+ | ^^^
+
+error: this expression will panic at runtime
+ --> $DIR/const-len-underflow-separate-spans.rs:21:17
+ |
+LL | let a: [i8; LEN] = unimplemented!();
+ | ^^^ referenced constant has errors
error[E0080]: referenced constant
- --> $DIR/const-len-underflow-separate-spans.rs:22:12
+ --> $DIR/const-len-underflow-separate-spans.rs:21:12
|
LL | const LEN: usize = ONE - TWO;
| --------- attempt to subtract with overflow
| ^^^^^^^^^
error[E0080]: could not evaluate constant expression
- --> $DIR/const-len-underflow-separate-spans.rs:22:12
+ --> $DIR/const-len-underflow-separate-spans.rs:21:12
|
LL | let a: [i8; LEN] = unimplemented!();
| ^^^^^---^
| |
| referenced constant has errors
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0080`.