rust-lang / rfcs

RFCs for changes to Rust
https://rust-lang.github.io/rfcs/
Apache License 2.0
5.95k stars 1.57k forks source link

Make it possible to use the same function name when "wrapping" a function in an extern block #1436

Closed thesam closed 8 years ago

thesam commented 8 years ago

The following example won't work since there's a duplicate definition of "exit".

It would be nice if the public function could be defined as "syscall::exit" even though the function in the extern block is also called "exit".

Input:

mod syscall {
    extern {
        fn exit() -> ();
    }

    pub fn exit() {
        unsafe { exit() }
    }
}

fn main() {
    syscall::exit();
}

Output:

poc.rs:6:5: 8:6 error: duplicate definition of value `exit` [E0428]
poc.rs:6     pub fn exit() {
poc.rs:7         unsafe { exit() }
poc.rs:8     }
poc.rs:6:5: 8:6 help: run `rustc --explain E0428` to see a detailed explanation
poc.rs:3:9: 3:25 note: first definition of value `exit` here
poc.rs:3         fn exit() -> ();
                 ^~~~~~~~~~~~~~~~
error: aborting due to previous error

As a workaround, a nested module can be added to avoid the name clash:

mod syscall {
    mod ffi {
        extern {
            pub fn exit() -> ();
        }
    }

    pub fn exit() {
        unsafe { ffi::exit() }
    }
}

fn main() {
    syscall::exit();
}
nagisa commented 8 years ago

Here’s the question: which exit does the syscall::exit refer to in exit? If it is the rust exit function, that’s infinite recursion. If it is the extern function, how would one ever recurse to the rust function?

To me this special case doesn’t make sense, even if it looks OKish in your provided usecase.

thesam commented 8 years ago

Thank you for replying! "exit" may have been a poor example. It is not the Rust exit function. Let me clarify my usecase a little bit:

I am trying to port the xv6 "teaching operating system" to Rust, starting by porting the userspace applications while keeping the kernel in C. For example, echo: https://github.com/mit-pdos/xv6-public/blob/master/echo.c

Echo uses the user.h header file (https://github.com/mit-pdos/xv6-public/blob/master/user.h) to be able to call "exit". I want to do this from Rust instead and that's why I'm making a thin Rust wrapper for user.h.

When writing the wrapper I found it a bit inconvenient that I couldn't use the original function name for my safe wrapper function. In the FFI examples I've seen the Rust wrapper function always has another name, but in this case I think it would feel a bit forced to call it something other than "exit".

My workaround with the nested module lets me define the public syscall::exit function like I want to, but ideally I would like to be able to do something like this, inspired by the "use x as y" syntax:

mod syscall {
    extern {
        pub fn exit() -> () as real_exit;
    }

    pub fn exit() {
        unsafe { real_exit() }
    }
}

fn main() {
    syscall::exit();
}
nagisa commented 8 years ago

It is not the Rust exit function.

pub fn exit() {} is a function with rust ABI, or, in short, a rust function.

My workaround with the nested module lets me define the public syscall::exit function like I want to, but ideally I would like to be able to do something like this, inspired by the "use x as y" syntax:

AFAIK module scoping (like you shown in the alternative) is the way to do this, possibly with reexports if desired:

mod syscall {
    mod ffi {
        extern { pub fn exit() -> () }
    }
    pub use self::ffi::exit as real_exit;
    pub fn exit() { unsafe { real_exit() } }
}
// both syscall::exit (safe binding) and syscall::real_exit (ffi binding) are available.

Alternatively, we have a link_name attribute:

extern {
    #[link_name="exit"]
    pub fn myawesomeffiexit() -> ();
}

All in all, I do not see the immediate necessity to implement this, as we have tools to do both renaming and exporting extern functions in various ways.

thesam commented 8 years ago

I wasn't familiar with "link_name", but it is exactly what I was looking for! Thank you very much. I'll close this RFC.