Prepare for using miri in trans

This commit is contained in:
Alexander Regueiro 2018-01-02 23:22:09 +00:00 committed by Oliver Schneider
parent 4c9b1b13dd
commit b2b101befc
No known key found for this signature in database
GPG Key ID: A69F8D225B3AD7D9
18 changed files with 286 additions and 130 deletions

View File

@ -60,15 +60,15 @@
//! user of the `DepNode` API of having to know how to compute the expected
//! fingerprint for a given set of node parameters.
use mir::interpret::{GlobalId};
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
use hir::map::DefPathHash;
use hir::{HirId, ItemLocalId};
use ich::Fingerprint;
use ich::{Fingerprint, StableHashingContext};
use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
use ty::subst::Substs;
use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
use ich::StableHashingContext;
use std::fmt;
use std::hash::Hash;
use syntax_pos::symbol::InternedString;
@ -518,7 +518,7 @@ define_dep_nodes!( <'tcx>
[] TypeckTables(DefId),
[] UsedTraitImports(DefId),
[] HasTypeckTables(DefId),
[] ConstEval { param_env: ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)> },
[] ConstEval { param_env: ParamEnvAnd<'tcx, GlobalId<'tcx>> },
[] CheckMatch(DefId),
[] SymbolName(DefId),
[] InstanceSymbolName { instance: Instance<'tcx> },

View File

@ -585,3 +585,5 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::ClosureOutlivesSubjec
}
}
}
impl_stable_hash_for!(struct mir::interpret::GlobalId<'tcx> { instance, promoted });

View File

@ -926,13 +926,13 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::InstanceDef<'gcx> {
ty::InstanceDef::ClosureOnceShim { call_once } => {
call_once.hash_stable(hcx, hasher);
}
ty::InstanceDef::DropGlue(def_id, t) => {
ty::InstanceDef::DropGlue(def_id, ty) => {
def_id.hash_stable(hcx, hasher);
t.hash_stable(hcx, hasher);
ty.hash_stable(hcx, hasher);
}
ty::InstanceDef::CloneShim(def_id, t) => {
ty::InstanceDef::CloneShim(def_id, ty) => {
def_id.hash_stable(hcx, hasher);
t.hash_stable(hcx, hasher);
ty.hash_stable(hcx, hasher);
}
}
}

View File

@ -9,6 +9,9 @@
// except according to those terms.
use infer::{RegionObligation, InferCtxt};
use middle::const_val::ConstEvalErr;
use middle::const_val::ErrKind::TypeckError;
use mir::interpret::GlobalId;
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
use ty::error::ExpectedFound;
use rustc_data_structures::obligation_forest::{ObligationForest, Error};
@ -514,17 +517,34 @@ fn process_predicate<'a, 'gcx, 'tcx>(
}
Some(param_env) => {
match selcx.tcx().lift_to_global(&substs) {
Some(substs) => {
let instance = ty::Instance::resolve(
selcx.tcx().global_tcx(),
param_env,
def_id,
substs,
);
if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None,
};
match selcx.tcx().at(obligation.cause.span)
.const_eval(param_env.and(cid)) {
Ok(_) => Ok(Some(vec![])),
Err(e) => Err(CodeSelectionError(ConstEvalFailure(e)))
}
} else {
Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr {
span: selcx.tcx().def_span(def_id),
kind: TypeckError,
})))
}
},
None => {
pending_obligation.stalled_on = substs.types().collect();
Ok(None)
}
Some(substs) => {
match selcx.tcx().at(obligation.cause.span)
.const_eval(param_env.and((def_id, substs))) {
Ok(_) => Ok(Some(vec![])),
Err(e) => Err(CodeSelectionError(ConstEvalFailure(e)))
}
}
}
}
}

View File

