diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index ed46296389da..6824c015eabc 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -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> }, diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 67b4cfb6fa7e..40204943bb59 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -585,3 +585,5 @@ impl<'gcx> HashStable> for mir::ClosureOutlivesSubjec } } } + +impl_stable_hash_for!(struct mir::interpret::GlobalId<'tcx> { instance, promoted }); diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 08a42e61ea00..a25741c95aac 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -926,13 +926,13 @@ impl<'gcx> HashStable> 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); } } } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 2f3e19d92bcd..2eeef70a14e0 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -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))) - } - } } } } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 3fe72344e8fe..a9dc49157437 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -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 => {} } } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 600b4a515f0b..91d86394b019 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -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 => { diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index d880b022e2f1..21affcbc9ede 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -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())) } } diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs index 3dd482ad1640..8fb1ad0da823 100644 --- a/src/librustc/ty/maps/keys.rs +++ b/src/librustc/ty/maps/keys.rs @@ -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 diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 43a71f1c0d36..f41bdf61d9bf 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -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 } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8c955bf340e8..02bf409f33f4 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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))), .. diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 2cbe9da88b51..bae1ce31a5e7 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -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), diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index ad66cbd9eab3..7cc509f69141 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -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 { - 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 { + 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>(&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 { diff --git a/src/librustc_mir/const_eval/check.rs b/src/librustc_mir/const_eval/check.rs index 70435c16ff72..a9508defdcd8 100644 --- a/src/librustc_mir/const_eval/check.rs +++ b/src/librustc_mir/const_eval/check.rs @@ -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) diff --git a/src/librustc_mir/const_eval/pattern.rs b/src/librustc_mir/const_eval/pattern.rs index 48438e7dbfd5..a70ee2d1d644 100644 --- a/src/librustc_mir/const_eval/pattern.rs +++ b/src/librustc_mir/const_eval/pattern.rs @@ -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) => { diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index e65f8f3f683f..dc8bbdc60e03 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -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") }; diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 6929bccaa950..48f123b1f57a 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -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, + 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, + 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, + 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, ) -> 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() + }) } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 26b964933102..1ad26b4cda59 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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"); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 595ae463ab0f..0271ad269e12 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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