From 61cab770bd55fdc3d9d6ac86a9e0ccf7ddbb3f51 Mon Sep 17 00:00:00 2001 From: b-naber Date: Sun, 5 Dec 2021 11:13:51 +0100 Subject: [PATCH 1/2] allow for failure of subst_normalize_erasing_regions in const_eval --- .../src/interpret/eval_context.rs | 23 +++++++++++----- .../rustc_const_eval/src/interpret/operand.rs | 4 +-- .../rustc_const_eval/src/interpret/place.rs | 2 +- .../rustc_const_eval/src/interpret/step.rs | 5 ++-- compiler/rustc_middle/src/ty/instance.rs | 18 +++++++++++++ .../src/ty/normalize_erasing_regions.rs | 26 +++++++++++++++++++ 6 files changed, 67 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index cf084faade8cc..d46950ed90315 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -7,6 +7,7 @@ use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_middle::mir; +use rustc_middle::mir::interpret::{InterpError, InvalidProgramInfo}; use rustc_middle::ty::layout::{self, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::{ self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, @@ -14,7 +15,7 @@ use rustc_middle::ty::{ use rustc_mir_dataflow::storage::AlwaysLiveLocals; use rustc_query_system::ich::StableHashingContext; use rustc_session::Limit; -use rustc_span::{Pos, Span}; +use rustc_span::{Pos, Span, DUMMY_SP}; use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout}; use super::{ @@ -508,7 +509,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub(super) fn subst_from_current_frame_and_normalize_erasing_regions>( &self, value: T, - ) -> T { + ) -> Result> { self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value) } @@ -518,8 +519,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, value: T, - ) -> T { - frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value) + ) -> Result> { + frame + .instance + .try_subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value) + .or_else(|e| { + self.tcx.sess.delay_span_bug( + DUMMY_SP, + format!("failed to normalize {}", e.get_type_for_failure()).as_str(), + ); + + Err(InterpError::InvalidProgram(InvalidProgramInfo::TooGeneric)) + }) } /// The `substs` are assumed to already be in our interpreter "universe" (param_env). @@ -554,7 +565,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = from_known_layout(self.tcx, self.param_env, layout, || { let local_ty = frame.body.local_decls[local].ty; let local_ty = - self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty); + self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty)?; self.layout_of(local_ty) })?; if let Some(state) = frame.locals.get(local) { @@ -702,7 +713,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { for const_ in &body.required_consts { let span = const_.span; let const_ = - self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal); + self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal)?; self.mir_const_to_op(&const_, None).map_err(|err| { // If there was an error, set the span of the current frame to this constant. // Avoiding doing this when evaluation succeeds. diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index de9e94ce2ac0c..e82ce73c814ff 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -512,7 +512,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.param_env, self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( place.ty(&self.frame().body.local_decls, *self.tcx).ty - ))?, + )?)?, op.layout, )); Ok(op) @@ -534,7 +534,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Constant(ref constant) => { let val = - self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal); + self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?; // This can still fail: // * During ConstProp, with `TooGeneric` or since the `requried_consts` were not all // checked yet. diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index d7f2853fc86f5..4c95da896a223 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -643,7 +643,7 @@ where self.param_env, self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( place.ty(&self.frame().body.local_decls, *self.tcx).ty - ))?, + )?)?, place_ty.layout, )); Ok(place_ty) diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 9299ae2b2b9f8..992cef1cb6aa0 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -276,7 +276,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } NullaryOp(null_op, ty) => { - let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty); + let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?; let layout = self.layout_of(ty)?; if layout.is_unsized() { // FIXME: This should be a span_bug (#80742) @@ -302,7 +302,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Cast(cast_kind, ref operand, cast_ty) => { let src = self.eval_operand(operand, None)?; - let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty); + let cast_ty = + self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty)?; self.cast(&src, cast_kind, cast_ty, &dest)?; } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 4b38105e44717..2d30126273064 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -7,6 +7,7 @@ use rustc_hir::def::Namespace; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::LangItem; use rustc_macros::HashStable; +use rustc_middle::ty::normalize_erasing_regions::NormalizationError; use std::fmt; @@ -575,6 +576,23 @@ impl<'tcx> Instance<'tcx> { } } + #[inline(always)] + pub fn try_subst_mir_and_normalize_erasing_regions( + &self, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + v: T, + ) -> Result> + where + T: TypeFoldable<'tcx> + Clone, + { + if let Some(substs) = self.substs_for_mir_body() { + tcx.try_subst_and_normalize_erasing_regions(substs, param_env, v) + } else { + tcx.try_normalize_erasing_regions(param_env, v) + } + } + /// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by /// identity parameters if they are determined to be unused in `instance.def`. pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self { diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index c0e1360640fd2..c472d4a5a4dc2 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -115,6 +115,8 @@ impl<'tcx> TyCtxt<'tcx> { /// Monomorphizes a type from the AST by first applying the /// in-scope substitutions and then normalizing any associated /// types. + /// Panics if normalization fails. In case normalization might fail + /// use `try_subst_and_normalize_erasing_regions` instead. pub fn subst_and_normalize_erasing_regions( self, param_substs: SubstsRef<'tcx>, @@ -134,6 +136,30 @@ impl<'tcx> TyCtxt<'tcx> { let substituted = value.subst(self, param_substs); self.normalize_erasing_regions(param_env, substituted) } + + /// Monomorphizes a type from the AST by first applying the + /// in-scope substitutions and then trying to normalize any associated + /// types. Contrary to `subst_and_normalize_erasing_regions` this does + /// not assume that normalization succeeds. + pub fn try_subst_and_normalize_erasing_regions( + self, + param_substs: SubstsRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: T, + ) -> Result> + 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.try_normalize_erasing_regions(param_env, substituted) + } } struct NormalizeAfterErasingRegionsFolder<'tcx> { From 3f831c64ccd210754d16d6ab9c287b02e3d3eabe Mon Sep 17 00:00:00 2001 From: b-naber Date: Sun, 5 Dec 2021 12:35:49 +0100 Subject: [PATCH 2/2] add test and bless existing ones --- .../ui/const-generics/issues/issue-72845.rs | 49 +++++++++++++++++++ .../const-generics/issues/issue-72845.stderr | 12 +++++ .../const-eval/const-eval-query-stack.stderr | 2 +- 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/const-generics/issues/issue-72845.rs create mode 100644 src/test/ui/const-generics/issues/issue-72845.stderr diff --git a/src/test/ui/const-generics/issues/issue-72845.rs b/src/test/ui/const-generics/issues/issue-72845.rs new file mode 100644 index 0000000000000..bea5dc8ba21e6 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72845.rs @@ -0,0 +1,49 @@ +#![feature(generic_const_exprs)] +#![feature(specialization)] +#![allow(incomplete_features)] + +//-------------------------------------------------- + +trait Depth { + const C: usize; +} + +trait Type { + type AT: Depth; +} + +//-------------------------------------------------- + +enum Predicate {} + +trait Satisfied {} + +impl Satisfied for Predicate {} + +//-------------------------------------------------- + +trait Spec1 {} + +impl Spec1 for T where Predicate<{T::AT::C > 0}>: Satisfied {} + +trait Spec2 {} + +//impl Spec2 for T where Predicate<{T::AT::C > 1}>: Satisfied {} +impl Spec2 for T where Predicate: Satisfied {} + +//-------------------------------------------------- + +trait Foo { + fn Bar(); +} + +impl Foo for T { + default fn Bar() {} +} + +impl Foo for T { +//~^ ERROR conflicting implementations of trait + fn Bar() {} +} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-72845.stderr b/src/test/ui/const-generics/issues/issue-72845.stderr new file mode 100644 index 0000000000000..631c8605fb4d6 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72845.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Foo` + --> $DIR/issue-72845.rs:44:1 + | +LL | impl Foo for T { + | ------------------------ first implementation here +... +LL | impl Foo for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr index e6fecef9fb3b2..45a3d901c9871 100644 --- a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr @@ -20,7 +20,7 @@ error[E0080]: evaluation of constant value failed LL | let x: &'static i32 = &X; | ^ referenced constant has errors query stack during panic: -#0 [normalize_mir_const_after_erasing_regions] normalizing `main::promoted[1]` +#0 [try_normalize_mir_const_after_erasing_regions] normalizing `main::promoted[1]` #1 [optimized_mir] optimizing MIR for `main` #2 [collect_and_partition_mono_items] collect_and_partition_mono_items end of query stack