Closed
Description
Turns out this is not only inconvenient, but also a serious problem.
// bar.rs
pub fn foo<T>() -> &'static int {
if false {
static a: int = 4;
return &a;
} else {
static a: int = 5;
return &a;
}
}
pub fn bar() -> &'static int {
foo::<int>()
}
// foo.rs
extern mod bar;
fn main() {
let a = bar::bar();
let b = bar::foo::<int>();
println!("{} {}", *a, *b);
}
$ rustc --lib bar.rs
warning: missing crate link meta `name`, using `bar` as default
warning: missing crate link meta `vers`, using `0.0` as default
warning: no debug symbols in executable (-arch x86_64)
$ rustc foo.rs -L.
warning: no debug symbols in executable (-arch x86_64)
$ ./foo
5 4
Here's what's happening (to the best of my knowledge):
- When compiling
bar.rs
, the same symbol name, N, is generated for both statics. LLVM will silently rename the second to N1, so we have N = 4, N1 = 5. Note that both statics are walked through because this is a generic function, meaning that we still walk the statics to emit them into this crate (may have to do that for inner functions as well). - The function
bar
is resolved in-crate, and because the symbol names have already been generated,N1
will be returned (5). - When compiling
foo.rs
, the functionbar::foo
is again instantiated, but this time we have our clever optimization which ignores the first block of theif
statement, hence only one of the statics is translated. In this case, it's declared with the name N. - When linking is done, the version of
bar::foo
inbar
returns N1, and the version ofbar::foo
infoo
returns N, hence the difference.
There's a lot of things going wrong here, and I'm not entirely sure why, but I think that this would all be fixed if inner statics had different symbol names (no silent renamings from LLVM).