Skip to content

Commit ced6c93

Browse files
committed
Add more tail call tests
1 parent c8b602a commit ced6c93

File tree

6 files changed

+199
-0
lines changed

6 files changed

+199
-0
lines changed

tests/codegen/explicit-tail-calls.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// min-llvm-version: 15.0 (for opaque pointers)
33
#![crate_type = "lib"]
44
#![feature(explicit_tail_calls)]
5+
#![feature(c_variadic)]
56

67
/// Something that is likely to be passed indirectly
78
#[repr(C)]
@@ -70,6 +71,33 @@ fn pair_g() -> (u32, u8) {
7071
}
7172

7273

74+
#[no_mangle]
75+
// CHECK-LABEL: @extern_c_f(i32 noundef %x)
76+
pub extern "C" fn extern_c_f(x: u32) -> u8 {
77+
unsafe {
78+
// CHECK: %0 = musttail call noundef i8 @extern_c_g(i32 noundef %x)
79+
// CHECK: ret i8 %0
80+
become extern_c_g(x);
81+
}
82+
}
83+
84+
extern "C" {
85+
fn extern_c_g(x: u32) -> u8;
86+
}
87+
88+
89+
#[no_mangle]
90+
// CHECK-LABEL: @c_variadic_f(i8 noundef %x, ...)
91+
pub unsafe extern "C" fn c_variadic_f(x: u8, ...) {
92+
// CHECK: musttail call void (i8, ...) @c_variadic_g(i8 noundef %_3, ...)
93+
// CHECK: ret void
94+
become c_variadic_g(x + 1)
95+
}
96+
97+
#[no_mangle]
98+
pub unsafe extern "C" fn c_variadic_g(_: u8, ...) {}
99+
100+
73101
#[no_mangle]
74102
/// Does `src + dst` in a recursive way
75103
// CHECK-LABEL: @flow(
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// run-pass
2+
#![feature(explicit_tail_calls)]
3+
#![feature(c_variadic)]
4+
5+
pub unsafe extern "C" fn c_variadic_f(x: u8, mut args: ...) {
6+
assert_eq!(x, 12);
7+
let (a, b) = (args.arg::<u32>(), args.arg::<u32>());
8+
become c_variadic_g(x + 1, a, b, 3u32);
9+
}
10+
11+
pub unsafe extern "C" fn c_variadic_g(x: u8, mut args: ...) {
12+
assert_eq!(x, 13);
13+
assert_eq!(args.arg::<u32>(), 1);
14+
assert_eq!(args.arg::<u32>(), 2);
15+
assert_eq!(args.arg::<u32>(), 3);
16+
}
17+
18+
fn main() {
19+
unsafe { c_variadic_f(12u8, 1u32, 2u32) };
20+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// run-pass
2+
#![feature(explicit_tail_calls)]
3+
use std::panic::Location;
4+
5+
fn main() {
6+
assert_eq!(get_caller_location().line(), 6);
7+
assert_eq!(get_caller_location().line(), 7);
8+
}
9+
10+
#[track_caller]
11+
fn get_caller_location() -> &'static Location<'static> {
12+
#[track_caller]
13+
fn inner() -> &'static Location<'static> {
14+
become Location::caller()
15+
}
16+
17+
become inner()
18+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// run-pass
2+
3+
fn fibonacci(n: u32) -> u128 {
4+
fibonacci_impl(n, 0, 1)
5+
}
6+
7+
fn fibonacci_impl(left: u32, prev_prev: u128, prev: u128) -> u128 {
8+
match left {
9+
0 => prev_prev,
10+
1 => prev,
11+
_ => fibonacci_impl(left - 1, prev, prev_prev + prev),
12+
}
13+
}
14+
15+
fn main() {
16+
let expected =
17+
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181];
18+
assert!((0..20).map(fibonacci).eq(expected));
19+
20+
// This is the highest fibonacci number that fits in a u128
21+
assert_eq!(
22+
std::hint::black_box(fibonacci(std::hint::black_box(186))),
23+
332825110087067562321196029789634457848
24+
);
25+
}

tests/ui/explicit-tail-calls/ll.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// revisions: tail nose
2+
//[tail] run-pass
3+
//[nose] run-fail
4+
#![feature(explicit_tail_calls)]
5+
6+
fn main() {
7+
with_smol_stack(|| List::from_elem((), 1024 * 32).rec_drop());
8+
}
9+
10+
struct List<T> {
11+
next: Option<Box<Node<T>>>,
12+
}
13+
14+
struct Node<T> {
15+
elem: T,
16+
next: Option<Box<Node<T>>>,
17+
}
18+
19+
impl<T> List<T> {
20+
fn from_elem(elem: T, n: usize) -> Self
21+
where
22+
T: Clone,
23+
{
24+
List { next: None }.prepend_n(elem, n)
25+
}
26+
27+
fn prepend_n(self, elem: T, n: usize) -> Self
28+
where
29+
T: Clone,
30+
{
31+
match n {
32+
0 => self,
33+
1 => Self { next: p(Node { elem, next: self.next }) },
34+
_ => {
35+
#[cfg(tail)]
36+
become Self { next: p(Node { elem: elem.clone(), next: self.next }) }
37+
.prepend_n(elem, n - 1);
38+
39+
#[cfg(nose)]
40+
return Self { next: p(Node { elem: elem.clone(), next: self.next }) }
41+
.prepend_n(elem, n - 1);
42+
}
43+
}
44+
}
45+
46+
fn rec_drop(self) {
47+
if let Some(node) = self.next {
48+
node.rec_drop()
49+
}
50+
}
51+
}
52+
53+
impl<T> Node<T> {
54+
fn rec_drop(self) {
55+
if let Some(node) = self.next {
56+
_ = node.elem;
57+
become node.rec_drop()
58+
}
59+
}
60+
}
61+
62+
fn p<T>(v: T) -> Option<Box<T>> {
63+
Some(Box::new(v))
64+
}
65+
66+
fn with_smol_stack(f: impl FnOnce() + Send + 'static) {
67+
std::thread::Builder::new()
68+
.stack_size(1024 /* bytes */)
69+
.name("smol thread".to_owned())
70+
.spawn(f)
71+
.unwrap()
72+
.join()
73+
.unwrap();
74+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// run-pass
2+
#![feature(explicit_tail_calls)]
3+
4+
fn fold<T, S>(slice: &[T], x: S, mut f: impl FnMut(S, &T) -> S) -> S {
5+
match slice {
6+
[] => x,
7+
[head, tail @ ..] => become fold(tail, f(x, head), f),
8+
}
9+
}
10+
11+
fn main() {
12+
let numbers = [
13+
11, 49, 81, 32, 33, 52, 121, 28, 64, 106, 99, 101, 110, 84, 123, 66, 80, 88, 94, 21, 65,
14+
85, 3, 54, 46, 69, 116, 26, 72, 114, 71, 86, 125, 70, 42, 68, 40, 91, 56, 22, 36, 115, 117,
15+
120, 18, 105, 30, 74, 63, 108, 43, 25, 122, 55, 104, 92, 12, 37, 20, 58, 35, 95, 98, 53,
16+
93, 100, 5, 112, 8, 78, 126, 102, 90, 97, 13, 51, 118, 62, 128, 34, 38, 4, 24, 6, 59, 48,
17+
44, 73, 7, 107, 61, 60, 14, 16, 111, 119, 96, 17, 57, 45, 15, 79, 10, 1, 124, 39, 9, 19,
18+
109, 127, 41, 47, 87, 76, 89, 50, 2, 23, 29, 27, 75, 103, 113, 77, 83, 67, 31, 82, 11, 71,
19+
67, 39, 64, 66, 100, 9, 92, 21, 35, 12, 6, 91, 62, 85, 13, 79, 98, 95, 30, 24, 38, 3, 78,
20+
99, 60, 25, 15, 82, 75, 97, 80, 2, 8, 16, 7, 19, 57, 26, 81, 33, 5, 47, 58, 68, 93, 52, 69,
21+
53, 49, 87, 73, 84, 76, 63, 48, 14, 34, 10, 56, 41, 20, 59, 96, 61, 42, 74, 88, 17, 43, 72,
22+
50, 37, 1, 70, 83, 45, 89, 90, 94, 18, 4, 31, 44, 36, 23, 29, 46, 55, 40, 77, 28, 32, 86,
23+
65, 54, 27, 22, 51, 8, 21, 36, 65, 66, 20, 6, 77, 94, 55, 32, 45, 12, 98, 28, 91, 64, 18,
24+
43, 70, 13, 73, 69, 85, 2, 39, 4, 11, 84, 71, 74, 23, 10, 40, 83, 9, 72, 62, 63, 25, 53,
25+
15, 96, 95, 68, 37, 79, 26, 76, 87, 89, 81, 51, 61, 5, 34, 44, 1, 46, 17, 86, 78, 82, 27,
26+
56, 41, 47, 90, 75, 92, 22, 50, 54, 97, 67, 57, 59, 42, 100, 35, 7, 24, 3, 19, 38, 58, 93,
27+
30, 49, 14, 99, 33, 48, 80, 31, 88, 52, 16, 29, 60,
28+
];
29+
30+
let expected = numbers.iter().sum();
31+
let res = fold(&numbers, 0, |s, &e| s + e);
32+
33+
assert_eq!(res, expected);
34+
}

0 commit comments

Comments
 (0)