3

I wanted to create a function pointer using the reference operator:

fn main() {
    let fcn_ptr = &add;

    println!("{:p}", fcn_ptr);
    println!("{}", fcn_ptr(10, 10));
}

fn add(x: i32, y: i32) -> i32 {
    x + y
}

The compiler output:

warning: taking a reference to a function item does not give a function pointer
 --> src/main.rs:4:22
  |
4 |     println!("{:p}", fcn_ptr);
  |                      ^^^^^^^ help: cast `add` to obtain a function pointer: `add as fn(_, _) -> _`
  |
  = note: `#[warn(function_item_references)]` on by default

And the execution output:

0x55c0890fa000
20

What are the reasons behind the warning?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Yousuf
  • 153
  • 1
  • 1
  • 9
  • 1
    @Shepmaster actually the OP coming from C++ background is relevant here (not sure if this should be included, just noting). – Chayim Friedman May 10 '22 at 16:17
  • 1
    @ChayimFriedman I disagree. In your answer, you explain the problem for someone with a C++ background, and that's fine, but that doesn't mean that all the answers should be required to do so. In fact, it's better if they don't only use that so that other people without that background can benefit from the solutions / insights. That said, I won't be mad if you edit it back in in a way that flows well with the rest of the prose. – Shepmaster May 10 '22 at 16:21
  • 1
    related: https://stackoverflow.com/questions/64298245/in-rust-what-is-fn – trent May 10 '22 at 17:24

2 Answers2

2

fcn_ptr contains a reference to the function item, not a function pointer.

Anything that is sensible to do with a reference to a function item can be done instead with the function item itself. So, (except perhaps for some generic code, which isn't the case here) there's no legitimate reason to take a reference to a function item, and the most sensible interpretation is that you wanted a function pointer. The warning is to alert you to this mistake (hkBst's answer shows that it is a mistake).

You will need to cast your function item into a function pointer if you want the latter, as the compiler suggests:

fn main() {
    let fcn_ptr = add as fn(_, _) -> _;

    println!("{:p}", fcn_ptr);
    println!("{}", fcn_ptr(10, 10));
}

fn add(x: i32, y: i32) -> i32 {
    x + y
}
trent
  • 25,033
  • 7
  • 51
  • 90
jh316
  • 901
  • 7
  • 9
  • 1
    This answer would be improved by explaining _why_ the warning exists. – Shepmaster May 10 '22 at 16:27
  • @Shepmaster Thank you for your edits. Regarding why the warning exists, isn't it self-explanatory that the warning exists because the user intended to use a function item as a function pointer, even though it is not one? – jh316 May 10 '22 at 16:38
  • Can you explain what a function item is? I recognize that it's covered in the first link, but the answer would read better if it were explained inline IMO. – John Kugelman May 10 '22 at 21:39
1

Following the advice of the compiler and comparing the results shows that we get a difference:

fn main() {
    let fcn_ref = &add;
    let fcn_ptr = &(add as fn(_, _) -> _);

    // these print different values!
    println!("{:p}", fcn_ptr);
    println!("{:p}", fcn_ref); // warning: taking a reference to a function item does not give a function pointer
}

fn add(x: i32, y: i32) -> i32 {
    x + y
}

Example output:

0x56098b65a088
0x56098b64c000
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
hkBst
  • 2,818
  • 10
  • 29
  • 1
    Functions are data, they are saved in the program's binary as sequences of bytes that make sense to the CPU. A function pointer holds the address of the start of that sequence. So `fcn_ptr` holds the address of the first byte where the `add` function is saved. When we refer to a function by its name, we get a zero-sized value of the function's item type. So `fcn_ref` holds the address of a zero-sized value of the function's item types. Zero-sized type doesn't contain any data so it doesn't need to allocate memory, then why does the `fcn_ref` still hold a memory address(`0x56098b64c000`)? – Yousuf May 19 '22 at 09:22
  • @Yousuf, I don't know the reason for the difference between function pointer and function reference, and I don't know the rules for taking the address of a zero-sized type. – hkBst May 19 '22 at 12:53