@ -29,6 +29,7 @@ use hir::def_id::DefId;
use infer::{InferCtxt, InferOk};
use infer::type_variable::TypeVariableOrigin;
use middle::const_val::ConstVal;
use mir::interpret::{GlobalId};
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
use syntax::symbol::Symbol;
use ty::subst::{Subst, Substs};
@ -400,12 +401,17 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if let ConstVal::Unevaluated(def_id, substs) = constant.val {
if substs.needs_infer() {
let identity_substs = Substs::identity_for_item(self.tcx(), def_id);
let data = self.param_env.and((def_id, identity_substs));
match self.tcx().lift_to_global(&data) {
Some(data) => {
match self.tcx().const_eval(data) {
let tcx = self.selcx.tcx().global_tcx();
if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) {
if substs.needs_infer() {
let identity_substs = Substs::identity_for_item(tcx, def_id);
let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs);
if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None
};
match tcx.const_eval(param_env.and(cid)) {
Ok(evaluated) => {
let evaluated = evaluated.subst(self.tcx(), substs);
return self.fold_const(evaluated);
@ -413,18 +419,20 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
Err(_) => {}
}
}
None => {}
}
} else {
let data = self.param_env.and((def_id, substs));
match self.tcx().lift_to_global(&data) {
Some(data) => {
match self.tcx().const_eval(data) {
Ok(evaluated) => return self.fold_const(evaluated),
Err(_) => {}
} else {
if let Some(substs) = self.tcx().lift_to_global(&substs) {
let instance = ty::Instance::resolve(tcx, param_env, def_id, substs);
if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None
};
match tcx.const_eval(param_env.and(cid)) {
Ok(evaluated) => return self.fold_const(evaluated),
Err(_) => {}
}
}
}
None => {}
}
}
}

View File

@ -42,6 +42,7 @@ use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use ty::fast_reject;
use ty::relate::TypeRelation;
use middle::lang_items;
use mir::interpret::{GlobalId};
use rustc_data_structures::bitvec::BitVector;
use std::iter;
@ -732,11 +733,26 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}
ty::Predicate::ConstEvaluatable(def_id, substs) => {
match self.tcx().lift_to_global(&(obligation.param_env, substs)) {
let tcx = self.tcx();
match tcx.lift_to_global(&(obligation.param_env, substs)) {
Some((param_env, substs)) => {
match self.tcx().const_eval(param_env.and((def_id, substs))) {
Ok(_) => EvaluatedToOk,
Err(_) => EvaluatedToErr
let instance = ty::Instance::resolve(
tcx.global_tcx(),
param_env,
def_id,
substs,
);
if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None
};
match self.tcx().const_eval(param_env.and(cid)) {
Ok(_) => EvaluatedToOk,
Err(_) => EvaluatedToErr
}
} else {
EvaluatedToErr
}
}
None => {

View File

@ -10,9 +10,10 @@
use dep_graph::SerializedDepNodeIndex;
use hir::def_id::{CrateNum, DefId, DefIndex};
use mir::interpret::{GlobalId};
use ty::{self, Ty, TyCtxt};
use ty::maps::queries;
use ty::subst::Substs;
use ty::maps::queries;
use std::hash::Hash;
use syntax_pos::symbol::InternedString;
@ -152,8 +153,8 @@ impl<'tcx> QueryDescription<'tcx> for queries::reachable_set<'tcx> {
}
impl<'tcx> QueryDescription<'tcx> for queries::const_eval<'tcx> {
fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) -> String {
format!("const-evaluating `{}`", tcx.item_path_str(key.value.0))
fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> String {
format!("const-evaluating `{}`", tcx.item_path_str(key.value.instance.def.def_id()))
}
}

View File

@ -53,6 +53,16 @@ impl<'tcx> Key for ty::Instance<'tcx> {
}
}
impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
fn map_crate(&self) -> CrateNum {
self.instance.map_crate()
}
fn default_span(&self, tcx: TyCtxt) -> Span {
self.instance.default_span(tcx)
}
}
impl Key for CrateNum {
fn map_crate(&self) -> CrateNum {
*self

View File

@ -29,6 +29,7 @@ use middle::lang_items::{LanguageItems, LangItem};
use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol};
use mir::mono::{CodegenUnit, Stats};
use mir;
use mir::interpret::{GlobalId};
use session::{CompileResult, CrateDisambiguator};
use session::config::OutputFilenames;
use traits::Vtable;
@ -210,7 +211,7 @@ define_maps! { <'tcx>
/// Results of evaluating const items or constants embedded in
/// other items (such as enum variant explicit discriminants).
[] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
[] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
-> const_val::EvalResult<'tcx>,
[] fn check_match: CheckMatch(DefId)
@ -450,7 +451,7 @@ fn typeck_item_bodies_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
DepConstructor::TypeckBodiesKrate
}
fn const_eval_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
fn const_eval_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
-> DepConstructor<'tcx> {
DepConstructor::ConstEval { param_env }
}

