1 // compile-flags: -O --target=avr-unknown-gnu-atmega328 --crate-type=rlib
2 // needs-llvm-components: avr
3 
4 // This test validates that function pointers can be stored in global variables
5 // and called upon. It ensures that Rust emits function pointers in the correct
6 // address space to LLVM so that an assertion error relating to casting is
7 // not triggered.
8 //
9 // It also validates that functions can be called through function pointers
10 // through traits.
11 
12 #![feature(no_core, lang_items, unboxed_closures, arbitrary_self_types)]
13 #![crate_type = "lib"]
14 #![no_core]
15 
16 #[lang = "sized"]
17 pub trait Sized { }
18 #[lang = "copy"]
19 pub trait Copy { }
20 #[lang = "receiver"]
21 pub trait Receiver { }
22 
23 pub struct Result<T, E> { _a: T, _b: E }
24 
25 impl Copy for usize {}
26 impl Copy for &usize {}
27 
28 #[lang = "drop_in_place"]
drop_in_place<T: ?Sized>(_: *mut T)29 pub unsafe fn drop_in_place<T: ?Sized>(_: *mut T) {}
30 
31 #[lang = "fn_once"]
32 pub trait FnOnce<Args> {
33     #[lang = "fn_once_output"]
34     type Output;
35 
call_once(self, args: Args) -> Self::Output36     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
37 }
38 
39 #[lang = "fn_mut"]
40 pub trait FnMut<Args> : FnOnce<Args> {
call_mut(&mut self, args: Args) -> Self::Output41     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
42 }
43 
44 #[lang = "fn"]
45 pub trait Fn<Args>: FnOnce<Args> {
46     /// Performs the call operation.
call(&self, args: Args) -> Self::Output47     extern "rust-call" fn call(&self, args: Args) -> Self::Output;
48 }
49 
50 impl<'a, A, R> FnOnce<A> for &'a fn(A) -> R {
51     type Output = R;
52 
call_once(self, args: A) -> R53     extern "rust-call" fn call_once(self, args: A) -> R {
54         (*self)(args)
55     }
56 }
57 
58 pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box;
59 pub static mut STORAGE_BAR: u32 = 12;
60 
arbitrary_black_box(ptr: &usize, _: &mut u32) -> Result<(), ()>61 fn arbitrary_black_box(ptr: &usize, _: &mut u32) -> Result<(), ()> {
62     let raw_ptr = ptr as *const usize;
63     let _v: usize = unsafe { *raw_ptr };
64     loop {}
65 }
66 
67 #[inline(never)]
68 #[no_mangle]
call_through_fn_trait(a: &mut impl Fn<(), Output=()>)69 fn call_through_fn_trait(a: &mut impl Fn<(), Output=()>) {
70     (*a)()
71 }
72 
73 #[inline(never)]
update_bar_value()74 fn update_bar_value() {
75     unsafe {
76         STORAGE_BAR = 88;
77     }
78 }
79 
80 // CHECK: define void @test(){{.+}}addrspace(1)
81 #[no_mangle]
test()82 pub extern "C" fn test() {
83     let mut buf = 7;
84 
85     // A call through the Fn trait must use address space 1.
86     //
87     // CHECK: call{{.+}}addrspace(1) void @call_through_fn_trait()
88     call_through_fn_trait(&mut update_bar_value);
89 
90     // A call through a global variable must use address space 1.
91     // CHECK: load {{.*}}addrspace(1){{.+}}FOO
92     unsafe {
93         STORAGE_FOO(&1, &mut buf);
94     }
95 }
96