Collision between extern-block fn and #[no_mangle] fn not detected
This code compiles and x::foo calls itself recursively.
#![crate_type="lib"]
extern {
fn foo();
}
pub mod x {
#[no_mangle]
pub unsafe extern "C" fn foo() { ::foo() }
}
https://play.rust-lang.org/?gist=dc191ae3cfb84887ba39bbf327a2e6fe&version=stable&backtrace=1
We don't end up seeing a re-definition because the foo in the extern block only creates a declaration.
EDIT: Here's an example that is actually a problem we should probably prevent:
#![crate_type="lib"]
extern {
fn foo(x: i32);
}
pub mod x {
#[no_mangle]
pub unsafe extern "C" fn foo() { ::foo(0) }
}
This happily compiles, and probably shouldn't.
I have code which (ab)uses this behaviour for doing exactly this (well, not calling recursively) and wouldn’t consider it a bug.
Simonas Kazlauskas at 2016-09-19 09:49:21
I also don't see it as a bug. The
externdeclaration says "hey,foois defined somewhere, don't complain if I call it". "Somewhere" can be right here.Alex Burka at 2016-09-19 11:30:02
The problem is that this also works:
#![crate_type="lib"] extern { fn foo(x: i32); } pub mod x { #[no_mangle] pub unsafe extern "C" fn foo() { ::foo(0) } }So now there are different signatures which can lead to bad things happening at runtime.
James Miller at 2016-09-19 22:15:16
Might be an interesting exercise to try make rust recognize this particular case, but its not that much different from the signature mismatch case between different compilation units, which we have no real way of handling. (i.e.
// stuff.c void foo() {}// stuff.rs extern { fn foo(x: i32) })
As for implementation strategy, we already check that the same symbol is not defined (note: defined as opposed to declared); we could check for signature mismatch there as well.
Simonas Kazlauskas at 2016-09-19 23:29:21