Skip to content

Commit 7752498

Browse files
authored
Rollup merge of rust-lang#91551 - b-naber:const-eval-normalization-ice, 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?
2 parents 0a1cfa9 + 3f831c6 commit 7752498

File tree

9 files changed

+129
-12
lines changed

9 files changed

+129
-12
lines changed

compiler/rustc_const_eval/src/interpret/eval_context.rs

+17-6
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
77
use rustc_index::vec::IndexVec;
88
use rustc_macros::HashStable;
99
use rustc_middle::mir;
10+
use rustc_middle::mir::interpret::{InterpError, InvalidProgramInfo};
1011
use rustc_middle::ty::layout::{self, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
1112
use rustc_middle::ty::{
1213
self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
1314
};
1415
use rustc_mir_dataflow::storage::AlwaysLiveLocals;
1516
use rustc_query_system::ich::StableHashingContext;
1617
use rustc_session::Limit;
17-
use rustc_span::{Pos, Span};
18+
use rustc_span::{Pos, Span, DUMMY_SP};
1819
use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout};
1920

2021
use super::{
@@ -508,7 +509,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
508509
pub(super) fn subst_from_current_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
509510
&self,
510511
value: T,
511-
) -> T {
512+
) -> Result<T, InterpError<'tcx>> {
512513
self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value)
513514
}
514515

@@ -518,8 +519,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
518519
&self,
519520
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
520521
value: T,
521-
) -> T {
522-
frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value)
522+
) -> Result<T, InterpError<'tcx>> {
523+
frame
524+
.instance
525+
.try_subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value)
526+
.or_else(|e| {
527+
self.tcx.sess.delay_span_bug(
528+
DUMMY_SP,
529+
format!("failed to normalize {}", e.get_type_for_failure()).as_str(),
530+
);
531+
532+
Err(InterpError::InvalidProgram(InvalidProgramInfo::TooGeneric))
533+
})
523534
}
524535

525536
/// 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> {
554565
let layout = from_known_layout(self.tcx, self.param_env, layout, || {
555566
let local_ty = frame.body.local_decls[local].ty;
556567
let local_ty =
557-
self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty);
568+
self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
558569
self.layout_of(local_ty)
559570
})?;
560571
if let Some(state) = frame.locals.get(local) {
@@ -702,7 +713,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
702713
for const_ in &body.required_consts {
703714
let span = const_.span;
704715
let const_ =
705-
self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal);
716+
self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal)?;
706717
self.mir_const_to_op(&const_, None).map_err(|err| {
707718
// If there was an error, set the span of the current frame to this constant.
708719
// Avoiding doing this when evaluation succeeds.

compiler/rustc_const_eval/src/interpret/operand.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
512512
self.param_env,
513513
self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
514514
place.ty(&self.frame().body.local_decls, *self.tcx).ty
515-
))?,
515+
)?)?,
516516
op.layout,
517517
));
518518
Ok(op)
@@ -534,7 +534,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
534534

535535
Constant(ref constant) => {
536536
let val =
537-
self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal);
537+
self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?;
538538
// This can still fail:
539539
// * During ConstProp, with `TooGeneric` or since the `requried_consts` were not all
540540
// checked yet.

compiler/rustc_const_eval/src/interpret/place.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ where
643643
self.param_env,
644644
self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
645645
place.ty(&self.frame().body.local_decls, *self.tcx).ty
646-
))?,
646+
)?)?,
647647
place_ty.layout,
648648
));
649649
Ok(place_ty)

compiler/rustc_const_eval/src/interpret/step.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
276276
}
277277

278278
NullaryOp(null_op, ty) => {
279-
let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty);
279+
let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
280280
let layout = self.layout_of(ty)?;
281281
if layout.is_unsized() {
282282
// FIXME: This should be a span_bug (#80742)
@@ -302,7 +302,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
302302

303303
Cast(cast_kind, ref operand, cast_ty) => {
304304
let src = self.eval_operand(operand, None)?;
305-
let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty);
305+
let cast_ty =
306+
self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty)?;
306307
self.cast(&src, cast_kind, cast_ty, &dest)?;
307308
}
308309

compiler/rustc_middle/src/ty/instance.rs

+18
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_hir::def::Namespace;
77
use rustc_hir::def_id::{CrateNum, DefId};
88
use rustc_hir::lang_items::LangItem;
99
use rustc_macros::HashStable;
10+
use rustc_middle::ty::normalize_erasing_regions::NormalizationError;
1011

1112
use std::fmt;
1213

@@ -575,6 +576,23 @@ impl<'tcx> Instance<'tcx> {
575576
}
576577
}
577578

