Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for failure of subst_normalize_erasing_regions in const_eval #91551

Merged
merged 2 commits into from
Dec 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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(
oli-obk marked this conversation as resolved.
Show resolved Hide resolved
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