diff options
| author | Dylan DPC <99973273+Dylan-DPC@users.noreply.github.com> | 2022-08-19 12:26:43 +0530 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-19 12:26:43 +0530 |
| commit | d83abe8c123e4a59edafffe9825ce3f398d31aa6 (patch) | |
| tree | 97dd0606e5b1c8a9b2ffcd9e6353f5068d8d99fc | |
| parent | 3cebcbaaeb7defb2627af13dd7853e4eca6c3527 (diff) | |
| parent | 86645c9cf7e7a73e01c006c8bc39c431cae0e8df (diff) | |
| download | rust-d83abe8c123e4a59edafffe9825ce3f398d31aa6.tar.gz rust-d83abe8c123e4a59edafffe9825ce3f398d31aa6.zip | |
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 https://github.com/rust-lang/rust/pull/100522#issuecomment-1214769757, in practice only very few inlining decisions change. Fixes https://github.com/rust-lang/rust/issues/100476
| -rw-r--r-- | compiler/rustc_mir_transform/src/inline.rs | 13 | ||||
| -rw-r--r-- | src/test/mir-opt/inline/polymorphic-recursion.rs | 25 |
2 files changed, 34 insertions, 4 deletions
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 1e46b0a0e81..6704d3462f4 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -10,6 +10,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; use rustc_session::config::OptLevel; +use rustc_span::def_id::DefId; use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span}; use rustc_target::spec::abi::Abi; @@ -103,8 +104,12 @@ struct Inliner<'tcx> { param_env: ParamEnv<'tcx>, /// Caller codegen attributes. codegen_fn_attrs: &'tcx CodegenFnAttrs, - /// Stack of inlined Instances. - history: Vec<ty::Instance<'tcx>>, + /// Stack of inlined instances. + /// We only check the `DefId` and not the substs because we want to + /// avoid inlining cases of polymorphic recursion. + /// The number of `DefId`s is finite, so checking history is enough + /// to ensure that we do not loop endlessly while inlining. + history: Vec<DefId>, /// Indicates that the caller body has been modified. changed: bool, } @@ -132,7 +137,7 @@ impl<'tcx> Inliner<'tcx> { Ok(new_blocks) => { debug!("inlined {}", callsite.callee); self.changed = true; - self.history.push(callsite.callee); + self.history.push(callsite.callee.def_id()); self.process_blocks(caller_body, new_blocks); self.history.pop(); } @@ -308,7 +313,7 @@ impl<'tcx> Inliner<'tcx> { return None; } - if self.history.contains(&callee) { + if self.history.contains(&callee.def_id()) { return None; } diff --git a/src/test/mir-opt/inline/polymorphic-recursion.rs b/src/test/mir-opt/inline/polymorphic-recursion.rs new file mode 100644 index 00000000000..7388722b776 --- /dev/null +++ b/src/test/mir-opt/inline/polymorphic-recursion.rs @@ -0,0 +1,25 @@ +// Make sure that the MIR inliner does not loop indefinitely on polymorphic recursion. +// compile-flags: --crate-type lib + +// Randomize `def_path_hash` by defining them under a module with different names +macro_rules! emit { + ($($m:ident)*) => {$( + pub mod $m { + pub trait Tr { type Next: Tr; } + + pub fn hoge<const N: usize, T: Tr>() { + inner::<N, T>(); + } + + #[inline(always)] + fn inner<const N: usize, T: Tr>() + { + inner::<N, T::Next>(); + inner::<N, T::Next>(); + } + } + )*}; +} + +// Increase the chance of triggering the bug +emit!(m00 m01 m02 m03 m04 m05 m06 m07 m08 m09 m10 m11 m12 m13 m14 m15 m16 m17 m18 m19); |
