inliner: Break inlining cycles
When examining candidates for inlining, reject those that are determined to be recursive either because of self-recursive calls or calls to any instances already inlined.
This commit is contained in:
parent
b7f16c56d1
commit
dc4d74d149
4 changed files with 243 additions and 107 deletions
60
src/test/mir-opt/inline/inline-cycle.rs
Normal file
60
src/test/mir-opt/inline/inline-cycle.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Check that inliner handles various forms of recursion and doesn't fall into
|
||||
// an infinite inlining cycle. The particular outcome of inlining is not
|
||||
// crucial otherwise.
|
||||
//
|
||||
// Regression test for issue #78573.
|
||||
|
||||
fn main() {
|
||||
one();
|
||||
two();
|
||||
}
|
||||
|
||||
// EMIT_MIR inline_cycle.one.Inline.diff
|
||||
fn one() {
|
||||
<C as Call>::call();
|
||||
}
|
||||
|
||||
pub trait Call {
|
||||
fn call();
|
||||
}
|
||||
|
||||
pub struct A<T>(T);
|
||||
pub struct B<T>(T);
|
||||
pub struct C;
|
||||
|
||||
impl<T: Call> Call for A<T> {
|
||||
#[inline]
|
||||
fn call() {
|
||||
<B<T> as Call>::call()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T: Call> Call for B<T> {
|
||||
#[inline]
|
||||
fn call() {
|
||||
<T as Call>::call()
|
||||
}
|
||||
}
|
||||
|
||||
impl Call for C {
|
||||
#[inline]
|
||||
fn call() {
|
||||
A::<C>::call()
|
||||
}
|
||||
}
|
||||
|
||||
// EMIT_MIR inline_cycle.two.Inline.diff
|
||||
fn two() {
|
||||
call(f);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn call<F: FnOnce()>(f: F) {
|
||||
f();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn f() {
|
||||
call(f);
|
||||
}
|
||||
27
src/test/mir-opt/inline/inline_cycle.one.Inline.diff
Normal file
27
src/test/mir-opt/inline/inline_cycle.one.Inline.diff
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
- // MIR for `one` before Inline
|
||||
+ // MIR for `one` after Inline
|
||||
|
||||
fn one() -> () {
|
||||
let mut _0: (); // return place in scope 0 at $DIR/inline-cycle.rs:13:10: 13:10
|
||||
let _1: (); // in scope 0 at $DIR/inline-cycle.rs:14:5: 14:24
|
||||
+ scope 1 (inlined <C as Call>::call) { // at $DIR/inline-cycle.rs:14:5: 14:24
|
||||
+ }
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1); // scope 0 at $DIR/inline-cycle.rs:14:5: 14:24
|
||||
- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle.rs:14:5: 14:24
|
||||
+ _1 = <A<C> as Call>::call() -> bb1; // scope 1 at $DIR/inline-cycle.rs:14:5: 14:24
|
||||
// mir::Constant
|
||||
- // + span: $DIR/inline-cycle.rs:14:5: 14:22
|
||||
- // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(Scalar(<ZST>)) }
|
||||
+ // + span: $DIR/inline-cycle.rs:14:5: 14:24
|
||||
+ // + literal: Const { ty: fn() {<A<C> as Call>::call}, val: Value(Scalar(<ZST>)) }
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageDead(_1); // scope 0 at $DIR/inline-cycle.rs:14:24: 14:25
|
||||
_0 = const (); // scope 0 at $DIR/inline-cycle.rs:13:10: 15:2
|
||||
return; // scope 0 at $DIR/inline-cycle.rs:15:2: 15:2
|
||||
}
|
||||
}
|
||||
|
||||
47
src/test/mir-opt/inline/inline_cycle.two.Inline.diff
Normal file
47
src/test/mir-opt/inline/inline_cycle.two.Inline.diff
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
- // MIR for `two` before Inline
|
||||
+ // MIR for `two` after Inline
|
||||
|
||||
fn two() -> () {
|
||||
let mut _0: (); // return place in scope 0 at $DIR/inline-cycle.rs:48:10: 48:10
|
||||
let _1: (); // in scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ let mut _2: fn() {f}; // in scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ let mut _5: (); // in scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ scope 1 (inlined call::<fn() {f}>) { // at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ debug f => _2; // in scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ let _3: (); // in scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ let mut _4: fn() {f}; // in scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ }
|
||||
+ }
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1); // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
- _1 = call::<fn() {f}>(f) -> bb1; // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ StorageLive(_2); // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ _2 = f; // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
// mir::Constant
|
||||
- // + span: $DIR/inline-cycle.rs:49:5: 49:9
|
||||
- // + literal: Const { ty: fn(fn() {f}) {call::<fn() {f}>}, val: Value(Scalar(<ZST>)) }
|
||||
- // mir::Constant
|
||||
// + span: $DIR/inline-cycle.rs:49:10: 49:11
|
||||
// + literal: Const { ty: fn() {f}, val: Value(Scalar(<ZST>)) }
|
||||
+ StorageLive(_3); // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ StorageLive(_4); // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ _4 = move _2; // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ StorageLive(_5); // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ _5 = const (); // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ _3 = move _4() -> bb1; // scope 2 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
}
|
||||
|
||||
bb1: {
|
||||
+ StorageDead(_5); // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ StorageDead(_4); // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ StorageDead(_3); // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ _1 = const (); // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
+ StorageDead(_2); // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
|
||||
StorageDead(_1); // scope 0 at $DIR/inline-cycle.rs:49:12: 49:13
|
||||
_0 = const (); // scope 0 at $DIR/inline-cycle.rs:48:10: 50:2
|
||||
return; // scope 0 at $DIR/inline-cycle.rs:50:2: 50:2
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue