Skip to content

Commit 3ce4b4f

Browse files
Auto merge of #146096 - adwinwhite:handle_normalization_overflow_in_mono1, r=<try>
Fix normalization overflow ICEs in monomorphization
2 parents 9d82de1 + b8baaaa commit 3ce4b4f

25 files changed

+234
-13
lines changed

compiler/rustc_middle/src/query/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2709,6 +2709,11 @@ rustc_queries! {
27092709
cache_on_disk_if { true }
27102710
}
27112711

2712+
query has_normalization_error_in_mono(key: ty::Instance<'tcx>) -> bool {
2713+
desc { "checking whether {}'s body has post-analysis normalization error", key }
2714+
cache_on_disk_if { true }
2715+
}
2716+
27122717
query size_estimate(key: ty::Instance<'tcx>) -> usize {
27132718
desc { "estimating codegen size of `{}`", key }
27142719
cache_on_disk_if { true }

compiler/rustc_monomorphize/src/collector.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@
208208
mod autodiff;
209209

210210
use std::cell::OnceCell;
211+
use std::ops::ControlFlow;
211212

212213
use rustc_data_structures::fx::FxIndexMap;
213214
use rustc_data_structures::sync::{MTLock, par_for_each_in};
@@ -228,7 +229,7 @@ use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion};
228229
use rustc_middle::ty::layout::ValidityRequirement;
229230
use rustc_middle::ty::{
230231
self, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable,
231-
TypeVisitableExt, VtblEntry,
232+
TypeVisitable, TypeVisitableExt, TypeVisitor, VtblEntry,
232233
};
233234
use rustc_middle::util::Providers;
234235
use rustc_middle::{bug, span_bug};
@@ -473,6 +474,23 @@ fn collect_items_rec<'tcx>(
473474
recursion_limit,
474475
));
475476

477+
// Plenty of code paths later assume that everything can be normalized.
478+
// Check normalization here to provide better diagnostics.
479+
// Normalization errors here are usually due to trait solving overflow.
480+
// FIXME: I assume that there are few type errors at post-analysis stage, but not
481+
// entirely sure.
482+
if tcx.has_normalization_error_in_mono(instance) {
483+
let def_id = instance.def_id();
484+
let def_span = tcx.def_span(def_id);
485+
let def_path_str = tcx.def_path_str(def_id);
486+
tcx.dcx().emit_fatal(RecursionLimit {
487+
span: starting_item.span,
488+
instance,
489+
def_span,
490+
def_path_str,
491+
});
492+
}
493+
476494
rustc_data_structures::stack::ensure_sufficient_stack(|| {
477495
let (used, mentioned) = tcx.items_of_instance((instance, mode));
478496
used_items.extend(used.into_iter().copied());
@@ -603,6 +621,33 @@ fn collect_items_rec<'tcx>(
603621
}
604622
}
605623

624+
// Check whether we can normalize the MIR body. Make it a query since decoding MIR from disk cache
625+
// may be expensive.
626+
fn has_normalization_error_in_mono<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool {
627+
struct NormalizationChecker<'tcx> {
628+
tcx: TyCtxt<'tcx>,
629+
instance: Instance<'tcx>,
630+
}
631+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for NormalizationChecker<'tcx> {
632+
type Result = ControlFlow<()>;
633+
634+
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
635+
match self.instance.try_instantiate_mir_and_normalize_erasing_regions(
636+
self.tcx,
637+
ty::TypingEnv::fully_monomorphized(),
638+
ty::EarlyBinder::bind(t),
639+
) {
640+
Ok(_) => ControlFlow::Continue(()),
641+
Err(_) => ControlFlow::Break(()),
642+
}
643+
}
644+
}
645+
646+
let body = tcx.instance_mir(instance.def);
647+
let mut checker = NormalizationChecker { tcx, instance };
648+
body.visit_with(&mut checker).is_break()
649+
}
650+
606651
fn check_recursion_limit<'tcx>(
607652
tcx: TyCtxt<'tcx>,
608653
instance: Instance<'tcx>,
@@ -1770,4 +1815,5 @@ pub(crate) fn collect_crate_mono_items<'tcx>(
17701815
pub(crate) fn provide(providers: &mut Providers) {
17711816
providers.hooks.should_codegen_locally = should_codegen_locally;
17721817
providers.items_of_instance = items_of_instance;
1818+
providers.has_normalization_error_in_mono = has_normalization_error_in_mono;
17731819
}

