diff options
| author | Aaron Hill <aa1ronham@gmail.com> | 2020-01-02 00:42:31 -0500 |
|---|---|---|
| committer | Aaron Hill <aa1ronham@gmail.com> | 2020-01-05 14:37:59 -0500 |
| commit | ee922d47f2e6386be4f69346ab554c97db502cc0 (patch) | |
| tree | c49bfb27290b3031f2e9bbd55b7aea1e321b3ff1 /src | |
| parent | b69f6e65c081f9a628ef5db83ba77e3861e60e60 (diff) | |
| download | rust-ee922d47f2e6386be4f69346ab554c97db502cc0.tar.gz rust-ee922d47f2e6386be4f69346ab554c97db502cc0.zip | |
Fix ICE involving calling `Instance.ty` during const evaluation
Fixes #67639 `Instance.ty` assumes that we are in a fully monomorphic context (e.g. codegen), and can therefore use an empty `ParamEnv` when performing normalization. Howver, the MIR constant evaluator code ends up calling `Instance.ty` as a result of us attemptign to 'speculatively' const-evaluate generic functions during const propagation. As a result, we may end up with projections involving type parameters (e.g. <T as MyTrait>::Bar>) in the type we are trying to normalize. Normalization expects us to have proper predicates in the `ParamEnv` for such projections, and will ICE if we don't. This commit adds a new method `Instance.ty_env`, which takes a `ParamEnv` for use during normalization. The MIR const-evaluator code is changed to use this method, passing in the proper `ParamEnv` for the context at hand.
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc/ty/instance.rs | 28 | ||||
| -rw-r--r-- | src/librustc_mir/const_eval/eval_queries.rs | 2 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/terminator.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/mir/issue-67639-normalization-ice.rs | 34 |
4 files changed, 64 insertions, 2 deletions
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index a7e716ad7b7..8d4717384f7 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -62,10 +62,38 @@ pub enum InstanceDef<'tcx> { } impl<'tcx> Instance<'tcx> { + /// Returns the `Ty` corresponding to this `Instance`, + /// with generic substitutions applied and lifetimes erased. + /// + /// This method can only be called when the 'substs' for this Instance + /// are fully monomorphic (no `ty::Param`'s are present). + /// This is usually the case (e.g. during codegen). + /// However, during constant evaluation, we may want + /// to try to resolve a `Instance` using generic parameters + /// (e.g. when we are attempting to to do const-propagation). + /// In this case, `Instace.ty_env` should be used to provide + /// the `ParamEnv` for our generic context. pub fn ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { let ty = tcx.type_of(self.def.def_id()); + // There shouldn't be any params - if there are, then + // Instance.ty_env should have been used to provide the proper + // ParamEnv + if self.substs.has_param_types() { + panic!( + "Instance.ty called for type {:?} with projections in substs: {:?}", + ty, self.substs + ); + } tcx.subst_and_normalize_erasing_regions(self.substs, ty::ParamEnv::reveal_all(), &ty) } + + /// Like `Instance.ty`, but allows a `ParamEnv` to be specified for use during + /// normalization. This method is only really useful during constant evaluation, + /// where we are dealing with potentially generic types. + pub fn ty_env(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> { + let ty = tcx.type_of(self.def.def_id()); + tcx.subst_and_normalize_erasing_regions(self.substs, param_env, &ty) + } } impl<'tcx> InstanceDef<'tcx> { diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index d55620f657b..46e76512d35 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -221,7 +221,7 @@ 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(tcx); + let ty = key.value.instance.ty_env(tcx, key.param_env); let substs = match ty.kind { ty::FnDef(_, substs) => substs, _ => bug!("intrinsic with type {:?}", ty), diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 032062d6360..a28bb539fd0 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -204,7 +204,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // ABI check { let callee_abi = { - let instance_ty = instance.ty(*self.tcx); + let instance_ty = instance.ty_env(*self.tcx, self.param_env); match instance_ty.kind { ty::FnDef(..) => instance_ty.fn_sig(*self.tcx).abi(), ty::Closure(..) => Abi::RustCall, diff --git a/src/test/ui/mir/issue-67639-normalization-ice.rs b/src/test/ui/mir/issue-67639-normalization-ice.rs new file mode 100644 index 00000000000..21851a72525 --- /dev/null +++ b/src/test/ui/mir/issue-67639-normalization-ice.rs @@ -0,0 +1,34 @@ +// compile-flags: -Z mir-opt-level=3 +// build-pass + +// This used to ICE in const-prop due +// to an empty ParamEnv being used during normalization +// of a generic type + + +fn main() { + join_all::<u32>(); +} + +trait Foo { + type Item; +} + +impl Foo for u32 { + type Item = u8; +} + +trait Bar { + type Item2; +} + +impl Bar for u8 { + type Item2 = u64; +} + +fn join_all<I>() +where I: Foo, + I::Item: Bar +{ + Vec::<<I::Item as Bar>::Item2>::new(); // ICE occurs processing this line +} |
