Skip to content

Commit

Permalink
Rollup merge of rust-lang#91551 - b-naber:const-eval-normalization-ic…
Browse files Browse the repository at this point in the history
…e, r=oli-obk

Allow for failure of subst_normalize_erasing_regions in const_eval

Fixes rust-lang#72845

Using associated types that cannot be normalized previously resulted in an ICE. We now allow for normalization failure and return a "TooGeneric" error in that case.

r? `@RalfJung` maybe?
  • Loading branch information
matthiaskrgr authored Dec 8, 2021
2 parents 22afb94 + 3f831c6 commit 4da7fcc
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 12 deletions.
23 changes: 17 additions & 6 deletions compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ 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,
};
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::{
Expand Down Expand Up @@ -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<T: TypeFoldable<'tcx>>(
&self,
value: T,
) -> T {
) -> Result<T, InterpError<'tcx>> {
self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value)
}

Expand All @@ -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<T, InterpError<'tcx>> {
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).
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_const_eval/src/interpret/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)?;
}

Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_middle/src/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -575,6 +576,23 @@ impl<'tcx> Instance<'tcx> {
}
}

#[inline(always)]
pub fn try_subst_mir_and_normalize_erasing_regions<T>(
&self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
v: T,
) -> Result<T, NormalizationError<'tcx>>
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 {
Expand Down
26 changes: 26 additions & 0 deletions compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(
self,
param_substs: SubstsRef<'tcx>,
Expand All @@ -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<T>(
self,
param_substs: SubstsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
value: T,
) -> Result<T, NormalizationError<'tcx>>
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> {
Expand Down
49 changes: 49 additions & 0 deletions src/test/ui/const-generics/issues/issue-72845.rs
Original file line number Diff line number Diff line change
@@ -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<const B: bool> {}

trait Satisfied {}

impl Satisfied for Predicate<true> {}

//--------------------------------------------------

trait Spec1 {}

impl<T: Type> Spec1 for T where Predicate<{T::AT::C > 0}>: Satisfied {}

trait Spec2 {}

//impl<T: Type > Spec2 for T where Predicate<{T::AT::C > 1}>: Satisfied {}
impl<T: Type > Spec2 for T where Predicate<true>: Satisfied {}

//--------------------------------------------------

trait Foo {
fn Bar();
}

impl<T: Spec1> Foo for T {
default fn Bar() {}
}

impl<T: Spec2> Foo for T {
//~^ ERROR conflicting implementations of trait
fn Bar() {}
}

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/const-generics/issues/issue-72845.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0119]: conflicting implementations of trait `Foo`
--> $DIR/issue-72845.rs:44:1
|
LL | impl<T: Spec1> Foo for T {
| ------------------------ first implementation here
...
LL | impl<T: Spec2> Foo for T {
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation

error: aborting due to previous error

For more information about this error, try `rustc --explain E0119`.
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 4da7fcc

Please sign in to comment.