Skip to content

Commit d83abe8

Browse files
authored
Rollup merge of #100522 - cjgillot:inline-polymorphic-recursion, r=tmiasko
Only check the `DefId` for the recursion check in MIR inliner. The current history check compares `Instance`s, so it cannot detect cases of polymorphic recursion where `Substs` change. This PR makes it so we only compare `DefId`s, ignoring any change in `Substs`. According to #100522 (comment), in practice only very few inlining decisions change. Fixes #100476
2 parents 3cebcba + 86645c9 commit d83abe8

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

compiler/rustc_mir_transform/src/inline.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_middle::mir::*;
1010
use rustc_middle::ty::subst::Subst;
1111
use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
1212
use rustc_session::config::OptLevel;
13+
use rustc_span::def_id::DefId;
1314
use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span};
1415
use rustc_target::spec::abi::Abi;
1516

@@ -103,8 +104,12 @@ struct Inliner<'tcx> {
103104
param_env: ParamEnv<'tcx>,
104105
/// Caller codegen attributes.
105106
codegen_fn_attrs: &'tcx CodegenFnAttrs,
106-
/// Stack of inlined Instances.
107-
history: Vec<ty::Instance<'tcx>>,
107+
/// Stack of inlined instances.
108+
/// We only check the `DefId` and not the substs because we want to
109+
/// avoid inlining cases of polymorphic recursion.
110+
/// The number of `DefId`s is finite, so checking history is enough
111+
/// to ensure that we do not loop endlessly while inlining.
112+
history: Vec<DefId>,
108113
/// Indicates that the caller body has been modified.
109114
changed: bool,
110115
}
@@ -132,7 +137,7 @@ impl<'tcx> Inliner<'tcx> {
132137
Ok(new_blocks) => {
133138
debug!("inlined {}", callsite.callee);
134139
self.changed = true;
135-
self.history.push(callsite.callee);
140+
self.history.push(callsite.callee.def_id());
136141
self.process_blocks(caller_body, new_blocks);
137142
self.history.pop();
138143
}
@@ -308,7 +313,7 @@ impl<'tcx> Inliner<'tcx> {
308313
return None;
309314
}
310315

311-
if self.history.contains(&callee) {
316+
if self.history.contains(&callee.def_id()) {
312317
return None;
313318
}
314319

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Make sure that the MIR inliner does not loop indefinitely on polymorphic recursion.
2+
// compile-flags: --crate-type lib
3+
4+
// Randomize `def_path_hash` by defining them under a module with different names
5+
macro_rules! emit {
6+
($($m:ident)*) => {$(
7+
pub mod $m {
8+
pub trait Tr { type Next: Tr; }
9+
10+
pub fn hoge<const N: usize, T: Tr>() {
11+
inner::<N, T>();
12+
}
13+
14+
#[inline(always)]
15+
fn inner<const N: usize, T: Tr>()
16+
{
17+
inner::<N, T::Next>();
18+
inner::<N, T::Next>();
19+
}
20+
}
21+
)*};
22+
}
23+
24+
// Increase the chance of triggering the bug
25+
emit!(m00 m01 m02 m03 m04 m05 m06 m07 m08 m09 m10 m11 m12 m13 m14 m15 m16 m17 m18 m19);

0 commit comments

Comments
 (0)