579+
#[inline(always)]
580+
pub fn try_subst_mir_and_normalize_erasing_regions<T>(
581+
&self,
582+
tcx: TyCtxt<'tcx>,
583+
param_env: ty::ParamEnv<'tcx>,
584+
v: T,
585+
) -> Result<T, NormalizationError<'tcx>>
586+
where
587+
T: TypeFoldable<'tcx> + Clone,
588+
{
589+
if let Some(substs) = self.substs_for_mir_body() {
590+
tcx.try_subst_and_normalize_erasing_regions(substs, param_env, v)
591+
} else {
592+
tcx.try_normalize_erasing_regions(param_env, v)
593+
}
594+
}
595+
578596
/// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by
579597
/// identity parameters if they are determined to be unused in `instance.def`.
580598
pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self {

compiler/rustc_middle/src/ty/normalize_erasing_regions.rs

+26
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ impl<'tcx> TyCtxt<'tcx> {
115115
/// Monomorphizes a type from the AST by first applying the
116116
/// in-scope substitutions and then normalizing any associated
117117
/// types.
118+
/// Panics if normalization fails. In case normalization might fail
119+
/// use `try_subst_and_normalize_erasing_regions` instead.
118120
pub fn subst_and_normalize_erasing_regions<T>(
119121
self,
120122
param_substs: SubstsRef<'tcx>,
@@ -134,6 +136,30 @@ impl<'tcx> TyCtxt<'tcx> {
134136
let substituted = value.subst(self, param_substs);
135137
self.normalize_erasing_regions(param_env, substituted)
136138
}
139+
140+
/// Monomorphizes a type from the AST by first applying the
141+
/// in-scope substitutions and then trying to normalize any associated
142+
/// types. Contrary to `subst_and_normalize_erasing_regions` this does
143+
/// not assume that normalization succeeds.
144+
pub fn try_subst_and_normalize_erasing_regions<T>(
145+
self,
146+
param_substs: SubstsRef<'tcx>,
147+
param_env: ty::ParamEnv<'tcx>,
148+
value: T,
149+
) -> Result<T, NormalizationError<'tcx>>
150+
where
151+
T: TypeFoldable<'tcx>,
152+
{
153+
debug!(
154+
"subst_and_normalize_erasing_regions(\
155+
param_substs={:?}, \
156+
value={:?}, \
157+
param_env={:?})",
158+
param_substs, value, param_env,
159+
);
160+
let substituted = value.subst(self, param_substs);
161+
self.try_normalize_erasing_regions(param_env, substituted)
162+
}
137163
}
138164

139165
struct NormalizeAfterErasingRegionsFolder<'tcx> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#![feature(generic_const_exprs)]
2+
#![feature(specialization)]
3+
#![allow(incomplete_features)]
4+
5+
//--------------------------------------------------
6+
7+
trait Depth {
8+
const C: usize;
9+
}
10+
11+
trait Type {
12+
type AT: Depth;
13+
}
14+
15+
//--------------------------------------------------
16+
17+
enum Predicate<const B: bool> {}
18+
19+
trait Satisfied {}
20+
21+
impl Satisfied for Predicate<true> {}
22+
23+
//--------------------------------------------------
24+
25+
trait Spec1 {}
26+
27+
impl<T: Type> Spec1 for T where Predicate<{T::AT::C > 0}>: Satisfied {}
28+
29+
trait Spec2 {}
30+
31+
//impl<T: Type > Spec2 for T where Predicate<{T::AT::C > 1}>: Satisfied {}
32+
impl<T: Type > Spec2 for T where Predicate<true>: Satisfied {}
33+
34+
//--------------------------------------------------
35+
36+
trait Foo {
37+
fn Bar();
38+
}
39+
40+
impl<T: Spec1> Foo for T {
41+
default fn Bar() {}
42+
}
43+
44+
impl<T: Spec2> Foo for T {
45+
//~^ ERROR conflicting implementations of trait
46+
fn Bar() {}
47+
}
48+
49+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0119]: conflicting implementations of trait `Foo`
2+
--> $DIR/issue-72845.rs:44:1
3+
|
4+
LL | impl<T: Spec1> Foo for T {
5+
| ------------------------ first implementation here
6+
...
7+
LL | impl<T: Spec2> Foo for T {
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0119`.

src/test/ui/consts/const-eval/const-eval-query-stack.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ error[E0080]: evaluation of constant value failed
2020
LL | let x: &'static i32 = &X;
2121
| ^ referenced constant has errors
2222
query stack during panic:
23-
#0 [normalize_mir_const_after_erasing_regions] normalizing `main::promoted[1]`
23+
#0 [try_normalize_mir_const_after_erasing_regions] normalizing `main::promoted[1]`
2424
#1 [optimized_mir] optimizing MIR for `main`
2525
#2 [collect_and_partition_mono_items] collect_and_partition_mono_items
2626
end of query stack

0 commit comments

Comments
 (0)