From 95a3dd14ad718af7b94c301c8f9c0bc71d8cf630 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Sun, 15 Dec 2019 20:12:06 +1300 Subject: [PATCH 1/8] Turn const eval queries in canonical queries, and add inference context into mir execution context. --- src/librustc/dep_graph/dep_node.rs | 2 +- src/librustc/infer/canonical/canonicalizer.rs | 11 +- src/librustc/infer/canonical/mod.rs | 11 + src/librustc/mir/interpret/mod.rs | 3 + src/librustc/mir/interpret/queries.rs | 52 ++- src/librustc/query/mod.rs | 10 +- src/librustc/traits/fulfill.rs | 26 +- src/librustc/traits/select.rs | 19 +- src/librustc/ty/query/keys.rs | 14 +- src/librustc/ty/query/mod.rs | 3 +- src/librustc_mir/const_eval.rs | 54 ++-- src/librustc_mir/const_eval/error.rs | 2 +- src/librustc_mir/const_eval/eval_queries.rs | 305 ++++++++++-------- src/librustc_mir/const_eval/machine.rs | 24 +- src/librustc_mir/interpret/cast.rs | 2 +- src/librustc_mir/interpret/eval_context.rs | 51 ++- src/librustc_mir/interpret/intern.rs | 18 +- src/librustc_mir/interpret/intrinsics.rs | 7 +- .../interpret/intrinsics/caller_location.rs | 2 +- src/librustc_mir/interpret/machine.rs | 25 +- src/librustc_mir/interpret/memory.rs | 22 +- src/librustc_mir/interpret/operand.rs | 6 +- src/librustc_mir/interpret/operator.rs | 4 +- src/librustc_mir/interpret/place.rs | 2 +- src/librustc_mir/interpret/step.rs | 2 +- src/librustc_mir/interpret/terminator.rs | 2 +- src/librustc_mir/interpret/traits.rs | 2 +- src/librustc_mir/interpret/validity.rs | 14 +- src/librustc_mir/interpret/visitor.rs | 38 ++- src/librustc_mir/transform/const_prop.rs | 58 ++-- 30 files changed, 455 insertions(+), 336 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 858627a1e8962..4818516a76aae 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -52,7 +52,7 @@ use crate::hir::map::DefPathHash; use crate::ich::{Fingerprint, StableHashingContext}; use crate::mir; -use crate::mir::interpret::GlobalId; +use crate::mir::interpret::ConstEvalInput; use crate::traits; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index b720168f3563e..d86b8813e0862 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -13,12 +13,12 @@ use crate::infer::InferCtxt; use crate::ty::flags::FlagComputation; use crate::ty::fold::{TypeFoldable, TypeFolder}; use crate::ty::subst::GenericArg; -use crate::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags}; -use std::sync::atomic::Ordering; +use crate::ty::{self, BoundVar, InferConst, Ty, TyCtxt, TypeFlags}; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::Idx; use smallvec::SmallVec; +use std::sync::atomic::Ordering; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// Canonicalizes a query value `V`. When we canonicalize a query, @@ -496,12 +496,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { // Fast path: nothing that needs to be canonicalized. if !value.has_type_flags(needs_canonical_flags) { - let canon_value = Canonical { - max_universe: ty::UniverseIndex::ROOT, - variables: List::empty(), - value: value.clone(), - }; - return canon_value; + return Canonical::empty(value.clone()); } let mut canonicalizer = Canonicalizer { diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index a588d3d028a2c..8f6b19877b4d1 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -266,6 +266,17 @@ impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> { } } +impl<'tcx, V: TypeFoldable<'tcx>> Canonical<'tcx, V> { + pub fn empty(value: V) -> Canonical<'tcx, V> { + assert!(!value.has_local_value() && !value.has_placeholders()); + Canonical { + max_universe: ty::UniverseIndex::ROOT, + variables: List::empty(), + value: value.clone(), + } + } +} + impl<'tcx, V> Canonical<'tcx, V> { /// Allows you to map the `value` of a canonical while keeping the /// same set of bound variables. diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 99113d6ef1836..d94a2f72e4602 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -115,6 +115,7 @@ pub use self::allocation::{Allocation, AllocationExtra, Relocations, UndefMask}; pub use self::pointer::{CheckInAllocMsg, Pointer, PointerArithmetic}; +use crate::infer::canonical::Canonical; use crate::mir; use crate::ty::codec::TyDecoder; use crate::ty::layout::{self, Size}; @@ -147,6 +148,8 @@ pub struct GlobalId<'tcx> { pub promoted: Option, } +pub type ConstEvalInput<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>>; + #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)] pub struct AllocId(pub u64); diff --git a/src/librustc/mir/interpret/queries.rs b/src/librustc/mir/interpret/queries.rs index 161c9a3fcc1f7..7b0a3e109c8f0 100644 --- a/src/librustc/mir/interpret/queries.rs +++ b/src/librustc/mir/interpret/queries.rs @@ -1,5 +1,7 @@ use super::{ConstEvalResult, ErrorHandled, GlobalId}; +use crate::infer::canonical::{Canonical, OriginalQueryValues}; +use crate::infer::InferCtxt; use crate::mir; use crate::ty::subst::{InternalSubsts, SubstsRef}; use crate::ty::{self, TyCtxt}; @@ -19,7 +21,7 @@ impl<'tcx> TyCtxt<'tcx> { let instance = ty::Instance::new(def_id, substs); let cid = GlobalId { instance, promoted: None }; let param_env = self.param_env(def_id).with_reveal_all(); - self.const_eval_validated(param_env.and(cid)) + self.const_eval_validated(Canonical::empty(param_env.and(cid))) } /// Resolves and evaluates a constant. @@ -38,12 +40,8 @@ impl<'tcx> TyCtxt<'tcx> { substs: SubstsRef<'tcx>, span: Option, ) -> ConstEvalResult<'tcx> { - let instance = ty::Instance::resolve(self, param_env, def_id, substs); - if let Some(instance) = instance { - self.const_eval_instance(param_env, instance, span) - } else { - Err(ErrorHandled::TooGeneric) - } + self.infer_ctxt() + .enter(|ref infcx| infcx.const_eval_resolve(param_env, def_id, substs, span)) } pub fn const_eval_instance( @@ -53,10 +51,11 @@ impl<'tcx> TyCtxt<'tcx> { span: Option, ) -> ConstEvalResult<'tcx> { let cid = GlobalId { instance, promoted: None }; + let canonical = Canonical::empty(param_env.and(cid)); if let Some(span) = span { - self.at(span).const_eval_validated(param_env.and(cid)) + self.at(span).const_eval_validated(canonical) } else { - self.const_eval_validated(param_env.and(cid)) + self.const_eval_validated(canonical) } } @@ -68,6 +67,39 @@ impl<'tcx> TyCtxt<'tcx> { ) -> ConstEvalResult<'tcx> { let cid = GlobalId { instance, promoted: Some(promoted) }; let param_env = ty::ParamEnv::reveal_all(); - self.const_eval_validated(param_env.and(cid)) + self.const_eval_validated(Canonical::empty(param_env.and(cid))) + } +} + +impl<'a, 'tcx> InferCtxt<'a, 'tcx> { + pub fn const_eval_instance( + &self, + param_env: ty::ParamEnv<'tcx>, + instance: ty::Instance<'tcx>, + span: Option, + ) -> ConstEvalResult<'tcx> { + let cid = GlobalId { instance, promoted: None }; + let mut orig_values = OriginalQueryValues::default(); + let canonical = self.canonicalize_query(¶m_env.and(cid), &mut orig_values); + if let Some(span) = span { + self.tcx.at(span).const_eval_validated(canonical) + } else { + self.tcx.const_eval_validated(canonical) + } + } + + pub fn const_eval_resolve( + &self, + param_env: ty::ParamEnv<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, + span: Option, + ) -> ConstEvalResult<'tcx> { + let instance = ty::Instance::resolve(self, param_env, def_id, substs); + if let Some(instance) = instance { + self.const_eval_instance(param_env, instance, span) + } else { + Err(ErrorHandled::TooGeneric) + } } } diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 4a2ec9b9687f3..baadb0cbb8421 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -1,6 +1,6 @@ use crate::dep_graph::{DepKind, DepNode, RecoverKey, SerializedDepNodeIndex}; use crate::mir; -use crate::mir::interpret::GlobalId; +use crate::mir::interpret::ConstEvalInput; use crate::traits; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, @@ -467,12 +467,12 @@ rustc_queries! { /// during validation. Please add a comment to every use site explaining why using /// `const_eval_validated` isn't sufficient. The returned constant also isn't in a suitable /// form to be used outside of const eval. - query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + query const_eval_raw(key: ConstEvalInput<'tcx>) -> ConstEvalRawResult<'tcx> { no_force desc { |tcx| "const-evaluating `{}`", - tcx.def_path_str(key.value.instance.def.def_id()) + tcx.def_path_str(key.value.value.instance.def.def_id()) } } @@ -484,12 +484,12 @@ rustc_queries! { /// /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`, /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_promoted`. - query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + query const_eval_validated(key: ConstEvalInput<'tcx>) -> ConstEvalResult<'tcx> { no_force desc { |tcx| "const-evaluating + checking `{}`", - tcx.def_path_str(key.value.instance.def.def_id()) + tcx.def_path_str(key.value.value.instance.def.def_id()) } cache_on_disk_if(_, opt_result) { // Only store results without errors diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 614375287ba6e..f918a1a235a05 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -15,6 +15,7 @@ use super::CodeSelectionError; use super::{ConstEvalFailure, Unimplemented}; use super::{FulfillmentError, FulfillmentErrorCode}; use super::{ObligationCause, PredicateObligation}; +use crate::mir::interpret::ErrorHandled; impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { type Predicate = ty::Predicate<'tcx>; @@ -506,26 +507,19 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } ty::Predicate::ConstEvaluatable(def_id, substs) => { - if obligation.param_env.has_local_value() { - ProcessResult::Unchanged - } else { - if !substs.has_local_value() { - match self.selcx.tcx().const_eval_resolve( - obligation.param_env, - def_id, - substs, - Some(obligation.cause.span), - ) { - Ok(_) => ProcessResult::Changed(vec![]), - Err(err) => { - ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))) - } - } - } else { + match self.selcx.infcx().const_eval_resolve( + obligation.param_env, + def_id, + substs, + Some(obligation.cause.span), + ) { + Ok(_) => ProcessResult::Changed(vec![]), + Err(ErrorHandled::TooGeneric) => { pending_obligation.stalled_on = substs.types().map(|ty| infer_ty(ty)).collect(); ProcessResult::Unchanged } + Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))), } } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 94d5723778a9a..5a5b813d436c8 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -32,6 +32,7 @@ use super::{ use crate::dep_graph::{DepKind, DepNodeIndex}; use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener}; use crate::middle::lang_items; +use crate::mir::interpret::ErrorHandled; use crate::ty::fast_reject; use crate::ty::relate::TypeRelation; use crate::ty::subst::{Subst, SubstsRef}; @@ -799,15 +800,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::Predicate::ConstEvaluatable(def_id, substs) => { - if !(obligation.param_env, substs).has_local_value() { - match self.tcx().const_eval_resolve(obligation.param_env, def_id, substs, None) - { - Ok(_) => Ok(EvaluatedToOk), - Err(_) => Ok(EvaluatedToErr), - } - } else { - // Inference variables still left in param_env or substs. - Ok(EvaluatedToAmbig) + match self.infcx.const_eval_resolve( + obligation.param_env, + def_id, + substs, + Some(obligation.cause.span), + ) { + Ok(_) => Ok(EvaluatedToOk), + Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig), + Err(_) => Ok(EvaluatedToErr), } } } diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs index 8a713e3b6a096..bfd3e2b00c3d2 100644 --- a/src/librustc/ty/query/keys.rs +++ b/src/librustc/ty/query/keys.rs @@ -199,15 +199,25 @@ impl Key for Symbol { /// Canonical query goals correspond to abstract trait operations that /// are not tied to any crate in particular. impl<'tcx, T> Key for Canonical<'tcx, T> { - fn query_crate(&self) -> CrateNum { + default fn query_crate(&self) -> CrateNum { LOCAL_CRATE } - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { + default fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } } +impl<'tcx, T: Key> Key for Canonical<'tcx, T> { + fn query_crate(&self) -> CrateNum { + self.value.query_crate() + } + + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + self.value.default_span(tcx) + } +} + impl Key for (Symbol, u32, u32) { fn query_crate(&self) -> CrateNum { LOCAL_CRATE diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index b163d23e2394b..a717366d8cb1d 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -13,8 +13,7 @@ use crate::middle::region; use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLifetimes}; use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; -use crate::mir::interpret::GlobalId; -use crate::mir::interpret::{ConstEvalRawResult, ConstEvalResult}; +use crate::mir::interpret::{ConstEvalInput, ConstEvalRawResult, ConstEvalResult}; use crate::mir::mono::CodegenUnit; use crate::session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use crate::session::CrateDisambiguator; diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index ac04ae285884b..c0fe5ee72e5ef 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -26,19 +26,20 @@ pub(crate) fn const_field<'tcx>( value: &'tcx ty::Const<'tcx>, ) -> &'tcx ty::Const<'tcx> { trace!("const_field: {:?}, {:?}", field, value); - let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); - // get the operand again - let op = ecx.eval_const_to_op(value, None).unwrap(); - // downcast - let down = match variant { - None => op, - Some(variant) => ecx.operand_downcast(op, variant).unwrap(), - }; - // then project - let field = ecx.operand_field(down, field.index() as u64).unwrap(); - // and finally move back to the const world, always normalizing because - // this is not called for statics. - op_to_const(&ecx, field) + enter_eval_cx(tcx, DUMMY_SP, param_env, false, |ecx| { + // get the operand again + let op = ecx.eval_const_to_op(value, None).unwrap(); + // downcast + let down = match variant { + None => op, + Some(variant) => ecx.operand_downcast(op, variant).unwrap(), + }; + // then project + let field = ecx.operand_field(down, field.index() as u64).unwrap(); + // and finally move back to the const world, always normalizing because + // this is not called for statics. + op_to_const(&ecx, field) + }) } pub(crate) fn const_caller_location<'tcx>( @@ -46,17 +47,17 @@ pub(crate) fn const_caller_location<'tcx>( (file, line, col): (Symbol, u32, u32), ) -> &'tcx ty::Const<'tcx> { trace!("const_caller_location: {}:{}:{}", file, line, col); - let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false); + enter_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false, |mut ecx| { + let loc_ty = tcx.caller_location_ty(); + let loc_place = ecx.alloc_caller_location(file, line, col); + intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap(); + let loc_const = ty::Const { + ty: loc_ty, + val: ty::ConstKind::Value(ConstValue::Scalar(loc_place.ptr.into())), + }; - let loc_ty = tcx.caller_location_ty(); - let loc_place = ecx.alloc_caller_location(file, line, col); - intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap(); - let loc_const = ty::Const { - ty: loc_ty, - val: ty::ConstKind::Value(ConstValue::Scalar(loc_place.ptr.into())), - }; - - tcx.mk_const(loc_const) + tcx.mk_const(loc_const) + }) } // this function uses `unwrap` copiously, because an already validated constant must have valid @@ -67,7 +68,8 @@ pub(crate) fn const_variant_index<'tcx>( val: &'tcx ty::Const<'tcx>, ) -> VariantIdx { trace!("const_variant_index: {:?}", val); - let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); - let op = ecx.eval_const_to_op(val, None).unwrap(); - ecx.read_discriminant(op).unwrap().1 + enter_eval_cx(tcx, DUMMY_SP, param_env, false, |ecx| { + let op = ecx.eval_const_to_op(val, None).unwrap(); + ecx.read_discriminant(op).unwrap().1 + }) } diff --git a/src/librustc_mir/const_eval/error.rs b/src/librustc_mir/const_eval/error.rs index c2db3c31f85be..740d734f4586a 100644 --- a/src/librustc_mir/const_eval/error.rs +++ b/src/librustc_mir/const_eval/error.rs @@ -33,7 +33,7 @@ impl Error for ConstEvalError {} /// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace. /// Should be called only if the error is actually going to to be reported! pub fn error_to_const_error<'mir, 'tcx, M: Machine<'mir, 'tcx>>( - ecx: &InterpCx<'mir, 'tcx, M>, + ecx: &InterpCx<'_, 'mir, 'tcx, M>, mut error: InterpErrorInfo<'tcx>, ) -> ConstEvalErr<'tcx> { error.print_backtrace(); diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index dbeb75b60c290..4a3fe2268b73d 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -6,9 +6,9 @@ use crate::interpret::{ StackPopCleanup, }; use rustc::mir; -use rustc::mir::interpret::{ConstEvalErr, ErrorHandled}; +use rustc::mir::interpret::{ConstEvalErr, ConstEvalInput, ErrorHandled}; use rustc::traits::Reveal; -use rustc::ty::{self, layout, layout::LayoutOf, subst::Subst, TyCtxt}; +use rustc::ty::{self, layout, layout::LayoutOf, subst::Subst, ParamEnvAnd, TyCtxt}; use rustc_hir::def::DefKind; use rustc_span::source_map::Span; use std::convert::TryInto; @@ -20,8 +20,8 @@ pub fn note_on_undefined_behavior_error() -> &'static str { } // Returns a pointer to where the result lives -fn eval_body_using_ecx<'mir, 'tcx>( - ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, +fn eval_body_using_ecx<'infcx, 'mir, 'tcx>( + ecx: &mut CompileTimeEvalContext<'infcx, 'mir, 'tcx>, cid: GlobalId<'tcx>, body: &'mir mir::Body<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { @@ -68,24 +68,29 @@ fn eval_body_using_ecx<'mir, 'tcx>( /// The function containing the `match` that is currently being analyzed may have generic bounds /// that inform us about the generic bounds of the constant. E.g., using an associated constant /// of a function's generic parameter will require knowledge about the bounds on the generic -/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. -pub(super) fn mk_eval_cx<'mir, 'tcx>( +/// parameter. These bounds are passed to `enter_eval_cx` via the `ParamEnv` argument. +pub(super) fn enter_eval_cx<'mir, 'tcx: 'mir, R>( tcx: TyCtxt<'tcx>, span: Span, param_env: ty::ParamEnv<'tcx>, can_access_statics: bool, -) -> CompileTimeEvalContext<'mir, 'tcx> { - debug!("mk_eval_cx: {:?}", param_env); - InterpCx::new( - tcx.at(span), - param_env, - CompileTimeInterpreter::new(), - MemoryExtra { can_access_statics }, - ) + f: impl for<'infcx> FnOnce(CompileTimeEvalContext<'infcx, 'mir, 'tcx>) -> R, +) -> R { + debug!("enter_eval_cx: {:?}", param_env); + tcx.infer_ctxt().enter(|ref infcx| { + let ecx = InterpCx::new( + tcx.at(span), + infcx, + param_env, + CompileTimeInterpreter::new(), + MemoryExtra { can_access_statics }, + ); + f(ecx) + }) } pub(super) fn op_to_const<'tcx>( - ecx: &CompileTimeEvalContext<'_, 'tcx>, + ecx: &CompileTimeEvalContext<'_, '_, 'tcx>, op: OpTy<'tcx>, ) -> &'tcx ty::Const<'tcx> { // We do not have value optimizations for everything. @@ -160,56 +165,70 @@ pub(super) fn op_to_const<'tcx>( fn validate_and_turn_into_const<'tcx>( tcx: TyCtxt<'tcx>, constant: RawConst<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, + key: ConstEvalInput<'tcx>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { - let cid = key.value; - let def_id = cid.instance.def.def_id(); - let is_static = tcx.is_static(def_id); - let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static); - let val = (|| { - let mplace = ecx.raw_const_to_mplace(constant)?; - let mut ref_tracking = RefTracking::new(mplace); - while let Some((mplace, path)) = ref_tracking.todo.pop() { - ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?; - } - // Now that we validated, turn this into a proper constant. - // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides - // whether they become immediates. - if is_static || cid.promoted.is_some() { - let ptr = mplace.ptr.assert_ptr(); - Ok(tcx.mk_const(ty::Const { - val: ty::ConstKind::Value(ConstValue::ByRef { - alloc: ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), - offset: ptr.offset, - }), - ty: mplace.layout.ty, - })) - } else { - Ok(op_to_const(&ecx, mplace.into())) - } - })(); + let span = tcx.def_span(key.value.value.instance.def_id()); + tcx.infer_ctxt().enter_with_canonical( + span, + &key, + |ref infcx, ty::ParamEnvAnd { param_env, value: cid }, _| { + let def_id = cid.instance.def.def_id(); + let is_static = tcx.is_static(def_id); + let ecx = InterpCx::new( + tcx.at(span), + infcx, + param_env, + CompileTimeInterpreter::new(), + MemoryExtra { can_access_statics: is_static }, + ); + let val = (|| { + let mplace = ecx.raw_const_to_mplace(constant)?; + let mut ref_tracking = RefTracking::new(mplace); + while let Some((mplace, path)) = ref_tracking.todo.pop() { + ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?; + } + // Now that we validated, turn this into a proper constant. + // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides + // whether they become immediates. + if is_static || cid.promoted.is_some() { + let ptr = mplace.ptr.assert_ptr(); + Ok(tcx.mk_const(ty::Const { + val: ty::ConstKind::Value(ConstValue::ByRef { + alloc: ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), + offset: ptr.offset, + }), + ty: mplace.layout.ty, + })) + } else { + Ok(op_to_const(&ecx, mplace.into())) + } + })(); - val.map_err(|error| { - let err = error_to_const_error(&ecx, error); - match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") { - Ok(mut diag) => { - diag.note(note_on_undefined_behavior_error()); - diag.emit(); - ErrorHandled::Reported - } - Err(err) => err, - } - }) + val.map_err(|error| { + let err = error_to_const_error(&ecx, error); + match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") { + Ok(mut diag) => { + diag.note(note_on_undefined_behavior_error()); + diag.emit(); + ErrorHandled::Reported + } + Err(err) => err, + } + }) + }, + ) } pub fn const_eval_validated_provider<'tcx>( tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, + key: ConstEvalInput<'tcx>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { + let ParamEnvAnd { param_env, value: cid } = key.value; + // see comment in const_eval_raw_provider for what we're doing here - if key.param_env.reveal == Reveal::All { + if param_env.reveal == Reveal::All { let mut key = key.clone(); - key.param_env.reveal = Reveal::UserFacing; + key.value.param_env.reveal = Reveal::UserFacing; match tcx.const_eval_validated(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} @@ -220,13 +239,13 @@ pub fn const_eval_validated_provider<'tcx>( // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. // Catch such calls and evaluate them instead of trying to load a constant's MIR. - if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def { - let ty = key.value.instance.ty_env(tcx, key.param_env); + if let ty::InstanceDef::Intrinsic(def_id) = cid.instance.def { + let ty = cid.instance.ty_env(tcx, param_env); let substs = match ty.kind { ty::FnDef(_, substs) => substs, _ => bug!("intrinsic with type {:?}", ty), }; - return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| { + return eval_nullary_intrinsic(tcx, param_env, def_id, substs).map_err(|error| { let span = tcx.def_span(def_id); let error = ConstEvalErr { error: error.kind, stacktrace: vec![], span }; error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic") @@ -238,8 +257,10 @@ pub fn const_eval_validated_provider<'tcx>( pub fn const_eval_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, + key: ConstEvalInput<'tcx>, ) -> ::rustc::mir::interpret::ConstEvalRawResult<'tcx> { + let ParamEnvAnd { param_env, value: cid } = key.value; + // Because the constant is computed twice (once per value of `Reveal`), we are at risk of // reporting the same error twice here. To resolve this, we check whether we can evaluate the // constant in the more restrictive `Reveal::UserFacing`, which most likely already was @@ -248,9 +269,9 @@ pub fn const_eval_raw_provider<'tcx>( // information being available. // In case we fail in the `UserFacing` variant, we just do the real computation. - if key.param_env.reveal == Reveal::All { + if param_env.reveal == Reveal::All { let mut key = key.clone(); - key.param_env.reveal = Reveal::UserFacing; + key.value.param_env.reveal = Reveal::UserFacing; match tcx.const_eval_raw(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} @@ -264,11 +285,10 @@ pub fn const_eval_raw_provider<'tcx>( // The next two lines concatenated contain some discussion: // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/ // subject/anon_const_instance_printing/near/135980032 - let instance = key.value.instance.to_string(); + let instance = cid.instance.to_string(); trace!("const eval: {:?} ({})", key, instance); } - let cid = key.value; let def_id = cid.instance.def.def_id(); if def_id.is_local() && tcx.typeck_tables_of(def_id).tainted_by_errors { @@ -278,87 +298,94 @@ pub fn const_eval_raw_provider<'tcx>( let is_static = tcx.is_static(def_id); let span = tcx.def_span(cid.instance.def_id()); - let mut ecx = InterpCx::new( - tcx.at(span), - key.param_env, - CompileTimeInterpreter::new(), - MemoryExtra { can_access_statics: is_static }, - ); + tcx.infer_ctxt().enter_with_canonical( + span, + &key, + |ref infcx, ParamEnvAnd { param_env, value: cid }, _| { + let mut ecx = InterpCx::new( + tcx.at(span), + infcx, + param_env, + CompileTimeInterpreter::new(), + MemoryExtra { can_access_statics: is_static }, + ); - let res = ecx.load_mir(cid.instance.def, cid.promoted); - res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, *body)) - .and_then(|place| { - Ok(RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, ty: place.layout.ty }) - }) - .map_err(|error| { - let err = error_to_const_error(&ecx, error); - // errors in statics are always emitted as fatal errors - if is_static { - // Ensure that if the above error was either `TooGeneric` or `Reported` - // an error must be reported. - let v = err.report_as_error(ecx.tcx, "could not evaluate static initializer"); + let res = ecx.load_mir(cid.instance.def, cid.promoted); + res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, *body)) + .and_then(|place| { + Ok(RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, ty: place.layout.ty }) + }) + .map_err(|error| { + let err = error_to_const_error(&ecx, error); + // errors in statics are always emitted as fatal errors + if is_static { + // Ensure that if the above error was either `TooGeneric` or `Reported` + // an error must be reported. + let v = + err.report_as_error(ecx.tcx, "could not evaluate static initializer"); - // If this is `Reveal:All`, then we need to make sure an error is reported but if - // this is `Reveal::UserFacing`, then it's expected that we could get a - // `TooGeneric` error. When we fall back to `Reveal::All`, then it will either - // succeed or we'll report this error then. - if key.param_env.reveal == Reveal::All { - tcx.sess.delay_span_bug( - err.span, - &format!("static eval failure did not emit an error: {:#?}", v), - ); - } - - v - } else if def_id.is_local() { - // constant defined in this crate, we can figure out a lint level! - match tcx.def_kind(def_id) { - // constants never produce a hard error at the definition site. Anything else is - // a backwards compatibility hazard (and will break old versions of winapi for - // sure) - // - // note that validation may still cause a hard error on this very same constant, - // because any code that existed before validation could not have failed - // validation thus preventing such a hard error from being a backwards - // compatibility hazard - Some(DefKind::Const) | Some(DefKind::AssocConst) => { - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - err.report_as_lint( - tcx.at(tcx.def_span(def_id)), - "any use of this value will cause an error", - hir_id, - Some(err.span), - ) - } - // promoting runtime code is only allowed to error if it references broken - // constants any other kind of error will be reported to the user as a - // deny-by-default lint - _ => { - if let Some(p) = cid.promoted { - let span = tcx.promoted_mir(def_id)[p].span; - if let err_inval!(ReferencedConstant) = err.error { - err.report_as_error( - tcx.at(span), - "evaluation of constant expression failed", - ) - } else { + // If this is `Reveal:All`, then we need to make sure an error is reported but if + // this is `Reveal::UserFacing`, then it's expected that we could get a + // `TooGeneric` error. When we fall back to `Reveal::All`, then it will either + // succeed or we'll report this error then. + if param_env.reveal == Reveal::All { + tcx.sess.delay_span_bug( + err.span, + &format!("static eval failure did not emit an error: {:#?}", v), + ); + } + v + } else if def_id.is_local() { + // constant defined in this crate, we can figure out a lint level! + match tcx.def_kind(def_id) { + // constants never produce a hard error at the definition site. Anything else is + // a backwards compatibility hazard (and will break old versions of winapi for sure) + // + // note that validation may still cause a hard error on this very same constant, + // because any code that existed before validation could not have failed validation + // thus preventing such a hard error from being a backwards compatibility hazard + Some(DefKind::Const) | Some(DefKind::AssocConst) => { + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); err.report_as_lint( - tcx.at(span), - "reaching this expression at runtime will panic or abort", - tcx.hir().as_local_hir_id(def_id).unwrap(), + tcx.at(tcx.def_span(def_id)), + "any use of this value will cause an error", + hir_id, Some(err.span), ) } - // anything else (array lengths, enum initializers, constant patterns) are - // reported as hard errors - } else { - err.report_as_error(ecx.tcx, "evaluation of constant value failed") + // promoting runtime code is only allowed to error if it references broken constants + // any other kind of error will be reported to the user as a deny-by-default lint + _ => { + if let Some(p) = cid.promoted { + let span = tcx.promoted_mir(def_id)[p].span; + if let err_inval!(ReferencedConstant) = err.error { + err.report_as_error( + tcx.at(span), + "evaluation of constant expression failed", + ) + } else { + err.report_as_lint( + tcx.at(span), + "reaching this expression at runtime will panic or abort", + tcx.hir().as_local_hir_id(def_id).unwrap(), + Some(err.span), + ) + } + // anything else (array lengths, enum initializers, constant patterns) are reported + // as hard errors + } else { + err.report_as_error( + ecx.tcx, + "evaluation of constant value failed", + ) + } + } } + } else { + // use of broken constant from other crate + err.report_as_error(ecx.tcx, "could not evaluate constant") } - } - } else { - // use of broken constant from other crate - err.report_as_error(ecx.tcx, "could not evaluate constant") - } - }) + }) + }, + ) } diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs index 1aed91baba6a8..286f2647c821e 100644 --- a/src/librustc_mir/const_eval/machine.rs +++ b/src/librustc_mir/const_eval/machine.rs @@ -17,7 +17,7 @@ use crate::interpret::{ use super::error::*; -impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { +impl<'infcx, 'mir, 'tcx> InterpCx<'infcx, 'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { /// Evaluate a const function where all arguments (if any) are zero-sized types. /// The evaluation is memoized thanks to the query system. /// @@ -142,8 +142,8 @@ impl interpret::AllocMap for FxHashMap { } } -crate type CompileTimeEvalContext<'mir, 'tcx> = - InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>; +crate type CompileTimeEvalContext<'infcx, 'mir, 'tcx> = + InterpCx<'infcx, 'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>; impl interpret::MayLeak for ! { #[inline(always)] @@ -171,12 +171,12 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, const CHECK_ALIGN: bool = false; #[inline(always)] - fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + fn enforce_validity(_ecx: &InterpCx<'_, 'mir, 'tcx, Self>) -> bool { false // for now, we don't enforce validity } fn find_mir_or_eval_fn( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], @@ -224,7 +224,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } fn call_extra_fn( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, fn_val: !, _args: &[OpTy<'tcx>], _ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, @@ -234,7 +234,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } fn call_intrinsic( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], @@ -250,7 +250,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } fn assert_panic( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, _span: Span, msg: &AssertMessage<'tcx>, _unwind: Option, @@ -286,7 +286,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } fn binary_ptr_op( - _ecx: &InterpCx<'mir, 'tcx, Self>, + _ecx: &InterpCx<'_, 'mir, 'tcx, Self>, _bin_op: mir::BinOp, _left: ImmTy<'tcx>, _right: ImmTy<'tcx>, @@ -318,13 +318,13 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } fn box_alloc( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, _dest: PlaceTy<'tcx>, ) -> InterpResult<'tcx> { Err(ConstEvalError::NeedsRfc("heap allocations via `box` keyword".to_string()).into()) } - fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + fn before_terminator(ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>) -> InterpResult<'tcx> { { let steps = &mut ecx.machine.steps_since_detector_enabled; @@ -344,7 +344,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } #[inline(always)] - fn stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + fn stack_push(_ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>) -> InterpResult<'tcx> { Ok(()) } diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 9461a06690212..61b46a8a8e576 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -11,7 +11,7 @@ use rustc_apfloat::{Float, FloatConvert}; use super::{FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy}; -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { pub fn cast( &mut self, src: OpTy<'tcx, M::PointerTag>, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 551e3e837c988..c795432a653c0 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -10,7 +10,7 @@ use rustc::mir::interpret::{ use rustc::ty::layout::{self, Align, HasDataLayout, LayoutOf, Size, TyLayout}; use rustc::ty::query::TyCtxtAt; use rustc::ty::subst::SubstsRef; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def::DefKind; @@ -23,14 +23,18 @@ use super::{ Immediate, MPlaceTy, Machine, MemPlace, Memory, OpTy, Operand, Place, PlaceTy, ScalarMaybeUndef, StackPopInfo, }; +use rustc::infer::canonical::OriginalQueryValues; +use rustc::infer::InferCtxt; -pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { +pub struct InterpCx<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// Stores the `Machine` instance. pub machine: M, /// The results of the type checker, from rustc. pub tcx: TyCtxtAt<'tcx>, + pub(super) infcx: &'infcx InferCtxt<'infcx, 'tcx>, + /// Bounds in scope for polymorphic evaluations. pub(crate) param_env: ty::ParamEnv<'tcx>, @@ -174,14 +178,14 @@ impl<'mir, 'tcx, Tag, Extra> Frame<'mir, 'tcx, Tag, Extra> { } } -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M> { +impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'infcx, 'mir, 'tcx, M> { #[inline] fn data_layout(&self) -> &layout::TargetDataLayout { &self.tcx.data_layout } } -impl<'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpCx<'mir, 'tcx, M> +impl<'infcx, 'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpCx<'infcx, 'mir, 'tcx, M> where M: Machine<'mir, 'tcx>, { @@ -191,7 +195,7 @@ where } } -impl<'mir, 'tcx, M> layout::HasParamEnv<'tcx> for InterpCx<'mir, 'tcx, M> +impl<'infcx, 'mir, 'tcx, M> layout::HasParamEnv<'tcx> for InterpCx<'infcx, 'mir, 'tcx, M> where M: Machine<'mir, 'tcx>, { @@ -200,7 +204,7 @@ where } } -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> { +impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'infcx, 'mir, 'tcx, M> { type Ty = Ty<'tcx>; type TyLayout = InterpResult<'tcx, TyLayout<'tcx>>; @@ -212,9 +216,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> { } } -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { pub fn new( tcx: TyCtxtAt<'tcx>, + infcx: &'infcx InferCtxt<'infcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, machine: M, memory_extra: M::MemoryExtra, @@ -222,6 +227,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { InterpCx { machine, tcx, + infcx, param_env, memory: Memory::new(tcx, memory_extra), stack: Vec::new(), @@ -339,9 +345,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, value: T, ) -> T { + let mut param_env = self.param_env; + param_env.caller_bounds = + self.tcx.mk_predicates(param_env.caller_bounds.iter().filter(|predicate| { + match *predicate { + ty::Predicate::Trait(..) + | ty::Predicate::Subtype(..) + | ty::Predicate::Projection(..) + | ty::Predicate::WellFormed(..) + | ty::Predicate::ObjectSafe(..) + | ty::Predicate::ClosureKind(..) + | ty::Predicate::ConstEvaluatable(..) => true, + ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => false, + } + })); + self.tcx.subst_and_normalize_erasing_regions( self.frame().instance.substs, - self.param_env, + param_env, &value, ) } @@ -756,14 +777,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub(super) fn const_eval( &self, - gid: GlobalId<'tcx>, + instance: Instance<'tcx>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - let val = if self.tcx.is_static(gid.instance.def_id()) { - self.tcx.const_eval_poly(gid.instance.def_id())? - } else if let Some(promoted) = gid.promoted { - self.tcx.const_eval_promoted(gid.instance, promoted)? + let val = if self.tcx.is_static(instance.def_id()) { + self.tcx.const_eval_poly(instance.def_id())? } else { - self.tcx.const_eval_instance(self.param_env, gid.instance, Some(self.tcx.span))? + self.infcx.const_eval_instance(self.param_env, instance, Some(self.tcx.span))? }; // Even though `ecx.const_eval` is called from `eval_const_to_op` we can never have a // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not @@ -786,11 +805,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { self.param_env }; + let mut orig_values = OriginalQueryValues::default(); + let canonical = self.infcx.canonicalize_query(¶m_env.and(gid), &mut orig_values); // We use `const_eval_raw` here, and get an unvalidated result. That is okay: // Our result will later be validated anyway, and there seems no good reason // to have to fail early here. This is also more consistent with // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles. - let val = self.tcx.const_eval_raw(param_env.and(gid))?; + let val = self.tcx.const_eval_raw(canonical)?; self.raw_const_to_mplace(val) } diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index 7c6129ef30ffd..ff9156d206f4f 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -24,9 +24,9 @@ pub trait CompileTimeMachine<'mir, 'tcx> = Machine< MemoryMap = FxHashMap, Allocation)>, >; -struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> { +struct InternVisitor<'rt, 'infcx, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> { /// The ectx from which we intern. - ecx: &'rt mut InterpCx<'mir, 'tcx, M>, + ecx: &'rt mut InterpCx<'infcx, 'mir, 'tcx, M>, /// Previously encountered safe references. ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>, /// A list of all encountered allocations. After type-based interning, we traverse this list to @@ -67,7 +67,7 @@ struct IsStaticOrFn; /// `ty` can be `None` if there is no potential interior mutability /// to account for (e.g. for vtables). fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( - ecx: &'rt mut InterpCx<'mir, 'tcx, M>, + ecx: &'rt mut InterpCx<'_, 'mir, 'tcx, M>, leftover_allocations: &'rt mut FxHashSet, mode: InternMode, alloc_id: AllocId, @@ -132,7 +132,9 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( Ok(None) } -impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir, 'tcx, M> { +impl<'rt, 'infcx, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> + InternVisitor<'rt, 'infcx, 'mir, 'tcx, M> +{ fn intern_shallow( &mut self, alloc_id: AllocId, @@ -143,13 +145,13 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir } } -impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> - for InternVisitor<'rt, 'mir, 'tcx, M> +impl<'rt, 'infcx, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'infcx, 'mir, 'tcx, M> + for InternVisitor<'rt, 'infcx, 'mir, 'tcx, M> { type V = MPlaceTy<'tcx>; #[inline(always)] - fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> { + fn ecx(&self) -> &InterpCx<'infcx, 'mir, 'tcx, M> { &self.ecx } @@ -261,7 +263,7 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx } pub fn intern_const_alloc_recursive>( - ecx: &mut InterpCx<'mir, 'tcx, M>, + ecx: &mut InterpCx<'_, 'mir, 'tcx, M>, // The `mutability` of the place, ignoring the type. place_mut: Option, ret: MPlaceTy<'tcx>, diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index cd6d94357e414..bfedd90975fe9 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -4,7 +4,7 @@ use rustc::mir::{ self, - interpret::{ConstValue, GlobalId, InterpResult, Scalar}, + interpret::{ConstValue, InterpResult, Scalar}, BinOp, }; use rustc::ty; @@ -81,7 +81,7 @@ crate fn eval_nullary_intrinsic<'tcx>( }) } -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { /// Returns `true` if emulation happened. pub fn emulate_intrinsic( &mut self, @@ -118,8 +118,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | sym::size_of | sym::type_id | sym::type_name => { - let gid = GlobalId { instance, promoted: None }; - let val = self.const_eval(gid)?; + let val = self.const_eval(instance)?; self.copy_op(val, dest)?; } diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs index 0525108d2d129..270e4aaf54626 100644 --- a/src/librustc_mir/interpret/intrinsics/caller_location.rs +++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs @@ -8,7 +8,7 @@ use crate::interpret::{ MPlaceTy, MemoryKind, Scalar, }; -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a /// frame which is not `#[track_caller]`. If the first frame found lacks `#[track_caller]`, then /// `None` is returned and the callsite of the function invocation itself should be used. diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 6d15827536c55..b67cc9a8d0477 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -121,11 +121,11 @@ pub trait Machine<'mir, 'tcx>: Sized { const CHECK_ALIGN: bool; /// Whether to enforce the validity invariant - fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + fn enforce_validity(ecx: &InterpCx<'_, 'mir, 'tcx, Self>) -> bool; /// Called before a basic block terminator is executed. /// You can use this to detect endlessly running programs. - fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>; + fn before_terminator(ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>) -> InterpResult<'tcx>; /// Entry point to all function calls. /// @@ -138,7 +138,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them /// was used. fn find_mir_or_eval_fn( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Self::PointerTag>], @@ -149,7 +149,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Execute `fn_val`. It is the hook's responsibility to advance the instruction /// pointer as appropriate. fn call_extra_fn( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, fn_val: Self::ExtraFnVal, args: &[OpTy<'tcx, Self::PointerTag>], ret: Option<(PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>, @@ -159,7 +159,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Directly process an intrinsic without pushing a stack frame. It is the hook's /// responsibility to advance the instruction pointer as appropriate. fn call_intrinsic( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Self::PointerTag>], @@ -169,7 +169,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Called to evaluate `Assert` MIR terminators that trigger a panic. fn assert_panic( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, span: Span, msg: &AssertMessage<'tcx>, unwind: Option, @@ -191,7 +191,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// /// Returns a (value, overflowed) pair if the operation succeeded fn binary_ptr_op( - ecx: &InterpCx<'mir, 'tcx, Self>, + ecx: &InterpCx<'_, 'mir, 'tcx, Self>, bin_op: mir::BinOp, left: ImmTy<'tcx, Self::PointerTag>, right: ImmTy<'tcx, Self::PointerTag>, @@ -199,13 +199,13 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Heap allocations via the `box` keyword. fn box_alloc( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, dest: PlaceTy<'tcx, Self::PointerTag>, ) -> InterpResult<'tcx>; /// Called to read the specified `local` from the `frame`. fn access_local( - _ecx: &InterpCx<'mir, 'tcx, Self>, + _ecx: &InterpCx<'_, 'mir, 'tcx, Self>, frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, local: mir::Local, ) -> InterpResult<'tcx, Operand> { @@ -252,7 +252,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Executes a retagging operation #[inline] fn retag( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, _kind: mir::RetagKind, _place: PlaceTy<'tcx, Self::PointerTag>, ) -> InterpResult<'tcx> { @@ -260,11 +260,12 @@ pub trait Machine<'mir, 'tcx>: Sized { } /// Called immediately before a new stack frame got pushed - fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, Self::FrameExtra>; + fn stack_push(ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>) + -> InterpResult<'tcx, Self::FrameExtra>; /// Called immediately after a stack frame gets popped fn stack_pop( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, _extra: Self::FrameExtra, _unwinding: bool, ) -> InterpResult<'tcx, StackPopInfo> { diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index cb676821fd438..87e0f71491fef 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -20,6 +20,7 @@ use super::{ AllocId, AllocMap, Allocation, AllocationExtra, CheckInAllocMsg, ErrorHandled, GlobalAlloc, GlobalId, InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Scalar, }; +use rustc::infer::canonical::Canonical; #[derive(Debug, PartialEq, Copy, Clone)] pub enum MemoryKind { @@ -442,16 +443,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { let gid = GlobalId { instance, promoted: None }; // use the raw query here to break validation cycles. Later uses of the static // will call the full query anyway - let raw_const = - tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| { - // no need to report anything, the const_eval call takes care of that - // for statics - assert!(tcx.is_static(def_id)); - match err { - ErrorHandled::Reported => err_inval!(ReferencedConstant), - ErrorHandled::TooGeneric => err_inval!(TooGeneric), - } - })?; + + let canonical = Canonical::empty(ty::ParamEnv::reveal_all().and(gid)); + let raw_const = tcx.const_eval_raw(canonical).map_err(|err| { + // no need to report anything, the const_eval call takes care of that + // for statics + assert!(tcx.is_static(def_id)); + match err { + ErrorHandled::Reported => err_inval!(ReferencedConstant), + ErrorHandled::TooGeneric => err_inval!(TooGeneric), + } + })?; // Make sure we use the ID of the resolved memory, not the lazy one! let id = raw_const.alloc_id; let allocation = tcx.alloc_map.lock().unwrap_memory(id); diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index def979b63b52a..306adba0dce73 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -11,7 +11,7 @@ use rustc::{mir, ty}; use super::{InterpCx, MPlaceTy, Machine, MemPlace, Place, PlaceTy}; pub use rustc::mir::interpret::ScalarMaybeUndef; use rustc::mir::interpret::{ - sign_extend, truncate, AllocId, ConstValue, GlobalId, InterpResult, Pointer, Scalar, + sign_extend, truncate, AllocId, ConstValue, InterpResult, Pointer, Scalar, }; use rustc_macros::HashStable; use syntax::ast; @@ -259,7 +259,7 @@ pub(super) fn from_known_layout<'tcx>( } } -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { /// Normalice `place.ptr` to a `Pointer` if this is a place and not a ZST. /// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot. #[inline] @@ -586,7 +586,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // happening. // FIXME(oli-obk): eliminate all the `const_eval_raw` usages when we get rid of // `StaticKind` once and for all. - return self.const_eval(GlobalId { instance, promoted: None }); + return self.const_eval(instance); } ty::ConstKind::Infer(..) | ty::ConstKind::Bound(..) diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index 5050fe4906474..87f21475751a6 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -10,7 +10,7 @@ use syntax::ast::FloatTy; use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy}; -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { /// Applies the binary operation `op` to the two operands and writes a tuple of the result /// and a boolean signifying the potential overflow to the destination. pub fn binop_with_overflow( @@ -46,7 +46,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { fn binary_char_op( &self, bin_op: mir::BinOp, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index f4ac7de852af0..906dc2c8620e1 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -247,7 +247,7 @@ impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> { } // separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385 -impl<'mir, 'tcx, Tag, M> InterpCx<'mir, 'tcx, M> +impl<'infcx, 'mir, 'tcx, Tag, M> InterpCx<'infcx, 'mir, 'tcx, M> where // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 Tag: ::std::fmt::Debug + Copy + Eq + Hash + 'static, diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index a99abc4cbf428..6cfff22830e9d 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -29,7 +29,7 @@ fn binop_right_homogeneous(op: mir::BinOp) -> bool { } } -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { pub fn run(&mut self) -> InterpResult<'tcx> { while self.step()? {} Ok(()) diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index a28bb539fd070..2c92233bb7866 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -10,7 +10,7 @@ use super::{ FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, StackPopCleanup, }; -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { pub(super) fn eval_terminator( &mut self, terminator: &mir::Terminator<'tcx>, diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index efbbca534856a..47e03367c364a 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -4,7 +4,7 @@ use rustc::mir::interpret::{InterpResult, Pointer, PointerArithmetic, Scalar}; use rustc::ty::layout::{Align, HasDataLayout, LayoutOf, Size}; use rustc::ty::{self, Instance, Ty, TypeFoldable}; -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for /// objects. /// diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 7b82bed2e7a61..f748369d8ba2b 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -161,17 +161,17 @@ fn wrapping_range_format(r: &RangeInclusive, max_hi: u128) -> String { } } -struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { +struct ValidityVisitor<'rt, 'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// The `path` may be pushed to, but the part that is present when a function /// starts must not be changed! `visit_fields` and `visit_array` rely on /// this stack discipline. path: Vec, ref_tracking_for_consts: Option<&'rt mut RefTracking, Vec>>, - ecx: &'rt InterpCx<'mir, 'tcx, M>, + ecx: &'rt InterpCx<'infcx, 'mir, 'tcx, M>, } -impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M> { +impl<'rt, 'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'infcx, 'mir, 'tcx, M> { fn aggregate_field_path_elem(&mut self, layout: TyLayout<'tcx>, field: usize) -> PathElem { match layout.ty.kind { // generators and closures. @@ -294,13 +294,13 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M } } -impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> - for ValidityVisitor<'rt, 'mir, 'tcx, M> +impl<'rt, 'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'infcx, 'mir, 'tcx, M> + for ValidityVisitor<'rt, 'infcx, 'mir, 'tcx, M> { type V = OpTy<'tcx, M::PointerTag>; #[inline(always)] - fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> { + fn ecx(&self) -> &InterpCx<'infcx, 'mir, 'tcx, M> { &self.ecx } @@ -663,7 +663,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } } -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { /// This function checks the data at `op`. `op` is assumed to cover valid memory if it /// is an indirect operand. /// It will error if the bits at the destination do not match the ones described by the layout. diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index 2cfcf0ff06d0f..a59d8de00c5cc 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -15,7 +15,10 @@ pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { fn layout(&self) -> TyLayout<'tcx>; /// Makes this into an `OpTy`. - fn to_op(self, ecx: &InterpCx<'mir, 'tcx, M>) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; + fn to_op( + self, + ecx: &InterpCx<'_, 'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; /// Creates this from an `MPlaceTy`. fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self; @@ -23,12 +26,16 @@ pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { /// Projects to the given enum variant. fn project_downcast( self, - ecx: &InterpCx<'mir, 'tcx, M>, + ecx: &InterpCx<'_, 'mir, 'tcx, M>, variant: VariantIdx, ) -> InterpResult<'tcx, Self>; /// Projects to the n-th field. - fn project_field(self, ecx: &InterpCx<'mir, 'tcx, M>, field: u64) -> InterpResult<'tcx, Self>; + fn project_field( + self, + ecx: &InterpCx<'_, 'mir, 'tcx, M>, + field: u64, + ) -> InterpResult<'tcx, Self>; } // Operands and memory-places are both values. @@ -42,7 +49,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tcx, M:: #[inline(always)] fn to_op( self, - _ecx: &InterpCx<'mir, 'tcx, M>, + _ecx: &InterpCx<'_, 'mir, 'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { Ok(self) } @@ -55,14 +62,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tcx, M:: #[inline(always)] fn project_downcast( self, - ecx: &InterpCx<'mir, 'tcx, M>, + ecx: &InterpCx<'_, 'mir, 'tcx, M>, variant: VariantIdx, ) -> InterpResult<'tcx, Self> { ecx.operand_downcast(self, variant) } #[inline(always)] - fn project_field(self, ecx: &InterpCx<'mir, 'tcx, M>, field: u64) -> InterpResult<'tcx, Self> { + fn project_field( + self, + ecx: &InterpCx<'_, 'mir, 'tcx, M>, + field: u64, + ) -> InterpResult<'tcx, Self> { ecx.operand_field(self, field) } } @@ -76,7 +87,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for MPlaceTy<'tcx, #[inline(always)] fn to_op( self, - _ecx: &InterpCx<'mir, 'tcx, M>, + _ecx: &InterpCx<'_, 'mir, 'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { Ok(self.into()) } @@ -89,14 +100,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for MPlaceTy<'tcx, #[inline(always)] fn project_downcast( self, - ecx: &InterpCx<'mir, 'tcx, M>, + ecx: &InterpCx<'_, 'mir, 'tcx, M>, variant: VariantIdx, ) -> InterpResult<'tcx, Self> { ecx.mplace_downcast(self, variant) } #[inline(always)] - fn project_field(self, ecx: &InterpCx<'mir, 'tcx, M>, field: u64) -> InterpResult<'tcx, Self> { + fn project_field( + self, + ecx: &InterpCx<'_, 'mir, 'tcx, M>, + field: u64, + ) -> InterpResult<'tcx, Self> { ecx.mplace_field(self, field) } } @@ -104,12 +119,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for MPlaceTy<'tcx, macro_rules! make_value_visitor { ($visitor_trait_name:ident, $($mutability:ident)?) => { // How to traverse a value and what to do when we are at the leaves. - pub trait $visitor_trait_name<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized { + pub trait $visitor_trait_name< + 'infcx, 'mir, 'tcx: 'infcx + 'mir, M: Machine<'mir, 'tcx>>: Sized { type V: Value<'mir, 'tcx, M>; /// The visitor must have an `InterpCx` in it. fn ecx(&$($mutability)? self) - -> &$($mutability)? InterpCx<'mir, 'tcx, M>; + -> &$($mutability)? InterpCx<'infcx, 'mir, 'tcx, M>; // Recursive actions, ready to be overloaded. /// Visits the given value, dispatching as appropriate to more specialized visitors. diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 6b0f7be86841e..80dfb3ae974c5 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -35,6 +35,7 @@ use crate::interpret::{ }; use crate::rustc::ty::subst::Subst; use crate::transform::{MirPass, MirSource}; +use rustc::infer::InferCtxt; /// The maximum number of bytes that we'll allocate space for a return value. const MAX_ALLOC_LIMIT: u64 = 1024; @@ -89,13 +90,15 @@ impl<'tcx> MirPass<'tcx> for ConstProp { body.generator_kind, ); - // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold - // constants, instead of just checking for const-folding succeeding. - // That would require an uniform one-def no-mutation analysis - // and RPO (or recursing when needing the value of a local). - let mut optimization_finder = - ConstPropagator::new(read_only!(body), dummy_body, tcx, source); - optimization_finder.visit_body(body); + tcx.infer_ctxt().enter(|ref infcx| { + // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold + // constants, instead of just checking for const-folding succeeding. + // That would require an uniform one-def no-mutation analysis + // and RPO (or recursing when needing the value of a local). + let mut optimization_finder = + ConstPropagator::new(read_only!(body), dummy_body, infcx, source); + optimization_finder.visit_body(body); + }); trace!("ConstProp done for {:?}", source.def_id()); } @@ -119,12 +122,12 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { const CHECK_ALIGN: bool = false; #[inline(always)] - fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + fn enforce_validity(_ecx: &InterpCx<'_, 'mir, 'tcx, Self>) -> bool { false } fn find_mir_or_eval_fn( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, _span: Span, _instance: ty::Instance<'tcx>, _args: &[OpTy<'tcx>], @@ -135,7 +138,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { } fn call_extra_fn( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, fn_val: !, _args: &[OpTy<'tcx>], _ret: Option<(PlaceTy<'tcx>, BasicBlock)>, @@ -145,7 +148,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { } fn call_intrinsic( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, _span: Span, _instance: ty::Instance<'tcx>, _args: &[OpTy<'tcx>], @@ -156,7 +159,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { } fn assert_panic( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, _span: Span, _msg: &rustc::mir::interpret::AssertMessage<'tcx>, _unwind: Option, @@ -169,7 +172,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { } fn binary_ptr_op( - _ecx: &InterpCx<'mir, 'tcx, Self>, + _ecx: &InterpCx<'_, 'mir, 'tcx, Self>, _bin_op: BinOp, _left: ImmTy<'tcx>, _right: ImmTy<'tcx>, @@ -205,14 +208,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { } fn box_alloc( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>, _dest: PlaceTy<'tcx>, ) -> InterpResult<'tcx> { throw_unsup!(ConstPropUnsupported("can't const prop `box` keyword")); } fn access_local( - _ecx: &InterpCx<'mir, 'tcx, Self>, + _ecx: &InterpCx<'_, 'mir, 'tcx, Self>, frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, local: Local, ) -> InterpResult<'tcx, InterpOperand> { @@ -238,12 +241,12 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { Ok(()) } - fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + fn before_terminator(_ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>) -> InterpResult<'tcx> { Ok(()) } #[inline(always)] - fn stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + fn stack_push(_ecx: &mut InterpCx<'_, 'mir, 'tcx, Self>) -> InterpResult<'tcx> { Ok(()) } } @@ -251,8 +254,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { type Const<'tcx> = OpTy<'tcx>; /// Finds optimization opportunities on the MIR. -struct ConstPropagator<'mir, 'tcx> { - ecx: InterpCx<'mir, 'tcx, ConstPropMachine>, +struct ConstPropagator<'infcx, 'mir, 'tcx> { + ecx: InterpCx<'infcx, 'mir, 'tcx, ConstPropMachine>, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, can_const_prop: IndexVec, @@ -267,7 +270,7 @@ struct ConstPropagator<'mir, 'tcx> { source_info: Option, } -impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> { +impl<'infcx, 'mir, 'tcx> LayoutOf for ConstPropagator<'infcx, 'mir, 'tcx> { type Ty = Ty<'tcx>; type TyLayout = Result, LayoutError<'tcx>>; @@ -276,27 +279,28 @@ impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> { } } -impl<'mir, 'tcx> HasDataLayout for ConstPropagator<'mir, 'tcx> { +impl<'infcx, 'mir, 'tcx> HasDataLayout for ConstPropagator<'infcx, 'mir, 'tcx> { #[inline] fn data_layout(&self) -> &TargetDataLayout { &self.tcx.data_layout } } -impl<'mir, 'tcx> HasTyCtxt<'tcx> for ConstPropagator<'mir, 'tcx> { +impl<'infcx, 'mir, 'tcx> HasTyCtxt<'tcx> for ConstPropagator<'infcx, 'mir, 'tcx> { #[inline] fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } } -impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { +impl<'infcx, 'mir, 'tcx> ConstPropagator<'infcx, 'mir, 'tcx> { fn new( body: ReadOnlyBodyAndCache<'_, 'tcx>, dummy_body: &'mir Body<'tcx>, - tcx: TyCtxt<'tcx>, + infcx: &'infcx InferCtxt<'infcx, 'tcx>, source: MirSource<'tcx>, - ) -> ConstPropagator<'mir, 'tcx> { + ) -> ConstPropagator<'infcx, 'mir, 'tcx> { + let tcx = infcx.tcx; let def_id = source.def_id(); let substs = &InternalSubsts::identity_for_item(tcx, def_id); let mut param_env = tcx.param_env(def_id); @@ -309,7 +313,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } let span = tcx.def_span(def_id); - let mut ecx = InterpCx::new(tcx.at(span), param_env, ConstPropMachine, ()); + let mut ecx = InterpCx::new(tcx.at(span), infcx, param_env, ConstPropMachine, ()); let can_const_prop = CanConstProp::check(body); let ret = ecx @@ -788,7 +792,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { } } -impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { +impl<'infcx, 'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'infcx, 'mir, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } From 5a5a8cfa46148f0a7e349387954dd20924572d05 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Sat, 28 Dec 2019 16:11:51 +1300 Subject: [PATCH 2/8] Change Instance::resolve* to take InferCtxt instead of TyCtxt. This will allow param env to contain inference variables. --- src/librustc/ty/instance.rs | 58 +++++++++++++++++----- src/librustc_codegen_llvm/context.rs | 23 ++------- src/librustc_codegen_ssa/base.rs | 14 ++---- src/librustc_codegen_ssa/meth.rs | 10 +--- src/librustc_codegen_ssa/mir/block.rs | 10 ++-- src/librustc_codegen_ssa/mir/rvalue.rs | 14 ++---- src/librustc_mir/interpret/cast.rs | 2 +- src/librustc_mir/interpret/eval_context.rs | 2 +- src/librustc_mir/interpret/traits.rs | 2 +- src/librustc_mir/lints.rs | 22 ++++---- src/librustc_mir/monomorphize/collector.rs | 28 ++++------- src/librustc_mir/transform/inline.rs | 4 +- 12 files changed, 91 insertions(+), 98 deletions(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 0db49183d1014..0513069968d7b 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -1,8 +1,9 @@ +use crate::infer::InferCtxt; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::middle::lang_items::DropInPlaceFnLangItem; use crate::traits; use crate::ty::print::{FmtPrinter, Printer}; -use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, ParamEnv, SubstsRef, Ty, TyCtxt, TypeFoldable}; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; @@ -206,17 +207,18 @@ impl<'tcx> Instance<'tcx> { /// Presuming that coherence and type-check have succeeded, if this method is invoked /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return /// `Some`. - pub fn resolve( - tcx: TyCtxt<'tcx>, + pub fn resolve<'infcx>( + infcx: &'infcx InferCtxt<'infcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, ) -> Option> { + let tcx = infcx.tcx; debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env); let item = tcx.associated_item(def_id); - resolve_associated_item(tcx, &item, param_env, trait_def_id, substs) + resolve_associated_item(infcx, &item, param_env, trait_def_id, substs) } else { let ty = tcx.type_of(def_id); let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty); @@ -253,16 +255,26 @@ impl<'tcx> Instance<'tcx> { result } - pub fn resolve_for_fn_ptr( + pub fn resolve_mono( tcx: TyCtxt<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> Instance<'tcx> { + tcx.infer_ctxt().enter(|ref infcx| { + Instance::resolve(infcx, ParamEnv::reveal_all(), def_id, substs).unwrap() + }) + } + + pub fn resolve_for_fn_ptr<'infcx>( + infcx: &'infcx InferCtxt<'infcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, ) -> Option> { debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); - Instance::resolve(tcx, param_env, def_id, substs).map(|mut resolved| { + Instance::resolve(infcx, param_env, def_id, substs).map(|mut resolved| { match resolved.def { - InstanceDef::Item(def_id) if resolved.def.requires_caller_location(tcx) => { + InstanceDef::Item(def_id) if resolved.def.requires_caller_location(infcx.tcx) => { debug!(" => fn pointer created for function with #[track_caller]"); resolved.def = InstanceDef::ReifyShim(def_id); } @@ -277,13 +289,24 @@ impl<'tcx> Instance<'tcx> { }) } - pub fn resolve_for_vtable( + pub fn resolve_for_fn_ptr_mono( tcx: TyCtxt<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> Instance<'tcx> { + tcx.infer_ctxt().enter(|ref infcx| { + Instance::resolve_for_fn_ptr(infcx, ParamEnv::reveal_all(), def_id, substs).unwrap() + }) + } + + pub fn resolve_for_vtable<'infcx>( + infcx: &'infcx InferCtxt<'infcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, ) -> Option> { debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); + let tcx = infcx.tcx; let fn_sig = tcx.fn_sig(def_id); let is_vtable_shim = fn_sig.inputs().skip_binder().len() > 0 && fn_sig.input(0).skip_binder().is_param(0) @@ -292,10 +315,20 @@ impl<'tcx> Instance<'tcx> { debug!(" => associated item with unsizeable self: Self"); Some(Instance { def: InstanceDef::VtableShim(def_id), substs }) } else { - Instance::resolve(tcx, param_env, def_id, substs) + Instance::resolve(infcx, param_env, def_id, substs) } } + pub fn resolve_for_vtable_mono( + tcx: TyCtxt<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> Instance<'tcx> { + tcx.infer_ctxt().enter(|ref infcx| { + Instance::resolve_for_vtable(infcx, ParamEnv::reveal_all(), def_id, substs).unwrap() + }) + } + pub fn resolve_closure( tcx: TyCtxt<'tcx>, def_id: DefId, @@ -313,7 +346,7 @@ impl<'tcx> Instance<'tcx> { pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(DropInPlaceFnLangItem, None); let substs = tcx.intern_substs(&[ty.into()]); - Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap() + Instance::resolve_mono(tcx, def_id, substs) } pub fn fn_once_adapter_instance( @@ -346,13 +379,14 @@ impl<'tcx> Instance<'tcx> { } } -fn resolve_associated_item<'tcx>( - tcx: TyCtxt<'tcx>, +fn resolve_associated_item<'infcx, 'tcx>( + infcx: &'infcx InferCtxt<'infcx, 'tcx>, trait_item: &ty::AssocItem, param_env: ty::ParamEnv<'tcx>, trait_id: DefId, rcvr_substs: SubstsRef<'tcx>, ) -> Option> { + let tcx = infcx.tcx; let def_id = trait_item.def_id; debug!( "resolve_associated_item(trait_item={:?}, \ diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index f07601ed383fe..b76188dcc9d88 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -363,15 +363,9 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { } let tcx = self.tcx; let llfn = match tcx.lang_items().eh_personality() { - Some(def_id) if !wants_msvc_seh(self.sess()) => self.get_fn_addr( - ty::Instance::resolve( - tcx, - ty::ParamEnv::reveal_all(), - def_id, - tcx.intern_substs(&[]), - ) - .unwrap(), - ), + Some(def_id) if !wants_msvc_seh(self.sess()) => { + self.get_fn_addr(ty::Instance::resolve_mono(tcx, def_id, tcx.intern_substs(&[]))) + } _ => { let name = if wants_msvc_seh(self.sess()) { "__CxxFrameHandler3" @@ -398,15 +392,8 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { let tcx = self.tcx; assert!(self.sess().target.target.options.custom_unwind_resume); if let Some(def_id) = tcx.lang_items().eh_unwind_resume() { - let llfn = self.get_fn_addr( - ty::Instance::resolve( - tcx, - ty::ParamEnv::reveal_all(), - def_id, - tcx.intern_substs(&[]), - ) - .unwrap(), - ); + let llfn = + self.get_fn_addr(ty::Instance::resolve_mono(tcx, def_id, tcx.intern_substs(&[]))); unwresume.set(Some(llfn)); return llfn; } diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index ededb36c7127f..0de176dd74c3c 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -459,15 +459,11 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &' let (start_fn, args) = if use_start_lang_item { let start_def_id = cx.tcx().require_lang_item(StartFnLangItem, None); - let start_fn = cx.get_fn_addr( - ty::Instance::resolve( - cx.tcx(), - ty::ParamEnv::reveal_all(), - start_def_id, - cx.tcx().intern_substs(&[main_ret_ty.into()]), - ) - .unwrap(), - ); + let start_fn = cx.get_fn_addr(ty::Instance::resolve_mono( + cx.tcx(), + start_def_id, + cx.tcx().intern_substs(&[main_ret_ty.into()]), + )); ( start_fn, vec![bx.pointercast(rust_main, cx.type_ptr_to(cx.type_i8p())), arg_argc, arg_argv], diff --git a/src/librustc_codegen_ssa/meth.rs b/src/librustc_codegen_ssa/meth.rs index c36ef9b480cf0..029ad44b08112 100644 --- a/src/librustc_codegen_ssa/meth.rs +++ b/src/librustc_codegen_ssa/meth.rs @@ -87,15 +87,7 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( let methods = methods.cloned().map(|opt_mth| { opt_mth.map_or(nullptr, |(def_id, substs)| { - cx.get_fn_addr( - ty::Instance::resolve_for_vtable( - cx.tcx(), - ty::ParamEnv::reveal_all(), - def_id, - substs, - ) - .unwrap(), - ) + cx.get_fn_addr(ty::Instance::resolve_for_vtable_mono(cx.tcx(), def_id, substs)) }) }); diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index a1d4c0c820bc6..8bed1dd710eae 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -449,13 +449,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let callee = self.codegen_operand(&mut bx, func); let (instance, mut llfn) = match callee.layout.ty.kind { - ty::FnDef(def_id, substs) => ( - Some( - ty::Instance::resolve(bx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs) - .unwrap(), - ), - None, - ), + ty::FnDef(def_id, substs) => { + (Some(ty::Instance::resolve_mono(bx.tcx(), def_id, substs)), None) + } ty::FnPtr(_) => (None, Some(callee.immediate())), _ => bug!("{} is not callable", callee.layout.ty), }; diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 39cb501b7aa98..b7391ba11ce5c 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -188,17 +188,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) { bug!("reifying a fn ptr that requires const arguments"); } - OperandValue::Immediate( - bx.get_fn_addr( - ty::Instance::resolve_for_fn_ptr( - bx.tcx(), - ty::ParamEnv::reveal_all(), - def_id, - substs, - ) - .unwrap(), - ), - ) + OperandValue::Immediate(bx.get_fn_addr( + ty::Instance::resolve_for_fn_ptr_mono(bx.tcx(), def_id, substs), + )) } _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty), } diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 61b46a8a8e576..5b08bea07d7bd 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -46,7 +46,7 @@ impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> } let instance = ty::Instance::resolve_for_fn_ptr( - *self.tcx, + self.infcx, self.param_env, def_id, substs, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index c795432a653c0..83d9f3364d49f 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -376,7 +376,7 @@ impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> trace!("resolve: {:?}, {:#?}", def_id, substs); trace!("param_env: {:#?}", self.param_env); trace!("substs: {:#?}", substs); - ty::Instance::resolve(*self.tcx, self.param_env, def_id, substs) + ty::Instance::resolve(self.infcx, self.param_env, def_id, substs) .ok_or_else(|| err_inval!(TooGeneric).into()) } diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 47e03367c364a..b44cf0da0d0bf 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -78,7 +78,7 @@ impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> if let Some((def_id, substs)) = *method { // resolve for vtable: insert shims where needed let instance = - ty::Instance::resolve_for_vtable(*tcx, self.param_env, def_id, substs) + ty::Instance::resolve_for_vtable(self.infcx, self.param_env, def_id, substs) .ok_or_else(|| err_inval!(TooGeneric))?; let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); // We cannot use `vtable_allic` as we are creating fn ptrs in this loop. diff --git a/src/librustc_mir/lints.rs b/src/librustc_mir/lints.rs index fc7f2eb18b23a..42df451efef89 100644 --- a/src/librustc_mir/lints.rs +++ b/src/librustc_mir/lints.rs @@ -83,16 +83,18 @@ fn check_fn_for_unconditional_recursion( let func_ty = func.ty(body, tcx); if let ty::FnDef(fn_def_id, substs) = func_ty.kind { - let (call_fn_id, call_substs) = if let Some(instance) = - Instance::resolve(tcx, param_env, fn_def_id, substs) - { - (instance.def_id(), instance.substs) - } else { - (fn_def_id, substs) - }; - - let is_self_call = call_fn_id == def_id - && &call_substs[..caller_substs.len()] == caller_substs; + let is_self_call = tcx.infer_ctxt().enter(|ref infcx| { + let (call_fn_id, call_substs) = if let Some(instance) = + Instance::resolve(infcx, param_env, fn_def_id, substs) + { + (instance.def_id(), instance.substs) + } else { + (fn_def_id, substs) + }; + + call_fn_id == def_id + && &call_substs[..caller_substs.len()] == caller_substs + }); if is_self_call { self_call_locations.push(terminator.source_info); diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 0943be9d95c38..37bc57edf7177 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -697,9 +697,12 @@ fn visit_fn_use<'tcx>( output: &mut Vec>, ) { if let ty::FnDef(def_id, substs) = ty.kind { - let resolver = - if is_direct_call { ty::Instance::resolve } else { ty::Instance::resolve_for_fn_ptr }; - let instance = resolver(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap(); + let resolver = if is_direct_call { + ty::Instance::resolve_mono + } else { + ty::Instance::resolve_for_fn_ptr_mono + }; + let instance = resolver(tcx, def_id, substs); visit_instance_use(tcx, instance, is_direct_call, output); } } @@ -941,15 +944,7 @@ fn create_mono_items_for_vtable_methods<'tcx>( .iter() .cloned() .filter_map(|method| method) - .map(|(def_id, substs)| { - ty::Instance::resolve_for_vtable( - tcx, - ty::ParamEnv::reveal_all(), - def_id, - substs, - ) - .unwrap() - }) + .map(|(def_id, substs)| ty::Instance::resolve_for_vtable_mono(tcx, def_id, substs)) .filter(|&instance| should_monomorphize_locally(tcx, &instance)) .map(|instance| create_fn_mono_item(instance)); output.extend(methods); @@ -1106,13 +1101,11 @@ impl RootCollector<'_, 'v> { // listing. let main_ret_ty = self.tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap()); - let start_instance = Instance::resolve( + let start_instance = Instance::resolve_mono( self.tcx, - ty::ParamEnv::reveal_all(), start_def_id, self.tcx.intern_substs(&[main_ret_ty.into()]), - ) - .unwrap(); + ); self.output.push(create_fn_mono_item(start_instance)); } @@ -1167,8 +1160,7 @@ fn create_mono_items_for_default_impls<'tcx>( trait_ref.substs[param.index as usize] } }); - let instance = - ty::Instance::resolve(tcx, param_env, method.def_id, substs).unwrap(); + let instance = ty::Instance::resolve_mono(tcx, method.def_id, substs); let mono_item = create_fn_mono_item(instance); if mono_item.is_instantiable(tcx) && should_monomorphize_locally(tcx, &instance) diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 3c5d2c9f310bb..f177620243188 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -185,7 +185,9 @@ impl Inliner<'tcx> { let terminator = bb_data.terminator(); if let TerminatorKind::Call { func: ref op, .. } = terminator.kind { if let ty::FnDef(callee_def_id, substs) = op.ty(caller_body, self.tcx).kind { - let instance = Instance::resolve(self.tcx, param_env, callee_def_id, substs)?; + let instance = self.tcx.infer_ctxt().enter(|ref infcx| { + Instance::resolve(infcx, param_env, callee_def_id, substs) + })?; if let InstanceDef::Virtual(..) = instance.def { return None; From 77a6e8530184e61f0260ee2c0043bb52b2751460 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Sun, 29 Dec 2019 17:37:01 +1300 Subject: [PATCH 3/8] Make `codegen_fulfill_obligation` a canonical query and rename it to `resolve_vtable`. --- src/librustc/arena.rs | 6 ++ src/librustc/dep_graph/dep_node.rs | 2 +- src/librustc/query/mod.rs | 16 ++- src/librustc/traits/codegen/mod.rs | 103 -------------------- src/librustc/traits/mod.rs | 1 - src/librustc/traits/query/mod.rs | 3 + src/librustc/traits/query/resolve_vtable.rs | 31 ++++++ src/librustc/ty/instance.rs | 3 +- src/librustc/ty/query/mod.rs | 2 +- src/librustc_mir/monomorphize/mod.rs | 22 ++--- src/librustc_traits/lib.rs | 2 + src/librustc_traits/resolve_vtable.rs | 63 ++++++++++++ 12 files changed, 127 insertions(+), 127 deletions(-) create mode 100644 src/librustc/traits/query/resolve_vtable.rs create mode 100644 src/librustc_traits/resolve_vtable.rs diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index cb3fdff53a3b0..24adeaed425d5 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -65,6 +65,12 @@ macro_rules! arena_types { Vec> > >, + [] resolve_vtables: + rustc::infer::canonical::Canonical<'tcx, + rustc::infer::canonical::QueryResponse<'tcx, + rustc::traits::Vtable<'tcx, ()> + > + >, [] type_op_subtype: rustc::infer::canonical::Canonical<'tcx, rustc::infer::canonical::QueryResponse<'tcx, ()> diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 4818516a76aae..8f62cd2991089 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -55,7 +55,7 @@ use crate::mir; use crate::mir::interpret::ConstEvalInput; use crate::traits; use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, + CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTraitGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, }; diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index baadb0cbb8421..6501aa9e1b504 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -3,7 +3,7 @@ use crate::mir; use crate::mir::interpret::ConstEvalInput; use crate::traits; use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, + CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTraitGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, }; @@ -592,17 +592,15 @@ rustc_queries! { no_force desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) } } - } - Codegen { - query codegen_fulfill_obligation( - key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) - ) -> Vtable<'tcx, ()> { + /// Do not call this query directly: invoke `infcx.resolve_vtable()` instead. + query resolve_vtable( + goal: CanonicalTraitGoal<'tcx> + ) -> Result<&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vtable<'tcx, ()>>>, NoSolution> { no_force - cache_on_disk_if { true } desc { |tcx| - "checking if `{}` fulfills its obligations", - tcx.def_path_str(key.1.def_id()) + "resolving vtable for `{}`", + tcx.def_path_str(goal.value.value.def_id()) } } } diff --git a/src/librustc/traits/codegen/mod.rs b/src/librustc/traits/codegen/mod.rs index 8bd3f3141d53d..523cdc9a5bccd 100644 --- a/src/librustc/traits/codegen/mod.rs +++ b/src/librustc/traits/codegen/mod.rs @@ -3,79 +3,10 @@ // seems likely that they should eventually be merged into more // general routines. -use crate::infer::InferCtxt; -use crate::traits::{ - FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable, -}; use crate::ty::fold::TypeFoldable; use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::{self, TyCtxt}; -/// Attempts to resolve an obligation to a vtable. The result is -/// a shallow vtable resolution, meaning that we do not -/// (necessarily) resolve all nested obligations on the impl. Note -/// that type check should guarantee to us that all nested -/// obligations *could be* resolved if we wanted to. -/// Assumes that this is run after the entire crate has been successfully type-checked. -pub fn codegen_fulfill_obligation<'tcx>( - ty: TyCtxt<'tcx>, - (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), -) -> Vtable<'tcx, ()> { - // Remove any references to regions; this helps improve caching. - let trait_ref = ty.erase_regions(&trait_ref); - - debug!( - "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})", - (param_env, trait_ref), - trait_ref.def_id() - ); - - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - ty.infer_ctxt().enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = ObligationCause::dummy(); - let obligation = - Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate()); - - let selection = match selcx.select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => { - // Ambiguity can happen when monomorphizing during trans - // expands to some humongo type that never occurred - // statically -- this humongo type can then overflow, - // leading to an ambiguous result. So report this as an - // overflow bug, since I believe this is the only case - // where ambiguity can result. - bug!( - "Encountered ambiguity selecting `{:?}` during codegen, \ - presuming due to overflow", - trait_ref - ) - } - Err(e) => { - bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) - } - }; - - debug!("fulfill_obligation: selection={:?}", selection); - - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - let mut fulfill_cx = FulfillmentContext::new(); - let vtable = selection.map(|predicate| { - debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); - let vtable = infcx.drain_fulfillment_cx_or_panic(&mut fulfill_cx, &vtable); - - info!("Cache miss: {:?} => {:?}", trait_ref, vtable); - vtable - }) -} - impl<'tcx> TyCtxt<'tcx> { /// Monomorphizes a type from the AST by first applying the /// in-scope substitutions and then normalizing any associated @@ -100,37 +31,3 @@ impl<'tcx> TyCtxt<'tcx> { self.normalize_erasing_regions(param_env, substituted) } } - -// # Global Cache - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - /// Finishes processes any obligations that remain in the - /// fulfillment context, and then returns the result with all type - /// variables removed and regions erased. Because this is intended - /// for use after type-check has completed, if any errors occur, - /// it will panic. It is used during normalization and other cases - /// where processing the obligations in `fulfill_cx` may cause - /// type inference variables that appear in `result` to be - /// unified, and hence we need to process those obligations to get - /// the complete picture of the type. - fn drain_fulfillment_cx_or_panic( - &self, - fulfill_cx: &mut FulfillmentContext<'tcx>, - result: &T, - ) -> T - where - T: TypeFoldable<'tcx>, - { - debug!("drain_fulfillment_cx_or_panic()"); - - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - if let Err(errors) = fulfill_cx.select_all_or_error(self) { - bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors); - } - - let result = self.resolve_vars_if_possible(result); - self.tcx.erase_regions(&result) - } -} diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 3ba673d1a7d49..bbe89e6411a32 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -1235,7 +1235,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { is_object_safe: object_safety::is_object_safe_provider, specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, - codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, vtable_methods, substitute_normalize_and_test_predicates, ..*providers diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index fb9f46011b99b..1ede1b686fc70 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -15,6 +15,7 @@ pub mod method_autoderef; pub mod normalize; pub mod normalize_erasing_regions; pub mod outlives_bounds; +pub mod resolve_vtable; pub mod type_op; pub type CanonicalProjectionGoal<'tcx> = @@ -24,6 +25,8 @@ pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>> pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>; +pub type CanonicalTraitGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>>; + pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ascribe_user_type::AscribeUserType<'tcx>>>; diff --git a/src/librustc/traits/query/resolve_vtable.rs b/src/librustc/traits/query/resolve_vtable.rs new file mode 100644 index 0000000000000..2216a1ee0ef2b --- /dev/null +++ b/src/librustc/traits/query/resolve_vtable.rs @@ -0,0 +1,31 @@ +use crate::infer::canonical::OriginalQueryValues; +use crate::infer::InferCtxt; +use crate::traits::{ObligationCause, Vtable}; +use crate::ty; + +impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { + pub fn resolve_vtable( + &self, + param_env: ty::ParamEnv<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + ) -> Option> { + // Remove any references to regions; this helps improve caching. + let trait_ref = self.tcx.erase_regions(&trait_ref); + + let mut orig_values = OriginalQueryValues::default(); + let canonical = + self.canonicalize_query(¶m_env.and(ty::Binder::bind(trait_ref)), &mut orig_values); + if let Ok(query_response) = self.tcx.resolve_vtable(canonical) { + if query_response.is_proven() { + let result = self.instantiate_query_response_and_region_obligations( + &ObligationCause::dummy(), + param_env, + &orig_values, + query_response, + ); + return Some(result.unwrap().value); + } + }; + None + } +} diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 0513069968d7b..41eace3ef57e6 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -397,7 +397,8 @@ fn resolve_associated_item<'infcx, 'tcx>( ); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref))); + + let vtbl = infcx.resolve_vtable(param_env, trait_ref)?; // Now that we know which impl is being used, we can dispatch to // the actual function: diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index a717366d8cb1d..eb80133a7d4d1 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -22,7 +22,7 @@ use crate::traits::query::method_autoderef::MethodAutoderefStepsResult; use crate::traits::query::normalize::NormalizationResult; use crate::traits::query::outlives_bounds::OutlivesBound; use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, + CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTraitGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution, }; diff --git a/src/librustc_mir/monomorphize/mod.rs b/src/librustc_mir/monomorphize/mod.rs index 8bc63bfcfcbe3..6ee157e990799 100644 --- a/src/librustc_mir/monomorphize/mod.rs +++ b/src/librustc_mir/monomorphize/mod.rs @@ -12,17 +12,17 @@ pub fn custom_coerce_unsize_info<'tcx>( ) -> CustomCoerceUnsized { let def_id = tcx.lang_items().coerce_unsized_trait().unwrap(); - let trait_ref = ty::Binder::bind(ty::TraitRef { - def_id: def_id, - substs: tcx.mk_substs_trait(source_ty, &[target_ty.into()]), - }); + let trait_ref = + ty::TraitRef { def_id, substs: tcx.mk_substs_trait(source_ty, &[target_ty.into()]) }; - match tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref)) { - traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { - tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap() - } - vtable => { - bug!("invalid `CoerceUnsized` vtable: {:?}", vtable); + let impl_def_id = tcx.infer_ctxt().enter(|ref infcx| { + match infcx.resolve_vtable(ty::ParamEnv::reveal_all(), trait_ref).unwrap() { + traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => impl_def_id, + vtable => { + bug!("invalid `CoerceUnsized` vtable: {:?}", vtable); + } } - } + }); + + tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap() } diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index fefe82fdece93..235a07aecf3c1 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -19,6 +19,7 @@ mod implied_outlives_bounds; pub mod lowering; mod normalize_erasing_regions; mod normalize_projection_ty; +mod resolve_vtable; mod type_op; use rustc::ty::query::Providers; @@ -31,5 +32,6 @@ pub fn provide(p: &mut Providers<'_>) { chalk_context::provide(p); normalize_projection_ty::provide(p); normalize_erasing_regions::provide(p); + resolve_vtable::provide(p); type_op::provide(p); } diff --git a/src/librustc_traits/resolve_vtable.rs b/src/librustc_traits/resolve_vtable.rs new file mode 100644 index 0000000000000..83370f2a4f746 --- /dev/null +++ b/src/librustc_traits/resolve_vtable.rs @@ -0,0 +1,63 @@ +use rustc::infer::canonical::{Canonical, QueryResponse}; +use rustc::traits::query::{CanonicalTraitGoal, NoSolution}; +use rustc::traits::{Obligation, ObligationCause, SelectionContext, TraitQueryMode, Vtable}; +use rustc::ty::query::Providers; +use rustc::ty::{ParamEnvAnd, TyCtxt}; + +crate fn provide(p: &mut Providers<'_>) { + *p = Providers { resolve_vtable, ..*p }; +} + +/// Attempts to resolve a vtable. +pub fn resolve_vtable<'tcx>( + tcx: TyCtxt<'tcx>, + canonical_goal: CanonicalTraitGoal<'tcx>, +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, Vtable<'tcx, ()>>>, NoSolution> { + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + tcx.infer_ctxt().enter_canonical_trait_query( + &canonical_goal, + |infcx, fulfill_cx, ParamEnvAnd { param_env, value: trait_ref }| { + debug!( + "resolve_vtable(param_env={:?}, trait_ref={:?}, def_id={:?})", + param_env, + trait_ref, + trait_ref.def_id() + ); + + let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical); + + let obligation_cause = ObligationCause::dummy(); + let obligation = + Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate()); + + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => return Err(NoSolution), + Err(e) => { + debug!( + "Encountered error `{:?}` when resolving vtable for `{:?}`", + e, trait_ref + ); + return Err(NoSolution); + } + }; + + debug!("resolve_vtable: selection={:?}", selection); + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut vtable = selection.map(|predicate| { + debug!("resolve_vtable: register_predicate_obligation {:?}", predicate); + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); + + vtable = infcx.resolve_vars_if_possible(&vtable); + vtable = tcx.erase_regions(&vtable); + + info!("Cache miss: {:?} => {:?}", trait_ref, vtable); + Ok(vtable) + }, + ) +} From fe87b6a74d0fdfec0843db1c3629d36cfaec0a90 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Sun, 29 Dec 2019 19:57:55 +1300 Subject: [PATCH 4/8] Use `infcx.at(..).normalize()` in const eval to deal with inference variables. --- src/librustc_mir/interpret/eval_context.rs | 35 +++++++++------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 83d9f3364d49f..b0ae21d748fc5 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -9,7 +9,7 @@ use rustc::mir::interpret::{ }; use rustc::ty::layout::{self, Align, HasDataLayout, LayoutOf, Size, TyLayout}; use rustc::ty::query::TyCtxtAt; -use rustc::ty::subst::SubstsRef; +use rustc::ty::subst::{Subst, SubstsRef}; use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -25,6 +25,7 @@ use super::{ }; use rustc::infer::canonical::OriginalQueryValues; use rustc::infer::InferCtxt; +use rustc::traits::ObligationCause; pub struct InterpCx<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// Stores the `Machine` instance. @@ -345,26 +346,18 @@ impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> &self, value: T, ) -> T { - let mut param_env = self.param_env; - param_env.caller_bounds = - self.tcx.mk_predicates(param_env.caller_bounds.iter().filter(|predicate| { - match *predicate { - ty::Predicate::Trait(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::Projection(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::ConstEvaluatable(..) => true, - ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => false, - } - })); - - self.tcx.subst_and_normalize_erasing_regions( - self.frame().instance.substs, - param_env, - &value, - ) + let substituted = value.subst(*self.tcx, self.frame().instance.substs); + let erased_value = self.tcx.erase_regions(&substituted); + + // TODO handle normalization failure and obligations + let normalized_value = self + .infcx + .at(&ObligationCause::dummy(), self.param_env) + .normalize(&erased_value) + .unwrap() + .value; + let normalized_value = self.infcx.resolve_vars_if_possible(&normalized_value); + self.tcx.erase_regions(&normalized_value) } /// The `substs` are assumed to already be in our interpreter "universe" (param_env). From 5a922367e2af16e0ac818193e875b2a90e81caf4 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Sun, 29 Dec 2019 20:02:58 +1300 Subject: [PATCH 5/8] Move `subst_and_normalize_erasing_regions` into `normalize_erasing_regions.rs` so that it's not weirdly on it's own within the codegen module. --- src/librustc/traits/codegen/mod.rs | 33 ------------------- src/librustc/traits/mod.rs | 1 - .../traits/query/normalize_erasing_regions.rs | 24 ++++++++++++++ 3 files changed, 24 insertions(+), 34 deletions(-) delete mode 100644 src/librustc/traits/codegen/mod.rs diff --git a/src/librustc/traits/codegen/mod.rs b/src/librustc/traits/codegen/mod.rs deleted file mode 100644 index 523cdc9a5bccd..0000000000000 --- a/src/librustc/traits/codegen/mod.rs +++ /dev/null @@ -1,33 +0,0 @@ -// This file contains various trait resolution methods used by codegen. -// They all assume regions can be erased and monomorphic types. It -// seems likely that they should eventually be merged into more -// general routines. - -use crate::ty::fold::TypeFoldable; -use crate::ty::subst::{Subst, SubstsRef}; -use crate::ty::{self, TyCtxt}; - -impl<'tcx> TyCtxt<'tcx> { - /// Monomorphizes a type from the AST by first applying the - /// in-scope substitutions and then normalizing any associated - /// types. - pub fn subst_and_normalize_erasing_regions( - self, - param_substs: SubstsRef<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &T, - ) -> T - where - T: TypeFoldable<'tcx>, - { - debug!( - "subst_and_normalize_erasing_regions(\ - param_substs={:?}, \ - value={:?}, \ - param_env={:?})", - param_substs, value, param_env, - ); - let substituted = value.subst(self, param_substs); - self.normalize_erasing_regions(param_env, substituted) - } -} diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index bbe89e6411a32..f883883d0b295 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -5,7 +5,6 @@ #[allow(dead_code)] pub mod auto_trait; mod chalk_fulfill; -pub mod codegen; mod coherence; mod engine; pub mod error_reporting; diff --git a/src/librustc/traits/query/normalize_erasing_regions.rs b/src/librustc/traits/query/normalize_erasing_regions.rs index 2fa52e8810bd9..090aef9cc5e91 100644 --- a/src/librustc/traits/query/normalize_erasing_regions.rs +++ b/src/librustc/traits/query/normalize_erasing_regions.rs @@ -8,6 +8,7 @@ //! within. (This underlying query is what is cached.) use crate::ty::fold::{TypeFoldable, TypeFolder}; +use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::{self, Ty, TyCtxt}; impl<'tcx> TyCtxt<'tcx> { @@ -40,6 +41,29 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Monomorphizes a type from the AST by first applying the + /// in-scope substitutions and then normalizing any associated + /// types. + pub fn subst_and_normalize_erasing_regions( + self, + param_substs: SubstsRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: &T, + ) -> T + where + T: TypeFoldable<'tcx>, + { + debug!( + "subst_and_normalize_erasing_regions(\ + param_substs={:?}, \ + value={:?}, \ + param_env={:?})", + param_substs, value, param_env, + ); + let substituted = value.subst(self, param_substs); + self.normalize_erasing_regions(param_env, substituted) + } + /// If you have a `Binder`, you can do this to strip out the /// late-bound regions and then normalize the result, yielding up /// a `T` (with regions erased). This is appropriate when the From 0f0ed7f9a2e00d57d6a320a37cf3f9c8bd0093c9 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Mon, 30 Dec 2019 16:40:22 +1300 Subject: [PATCH 6/8] Fix TODO --- src/librustc_mir/interpret/eval_context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index b0ae21d748fc5..241d2866952a0 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -349,7 +349,7 @@ impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> let substituted = value.subst(*self.tcx, self.frame().instance.substs); let erased_value = self.tcx.erase_regions(&substituted); - // TODO handle normalization failure and obligations + // FIXME(skinny121) Can this fail or have obligations, as it has already been type checked? let normalized_value = self .infcx .at(&ObligationCause::dummy(), self.param_env) From b894a6bdce99eeb05b86bae59d29c5b71111c590 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Tue, 31 Dec 2019 09:51:07 +1300 Subject: [PATCH 7/8] Add docstrings, add `def_id` method to `ConstEvalInput`, and elide some lifetime parameters. --- src/librustc/infer/canonical/mod.rs | 2 ++ src/librustc/mir/interpret/mod.rs | 16 ++++++++++++++++ src/librustc/mir/interpret/queries.rs | 17 +++++++++++++++++ src/librustc/query/mod.rs | 4 ++-- src/librustc/traits/query/resolve_vtable.rs | 4 ++++ src/librustc/ty/instance.rs | 10 ++++++---- src/librustc_mir/const_eval/eval_queries.rs | 16 ++++++---------- src/librustc_mir/const_eval/machine.rs | 2 +- src/librustc_mir/interpret/cast.rs | 2 +- src/librustc_mir/interpret/eval_context.rs | 8 ++++---- src/librustc_mir/interpret/intrinsics.rs | 2 +- src/librustc_mir/interpret/operand.rs | 2 +- src/librustc_mir/interpret/operator.rs | 4 ++-- src/librustc_mir/interpret/place.rs | 2 +- src/librustc_mir/interpret/step.rs | 2 +- src/librustc_mir/interpret/terminator.rs | 2 +- src/librustc_mir/interpret/traits.rs | 2 +- src/librustc_mir/interpret/validity.rs | 2 +- src/librustc_traits/resolve_vtable.rs | 6 +++--- 19 files changed, 71 insertions(+), 34 deletions(-) diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index 8f6b19877b4d1..6bf6b073ab0c5 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -267,6 +267,8 @@ impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> { } impl<'tcx, V: TypeFoldable<'tcx>> Canonical<'tcx, V> { + /// Construct a canonical `value` with an empty set of variables + /// in the `ROOT` universe. pub fn empty(value: V) -> Canonical<'tcx, V> { assert!(!value.has_local_value() && !value.has_placeholders()); Canonical { diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index d94a2f72e4602..a105e4b0549dc 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -117,6 +117,7 @@ pub use self::pointer::{CheckInAllocMsg, Pointer, PointerArithmetic}; use crate::infer::canonical::Canonical; use crate::mir; +use crate::traits::Reveal; use crate::ty::codec::TyDecoder; use crate::ty::layout::{self, Size}; use crate::ty::subst::GenericArgKind; @@ -148,8 +149,23 @@ pub struct GlobalId<'tcx> { pub promoted: Option, } +/// The input type for const eval queries. Const eval queries a given both the `ParamEnv` in which +/// the constant is evaluated in and the identifier of the constant. pub type ConstEvalInput<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>>; +impl ConstEvalInput<'_> { + /// The `DefId` of the constant that is being evaluated. + pub fn def_id(&self) -> DefId { + self.value.value.instance.def_id() + } + + pub fn with_reveal_user_facing(&self) -> Self { + let mut new_input = self.clone(); + new_input.value.param_env.reveal = Reveal::UserFacing; + new_input + } +} + #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)] pub struct AllocId(pub u64); diff --git a/src/librustc/mir/interpret/queries.rs b/src/librustc/mir/interpret/queries.rs index 7b0a3e109c8f0..77f315dada198 100644 --- a/src/librustc/mir/interpret/queries.rs +++ b/src/librustc/mir/interpret/queries.rs @@ -44,6 +44,7 @@ impl<'tcx> TyCtxt<'tcx> { .enter(|ref infcx| infcx.const_eval_resolve(param_env, def_id, substs, span)) } + /// Evaluates the constant represented by the instance. pub fn const_eval_instance( self, param_env: ty::ParamEnv<'tcx>, @@ -72,6 +73,10 @@ impl<'tcx> TyCtxt<'tcx> { } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { + /// Evaluates the constant represented by the instance. + /// + /// The given `ParamEnv` and `Instance` can contain inference variables from this inference + /// context. pub fn const_eval_instance( &self, param_env: ty::ParamEnv<'tcx>, @@ -88,6 +93,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + /// Resolves and evaluates a constant. + /// + /// The constant can be located on a trait like `::C`, in which case the given + /// substitutions and environment are used to resolve the constant. Alternatively if the + /// constant has generic parameters in scope the substitutions are used to evaluate the value of + /// the constant. For example in `fn foo() { let _ = [0; bar::()]; }` the repeat count + /// constant `bar::()` requires a substitution for `T`, if the substitution for `T` is still + /// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is + /// returned. + /// + /// The given `ParamEnv` and `substs` can contain inference variables from this inference + /// context. pub fn const_eval_resolve( &self, param_env: ty::ParamEnv<'tcx>, diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 6501aa9e1b504..6b096634dc751 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -472,7 +472,7 @@ rustc_queries! { no_force desc { |tcx| "const-evaluating `{}`", - tcx.def_path_str(key.value.value.instance.def.def_id()) + tcx.def_path_str(key.def_id()) } } @@ -489,7 +489,7 @@ rustc_queries! { no_force desc { |tcx| "const-evaluating + checking `{}`", - tcx.def_path_str(key.value.value.instance.def.def_id()) + tcx.def_path_str(key.def_id()) } cache_on_disk_if(_, opt_result) { // Only store results without errors diff --git a/src/librustc/traits/query/resolve_vtable.rs b/src/librustc/traits/query/resolve_vtable.rs index 2216a1ee0ef2b..4e02390c903b0 100644 --- a/src/librustc/traits/query/resolve_vtable.rs +++ b/src/librustc/traits/query/resolve_vtable.rs @@ -4,6 +4,10 @@ use crate::traits::{ObligationCause, Vtable}; use crate::ty; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { + /// Attempts to resolves the `Vtable` for a given trait within a `ParamEnv`. + /// + /// If it can't due to the result being ambiguous, or an error occurred during selection, `None` + /// is returned. pub fn resolve_vtable( &self, param_env: ty::ParamEnv<'tcx>, diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 41eace3ef57e6..5ffba85af0ed5 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -203,10 +203,6 @@ impl<'tcx> Instance<'tcx> { /// trying to resolve `Debug::fmt` applied to `T` will yield `None`, because we do not /// know what code ought to run. (Note that this setting is also affected by the /// `RevealMode` in the parameter environment.) - /// - /// Presuming that coherence and type-check have succeeded, if this method is invoked - /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return - /// `Some`. pub fn resolve<'infcx>( infcx: &'infcx InferCtxt<'infcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -255,6 +251,12 @@ impl<'tcx> Instance<'tcx> { result } + /// Resolves a `(def_id, substs)` pair to an instance within a monomorphic context + /// (i.e., like during codegen). This is most commonly used to find the precise code that + /// will run for a trait method invocation. + /// + /// This assumes that resolving the instance will be successful, so should only be used after + /// coherence and type-check have succeeded. pub fn resolve_mono( tcx: TyCtxt<'tcx>, def_id: DefId, diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 4a3fe2268b73d..e7ade5f4ccdcb 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -167,12 +167,12 @@ fn validate_and_turn_into_const<'tcx>( constant: RawConst<'tcx>, key: ConstEvalInput<'tcx>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { - let span = tcx.def_span(key.value.value.instance.def_id()); + let def_id = key.def_id(); + let span = tcx.def_span(def_id); tcx.infer_ctxt().enter_with_canonical( span, &key, |ref infcx, ty::ParamEnvAnd { param_env, value: cid }, _| { - let def_id = cid.instance.def.def_id(); let is_static = tcx.is_static(def_id); let ecx = InterpCx::new( tcx.at(span), @@ -227,9 +227,7 @@ pub fn const_eval_validated_provider<'tcx>( // see comment in const_eval_raw_provider for what we're doing here if param_env.reveal == Reveal::All { - let mut key = key.clone(); - key.value.param_env.reveal = Reveal::UserFacing; - match tcx.const_eval_validated(key) { + match tcx.const_eval_validated(key.with_reveal_user_facing()) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} // dedupliate calls @@ -270,9 +268,7 @@ pub fn const_eval_raw_provider<'tcx>( // In case we fail in the `UserFacing` variant, we just do the real computation. if param_env.reveal == Reveal::All { - let mut key = key.clone(); - key.value.param_env.reveal = Reveal::UserFacing; - match tcx.const_eval_raw(key) { + match tcx.const_eval_raw(key.with_reveal_user_facing()) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} // dedupliate calls @@ -289,7 +285,7 @@ pub fn const_eval_raw_provider<'tcx>( trace!("const eval: {:?} ({})", key, instance); } - let def_id = cid.instance.def.def_id(); + let def_id = key.def_id(); if def_id.is_local() && tcx.typeck_tables_of(def_id).tainted_by_errors { return Err(ErrorHandled::Reported); @@ -297,7 +293,7 @@ pub fn const_eval_raw_provider<'tcx>( let is_static = tcx.is_static(def_id); - let span = tcx.def_span(cid.instance.def_id()); + let span = tcx.def_span(def_id); tcx.infer_ctxt().enter_with_canonical( span, &key, diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs index 286f2647c821e..54277ecd9370c 100644 --- a/src/librustc_mir/const_eval/machine.rs +++ b/src/librustc_mir/const_eval/machine.rs @@ -17,7 +17,7 @@ use crate::interpret::{ use super::error::*; -impl<'infcx, 'mir, 'tcx> InterpCx<'infcx, 'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { +impl<'mir, 'tcx> InterpCx<'_, 'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { /// Evaluate a const function where all arguments (if any) are zero-sized types. /// The evaluation is memoized thanks to the query system. /// diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 5b08bea07d7bd..e5363619d99a1 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -11,7 +11,7 @@ use rustc_apfloat::{Float, FloatConvert}; use super::{FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy}; -impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'_, 'mir, 'tcx, M> { pub fn cast( &mut self, src: OpTy<'tcx, M::PointerTag>, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 241d2866952a0..f68ae02384ac0 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -179,14 +179,14 @@ impl<'mir, 'tcx, Tag, Extra> Frame<'mir, 'tcx, Tag, Extra> { } } -impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'infcx, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'_, 'mir, 'tcx, M> { #[inline] fn data_layout(&self) -> &layout::TargetDataLayout { &self.tcx.data_layout } } -impl<'infcx, 'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpCx<'infcx, 'mir, 'tcx, M> +impl<'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpCx<'_, 'mir, 'tcx, M> where M: Machine<'mir, 'tcx>, { @@ -196,7 +196,7 @@ where } } -impl<'infcx, 'mir, 'tcx, M> layout::HasParamEnv<'tcx> for InterpCx<'infcx, 'mir, 'tcx, M> +impl<'mir, 'tcx, M> layout::HasParamEnv<'tcx> for InterpCx<'_, 'mir, 'tcx, M> where M: Machine<'mir, 'tcx>, { @@ -205,7 +205,7 @@ where } } -impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'infcx, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'_, 'mir, 'tcx, M> { type Ty = Ty<'tcx>; type TyLayout = InterpResult<'tcx, TyLayout<'tcx>>; diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index bfedd90975fe9..95b721e201b1f 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -81,7 +81,7 @@ crate fn eval_nullary_intrinsic<'tcx>( }) } -impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'_, 'mir, 'tcx, M> { /// Returns `true` if emulation happened. pub fn emulate_intrinsic( &mut self, diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 306adba0dce73..ad058557a426d 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -259,7 +259,7 @@ pub(super) fn from_known_layout<'tcx>( } } -impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'_, 'mir, 'tcx, M> { /// Normalice `place.ptr` to a `Pointer` if this is a place and not a ZST. /// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot. #[inline] diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index 87f21475751a6..b34afe616b421 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -10,7 +10,7 @@ use syntax::ast::FloatTy; use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy}; -impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'_, 'mir, 'tcx, M> { /// Applies the binary operation `op` to the two operands and writes a tuple of the result /// and a boolean signifying the potential overflow to the destination. pub fn binop_with_overflow( @@ -46,7 +46,7 @@ impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> } } -impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'_, 'mir, 'tcx, M> { fn binary_char_op( &self, bin_op: mir::BinOp, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 906dc2c8620e1..1bf33a3eb41d2 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -247,7 +247,7 @@ impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> { } // separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385 -impl<'infcx, 'mir, 'tcx, Tag, M> InterpCx<'infcx, 'mir, 'tcx, M> +impl<'mir, 'tcx, Tag, M> InterpCx<'_, 'mir, 'tcx, M> where // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 Tag: ::std::fmt::Debug + Copy + Eq + Hash + 'static, diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 6cfff22830e9d..17940f3ca61e3 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -29,7 +29,7 @@ fn binop_right_homogeneous(op: mir::BinOp) -> bool { } } -impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'_, 'mir, 'tcx, M> { pub fn run(&mut self) -> InterpResult<'tcx> { while self.step()? {} Ok(()) diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 2c92233bb7866..4650d4593350d 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -10,7 +10,7 @@ use super::{ FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, StackPopCleanup, }; -impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'_, 'mir, 'tcx, M> { pub(super) fn eval_terminator( &mut self, terminator: &mir::Terminator<'tcx>, diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index b44cf0da0d0bf..e0d01c9901c67 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -4,7 +4,7 @@ use rustc::mir::interpret::{InterpResult, Pointer, PointerArithmetic, Scalar}; use rustc::ty::layout::{Align, HasDataLayout, LayoutOf, Size}; use rustc::ty::{self, Instance, Ty, TypeFoldable}; -impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'_, 'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for /// objects. /// diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index f748369d8ba2b..84c44015592c3 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -663,7 +663,7 @@ impl<'rt, 'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'infcx, 'mir, } } -impl<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'infcx, 'mir, 'tcx, M> { +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'_, 'mir, 'tcx, M> { /// This function checks the data at `op`. `op` is assumed to cover valid memory if it /// is an indirect operand. /// It will error if the bits at the destination do not match the ones described by the layout. diff --git a/src/librustc_traits/resolve_vtable.rs b/src/librustc_traits/resolve_vtable.rs index 83370f2a4f746..7e305c78defce 100644 --- a/src/librustc_traits/resolve_vtable.rs +++ b/src/librustc_traits/resolve_vtable.rs @@ -48,13 +48,13 @@ pub fn resolve_vtable<'tcx>( // Currently, we use a fulfillment context to completely resolve // all nested obligations. This is because they can inform the // inference of the impl's type parameters. - let mut vtable = selection.map(|predicate| { + let vtable = selection.map(|predicate| { debug!("resolve_vtable: register_predicate_obligation {:?}", predicate); fulfill_cx.register_predicate_obligation(&infcx, predicate); }); - vtable = infcx.resolve_vars_if_possible(&vtable); - vtable = tcx.erase_regions(&vtable); + let vtable = infcx.resolve_vars_if_possible(&vtable); + let vtable = tcx.erase_regions(&vtable); info!("Cache miss: {:?} => {:?}", trait_ref, vtable); Ok(vtable) From 92b63b8db34d5431b5d35cf52df9a8e2b8f26226 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Tue, 7 Jan 2020 21:03:07 +1300 Subject: [PATCH 8/8] Fix/add doc comments and change FIXME --- src/librustc/mir/interpret/mod.rs | 2 +- src/librustc/ty/sty.rs | 5 +++-- src/librustc_mir/interpret/eval_context.rs | 3 +++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index a105e4b0549dc..6d45cac249e59 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -149,7 +149,7 @@ pub struct GlobalId<'tcx> { pub promoted: Option, } -/// The input type for const eval queries. Const eval queries a given both the `ParamEnv` in which +/// The input type for const eval queries. Const eval queries are given both the `ParamEnv` in which /// the constant is evaluated in and the identifier of the constant. pub type ConstEvalInput<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>>; diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index aeda2eb1a15c0..af41587a90921 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2396,8 +2396,9 @@ impl<'tcx> Const<'tcx> { // HACK(eddyb) when substs contain e.g. inference variables, // attempt using identity substs instead, that will succeed // when the expression doesn't depend on any parameters. - // FIXME(eddyb) make `const_eval` a canonical query instead, - // that would properly handle inference variables in `substs`. + // FIXME(skinny121) to handle inference variables correctly, the inference context + // needs to be passed into here so that the inference variables can be used within + // the `const_eval` canonical query. if substs.has_local_value() { let identity_substs = InternalSubsts::identity_for_item(tcx, did); // The `ParamEnv` needs to match the `identity_substs`. diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index f68ae02384ac0..a800233af255f 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -34,6 +34,9 @@ pub struct InterpCx<'infcx, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// The results of the type checker, from rustc. pub tcx: TyCtxtAt<'tcx>, + /// The inference context for inference variables that are within this `InterpCx`. Inference + /// variables may be within either the `param_env` or within `substs` of frames. Many operations + /// outside of mir which takes values that may contain variable require this context. pub(super) infcx: &'infcx InferCtxt<'infcx, 'tcx>, /// Bounds in scope for polymorphic evaluations.