compiler/rustc_traits/src/normalize_erasing_regions.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,18 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + Par
4242
// us a test case.
4343
debug_assert_eq!(normalized_value, resolved_value);
4444
let erased = infcx.tcx.erase_and_anonymize_regions(resolved_value);
45-
debug_assert!(!erased.has_infer(), "{erased:?}");
45+
if infcx.next_trait_solver() {
46+
debug_assert!(!erased.has_infer(), "{erased:?}");
47+
} else {
48+
// The old solver returns an ty var with the failed obligation in case of
49+
// selection error. And when the obligation is re-tried, the error should be
50+
// reported. However in case of overflow error, the obligation may be fulfilled
51+
// due to the original depth being dropped.
52+
// In conclusion, overflow results in an unconstrained ty var.
53+
if erased.has_infer() {
54+
return Err(NoSolution);
55+
}
56+
}
4657
Ok(erased)
4758
}
4859
Err(NoSolution) => Err(NoSolution),

tests/crashes/105275.rs renamed to tests/ui/codegen/normalization-overflow/recursion-issue-105275.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
//@ known-bug: #105275
1+
//@ build-fail
22
//@ compile-flags: -Copt-level=0
33

44
pub fn encode_num<Writer: ExampleWriter>(n: u32, mut writer: Writer) -> Result<(), Writer::Error> {
55
if n > 15 {
66
encode_num(n / 16, &mut writer)?;
7+
//~^ ERROR: reached the recursion limit while instantiating
78
}
89
Ok(())
910
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: reached the recursion limit while instantiating `encode_num::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Error>`
2+
--> $DIR/recursion-issue-105275.rs:6:9
3+
|
4+
LL | encode_num(n / 16, &mut writer)?;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
note: `encode_num` defined here
8+
--> $DIR/recursion-issue-105275.rs:4:1
9+
|
10+
LL | pub fn encode_num<Writer: ExampleWriter>(n: u32, mut writer: Writer) -> Result<(), Writer::Error> {
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: aborting due to 1 previous error
14+

tests/crashes/105937.rs renamed to tests/ui/codegen/normalization-overflow/recursion-issue-105937.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
//@ known-bug: #105937
1+
//@ build-fail
22
//@ compile-flags: -Copt-level=0
33

44
pub fn encode_num<Writer: ExampleWriter>(n: u32, mut writer: Writer) -> Result<(), Writer::Error> {
55
if n > 15 {
66
encode_num(n / 16, &mut writer)?;
7+
//~^ ERROR: reached the recursion limit while instantiating
78
}
89
Ok(())
910
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: reached the recursion limit while instantiating `encode_num::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Error>`
2+
--> $DIR/recursion-issue-105937.rs:6:9
3+
|
4+
LL | encode_num(n / 16, &mut writer)?;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
note: `encode_num` defined here
8+
--> $DIR/recursion-issue-105937.rs:4:1
9+
|
10+
LL | pub fn encode_num<Writer: ExampleWriter>(n: u32, mut writer: Writer) -> Result<(), Writer::Error> {
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: aborting due to 1 previous error
14+

tests/crashes/117696-1.rs renamed to tests/ui/codegen/normalization-overflow/recursion-issue-117696-1.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ known-bug: #117696
1+
//@ build-fail
22
fn main() {
33
let mut it = (Empty);
44
rec(&mut it);
@@ -23,6 +23,7 @@ where
2323
{
2424
if () == () {
2525
T::count(it);
26+
//~^ ERROR: reached the recursion limit while instantiating
2627
} else {
2728
rec(identity(&mut it))
2829
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: reached the recursion limit while instantiating `<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Empty as Iterator>::count`
2+
--> $DIR/recursion-issue-117696-1.rs:25:9
3+
|
4+
LL | T::count(it);
5+
| ^^^^^^^^^^^^
6+
|
7+
note: `count` defined here
8+
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
9+
10+
error: aborting due to 1 previous error
11+

tests/crashes/117696-2.rs renamed to tests/ui/codegen/normalization-overflow/recursion-issue-117696-2.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ known-bug: #117696
1+
//@ build-fail
22
//@ compile-flags: -Copt-level=0
33
fn main() {
44
rec(&mut None::<()>.into_iter());
@@ -9,5 +9,6 @@ fn rec<T: Iterator>(mut it: T) {
99
it.next();
1010
} else {
1111
rec(&mut it);
12+
//~^ ERROR: reached the recursion limit while instantiating
1213
}
1314
}

0 commit comments

Comments
 (0)