Skip to content

Commit fbddf9b

Browse files
Auto merge of #146096 - adwinwhite:handle_normalization_overflow_in_mono1, r=<try>
Fix normalization overflow ICEs in monomorphization
2 parents 54a8a1d + 152fd34 commit fbddf9b

26 files changed

+235
-12
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/mono_checks/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ use rustc_middle::ty::{Instance, TyCtxt};
77

88
mod abi_check;
99
mod move_check;
10+
mod normalization_check;
1011

1112
fn check_mono_item<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
1213
let body = tcx.instance_mir(instance.def);
14+
15+
normalization_check::check_normalization_error(tcx, instance, body);
1316
abi_check::check_feature_dependent_abi(tcx, instance, body);
1417
move_check::check_moves(tcx, instance, body);
1518
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use std::ops::ControlFlow;
2+
3+
use rustc_middle::mir::Body;
4+
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitable, TypeVisitor};
5+
6+
use crate::errors::RecursionLimit;
7+
8+
struct NormalizationChecker<'tcx> {
9+
tcx: TyCtxt<'tcx>,
10+
instance: Instance<'tcx>,
11+
}
12+
13+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for NormalizationChecker<'tcx> {
14+
type Result = ControlFlow<()>;
15+
16+
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
17+
match self.instance.try_instantiate_mir_and_normalize_erasing_regions(
18+
self.tcx,
19+
ty::TypingEnv::fully_monomorphized(),
20+
ty::EarlyBinder::bind(t),
21+
) {
22+
Ok(_) => ControlFlow::Continue(()),
23+
Err(_) => ControlFlow::Break(()),
24+
}
25+
}
26+
}
27+
28+
pub(crate) fn check_normalization_error<'tcx>(
29+
tcx: TyCtxt<'tcx>,
30+
instance: Instance<'tcx>,
31+
body: &Body<'tcx>,
32+
) {
33+
let mut checker = NormalizationChecker { tcx, instance };
34+
if body.visit_with(&mut checker).is_break() {
35+
// Plenty of code paths later assume that everything can be normalized.
36+
// Check normalization here to provide better diagnostics.
37+
// Normalization errors here are usually due to trait solving overflow.
38+
// FIXME: I assume that there are few type errors at post-analysis stage, but not
39+
// entirely sure.
40+
let def_id = instance.def_id();
41+
let def_span = tcx.def_span(def_id);
42+
let def_path_str = tcx.def_path_str(def_id);
43+
tcx.dcx().emit_fatal(RecursionLimit { span: def_span, instance, def_span, def_path_str });
44+
}
45+
}

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+

0 commit comments

Comments
 (0)