From 16911bdf944565050c8db8558271c82a6386b4fc Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 22 May 2019 15:51:39 +0200 Subject: [PATCH 01/23] Fix an ICE encountered in clippy integration tests --- src/librustc/query/mod.rs | 2 +- src/librustc/ty/query/keys.rs | 2 +- src/librustc/ty/structural_impls.rs | 14 ++++ src/librustc_codegen_ssa/mir/constant.rs | 4 +- src/librustc_mir/const_eval.rs | 23 ++++-- src/librustc_mir/hair/pattern/_match.rs | 8 +- src/librustc_mir/hair/pattern/check_match.rs | 14 +++- src/librustc_mir/hair/pattern/mod.rs | 4 +- src/librustc_mir/interpret/cast.rs | 7 +- src/librustc_mir/interpret/eval_context.rs | 82 +++++++++---------- src/librustc_mir/interpret/operand.rs | 2 +- src/librustc_mir/interpret/place.rs | 5 +- src/librustc_mir/interpret/step.rs | 2 +- src/librustc_mir/interpret/terminator.rs | 4 +- src/librustc_mir/interpret/traits.rs | 8 +- src/librustc_mir/lib.rs | 4 +- src/librustc_mir/transform/const_prop.rs | 5 +- src/test/incremental/no_mangle2.rs | 10 +++ src/test/ui/consts/too_generic_eval_ice.rs | 13 +++ .../ui/consts/too_generic_eval_ice.stderr | 47 +++++++++++ .../issue-58435-ice-with-assoc-const.rs | 4 +- 21 files changed, 190 insertions(+), 74 deletions(-) create mode 100644 src/test/incremental/no_mangle2.rs create mode 100644 src/test/ui/consts/too_generic_eval_ice.rs create mode 100644 src/test/ui/consts/too_generic_eval_ice.stderr diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 5ab1b90642a6a..673dcabc09a44 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -443,7 +443,7 @@ rustc_queries! { /// Extracts a field of a (variant of a) const. query const_field( - key: ty::ParamEnvAnd<'tcx, (&'tcx ty::Const<'tcx>, mir::Field)> + key: ty::ParamEnvAnd<'tcx, (&'tcx ty::Const<'tcx>, mir::Field, SubstsRef<'tcx>)> ) -> &'tcx ty::Const<'tcx> { eval_always no_force diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs index 30a3e53dddfbb..f637c46f4c9eb 100644 --- a/src/librustc/ty/query/keys.rs +++ b/src/librustc/ty/query/keys.rs @@ -127,7 +127,7 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { } } -impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) { +impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field, SubstsRef<'tcx>) { fn query_crate(&self) -> CrateNum { LOCAL_CRATE } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 649a5244728ba..adc9732be3d69 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -828,6 +828,20 @@ impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for self.0.visit_with(visitor) || self.1.visit_with(visitor) } } +impl< + 'tcx, + T: TypeFoldable<'tcx>, + U: TypeFoldable<'tcx>, + V: TypeFoldable<'tcx>, +> TypeFoldable<'tcx> for (T, U, V) { + fn super_fold_with>(&self, folder: &mut F) -> (T, U, V) { + (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder)) + } + + fn super_visit_with>(&self, visitor: &mut VIS) -> bool { + self.0.visit_with(visitor) || self.1.visit_with(visitor) || self.2.visit_with(visitor) + } +} EnumTypeFoldableImpl! { impl<'tcx, T> TypeFoldable<'tcx> for Option { diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 216e5a4645a46..794beff2c621f 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -46,7 +46,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let values: Vec<_> = (0..fields).map(|field| { let field = bx.tcx().const_field( - ty::ParamEnv::reveal_all().and((&c, mir::Field::new(field as usize))) + ty::ParamEnv::reveal_all().and(( + &c, mir::Field::new(field as usize), self.instance.substs, + )) ); if let Some(prim) = field.val.try_to_scalar() { let layout = bx.layout_of(field_ty); diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 36d80d0cb5767..9eae849a4a321 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -13,7 +13,7 @@ use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef}; use rustc::mir; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{self, LayoutOf, VariantIdx}; -use rustc::ty::subst::Subst; +use rustc::ty::subst::{Subst, SubstsRef}; use rustc::traits::Reveal; use rustc_data_structures::fx::FxHashMap; @@ -45,9 +45,12 @@ pub(crate) fn mk_eval_cx<'mir, 'tcx>( tcx: TyCtxt<'tcx>, span: Span, param_env: ty::ParamEnv<'tcx>, + substs: SubstsRef<'tcx>, ) -> CompileTimeEvalContext<'mir, 'tcx> { debug!("mk_eval_cx: {:?}", param_env); - InterpCx::new(tcx.at(span), param_env, CompileTimeInterpreter::new(), Default::default()) + InterpCx::new( + tcx.at(span), param_env, substs, CompileTimeInterpreter::new(), Default::default(), + ) } pub(crate) fn eval_promoted<'mir, 'tcx>( @@ -57,7 +60,7 @@ pub(crate) fn eval_promoted<'mir, 'tcx>( param_env: ty::ParamEnv<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let span = tcx.def_span(cid.instance.def_id()); - let mut ecx = mk_eval_cx(tcx, span, param_env); + let mut ecx = mk_eval_cx(tcx, span, param_env, cid.instance.substs); eval_body_using_ecx(&mut ecx, cid, body, param_env) } @@ -498,12 +501,13 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, pub fn const_field<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, + substs: SubstsRef<'tcx>, variant: Option, field: mir::Field, value: &'tcx ty::Const<'tcx>, ) -> &'tcx ty::Const<'tcx> { trace!("const_field: {:?}, {:?}", field, value); - let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env); + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, substs); // get the operand again let op = ecx.eval_const_to_op(value, None).unwrap(); // downcast @@ -523,10 +527,11 @@ pub fn const_field<'tcx>( pub fn const_variant_index<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, + substs: SubstsRef<'tcx>, val: &'tcx ty::Const<'tcx>, ) -> VariantIdx { trace!("const_variant_index: {:?}", val); - let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env); + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, substs); let op = ecx.eval_const_to_op(val, None).unwrap(); ecx.read_discriminant(op).unwrap().1 } @@ -546,7 +551,12 @@ fn validate_and_turn_into_const<'tcx>( key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { let cid = key.value; - let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env); + let ecx = mk_eval_cx( + tcx, + tcx.def_span(key.value.instance.def_id()), + key.param_env, + key.value.instance.substs, + ); let val = (|| { let mplace = ecx.raw_const_to_mplace(constant)?; let mut ref_tracking = RefTracking::new(mplace); @@ -658,6 +668,7 @@ pub fn const_eval_raw_provider<'tcx>( let mut ecx = InterpCx::new( tcx.at(span), key.param_env, + key.value.instance.substs, CompileTimeInterpreter::new(), Default::default() ); diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 8a3d904e77579..5bff20f5038b0 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -170,6 +170,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::RangeEnd; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const}; use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size}; +use rustc::ty::subst::SubstsRef; use rustc::mir::Field; use rustc::mir::interpret::{ConstValue, Scalar, truncate, AllocId, Pointer}; @@ -362,6 +363,7 @@ pub struct MatchCheckCtxt<'a, 'tcx> { /// statement. pub module: DefId, param_env: ty::ParamEnv<'tcx>, + identity_substs: SubstsRef<'tcx>, pub pattern_arena: &'a TypedArena>, pub byte_array_map: FxHashMap<*const Pattern<'tcx>, Vec<&'a Pattern<'tcx>>>, } @@ -370,6 +372,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { pub fn create_and_enter( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, + identity_substs: SubstsRef<'tcx>, module: DefId, f: F, ) -> R @@ -382,6 +385,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { tcx, param_env, module, + identity_substs, pattern_arena: &pattern_arena, byte_array_map: FxHashMap::default(), }) @@ -447,7 +451,9 @@ impl<'tcx> Constructor<'tcx> { assert!(!adt.is_enum()); VariantIdx::new(0) } - &ConstantValue(c) => crate::const_eval::const_variant_index(cx.tcx, cx.param_env, c), + &ConstantValue(c) => crate::const_eval::const_variant_index( + cx.tcx, cx.param_env, cx.identity_substs, c, + ), _ => bug!("bad constructor {:?} for adt {:?}", self, adt) } } diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 17fd9377a1629..93f0500abfc7c 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -165,7 +165,12 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { } let module = self.tcx.hir().get_module_parent(scrut.hir_id); - MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| { + MatchCheckCtxt::create_and_enter( + self.tcx, + self.param_env, + self.identity_substs, + module, + |ref mut cx| { let mut have_errors = false; let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| ( @@ -266,7 +271,12 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) { let module = self.tcx.hir().get_module_parent(pat.hir_id); - MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| { + MatchCheckCtxt::create_and_enter( + self.tcx, + self.param_env, + self.identity_substs, + module, + |ref mut cx| { let mut patcx = PatternContext::new(self.tcx, self.param_env.and(self.identity_substs), self.tables); diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 5ecfb84b63236..6930212b3e9b3 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -1036,7 +1036,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let mut adt_subpattern = |i, variant_opt| { let field = Field::new(i); let val = crate::const_eval::const_field( - self.tcx, self.param_env, variant_opt, field, cv + self.tcx, self.param_env, self.substs, variant_opt, field, cv ); self.const_to_pat_inner(instance, val, id, span, saw_const_match_error) }; @@ -1099,7 +1099,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatternKind::Wild } ty::Adt(adt_def, substs) if adt_def.is_enum() => { - let variant_index = const_variant_index(self.tcx, self.param_env, cv); + let variant_index = const_variant_index(self.tcx, self.param_env, self.substs, cv); let subpatterns = adt_subpatterns( adt_def.variants[variant_index].fields.len(), Some(variant_index), diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 26cfbfe53a35c..253614d6d3497 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -1,4 +1,4 @@ -use rustc::ty::{self, Ty, TypeAndMut}; +use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable}; use rustc::ty::layout::{self, TyLayout, Size}; use rustc::ty::adjustment::{PointerCast}; use syntax::ast::FloatTy; @@ -67,7 +67,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // The src operand does not matter, just its type match src.layout.ty.sty { ty::Closure(def_id, substs) => { - let substs = self.subst_and_normalize_erasing_regions(substs)?; + let substs = self.subst_and_normalize_erasing_regions_in_frame(substs); + if substs.needs_subst() { + return err!(TooGeneric); + } let instance = ty::Instance::resolve_closure( *self.tcx, def_id, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 6f4227ed34cc4..3db7a27012b4b 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -35,6 +35,11 @@ pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// Bounds in scope for polymorphic evaluations. pub(crate) param_env: ty::ParamEnv<'tcx>, + /// Base substitutions for when there are no frames that we can grab them from. + // HACK(oli-obk): this is because we don't want to push stack frames for `const_field` and + // `const_variant_index`, because that would be expensive + pub(crate) substs: SubstsRef<'tcx>, + /// The virtual memory system. pub(crate) memory: Memory<'mir, 'tcx, M>, @@ -199,6 +204,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn new( tcx: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>, + substs: SubstsRef<'tcx>, machine: M, memory_extra: M::MemoryExtra, ) -> Self { @@ -206,6 +212,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { machine, tcx, param_env, + substs, memory: Memory::new(tcx, memory_extra), stack: Vec::new(), vtables: FxHashMap::default(), @@ -291,22 +298,35 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP) } + pub(super) fn subst_and_normalize_erasing_regions_in_frame>( + &self, + value: T, + ) -> T { + // HACK(oli-obk): see `self.substs` docs + let substs = self.stack.last().map_or(self.substs, |frame| frame.instance.substs); + self.subst_and_normalize_erasing_regions(substs, value) + } + pub(super) fn subst_and_normalize_erasing_regions>( &self, - substs: T, - ) -> InterpResult<'tcx, T> { - match self.stack.last() { - Some(frame) => Ok(self.tcx.subst_and_normalize_erasing_regions( - frame.instance.substs, - self.param_env, - &substs, - )), - None => if substs.needs_subst() { - throw_inval!(TooGeneric) - } else { - Ok(substs) - }, + param_substs: SubstsRef<'tcx>, + value: T, + ) -> T { + if !value.needs_subst() { + return self.tcx.erase_regions(&value); + } + // can't use `TyCtxt::subst_and_normalize_erasing_regions`, because that call + // `normalize_erasing_regions`, even if the value still `needs_subst` after substituting. + // This will trigger an assertion in `normalize_erasing_regions`. So we handroll the code + // here. + let substituted = value.subst(self.tcx.tcx, param_substs); + if substituted.needs_subst() { + return self.tcx.erase_regions(&substituted); } + self.tcx.normalize_erasing_regions( + self.param_env, + substituted, + ) } pub(super) fn resolve( @@ -316,7 +336,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, ty::Instance<'tcx>> { trace!("resolve: {:?}, {:#?}", def_id, substs); trace!("param_env: {:#?}", self.param_env); - let substs = self.subst_and_normalize_erasing_regions(substs)?; + let substs = self.subst_and_normalize_erasing_regions_in_frame(substs); trace!("substs: {:#?}", substs); ty::Instance::resolve( *self.tcx, @@ -349,36 +369,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - pub(super) fn monomorphize + Subst<'tcx>>( - &self, - t: T, - ) -> InterpResult<'tcx, T> { - match self.stack.last() { - Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)?), - None => if t.needs_subst() { - throw_inval!(TooGeneric) - } else { - Ok(t) - }, - } - } - - fn monomorphize_with_substs + Subst<'tcx>>( - &self, - t: T, - substs: SubstsRef<'tcx> - ) -> InterpResult<'tcx, T> { - // miri doesn't care about lifetimes, and will choke on some crazy ones - // let's simply get rid of them - let substituted = t.subst(*self.tcx, substs); - - if substituted.needs_subst() { - throw_inval!(TooGeneric) - } - - Ok(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted)) - } - pub fn layout_of_local( &self, frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, @@ -391,7 +381,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { None => { let layout = crate::interpret::operand::from_known_layout(layout, || { let local_ty = frame.body.local_decls[local].ty; - let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs)?; + let local_ty = self.subst_and_normalize_erasing_regions( + frame.instance.substs, local_ty, + ); self.layout_of(local_ty) })?; if let Some(state) = frame.locals.get(local) { diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index f778eb1734c4b..09ee930e84d0e 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -554,7 +554,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // Other cases need layout. let layout = from_known_layout(layout, || { - self.layout_of(self.monomorphize(val.ty)?) + self.layout_of(self.subst_and_normalize_erasing_regions_in_frame(val.ty)) })?; let op = match val.val { ConstValue::ByRef { alloc, offset } => { diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index f66c4adf76397..e21ff1276cc63 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -616,10 +616,11 @@ where Some(return_place) => { // We use our layout to verify our assumption; caller will validate // their layout on return. + let ret_ty = self.frame().body.return_ty(); + let ret_ty = self.subst_and_normalize_erasing_regions_in_frame(ret_ty); PlaceTy { place: *return_place, - layout: self - .layout_of(self.monomorphize(self.frame().body.return_ty())?)?, + layout: self.layout_of(ret_ty)?, } } None => throw_unsup!(InvalidNullPointerUsage), diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index d152e2b50fa1b..c9a357f7673d0 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -249,7 +249,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } NullaryOp(mir::NullOp::SizeOf, ty) => { - let ty = self.monomorphize(ty)?; + let ty = self.subst_and_normalize_erasing_regions_in_frame(ty); let layout = self.layout_of(ty)?; assert!(!layout.is_unsized(), "SizeOf nullary MIR operator called for unsized type"); diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 1d6b48e9da4c4..68aa1b05f6d4f 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -242,7 +242,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { trace!("eval_fn_call: {:#?}", fn_val); let instance = match fn_val { - FnVal::Instance(instance) => instance, + FnVal::Instance(instance) => { + self.subst_and_normalize_erasing_regions_in_frame(instance) + }, FnVal::Other(extra) => { return M::call_extra_fn(self, extra, args, dest, ret); } diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index e55b0d0fb1f2a..dac326b3bfd09 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -1,4 +1,4 @@ -use rustc::ty::{self, Ty, Instance}; +use rustc::ty::{self, Ty, Instance, TypeFoldable}; use rustc::ty::layout::{Size, Align, LayoutOf}; use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic,}; @@ -32,6 +32,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty); let trait_ref = self.tcx.erase_regions(&trait_ref); + if trait_ref.needs_subst() { + return err!(TooGeneric); + } + self.tcx.vtable_methods(trait_ref) } else { &[] @@ -77,7 +81,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { for (i, method) in methods.iter().enumerate() { if let Some((def_id, substs)) = *method { // resolve for vtable: insert shims where needed - let substs = self.subst_and_normalize_erasing_regions(substs)?; + let substs = self.subst_and_normalize_erasing_regions_in_frame(substs); let instance = ty::Instance::resolve_for_vtable( *self.tcx, self.param_env, diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index cccf7b9545bdb..4c3c5bd6ee13c 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -57,8 +57,8 @@ pub fn provide(providers: &mut Providers<'_>) { providers.const_eval_raw = const_eval::const_eval_raw_provider; providers.check_match = hair::pattern::check_match; providers.const_field = |tcx, param_env_and_value| { - let (param_env, (value, field)) = param_env_and_value.into_parts(); - const_eval::const_field(tcx, param_env, None, field, value) + let (param_env, (value, field, substs)) = param_env_and_value.into_parts(); + const_eval::const_field(tcx, param_env, substs, None, field, value) }; providers.type_name = interpret::type_name; } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 38d26d0ba50a4..400e2787baa1f 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -162,11 +162,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let def_id = source.def_id(); let param_env = tcx.param_env(def_id); let span = tcx.def_span(def_id); - let mut ecx = mk_eval_cx(tcx, span, param_env); + let substs = InternalSubsts::identity_for_item(tcx, def_id); + let mut ecx = mk_eval_cx(tcx, span, param_env, substs); let can_const_prop = CanConstProp::check(body); ecx.push_stack_frame( - Instance::new(def_id, &InternalSubsts::identity_for_item(tcx, def_id)), + Instance::new(def_id, &substs), span, dummy_body, None, diff --git a/src/test/incremental/no_mangle2.rs b/src/test/incremental/no_mangle2.rs new file mode 100644 index 0000000000000..e6d844b1d4c93 --- /dev/null +++ b/src/test/incremental/no_mangle2.rs @@ -0,0 +1,10 @@ +// revisions:rpass1 rpass2 +// compile-flags: --crate-type staticlib +// skip-codegen + +#![deny(unused_attributes)] + +#[no_mangle] +pub extern "C" fn rust_no_mangle() -> i32 { + 42 +} diff --git a/src/test/ui/consts/too_generic_eval_ice.rs b/src/test/ui/consts/too_generic_eval_ice.rs new file mode 100644 index 0000000000000..7a299169bc4e1 --- /dev/null +++ b/src/test/ui/consts/too_generic_eval_ice.rs @@ -0,0 +1,13 @@ +pub struct Foo(A, B); + +impl Foo { + const HOST_SIZE: usize = std::mem::size_of::(); + + pub fn crash() -> bool { + [5; Self::HOST_SIZE] == [6; 0] //~ ERROR no associated item named `HOST_SIZE` + //~^ the size for values of type `A` cannot be known + //~| the size for values of type `B` cannot be known + } +} + +fn main() {} diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr new file mode 100644 index 0000000000000..eef79421270ce --- /dev/null +++ b/src/test/ui/consts/too_generic_eval_ice.stderr @@ -0,0 +1,47 @@ +error[E0599]: no associated item named `HOST_SIZE` found for type `Foo` in the current scope + --> $DIR/too_generic_eval_ice.rs:7:19 + | +LL | pub struct Foo(A, B); + | --------------------------- associated item `HOST_SIZE` not found for this +... +LL | [5; Self::HOST_SIZE] == [6; 0] + | ^^^^^^^^^ associated item not found in `Foo` + | + = note: the method `HOST_SIZE` exists but the following trait bounds were not satisfied: + `A : std::marker::Sized` + `B : std::marker::Sized` + +error[E0277]: the size for values of type `A` cannot be known at compilation time + --> $DIR/too_generic_eval_ice.rs:7:13 + | +LL | [5; Self::HOST_SIZE] == [6; 0] + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `A` + = note: to learn more, visit + = help: consider adding a `where A: std::marker::Sized` bound +note: required by `Foo` + --> $DIR/too_generic_eval_ice.rs:1:1 + | +LL | pub struct Foo(A, B); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the size for values of type `B` cannot be known at compilation time + --> $DIR/too_generic_eval_ice.rs:7:13 + | +LL | [5; Self::HOST_SIZE] == [6; 0] + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `B` + = note: to learn more, visit + = help: consider adding a `where B: std::marker::Sized` bound +note: required by `Foo` + --> $DIR/too_generic_eval_ice.rs:1:1 + | +LL | pub struct Foo(A, B); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-58435-ice-with-assoc-const.rs b/src/test/ui/issues/issue-58435-ice-with-assoc-const.rs index fac727d2d7dc9..f51d19ed5e59d 100644 --- a/src/test/ui/issues/issue-58435-ice-with-assoc-const.rs +++ b/src/test/ui/issues/issue-58435-ice-with-assoc-const.rs @@ -1,6 +1,6 @@ // run-pass -// The const-evaluator was at one point ICE'ing while trying to -// evaluate the body of `fn id` during the `s.id()` call in main. +// The const propagator was at one point ICE'ing while trying to +// propagate constants in the body of `fn id` during the `s.id()` call in main. struct S(T); From d38fb10f218d667995dcaeb09df0cc86d87441b6 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 28 Jul 2019 21:01:51 +0200 Subject: [PATCH 02/23] A comment mentioned the wrong function --- src/librustc_mir/interpret/eval_context.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 3db7a27012b4b..2ca8e7e686cc6 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -317,8 +317,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // can't use `TyCtxt::subst_and_normalize_erasing_regions`, because that call // `normalize_erasing_regions`, even if the value still `needs_subst` after substituting. - // This will trigger an assertion in `normalize_erasing_regions`. So we handroll the code - // here. + // This will trigger an assertion in `normalize_erasing_late_bound_regions`. + // So we handroll the code here. let substituted = value.subst(self.tcx.tcx, param_substs); if substituted.needs_subst() { return self.tcx.erase_regions(&substituted); From b5350906fc47b1419a921ab4b4c1d0d7b704ed10 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 28 Jul 2019 21:04:07 +0200 Subject: [PATCH 03/23] Typo --- 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 2ca8e7e686cc6..a2a3ace7c3f22 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -315,7 +315,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if !value.needs_subst() { return self.tcx.erase_regions(&value); } - // can't use `TyCtxt::subst_and_normalize_erasing_regions`, because that call + // can't use `TyCtxt::subst_and_normalize_erasing_regions`, because that calls // `normalize_erasing_regions`, even if the value still `needs_subst` after substituting. // This will trigger an assertion in `normalize_erasing_late_bound_regions`. // So we handroll the code here. From e849b83e2cc812747bd63a96931d3f6552b01bab Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 28 Jul 2019 21:07:48 +0200 Subject: [PATCH 04/23] Document all the things --- src/librustc_mir/interpret/eval_context.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index a2a3ace7c3f22..8e4b667f9ec46 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -298,6 +298,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP) } + /// Convenience wrapper around `subst_and_normalize_erasing_regions`, using the top (active) + /// frame's `substs`. pub(super) fn subst_and_normalize_erasing_regions_in_frame>( &self, value: T, @@ -307,6 +309,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.subst_and_normalize_erasing_regions(substs, value) } + /// Call this whenever you have a value that `needs_subst`. Not guaranteed to actually + /// monomorphize the value. If we are e.g. const propagating inside a generic function, some + /// things may depend on a generic parameter and thus can never be monomorphized. + /// + /// Only call this function if you want to compute the substs of a specific frame (that is + /// definitely not the frame currently being evaluated). You need to make sure to pass correct + /// substs. pub(super) fn subst_and_normalize_erasing_regions>( &self, param_substs: SubstsRef<'tcx>, From 600d679a8af4505684c0284058748cd6d22d1ca9 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 28 Jul 2019 21:08:13 +0200 Subject: [PATCH 05/23] WIP: Unbrittle the miri engine around unsubstituted values --- src/librustc/traits/query/normalize_erasing_regions.rs | 1 - src/librustc_mir/interpret/cast.rs | 5 +---- src/librustc_mir/interpret/traits.rs | 6 +----- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/librustc/traits/query/normalize_erasing_regions.rs b/src/librustc/traits/query/normalize_erasing_regions.rs index d09288461d444..47de72a8f8dee 100644 --- a/src/librustc/traits/query/normalize_erasing_regions.rs +++ b/src/librustc/traits/query/normalize_erasing_regions.rs @@ -56,7 +56,6 @@ impl<'tcx> TyCtxt<'tcx> { where T: TypeFoldable<'tcx>, { - assert!(!value.needs_subst()); let value = self.erase_late_bound_regions(value); self.normalize_erasing_regions(param_env, value) } diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 253614d6d3497..be3bae851228e 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -1,4 +1,4 @@ -use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable}; +use rustc::ty::{self, Ty, TypeAndMut}; use rustc::ty::layout::{self, TyLayout, Size}; use rustc::ty::adjustment::{PointerCast}; use syntax::ast::FloatTy; @@ -68,9 +68,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match src.layout.ty.sty { ty::Closure(def_id, substs) => { let substs = self.subst_and_normalize_erasing_regions_in_frame(substs); - if substs.needs_subst() { - return err!(TooGeneric); - } let instance = ty::Instance::resolve_closure( *self.tcx, def_id, diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index dac326b3bfd09..5b8e0b83c86e8 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -1,4 +1,4 @@ -use rustc::ty::{self, Ty, Instance, TypeFoldable}; +use rustc::ty::{self, Ty, Instance}; use rustc::ty::layout::{Size, Align, LayoutOf}; use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic,}; @@ -32,10 +32,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty); let trait_ref = self.tcx.erase_regions(&trait_ref); - if trait_ref.needs_subst() { - return err!(TooGeneric); - } - self.tcx.vtable_methods(trait_ref) } else { &[] From 27320e30b290a471ac3c22bf8dcdfcf9d7a4342b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 28 Jul 2019 21:13:02 +0200 Subject: [PATCH 06/23] Privatize `subst_and_normalize_erasing_regions` --- 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 8e4b667f9ec46..06b4e4e98aa89 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -316,7 +316,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Only call this function if you want to compute the substs of a specific frame (that is /// definitely not the frame currently being evaluated). You need to make sure to pass correct /// substs. - pub(super) fn subst_and_normalize_erasing_regions>( + fn subst_and_normalize_erasing_regions>( &self, param_substs: SubstsRef<'tcx>, value: T, From b84ed3004a6b79454ff2f454a57955a74ab2136a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 28 Jul 2019 21:17:42 +0200 Subject: [PATCH 07/23] Clarify doc comments some more --- src/librustc_mir/interpret/eval_context.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 06b4e4e98aa89..ad0f0bf9c846f 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -298,8 +298,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP) } - /// Convenience wrapper around `subst_and_normalize_erasing_regions`, using the top (active) - /// frame's `substs`. + /// Call this whenever you have a value that `needs_subst`. Not guaranteed to actually + /// monomorphize the value. If we are e.g. const propagating inside a generic function, some + /// things may depend on a generic parameter and thus can never be monomorphized. pub(super) fn subst_and_normalize_erasing_regions_in_frame>( &self, value: T, @@ -309,9 +310,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.subst_and_normalize_erasing_regions(substs, value) } - /// Call this whenever you have a value that `needs_subst`. Not guaranteed to actually - /// monomorphize the value. If we are e.g. const propagating inside a generic function, some - /// things may depend on a generic parameter and thus can never be monomorphized. + /// Same thing as `subst_and_normalize_erasing_regions_in_frame` but not taking its substs + /// from the top stack frame, but requiring you to pass specific substs. /// /// Only call this function if you want to compute the substs of a specific frame (that is /// definitely not the frame currently being evaluated). You need to make sure to pass correct From 7fac3a1b0aae83a176f4a6d9a7d39b26f50b82cd Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 28 Jul 2019 21:25:59 +0200 Subject: [PATCH 08/23] Simplify `subst_and_normalize_erasing_regions` --- src/librustc_mir/interpret/eval_context.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index ad0f0bf9c846f..4fe3619c3dc09 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -9,7 +9,7 @@ use rustc::mir; use rustc::ty::layout::{ self, Size, Align, HasDataLayout, LayoutOf, TyLayout }; -use rustc::ty::subst::{Subst, SubstsRef}; +use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::query::TyCtxtAt; use rustc_data_structures::indexed_vec::IndexVec; @@ -321,20 +321,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { param_substs: SubstsRef<'tcx>, value: T, ) -> T { - if !value.needs_subst() { - return self.tcx.erase_regions(&value); - } - // can't use `TyCtxt::subst_and_normalize_erasing_regions`, because that calls - // `normalize_erasing_regions`, even if the value still `needs_subst` after substituting. - // This will trigger an assertion in `normalize_erasing_late_bound_regions`. - // So we handroll the code here. - let substituted = value.subst(self.tcx.tcx, param_substs); - if substituted.needs_subst() { - return self.tcx.erase_regions(&substituted); - } - self.tcx.normalize_erasing_regions( + self.tcx.subst_and_normalize_erasing_regions( + param_substs, self.param_env, - substituted, + &value, ) } From 8ac4cb5c305540feb70c29243a1ca823ee3fd8da Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 29 Jul 2019 07:50:49 +0200 Subject: [PATCH 09/23] Fix incremental test --- src/test/incremental/no_mangle2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/incremental/no_mangle2.rs b/src/test/incremental/no_mangle2.rs index e6d844b1d4c93..d6b0889cc6374 100644 --- a/src/test/incremental/no_mangle2.rs +++ b/src/test/incremental/no_mangle2.rs @@ -1,6 +1,6 @@ // revisions:rpass1 rpass2 +// check-pass // compile-flags: --crate-type staticlib -// skip-codegen #![deny(unused_attributes)] From fe2013ca479b08858ffdb4af557073aaa6958593 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 29 Jul 2019 07:59:43 +0200 Subject: [PATCH 10/23] Substitute const generics so we can evaluate them --- src/librustc_mir/interpret/operand.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 09ee930e84d0e..6bbe0e1745b0a 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -538,11 +538,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Scalar::Ptr(ptr) => Scalar::Ptr(self.tag_static_base_pointer(ptr)), Scalar::Raw { data, size } => Scalar::Raw { data, size }, }; + let value = self.subst_and_normalize_erasing_regions_in_frame(val.val); // Early-return cases. - match val.val { - ConstValue::Param(_) => - // FIXME(oli-obk): try to monomorphize - throw_inval!(TooGeneric), + match value { + ConstValue::Param(_) => throw_inval!(TooGeneric), ConstValue::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; return Ok(OpTy::from(self.const_eval_raw(GlobalId { @@ -556,7 +555,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = from_known_layout(layout, || { self.layout_of(self.subst_and_normalize_erasing_regions_in_frame(val.ty)) })?; - let op = match val.val { + let op = match value { ConstValue::ByRef { alloc, offset } => { let id = self.tcx.alloc_map.lock().create_memory_alloc(alloc); // We rely on mutability being set correctly in that allocation to prevent writes From 1d26fda9b5d548343dd7c74061a71a50b93d5e0b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 31 Jul 2019 21:13:05 +0200 Subject: [PATCH 11/23] Explain partial substitution --- src/librustc_mir/interpret/operand.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 6bbe0e1745b0a..5d556f9fd729d 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -553,6 +553,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // Other cases need layout. let layout = from_known_layout(layout, || { + // Substituting is not a cached or O(1) operation. Substituting the type happens here, + // which may not happen if we already have a layout. Or if we use the early abort above. + // Thus we do not substitute and normalize `val` above, but only `val.val` and then + // substitute `val.ty` here. self.layout_of(self.subst_and_normalize_erasing_regions_in_frame(val.ty)) })?; let op = match value { From b917c4372a8ebdfddf1d12ded8940be7af28ca3e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 1 Aug 2019 15:58:48 +0200 Subject: [PATCH 12/23] Abort evaluation when substuting a value still requires more substitution. This is probably overly restrictive, but the safe choice for now. e.g. we can't evaluate `fn foo() -> i32 { 42 }` inside an associated constant of a generic trait, even though that should be doable --- src/librustc_mir/interpret/cast.rs | 2 +- src/librustc_mir/interpret/eval_context.rs | 25 +++++++++++++--------- src/librustc_mir/interpret/operand.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 +- 7 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index be3bae851228e..c2fd151b68aef 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -67,7 +67,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // The src operand does not matter, just its type match src.layout.ty.sty { ty::Closure(def_id, substs) => { - let substs = self.subst_and_normalize_erasing_regions_in_frame(substs); + let substs = self.subst_and_normalize_erasing_regions_in_frame(substs)?; let instance = ty::Instance::resolve_closure( *self.tcx, def_id, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 4fe3619c3dc09..852648df0d9e7 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -9,7 +9,7 @@ use rustc::mir; use rustc::ty::layout::{ self, Size, Align, HasDataLayout, LayoutOf, TyLayout }; -use rustc::ty::subst::SubstsRef; +use rustc::ty::subst::{SubstsRef, Subst}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::query::TyCtxtAt; use rustc_data_structures::indexed_vec::IndexVec; @@ -304,7 +304,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub(super) fn subst_and_normalize_erasing_regions_in_frame>( &self, value: T, - ) -> T { + ) -> InterpResult<'tcx, T> { // HACK(oli-obk): see `self.substs` docs let substs = self.stack.last().map_or(self.substs, |frame| frame.instance.substs); self.subst_and_normalize_erasing_regions(substs, value) @@ -320,12 +320,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, param_substs: SubstsRef<'tcx>, value: T, - ) -> T { - self.tcx.subst_and_normalize_erasing_regions( - param_substs, - self.param_env, - &value, - ) + ) -> InterpResult<'tcx, T> { + let substituted = value.subst(self.tcx.tcx, param_substs); + // we duplicate the body of `TyCtxt::subst_and_normalize_erasing_regions` here, because + // we can't normalize values with generic parameters. The difference between this function + // and the `TyCtxt` version is this early abort + if substituted.needs_subst() { + // FIXME(oli-obk): This aborts evaluating `fn foo() -> i32 { 42 }` inside an + // associated constant of a generic trait, even though that should be doable. + return Err(InterpError::TooGeneric.into()) + } + Ok(self.tcx.normalize_erasing_regions(self.param_env, substituted)) } pub(super) fn resolve( @@ -335,7 +340,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, ty::Instance<'tcx>> { trace!("resolve: {:?}, {:#?}", def_id, substs); trace!("param_env: {:#?}", self.param_env); - let substs = self.subst_and_normalize_erasing_regions_in_frame(substs); + let substs = self.subst_and_normalize_erasing_regions_in_frame(substs)?; trace!("substs: {:#?}", substs); ty::Instance::resolve( *self.tcx, @@ -382,7 +387,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let local_ty = frame.body.local_decls[local].ty; let local_ty = self.subst_and_normalize_erasing_regions( frame.instance.substs, local_ty, - ); + )?; self.layout_of(local_ty) })?; if let Some(state) = frame.locals.get(local) { diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 5d556f9fd729d..6d494db6b5561 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -538,7 +538,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Scalar::Ptr(ptr) => Scalar::Ptr(self.tag_static_base_pointer(ptr)), Scalar::Raw { data, size } => Scalar::Raw { data, size }, }; - let value = self.subst_and_normalize_erasing_regions_in_frame(val.val); + let value = self.subst_and_normalize_erasing_regions_in_frame(val.val)?; // Early-return cases. match value { ConstValue::Param(_) => throw_inval!(TooGeneric), @@ -557,7 +557,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // which may not happen if we already have a layout. Or if we use the early abort above. // Thus we do not substitute and normalize `val` above, but only `val.val` and then // substitute `val.ty` here. - self.layout_of(self.subst_and_normalize_erasing_regions_in_frame(val.ty)) + self.layout_of(self.subst_and_normalize_erasing_regions_in_frame(val.ty)?) })?; let op = match value { ConstValue::ByRef { alloc, offset } => { diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index e21ff1276cc63..8128518d8031d 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -617,7 +617,7 @@ where // We use our layout to verify our assumption; caller will validate // their layout on return. let ret_ty = self.frame().body.return_ty(); - let ret_ty = self.subst_and_normalize_erasing_regions_in_frame(ret_ty); + let ret_ty = self.subst_and_normalize_erasing_regions_in_frame(ret_ty)?; PlaceTy { place: *return_place, layout: self.layout_of(ret_ty)?, diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index c9a357f7673d0..1b0ecb8aa3647 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -249,7 +249,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } NullaryOp(mir::NullOp::SizeOf, ty) => { - let ty = self.subst_and_normalize_erasing_regions_in_frame(ty); + let ty = self.subst_and_normalize_erasing_regions_in_frame(ty)?; let layout = self.layout_of(ty)?; assert!(!layout.is_unsized(), "SizeOf nullary MIR operator called for unsized type"); diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 68aa1b05f6d4f..95b86ae8a7c26 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -243,7 +243,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let instance = match fn_val { FnVal::Instance(instance) => { - self.subst_and_normalize_erasing_regions_in_frame(instance) + self.subst_and_normalize_erasing_regions_in_frame(instance)? }, FnVal::Other(extra) => { return M::call_extra_fn(self, extra, args, dest, ret); diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 5b8e0b83c86e8..01171e6020b34 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -77,7 +77,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { for (i, method) in methods.iter().enumerate() { if let Some((def_id, substs)) = *method { // resolve for vtable: insert shims where needed - let substs = self.subst_and_normalize_erasing_regions_in_frame(substs); + let substs = self.subst_and_normalize_erasing_regions_in_frame(substs)?; let instance = ty::Instance::resolve_for_vtable( *self.tcx, self.param_env, From 5a8c9d3bd31b5e52c4ec5f9f0950b2128fdec14e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 12 Aug 2019 14:05:04 +0200 Subject: [PATCH 13/23] Substituting with identity substs is equivalent to not substituting at all --- src/librustc/query/mod.rs | 2 +- src/librustc/ty/query/keys.rs | 2 +- src/librustc_codegen_ssa/mir/constant.rs | 2 +- src/librustc_mir/const_eval.rs | 15 +++++---------- src/librustc_mir/hair/pattern/_match.rs | 6 +----- src/librustc_mir/hair/pattern/check_match.rs | 2 -- src/librustc_mir/hair/pattern/mod.rs | 4 ++-- src/librustc_mir/interpret/eval_context.rs | 19 +++++++------------ src/librustc_mir/lib.rs | 4 ++-- src/librustc_mir/transform/const_prop.rs | 2 +- 10 files changed, 21 insertions(+), 37 deletions(-) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 673dcabc09a44..5ab1b90642a6a 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -443,7 +443,7 @@ rustc_queries! { /// Extracts a field of a (variant of a) const. query const_field( - key: ty::ParamEnvAnd<'tcx, (&'tcx ty::Const<'tcx>, mir::Field, SubstsRef<'tcx>)> + key: ty::ParamEnvAnd<'tcx, (&'tcx ty::Const<'tcx>, mir::Field)> ) -> &'tcx ty::Const<'tcx> { eval_always no_force diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs index f637c46f4c9eb..30a3e53dddfbb 100644 --- a/src/librustc/ty/query/keys.rs +++ b/src/librustc/ty/query/keys.rs @@ -127,7 +127,7 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { } } -impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field, SubstsRef<'tcx>) { +impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) { fn query_crate(&self) -> CrateNum { LOCAL_CRATE } diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 794beff2c621f..4680f4a8c0ca1 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -47,7 +47,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let values: Vec<_> = (0..fields).map(|field| { let field = bx.tcx().const_field( ty::ParamEnv::reveal_all().and(( - &c, mir::Field::new(field as usize), self.instance.substs, + &c, mir::Field::new(field as usize), )) ); if let Some(prim) = field.val.try_to_scalar() { diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 9eae849a4a321..20ff437649977 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -13,7 +13,7 @@ use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef}; use rustc::mir; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{self, LayoutOf, VariantIdx}; -use rustc::ty::subst::{Subst, SubstsRef}; +use rustc::ty::subst::Subst; use rustc::traits::Reveal; use rustc_data_structures::fx::FxHashMap; @@ -45,11 +45,10 @@ pub(crate) fn mk_eval_cx<'mir, 'tcx>( tcx: TyCtxt<'tcx>, span: Span, param_env: ty::ParamEnv<'tcx>, - substs: SubstsRef<'tcx>, ) -> CompileTimeEvalContext<'mir, 'tcx> { debug!("mk_eval_cx: {:?}", param_env); InterpCx::new( - tcx.at(span), param_env, substs, CompileTimeInterpreter::new(), Default::default(), + tcx.at(span), param_env, CompileTimeInterpreter::new(), Default::default(), ) } @@ -60,7 +59,7 @@ pub(crate) fn eval_promoted<'mir, 'tcx>( param_env: ty::ParamEnv<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let span = tcx.def_span(cid.instance.def_id()); - let mut ecx = mk_eval_cx(tcx, span, param_env, cid.instance.substs); + let mut ecx = mk_eval_cx(tcx, span, param_env); eval_body_using_ecx(&mut ecx, cid, body, param_env) } @@ -501,13 +500,12 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, pub fn const_field<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - substs: SubstsRef<'tcx>, variant: Option, field: mir::Field, value: &'tcx ty::Const<'tcx>, ) -> &'tcx ty::Const<'tcx> { trace!("const_field: {:?}, {:?}", field, value); - let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, substs); + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env); // get the operand again let op = ecx.eval_const_to_op(value, None).unwrap(); // downcast @@ -527,11 +525,10 @@ pub fn const_field<'tcx>( pub fn const_variant_index<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - substs: SubstsRef<'tcx>, val: &'tcx ty::Const<'tcx>, ) -> VariantIdx { trace!("const_variant_index: {:?}", val); - let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, substs); + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env); let op = ecx.eval_const_to_op(val, None).unwrap(); ecx.read_discriminant(op).unwrap().1 } @@ -555,7 +552,6 @@ fn validate_and_turn_into_const<'tcx>( tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, - key.value.instance.substs, ); let val = (|| { let mplace = ecx.raw_const_to_mplace(constant)?; @@ -668,7 +664,6 @@ pub fn const_eval_raw_provider<'tcx>( let mut ecx = InterpCx::new( tcx.at(span), key.param_env, - key.value.instance.substs, CompileTimeInterpreter::new(), Default::default() ); diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 5bff20f5038b0..59da7a59339e3 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -170,7 +170,6 @@ use rustc::hir::def_id::DefId; use rustc::hir::RangeEnd; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const}; use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size}; -use rustc::ty::subst::SubstsRef; use rustc::mir::Field; use rustc::mir::interpret::{ConstValue, Scalar, truncate, AllocId, Pointer}; @@ -363,7 +362,6 @@ pub struct MatchCheckCtxt<'a, 'tcx> { /// statement. pub module: DefId, param_env: ty::ParamEnv<'tcx>, - identity_substs: SubstsRef<'tcx>, pub pattern_arena: &'a TypedArena>, pub byte_array_map: FxHashMap<*const Pattern<'tcx>, Vec<&'a Pattern<'tcx>>>, } @@ -372,7 +370,6 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { pub fn create_and_enter( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - identity_substs: SubstsRef<'tcx>, module: DefId, f: F, ) -> R @@ -385,7 +382,6 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { tcx, param_env, module, - identity_substs, pattern_arena: &pattern_arena, byte_array_map: FxHashMap::default(), }) @@ -452,7 +448,7 @@ impl<'tcx> Constructor<'tcx> { VariantIdx::new(0) } &ConstantValue(c) => crate::const_eval::const_variant_index( - cx.tcx, cx.param_env, cx.identity_substs, c, + cx.tcx, cx.param_env, c, ), _ => bug!("bad constructor {:?} for adt {:?}", self, adt) } diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 93f0500abfc7c..63c0ba3b2fac0 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -168,7 +168,6 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { MatchCheckCtxt::create_and_enter( self.tcx, self.param_env, - self.identity_substs, module, |ref mut cx| { let mut have_errors = false; @@ -274,7 +273,6 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { MatchCheckCtxt::create_and_enter( self.tcx, self.param_env, - self.identity_substs, module, |ref mut cx| { let mut patcx = PatternContext::new(self.tcx, diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 6930212b3e9b3..5ecfb84b63236 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -1036,7 +1036,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let mut adt_subpattern = |i, variant_opt| { let field = Field::new(i); let val = crate::const_eval::const_field( - self.tcx, self.param_env, self.substs, variant_opt, field, cv + self.tcx, self.param_env, variant_opt, field, cv ); self.const_to_pat_inner(instance, val, id, span, saw_const_match_error) }; @@ -1099,7 +1099,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatternKind::Wild } ty::Adt(adt_def, substs) if adt_def.is_enum() => { - let variant_index = const_variant_index(self.tcx, self.param_env, self.substs, cv); + let variant_index = const_variant_index(self.tcx, self.param_env, cv); let subpatterns = adt_subpatterns( adt_def.variants[variant_index].fields.len(), Some(variant_index), diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 852648df0d9e7..c225a860c35e8 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -35,11 +35,6 @@ pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// Bounds in scope for polymorphic evaluations. pub(crate) param_env: ty::ParamEnv<'tcx>, - /// Base substitutions for when there are no frames that we can grab them from. - // HACK(oli-obk): this is because we don't want to push stack frames for `const_field` and - // `const_variant_index`, because that would be expensive - pub(crate) substs: SubstsRef<'tcx>, - /// The virtual memory system. pub(crate) memory: Memory<'mir, 'tcx, M>, @@ -204,7 +199,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn new( tcx: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>, - substs: SubstsRef<'tcx>, machine: M, memory_extra: M::MemoryExtra, ) -> Self { @@ -212,7 +206,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { machine, tcx, param_env, - substs, memory: Memory::new(tcx, memory_extra), stack: Vec::new(), vtables: FxHashMap::default(), @@ -306,7 +299,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { value: T, ) -> InterpResult<'tcx, T> { // HACK(oli-obk): see `self.substs` docs - let substs = self.stack.last().map_or(self.substs, |frame| frame.instance.substs); + let substs = self.stack.last().map(|frame| frame.instance.substs); self.subst_and_normalize_erasing_regions(substs, value) } @@ -318,17 +311,19 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// substs. fn subst_and_normalize_erasing_regions>( &self, - param_substs: SubstsRef<'tcx>, + param_substs: Option>, value: T, ) -> InterpResult<'tcx, T> { - let substituted = value.subst(self.tcx.tcx, param_substs); + let substituted = param_substs + .map(|param_substs| value.subst(self.tcx.tcx, param_substs)) + .unwrap_or(value); // we duplicate the body of `TyCtxt::subst_and_normalize_erasing_regions` here, because // we can't normalize values with generic parameters. The difference between this function // and the `TyCtxt` version is this early abort if substituted.needs_subst() { // FIXME(oli-obk): This aborts evaluating `fn foo() -> i32 { 42 }` inside an // associated constant of a generic trait, even though that should be doable. - return Err(InterpError::TooGeneric.into()) + throw_inval!(TooGeneric); } Ok(self.tcx.normalize_erasing_regions(self.param_env, substituted)) } @@ -386,7 +381,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = crate::interpret::operand::from_known_layout(layout, || { let local_ty = frame.body.local_decls[local].ty; let local_ty = self.subst_and_normalize_erasing_regions( - frame.instance.substs, local_ty, + Some(frame.instance.substs), local_ty, )?; self.layout_of(local_ty) })?; diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 4c3c5bd6ee13c..cccf7b9545bdb 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -57,8 +57,8 @@ pub fn provide(providers: &mut Providers<'_>) { providers.const_eval_raw = const_eval::const_eval_raw_provider; providers.check_match = hair::pattern::check_match; providers.const_field = |tcx, param_env_and_value| { - let (param_env, (value, field, substs)) = param_env_and_value.into_parts(); - const_eval::const_field(tcx, param_env, substs, None, field, value) + let (param_env, (value, field)) = param_env_and_value.into_parts(); + const_eval::const_field(tcx, param_env, None, field, value) }; providers.type_name = interpret::type_name; } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 400e2787baa1f..cf656d7bb97e1 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -163,7 +163,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let param_env = tcx.param_env(def_id); let span = tcx.def_span(def_id); let substs = InternalSubsts::identity_for_item(tcx, def_id); - let mut ecx = mk_eval_cx(tcx, span, param_env, substs); + let mut ecx = mk_eval_cx(tcx, span, param_env); let can_const_prop = CanConstProp::check(body); ecx.push_stack_frame( From faa342fc56b5bdf2270fd2976487ffe89f8934e8 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 12 Aug 2019 14:07:44 +0200 Subject: [PATCH 14/23] Reintroduce sanity assert --- src/librustc/traits/query/normalize_erasing_regions.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc/traits/query/normalize_erasing_regions.rs b/src/librustc/traits/query/normalize_erasing_regions.rs index 47de72a8f8dee..d09288461d444 100644 --- a/src/librustc/traits/query/normalize_erasing_regions.rs +++ b/src/librustc/traits/query/normalize_erasing_regions.rs @@ -56,6 +56,7 @@ impl<'tcx> TyCtxt<'tcx> { where T: TypeFoldable<'tcx>, { + assert!(!value.needs_subst()); let value = self.erase_late_bound_regions(value); self.normalize_erasing_regions(param_env, value) } From 51e13431f5ac74d04f3ae0ffcb0597b0ec041009 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 12 Aug 2019 14:08:40 +0200 Subject: [PATCH 15/23] Remove now-useless impl --- src/librustc/ty/structural_impls.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index adc9732be3d69..649a5244728ba 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -828,20 +828,6 @@ impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for self.0.visit_with(visitor) || self.1.visit_with(visitor) } } -impl< - 'tcx, - T: TypeFoldable<'tcx>, - U: TypeFoldable<'tcx>, - V: TypeFoldable<'tcx>, -> TypeFoldable<'tcx> for (T, U, V) { - fn super_fold_with>(&self, folder: &mut F) -> (T, U, V) { - (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder)) - } - - fn super_visit_with>(&self, visitor: &mut VIS) -> bool { - self.0.visit_with(visitor) || self.1.visit_with(visitor) || self.2.visit_with(visitor) - } -} EnumTypeFoldableImpl! { impl<'tcx, T> TypeFoldable<'tcx> for Option { From 034939bdcc704816338cf01babeeb3baecbdd860 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 12 Aug 2019 14:09:22 +0200 Subject: [PATCH 16/23] Unbreak a line --- src/librustc_codegen_ssa/mir/constant.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 4680f4a8c0ca1..216e5a4645a46 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -46,9 +46,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let values: Vec<_> = (0..fields).map(|field| { let field = bx.tcx().const_field( - ty::ParamEnv::reveal_all().and(( - &c, mir::Field::new(field as usize), - )) + ty::ParamEnv::reveal_all().and((&c, mir::Field::new(field as usize))) ); if let Some(prim) = field.val.try_to_scalar() { let layout = bx.layout_of(field_ty); From 685e0e586ea43763ea4061d074be5baf49b5dec6 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 12 Aug 2019 14:10:44 +0200 Subject: [PATCH 17/23] Unbreak more lines --- src/librustc_mir/const_eval.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 20ff437649977..36d80d0cb5767 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -47,9 +47,7 @@ pub(crate) fn mk_eval_cx<'mir, 'tcx>( param_env: ty::ParamEnv<'tcx>, ) -> CompileTimeEvalContext<'mir, 'tcx> { debug!("mk_eval_cx: {:?}", param_env); - InterpCx::new( - tcx.at(span), param_env, CompileTimeInterpreter::new(), Default::default(), - ) + InterpCx::new(tcx.at(span), param_env, CompileTimeInterpreter::new(), Default::default()) } pub(crate) fn eval_promoted<'mir, 'tcx>( @@ -548,11 +546,7 @@ fn validate_and_turn_into_const<'tcx>( key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { let cid = key.value; - let ecx = mk_eval_cx( - tcx, - tcx.def_span(key.value.instance.def_id()), - key.param_env, - ); + let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env); let val = (|| { let mplace = ecx.raw_const_to_mplace(constant)?; let mut ref_tracking = RefTracking::new(mplace); From fdf54508e77db7f8787a937cff976a67311f1e18 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 12 Aug 2019 14:13:49 +0200 Subject: [PATCH 18/23] Address review comments and unbreak more lines --- src/librustc_mir/hair/pattern/_match.rs | 4 +--- src/librustc_mir/hair/pattern/check_match.rs | 12 ++---------- src/librustc_mir/interpret/terminator.rs | 4 +--- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 59da7a59339e3..8a3d904e77579 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -447,9 +447,7 @@ impl<'tcx> Constructor<'tcx> { assert!(!adt.is_enum()); VariantIdx::new(0) } - &ConstantValue(c) => crate::const_eval::const_variant_index( - cx.tcx, cx.param_env, c, - ), + &ConstantValue(c) => crate::const_eval::const_variant_index(cx.tcx, cx.param_env, c), _ => bug!("bad constructor {:?} for adt {:?}", self, adt) } } diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 63c0ba3b2fac0..17fd9377a1629 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -165,11 +165,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { } let module = self.tcx.hir().get_module_parent(scrut.hir_id); - MatchCheckCtxt::create_and_enter( - self.tcx, - self.param_env, - module, - |ref mut cx| { + MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| { let mut have_errors = false; let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| ( @@ -270,11 +266,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) { let module = self.tcx.hir().get_module_parent(pat.hir_id); - MatchCheckCtxt::create_and_enter( - self.tcx, - self.param_env, - module, - |ref mut cx| { + MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| { let mut patcx = PatternContext::new(self.tcx, self.param_env.and(self.identity_substs), self.tables); diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 95b86ae8a7c26..1d6b48e9da4c4 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -242,9 +242,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { trace!("eval_fn_call: {:#?}", fn_val); let instance = match fn_val { - FnVal::Instance(instance) => { - self.subst_and_normalize_erasing_regions_in_frame(instance)? - }, + FnVal::Instance(instance) => instance, FnVal::Other(extra) => { return M::call_extra_fn(self, extra, args, dest, ret); } From 3afcb1e435cc9907d474047b4e76c648a4e7b90f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 12 Aug 2019 14:30:13 +0200 Subject: [PATCH 19/23] Adjust incremental test --- src/test/incremental/no_mangle2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/incremental/no_mangle2.rs b/src/test/incremental/no_mangle2.rs index d6b0889cc6374..d243fd97e7aed 100644 --- a/src/test/incremental/no_mangle2.rs +++ b/src/test/incremental/no_mangle2.rs @@ -1,4 +1,4 @@ -// revisions:rpass1 rpass2 +// revisions:cfail1 cfail2 // check-pass // compile-flags: --crate-type staticlib From f0a16c40e23f32762a97c258902a458123c72310 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 12 Aug 2019 15:39:10 +0200 Subject: [PATCH 20/23] Address review comments --- src/librustc_mir/interpret/cast.rs | 1 - src/librustc_mir/interpret/eval_context.rs | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index c2fd151b68aef..a3a237a1d3c0d 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -67,7 +67,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // The src operand does not matter, just its type match src.layout.ty.sty { ty::Closure(def_id, substs) => { - let substs = self.subst_and_normalize_erasing_regions_in_frame(substs)?; let instance = ty::Instance::resolve_closure( *self.tcx, def_id, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index c225a860c35e8..6ef2f88ede4b1 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -334,9 +334,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { substs: SubstsRef<'tcx> ) -> InterpResult<'tcx, ty::Instance<'tcx>> { trace!("resolve: {:?}, {:#?}", def_id, substs); - trace!("param_env: {:#?}", self.param_env); - let substs = self.subst_and_normalize_erasing_regions_in_frame(substs)?; - trace!("substs: {:#?}", substs); ty::Instance::resolve( *self.tcx, self.param_env, From 3aa550a09f5c83b23443349660de4d0929e85c31 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 12 Aug 2019 15:41:34 +0200 Subject: [PATCH 21/23] We don't have polymorphic things without a stackframe anymore --- src/librustc_mir/interpret/eval_context.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 6ef2f88ede4b1..0f51a48be0722 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -298,9 +298,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, value: T, ) -> InterpResult<'tcx, T> { - // HACK(oli-obk): see `self.substs` docs - let substs = self.stack.last().map(|frame| frame.instance.substs); - self.subst_and_normalize_erasing_regions(substs, value) + self.subst_and_normalize_erasing_regions(self.frame().instance.substs, value) } /// Same thing as `subst_and_normalize_erasing_regions_in_frame` but not taking its substs @@ -311,12 +309,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// substs. fn subst_and_normalize_erasing_regions>( &self, - param_substs: Option>, + param_substs: SubstsRef<'tcx>, value: T, ) -> InterpResult<'tcx, T> { - let substituted = param_substs - .map(|param_substs| value.subst(self.tcx.tcx, param_substs)) - .unwrap_or(value); + let substituted = value.subst(self.tcx.tcx, param_substs); // we duplicate the body of `TyCtxt::subst_and_normalize_erasing_regions` here, because // we can't normalize values with generic parameters. The difference between this function // and the `TyCtxt` version is this early abort @@ -378,7 +374,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = crate::interpret::operand::from_known_layout(layout, || { let local_ty = frame.body.local_decls[local].ty; let local_ty = self.subst_and_normalize_erasing_regions( - Some(frame.instance.substs), local_ty, + frame.instance.substs, local_ty, )?; self.layout_of(local_ty) })?; From 82db274863ffba09296b519298cc163a7e551cb5 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 12 Aug 2019 16:08:36 +0200 Subject: [PATCH 22/23] Only monomorphize things from the current frame's MIR, not arbitrary polymorphic things --- src/librustc_mir/interpret/eval_context.rs | 7 ++++--- src/librustc_mir/interpret/operand.rs | 18 +++++++----------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 0f51a48be0722..520dc0ab38a61 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -291,8 +291,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP) } - /// Call this whenever you have a value that `needs_subst`. Not guaranteed to actually - /// monomorphize the value. If we are e.g. const propagating inside a generic function, some + /// Call this whenever you have a value that you took from the current frame's `mir::Body`. + /// Not guaranteed to actually monomorphize the value. + /// If we are e.g. const propagating inside a generic function, some /// things may depend on a generic parameter and thus can never be monomorphized. pub(super) fn subst_and_normalize_erasing_regions_in_frame>( &self, @@ -304,7 +305,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Same thing as `subst_and_normalize_erasing_regions_in_frame` but not taking its substs /// from the top stack frame, but requiring you to pass specific substs. /// - /// Only call this function if you want to compute the substs of a specific frame (that is + /// Only call this function if you want to apply the substs of a specific frame (that is /// definitely not the frame currently being evaluated). You need to make sure to pass correct /// substs. fn subst_and_normalize_erasing_regions>( diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 6d494db6b5561..97efd818131fd 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -511,7 +511,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Move(ref place) => self.eval_place_to_op(place, layout)?, - Constant(ref constant) => self.eval_const_to_op(constant.literal, layout)?, + Constant(ref constant) => { + let lit = self.subst_and_normalize_erasing_regions_in_frame(constant.literal)?; + self.eval_const_to_op(lit, layout)? + }, }; trace!("{:?}: {:?}", mir_op, *op); Ok(op) @@ -538,9 +541,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Scalar::Ptr(ptr) => Scalar::Ptr(self.tag_static_base_pointer(ptr)), Scalar::Raw { data, size } => Scalar::Raw { data, size }, }; - let value = self.subst_and_normalize_erasing_regions_in_frame(val.val)?; // Early-return cases. - match value { + match val.val { ConstValue::Param(_) => throw_inval!(TooGeneric), ConstValue::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; @@ -552,14 +554,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => {} } // Other cases need layout. - let layout = from_known_layout(layout, || { - // Substituting is not a cached or O(1) operation. Substituting the type happens here, - // which may not happen if we already have a layout. Or if we use the early abort above. - // Thus we do not substitute and normalize `val` above, but only `val.val` and then - // substitute `val.ty` here. - self.layout_of(self.subst_and_normalize_erasing_regions_in_frame(val.ty)?) - })?; - let op = match value { + let layout = from_known_layout(layout, || self.layout_of(val.ty))?; + let op = match val.val { ConstValue::ByRef { alloc, offset } => { let id = self.tcx.alloc_map.lock().create_memory_alloc(alloc); // We rely on mutability being set correctly in that allocation to prevent writes From 70124ecee678317fa60e261a34095df14c383b02 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 12 Aug 2019 16:34:16 +0200 Subject: [PATCH 23/23] Work around a MIR bug --- src/librustc_mir/const_eval.rs | 4 ++-- src/librustc_mir/interpret/operand.rs | 18 ++++++++++-------- src/librustc_mir/transform/const_prop.rs | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 36d80d0cb5767..c1d4cd35ef66b 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -505,7 +505,7 @@ pub fn const_field<'tcx>( trace!("const_field: {:?}, {:?}", field, value); let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env); // get the operand again - let op = ecx.eval_const_to_op(value, None).unwrap(); + let op = ecx.eval_const_to_op(value.val, value.ty, None).unwrap(); // downcast let down = match variant { None => op, @@ -527,7 +527,7 @@ pub fn const_variant_index<'tcx>( ) -> VariantIdx { trace!("const_variant_index: {:?}", val); let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env); - let op = ecx.eval_const_to_op(val, None).unwrap(); + let op = ecx.eval_const_to_op(val.val, val.ty, None).unwrap(); ecx.read_discriminant(op).unwrap().1 } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 97efd818131fd..a04215f11aff0 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -3,7 +3,7 @@ use std::convert::TryInto; -use rustc::{mir, ty}; +use rustc::{mir, ty::{self, Ty}}; use rustc::ty::layout::{ self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, VariantIdx, }; @@ -512,8 +512,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.eval_place_to_op(place, layout)?, Constant(ref constant) => { - let lit = self.subst_and_normalize_erasing_regions_in_frame(constant.literal)?; - self.eval_const_to_op(lit, layout)? + let val = self.subst_and_normalize_erasing_regions_in_frame(constant.literal.val)?; + let ty = self.subst_and_normalize_erasing_regions_in_frame(constant.ty)?; + self.eval_const_to_op(val, ty, layout)? }, }; trace!("{:?}: {:?}", mir_op, *op); @@ -534,7 +535,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // in patterns via the `const_eval` module crate fn eval_const_to_op( &self, - val: &'tcx ty::Const<'tcx>, + value: ConstValue<'tcx>, + ty: Ty<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let tag_scalar = |scalar| match scalar { @@ -542,7 +544,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Scalar::Raw { data, size } => Scalar::Raw { data, size }, }; // Early-return cases. - match val.val { + match value { ConstValue::Param(_) => throw_inval!(TooGeneric), ConstValue::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; @@ -554,8 +556,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => {} } // Other cases need layout. - let layout = from_known_layout(layout, || self.layout_of(val.ty))?; - let op = match val.val { + let layout = from_known_layout(layout, || self.layout_of(ty))?; + let op = match value { ConstValue::ByRef { alloc, offset } => { let id = self.tcx.alloc_map.lock().create_memory_alloc(alloc); // We rely on mutability being set correctly in that allocation to prevent writes @@ -582,7 +584,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ConstValue::Infer(..) | ConstValue::Placeholder(..) | ConstValue::Unevaluated(..) => - bug!("eval_const_to_op: Unexpected ConstValue {:?}", val), + bug!("eval_const_to_op: Unexpected ConstValue {:?}", value), }; Ok(OpTy { op, layout }) } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index cf656d7bb97e1..2fbea12819452 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -287,7 +287,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { c: &Constant<'tcx>, ) -> Option> { self.ecx.tcx.span = c.span; - match self.ecx.eval_const_to_op(c.literal, None) { + match self.ecx.eval_const_to_op(c.literal.val, c.literal.ty, None) { Ok(op) => { Some(op) },