Skip to content

Commit 798353f

Browse files
committed
add some ui nd codegen test skeletons
1 parent 0864097 commit 798353f

File tree

5 files changed

+237
-0
lines changed

5 files changed

+237
-0
lines changed

tests/ui/codegen/tail-call-become.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
@ compile-flags: -C opt-level=0 -Cpanic=abort -C no-prepopulate-passes
2+
//@ needs-llvm-components: x86
3+
4+
#![feature(explicit_tail_calls)]
5+
#![crate_type = "lib"]
6+
7+
// CHECK-LABEL: define {{.*}}@with_tail(
8+
#[no_mangle]
9+
#[inline(never)]
10+
pub fn with_tail(n: u32) -> u32 {
11+
// CHECK: tail call {{.*}}@with_tail(
12+
if n == 0 { 0 } else { become with_tail(n - 1) }
13+
}
14+
15+
// CHECK-LABEL: define {{.*}}@no_tail(
16+
#[no_mangle]
17+
#[inline(never)]
18+
pub fn no_tail(n: u32) -> u32 {
19+
// CHECK-NOT: tail call
20+
// CHECK: call {{.*}}@no_tail(
21+
if n == 0 { 0 } else { no_tail(n - 1) }
22+
}
23+
24+
// CHECK-LABEL: define {{.*}}@even_with_tail(
25+
#[no_mangle]
26+
#[inline(never)]
27+
pub fn even_with_tail(n: u32) -> bool {
28+
// CHECK: tail call {{.*}}@odd_with_tail(
29+
match n {
30+
0 => true,
31+
_ => become odd_with_tail(n - 1),
32+
}
33+
}
34+
35+
// CHECK-LABEL: define {{.*}}@odd_with_tail(
36+
#[no_mangle]
37+
#[inline(never)]
38+
pub fn odd_with_tail(n: u32) -> bool {
39+
// CHECK: tail call {{.*}}@even_with_tail(
40+
match n {
41+
0 => false,
42+
_ => become even_with_tail(n - 1),
43+
}
44+
}
45+
46+
// CHECK-LABEL: define {{.*}}@even_no_tail(
47+
#[no_mangle]
48+
#[inline(never)]
49+
pub fn even_no_tail(n: u32) -> bool {
50+
// CHECK-NOT: tail call
51+
// CHECK: call {{.*}}@odd_no_tail(
52+
match n {
53+
0 => true,
54+
_ => odd_no_tail(n - 1),
55+
}
56+
}
57+
58+
// CHECK-LABEL: define {{.*}}@odd_no_tail(
59+
#[no_mangle]
60+
#[inline(never)]
61+
pub fn odd_no_tail(n: u32) -> bool {
62+
// CHECK-NOT: tail call
63+
// CHECK: call {{.*}}@even_no_tail(
64+
match n {
65+
0 => false,
66+
_ => even_no_tail(n - 1),
67+
}
68+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//@ compile-flags: -C opt-level=0 -Cpanic=abort -C no-prepopulate-passes
2+
//@ needs-unwind
3+
4+
#![crate_type = "lib"]
5+
#![feature(explicit_tail_calls)]
6+
7+
// Ensure that explicit tail calls use musttail in LLVM
8+
9+
// CHECK-LABEL: define {{.*}}@simple_tail_call(
10+
#[no_mangle]
11+
#[inline(never)]
12+
pub fn simple_tail_call(n: i32) -> i32 {
13+
// CHECK: musttail call {{.*}}@simple_tail_call(
14+
// CHECK-NEXT: ret i32
15+
if n <= 0 {
16+
0
17+
} else {
18+
become simple_tail_call(n - 1)
19+
}
20+
}
21+
22+
// CHECK-LABEL: define {{.*}}@tail_call_with_args(
23+
#[no_mangle]
24+
#[inline(never)]
25+
pub fn tail_call_with_args(a: i32, b: i32, c: i32) -> i32 {
26+
// CHECK: musttail call {{.*}}@tail_call_with_args(
27+
// CHECK-NEXT: ret i32
28+
if a == 0 {
29+
b + c
30+
} else {
31+
become tail_call_with_args(a - 1, b + 1, c)
32+
}
33+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//@ compile-flags: -O
2+
//@ run-pass
3+
#![expect(incomplete_features)]
4+
#![feature(explicit_tail_calls)]
5+
6+
// A deep recursive function that uses explicit tail calls
7+
// This will cause stack overflow without tail call optimization
8+
fn deep_recursion(n: u32) -> u32 {
9+
match n {
10+
0 => 0,
11+
_ => become deep_recursion(n - 1)
12+
}
13+
}
14+
15+
// A deep recursive function without explicit tail calls
16+
// This will overflow the stack for large values
17+
fn deep_recursion_no_tail(n: u32) -> u32 {
18+
match n {
19+
0 => 0,
20+
_ => deep_recursion_no_tail(n - 1)
21+
}
22+
}
23+
24+
fn main() {
25+
// Verify correctness for small values
26+
assert_eq!(deep_recursion(10), 0);
27+
assert_eq!(deep_recursion_no_tail(10), 0);
28+
29+
// This will succeed only if tail call optimization is working
30+
// It would overflow the stack otherwise
31+
println!("Starting deep recursion with 50,000 calls");
32+
let result = deep_recursion(50_000);
33+
assert_eq!(result, 0);
34+
println!("Successfully completed 50,000 recursive calls with tail call optimization");
35+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//@ run-pass
2+
#![expect(incomplete_features)]
3+
#![feature(explicit_tail_calls)]
4+
5+
// This is a classic example of mutual recursion:
6+
// even(n) calls odd(n-1), and odd(n) calls even(n-1)
7+
// Without tail calls, this would quickly overflow the stack for large inputs
8+
9+
// Check if a number is even using mutual recursion
10+
fn is_even(n: u64) -> bool {
11+
match n {
12+
0 => true,
13+
_ => become is_odd(n - 1)
14+
}
15+
}
16+
17+
// Check if a number is odd using mutual recursion
18+
fn is_odd(n: u64) -> bool {
19+
match n {
20+
0 => false,
21+
_ => become is_even(n - 1)
22+
}
23+
}
24+
25+
// Versions without tail calls for comparison
26+
fn is_even_no_tail(n: u64) -> bool {
27+
match n {
28+
0 => true,
29+
_ => is_odd_no_tail(n - 1)
30+
}
31+
}
32+
33+
fn is_odd_no_tail(n: u64) -> bool {
34+
match n {
35+
0 => false,
36+
_ => is_even_no_tail(n - 1)
37+
}
38+
}
39+
40+
fn main() {
41+
// Verify correctness for small values
42+
assert_eq!(is_even(0), true);
43+
assert_eq!(is_odd(0), false);
44+
assert_eq!(is_even(1), false);
45+
assert_eq!(is_odd(1), true);
46+
assert_eq!(is_even(10), true);
47+
assert_eq!(is_odd(10), false);
48+
49+
// Test with an extremely large number that would definitely overflow the stack
50+
// without tail call optimization - each call creates 2 stack frames (alternating between functions)
51+
// so 100,000 would create 200,000 stack frames total
52+
assert_eq!(is_even(100_000), true);
53+
assert_eq!(is_odd(100_000), false);
54+
assert_eq!(is_even(100_001), false);
55+
assert_eq!(is_odd(100_001), true);
56+
57+
println!("Deep mutual recursion test passed with 100,000 alternating recursive calls!");
58+
59+
// Verify non-tail versions work for small values
60+
assert_eq!(is_even_no_tail(10), true);
61+
assert_eq!(is_odd_no_tail(10), false);
62+
// But would overflow for large values (not tested to avoid crashing)
63+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//@ run-pass
2+
#![expect(incomplete_features)]
3+
#![feature(explicit_tail_calls)]
4+
5+
// A function that causes deep recursion - counts down from n to 0
6+
// Without tail calls, this would overflow the stack for large n values
7+
fn countdown(n: u32) -> u32 {
8+
match n {
9+
0 => 0,
10+
_ => become countdown(n - 1)
11+
}
12+
}
13+
14+
// Same function but without tail call optimization
15+
fn countdown_no_tail(n: u32) -> u32 {
16+
match n {
17+
0 => 0,
18+
_ => countdown_no_tail(n - 1)
19+
}
20+
}
21+
22+
// This test is specifically designed to verify tail call optimization
23+
// We use an extremely large recursion depth (500,000) that would
24+
// absolutely overflow the stack without tail call optimization
25+
fn main() {
26+
// Small test to verify correctness
27+
assert_eq!(countdown(10), 0);
28+
29+
// Regular recursion would overflow here (500,000 stack frames)
30+
// Only works if tail call optimization is actually happening
31+
let result = countdown(500_000);
32+
assert_eq!(result, 0);
33+
println!("Successfully completed 500,000 recursive calls with tail call optimization");
34+
35+
// We can't test the non-tail version with a large number as it would crash,
36+
// but we can verify it works for small values
37+
assert_eq!(countdown_no_tail(10), 0);
38+
}

0 commit comments

Comments
 (0)