View File

@ -26,7 +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::interpret::{GlobalId, Value, PrimVal};
use mir::GeneratorLayout;
use session::CrateDisambiguator;
use traits;
@ -1835,7 +1835,12 @@ impl<'a, 'gcx, 'tcx> AdtDef {
let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
if let VariantDiscr::Explicit(expr_did) = v.discr {
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
match tcx.const_eval(param_env.and((expr_did, substs))) {
let instance = ty::Instance::new(expr_did, substs);
let cid = GlobalId {
instance,
promoted: None
};
match tcx.const_eval(param_env.and(cid)) {
Ok(&ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
..
@ -1885,7 +1890,12 @@ impl<'a, 'gcx, 'tcx> AdtDef {
}
ty::VariantDiscr::Explicit(expr_did) => {
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
match tcx.const_eval(param_env.and((expr_did, substs))) {
let instance = ty::Instance::new(expr_did, substs);
let cid = GlobalId {
instance,
promoted: None
};
match tcx.const_eval(param_env.and(cid)) {
Ok(&ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
..

View File

@ -20,7 +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 mir::interpret::{GlobalId, Value, PrimVal};
use util::common::ErrorReported;
use std::rc::Rc;
use std::iter;
@ -489,17 +489,29 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
match tcx.lift_to_global(&substs) {
Some(substs) => {
match tcx.const_eval(param_env.and((def_id, substs))) {
Ok(&ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
..
}) => {
assert_eq!(b as u64 as u128, b);
return Ok(b as u64);
let instance = ty::Instance::resolve(
tcx.global_tcx(),
param_env,
def_id,
substs,
);
if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None
};
match tcx.const_eval(param_env.and(cid)) {
Ok(&ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
..
}) => {
assert_eq!(b as u64 as u128, b);
return Ok(b as u64);
}
_ => {}
}
_ => {}
}
}
},
None => {}
}
tcx.sess.delay_span_bug(tcx.def_span(def_id),

View File

@ -57,6 +57,7 @@ CopyImpls! {
::syntax::abi::Abi,
::hir::def_id::DefId,
::mir::Local,
::mir::Promoted,
::traits::Reveal,
::syntax_pos::Span,
}
@ -589,7 +590,7 @@ impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> {
impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> {
type Lifted = interpret::EvalError<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
use mir::interpret::EvalErrorKind::*;
use ::mir::interpret::EvalErrorKind::*;
let kind = match self.kind {
MachineError(ref err) => MachineError(err.clone()),
FunctionPointerTyMismatch(a, b) => FunctionPointerTyMismatch(
@ -744,6 +745,42 @@ impl<'a, 'tcx> Lift<'tcx> for ty::layout::LayoutError<'a> {
}
}
impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
type Lifted = ty::InstanceDef<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
match *self {
ty::InstanceDef::Item(def_id) =>
Some(ty::InstanceDef::Item(def_id)),
ty::InstanceDef::Intrinsic(def_id) =>
Some(ty::InstanceDef::Intrinsic(def_id)),
ty::InstanceDef::FnPtrShim(def_id, ref ty) =>
Some(ty::InstanceDef::FnPtrShim(def_id, tcx.lift(ty)?)),
ty::InstanceDef::Virtual(def_id, n) =>
Some(ty::InstanceDef::Virtual(def_id, n)),
ty::InstanceDef::ClosureOnceShim { call_once } =>
Some(ty::InstanceDef::ClosureOnceShim { call_once }),
ty::InstanceDef::DropGlue(def_id, ref ty) =>
Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?)),
ty::InstanceDef::CloneShim(def_id, ref ty) =>
Some(ty::InstanceDef::CloneShim(def_id, tcx.lift(ty)?)),
}
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for ty::Instance<'a> {
type Lifted = ty::Instance<'tcx>;
def, substs
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for interpret::GlobalId<'a> {
type Lifted = interpret::GlobalId<'tcx>;
instance, promoted
}
}
///////////////////////////////////////////////////////////////////////////
// TypeFoldable implementations.
//
@ -945,6 +982,19 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
}
}
impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
Self {
instance: self.instance.fold_with(folder),
promoted: self.promoted
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.instance.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

@ -12,7 +12,7 @@
use rustc::mir::*;
use rustc::mir::visit::Visitor;
use rustc::mir::interpret::{Value, PrimVal};
use rustc::mir::interpret::{Value, PrimVal, GlobalId};
use rustc::middle::const_val::{ConstVal, ConstEvalErr, ErrKind};
use rustc::traits;
use interpret::{eval_body_as_integer, check_body};
@ -41,7 +41,11 @@ pub fn check<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
let instance = Instance::mono(tcx, def_id);
for i in 0.. mir.promoted.len() {
use rustc_data_structures::indexed_vec::Idx;
check_body(tcx, instance, Some(Promoted::new(i)), param_env);
let cid = GlobalId {
instance,
promoted: Some(Promoted::new(i)),
};
check_body(tcx, cid, param_env);
}
}
@ -65,7 +69,11 @@ impl<'a, 'tcx> ConstErrVisitor<'a, 'tcx> {
},
Literal::Promoted { index } => {
let instance = Instance::mono(self.tcx, self.def_id);
eval_body_as_integer(self.tcx, param_env, instance, Some(index)).unwrap()
let cid = GlobalId {
instance,
promoted: Some(index),
};
eval_body_as_integer(self.tcx, cid, param_env).unwrap()
}
};
Some(val)

View File

@ -12,7 +12,7 @@ use interpret::{const_val_field, const_discr};
use rustc::middle::const_val::{ConstEvalErr, ErrKind, ConstVal};
use rustc::mir::{Field, BorrowKind, Mutability};
use rustc::mir::interpret::{Value, PrimVal};
use rustc::mir::interpret::{GlobalId, Value, PrimVal};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
use rustc::ty::subst::{Substs, Kind};
use rustc::hir::{self, PatKind, RangeEnd};
@ -673,14 +673,18 @@ 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 self.tcx.at(span).const_eval(self.param_env.and((def_id, substs))) {
let instance = ty::Instance::resolve(
self.tcx,
self.param_env,
def_id,
substs,
).unwrap();
let cid = GlobalId {
instance,
promoted: None,
};
match self.tcx.at(span).const_eval(self.param_env.and(cid)) {
Ok(value) => {
let instance = ty::Instance::resolve(
self.tcx,
self.param_env,
def_id,
substs,
).unwrap();
return self.const_to_pat(instance, value, id, span)
},
Err(e) => {

View File

@ -15,6 +15,7 @@ use hair::cx::block;
use hair::cx::to_ref::ToRef;
use rustc::hir::def::{Def, CtorKind};
use rustc::middle::const_val::ConstVal;
use rustc::mir::interpret::{GlobalId, Value, PrimVal};
use rustc::ty::{self, AdtKind, VariantDef, Ty};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
use rustc::mir::interpret::{Value, PrimVal};
@ -511,7 +512,17 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
let c = &cx.tcx.hir.body(count).value;
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))) {
let instance = ty::Instance::resolve(
cx.tcx.global_tcx(),
cx.param_env,
def_id,
substs,
).unwrap();
let global_id = GlobalId {
instance,
promoted: None
};
let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) {
Ok(cv) => cv.val.unwrap_usize(cx.tcx),
Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression")
};

View File

@ -1,11 +1,10 @@
use rustc::ty::{self, TyCtxt, Ty, Instance};
use rustc::ty::layout::{self, LayoutOf};
use rustc::ty::subst::Substs;
use rustc::hir::def_id::DefId;
use rustc::mir;
use rustc::hir;
use rustc::middle::const_val::ErrKind::{CheckMatchError, TypeckError};
use rustc::middle::const_val::{ConstEvalErr, ConstVal};
use const_eval::lookup_const_by_id;
use rustc::mir;
use rustc::ty::{self, TyCtxt, Ty, Instance};
use rustc::ty::layout::{self, LayoutOf};
use rustc::ty::subst::Subst;
use syntax::ast::Mutability;
use syntax::codemap::Span;
@ -38,20 +37,18 @@ pub fn mk_eval_cx<'a, 'tcx>(
pub fn eval_body<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
instance: Instance<'tcx>,
promoted: Option<mir::Promoted>,
cid: GlobalId<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> {
eval_body_and_ecx(tcx, instance, promoted, param_env).0
eval_body_and_ecx(tcx, cid, param_env).0
}
pub fn check_body<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
instance: Instance<'tcx>,
promoted: Option<mir::Promoted>,
cid: GlobalId<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) {
let (res, ecx) = eval_body_and_ecx(tcx, instance, promoted, param_env);
let (res, ecx) = eval_body_and_ecx(tcx, cid, param_env);
if let Err(mut err) = res {
ecx.report(&mut err);
}
@ -59,26 +56,22 @@ pub fn check_body<'a, 'tcx>(
fn eval_body_and_ecx<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
instance: Instance<'tcx>,
promoted: Option<mir::Promoted>,
cid: GlobalId<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'tcx, CompileTimeEvaluator>) {
debug!("eval_body: {:?}, {:?}", instance, param_env);
debug!("eval_body: {:?}, {:?}", cid, param_env);
let limits = super::ResourceLimits::default();
let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ());
let cid = GlobalId {
instance,
promoted,
};
let res = (|| {
if ecx.tcx.has_attr(instance.def_id(), "linkage") {
let mut mir = ecx.load_mir(cid.instance.def)?;
if let Some(index) = cid.promoted {
mir = &mir.promoted[index];
}
let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
if ecx.tcx.has_attr(cid.instance.def_id(), "linkage") {
return Err(ConstEvalError::NotConst("extern global".to_string()).into());
}
let instance_ty = instance.ty(tcx);
if tcx.interpret_interner.borrow().get_cached(cid).is_none() {
let mir = ecx.load_mir(instance.def)?;
let layout = ecx.layout_of(instance_ty)?;
assert!(!layout.is_unsized());
let ptr = ecx.memory.allocate(
layout.size.bytes(),
@ -87,10 +80,10 @@ fn eval_body_and_ecx<'a, 'tcx>(
)?;
tcx.interpret_interner.borrow_mut().cache(cid, ptr.alloc_id);
let cleanup = StackPopCleanup::MarkStatic(Mutability::Immutable);
let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id()));
let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id()));
trace!("const_eval: pushing stack frame for global: {}", name);
ecx.push_stack_frame(
instance,
cid.instance,
mir.span,
mir,
Place::from_ptr(ptr, layout.align),
@ -100,24 +93,22 @@ fn eval_body_and_ecx<'a, 'tcx>(
while ecx.step()? {}
}
let alloc = tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached");
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)? {
let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? {
Some(val) => val,
_ => Value::ByRef(ptr, align),
_ => Value::ByRef(ptr, layout.align),
};
Ok((value, ptr, instance_ty))
Ok((value, ptr, layout.ty))
})();
(res, ecx)
}
pub fn eval_body_as_integer<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cid: GlobalId<'tcx>,
param_env: ty::ParamEnv<'tcx>,
instance: Instance<'tcx>,
promoted: Option<mir::Promoted>,
) -> EvalResult<'tcx, u128> {
let (value, _, ty) = eval_body(tcx, instance, promoted, param_env)?;
let (value, _, ty) = eval_body(tcx, cid, param_env)?;
match value {
Value::ByVal(prim) => prim.to_bytes(),
_ => err!(TypeNotPrimitive(ty)),
@ -325,7 +316,7 @@ fn const_val_field_inner<'a, 'tcx>(
field: mir::Field,
value: Value,
ty: Ty<'tcx>,
) -> ::rustc::mir::interpret::EvalResult<'tcx, (Value, Ty<'tcx>)> {
) -> EvalResult<'tcx, (Value, Ty<'tcx>)> {
trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
let (mut field, ty) = match value {
@ -376,51 +367,47 @@ pub fn const_discr<'a, 'tcx>(
pub fn const_eval_provider<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc::middle::const_val::EvalResult<'tcx> {
trace!("const eval: {:?}", key);
let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, key) {
resolved
} else {
return Err(ConstEvalErr {
span: tcx.def_span(key.value.0),
kind: TypeckError
});
};
let cid = key.value;
let def_id = cid.instance.def.def_id();
let span = tcx.def_span(def_id);
let tables = tcx.typeck_tables_of(def_id);
let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
let body_id = tcx.hir.body_owned_by(id);
if let Some(id) = tcx.hir.as_local_node_id(def_id) {
let tables = tcx.typeck_tables_of(def_id);
// Do match-check before building MIR
if tcx.check_match(def_id).is_err() {
return Err(ConstEvalErr {
span: tcx.def_span(key.value.0),
span,
kind: CheckMatchError,
});
}
tcx.mir_const_qualif(def_id);
tcx.hir.body(body_id)
} else {
tcx.extern_const_body(def_id).body
if let hir::BodyOwnerKind::Const = tcx.hir.body_owner_kind(id) {
tcx.mir_const_qualif(def_id);
}
// Do not continue into miri if typeck errors occurred; it will fail horribly
if tables.tainted_by_errors {
return Err(ConstEvalErr {
span,
kind: TypeckError
});
}
};
// do not continue into miri if typeck errors occurred
// it will fail horribly
if tables.tainted_by_errors {
return Err(ConstEvalErr { span: body.value.span, kind: TypeckError })
}
let instance = ty::Instance::new(def_id, substs);
match ::interpret::eval_body(tcx, instance, None, key.param_env) {
match ::interpret::eval_body(tcx, cid, 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() })
Err(ConstEvalErr {
span,
kind: err.into()
})
}
}
}

View File

@ -93,6 +93,7 @@ use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
use rustc::infer::anon_types::AnonTypeDecl;
use rustc::infer::type_variable::{TypeVariableOrigin};
use rustc::middle::region;
use rustc::mir::interpret::{GlobalId};
use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode};
use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate};
@ -3999,7 +4000,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let count_def_id = tcx.hir.body_owner_def_id(count);
let param_env = ty::ParamEnv::empty(traits::Reveal::UserFacing);
let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
let count = tcx.const_eval(param_env.and((count_def_id, substs)));
let instance = ty::Instance::resolve(
tcx.global_tcx(),
param_env,
count_def_id,
substs,
).unwrap();
let global_id = GlobalId {
instance,
promoted: None
};
let count = tcx.const_eval(param_env.and(global_id));
if let Err(ref err) = count {
err.report(tcx, tcx.def_span(count_def_id), "constant expression");

View File

@ -38,7 +38,7 @@ use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
use rustc::ty::maps::Providers;
use rustc::ty::util::IntTypeExt;
use rustc::util::nodemap::{FxHashSet, FxHashMap};
use rustc::mir::interpret::{Value, PrimVal};
use rustc::mir::interpret::{GlobalId, Value, PrimVal};
use rustc_const_math::ConstInt;
@ -524,7 +524,12 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
prev_discr = Some(if let Some(e) = variant.node.disr_expr {
let expr_did = tcx.hir.local_def_id(e.node_id);
let substs = Substs::identity_for_item(tcx, expr_did);
let result = tcx.at(variant.span).const_eval(param_env.and((expr_did, substs)));
let instance = ty::Instance::new(expr_did, substs);
let global_id = GlobalId {
instance,
promoted: None
};
let result = tcx.at(variant.span).const_eval(param_env.and(global_id));
// enum variant evaluation happens before the global constant check
// so we need to report the real error